ruby-sfml 3.0.0.0 → 3.0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +130 -0
- data/README.md +34 -45
- data/lib/sfml/audio/internal.rb +41 -0
- data/lib/sfml/audio/listener.rb +31 -0
- data/lib/sfml/audio/music.rb +64 -0
- data/lib/sfml/audio/sound.rb +82 -0
- data/lib/sfml/audio/sound_cone.rb +56 -0
- data/lib/sfml/audio/sound_stream.rb +206 -0
- data/lib/sfml/c/audio.rb +78 -0
- data/lib/sfml/c/graphics.rb +51 -0
- data/lib/sfml/c/network.rb +104 -0
- data/lib/sfml/c/system.rb +10 -0
- data/lib/sfml/c/window.rb +42 -0
- data/lib/sfml/graphics/image.rb +23 -0
- data/lib/sfml/graphics/render_states.rb +5 -3
- data/lib/sfml/graphics/render_target.rb +23 -2
- data/lib/sfml/graphics/render_window.rb +55 -0
- data/lib/sfml/graphics/shader.rb +71 -11
- data/lib/sfml/graphics/stencil_mode.rb +93 -0
- data/lib/sfml/graphics/vertex_buffer.rb +127 -0
- data/lib/sfml/network/ftp.rb +184 -0
- data/lib/sfml/network/http.rb +117 -0
- data/lib/sfml/network/socket_selector.rb +93 -0
- data/lib/sfml/version.rb +1 -1
- data/lib/sfml/window/event.rb +14 -0
- data/lib/sfml/window/sensor.rb +50 -0
- data/lib/sfml/window/touch.rb +39 -0
- data/lib/sfml/window/window.rb +57 -0
- data/lib/sfml.rb +27 -2
- metadata +11 -1
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
module SFML
|
|
2
|
+
# Procedural audio source. Subclass it and override `#on_get_data`
|
|
3
|
+
# to fill each chunk on demand — CSFML invokes the callback from
|
|
4
|
+
# its audio thread whenever the sound queue runs low.
|
|
5
|
+
#
|
|
6
|
+
# `#on_get_data` returns either:
|
|
7
|
+
# * an Array (or anything responding to `#to_a`) of Int16 PCM
|
|
8
|
+
# samples — they're packed into a buffer and handed to CSFML;
|
|
9
|
+
# * `nil` to stop the stream.
|
|
10
|
+
#
|
|
11
|
+
# Override `#on_seek(time)` to support `playing_offset=`. Default
|
|
12
|
+
# is a no-op (the next callback continues from wherever the
|
|
13
|
+
# subclass internal state happens to be).
|
|
14
|
+
#
|
|
15
|
+
# class SineWave < SFML::SoundStream
|
|
16
|
+
# def initialize(freq:, sample_rate: 44_100)
|
|
17
|
+
# super(channel_count: 1, sample_rate: sample_rate)
|
|
18
|
+
# @freq, @sample_rate = freq, sample_rate
|
|
19
|
+
# @phase = 0.0
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# def on_get_data
|
|
23
|
+
# n = @sample_rate / 10 # ~100ms chunks
|
|
24
|
+
# step = 2 * Math::PI * @freq / @sample_rate
|
|
25
|
+
# Array.new(n) do
|
|
26
|
+
# s = (Math.sin(@phase) * 30_000).to_i
|
|
27
|
+
# @phase = (@phase + step) % (2 * Math::PI)
|
|
28
|
+
# s
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# def on_seek(time)
|
|
33
|
+
# @phase = 0.0
|
|
34
|
+
# end
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
# CAVEATS
|
|
38
|
+
# * The callback runs on the SFML audio thread; doing heavy work
|
|
39
|
+
# there will glitch the audio. Generate samples and return.
|
|
40
|
+
# * Ruby threads still need the GVL — your callback acquires it
|
|
41
|
+
# each invocation. Long Ruby work on the main thread can starve
|
|
42
|
+
# the audio thread and produce dropouts.
|
|
43
|
+
# * Always keep a reference to the SoundStream object (assign to a
|
|
44
|
+
# variable, store in an instance var). If the Ruby object is GC'd
|
|
45
|
+
# while CSFML is still calling callbacks, the process crashes.
|
|
46
|
+
class SoundStream
|
|
47
|
+
DEFAULT_CHUNK_FRAMES = 4096
|
|
48
|
+
|
|
49
|
+
def initialize(channel_count:, sample_rate:)
|
|
50
|
+
raise ArgumentError, "channel_count must be >= 1" if channel_count < 1
|
|
51
|
+
raise ArgumentError, "sample_rate must be > 0" if sample_rate < 1
|
|
52
|
+
|
|
53
|
+
# Hold strong refs so neither GC nor reload disposes the
|
|
54
|
+
# callbacks while CSFML is still calling them.
|
|
55
|
+
@get_data_cb = FFI::Function.new(:bool, [:pointer, :pointer]) do |chunk_ptr, _user|
|
|
56
|
+
_on_get_data_callback(chunk_ptr)
|
|
57
|
+
end
|
|
58
|
+
@seek_cb = FFI::Function.new(:void, [C::System::Time.by_value, :pointer]) do |time, _user|
|
|
59
|
+
on_seek(Time.from_native(time))
|
|
60
|
+
nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
ptr = C::Audio.sfSoundStream_create(
|
|
64
|
+
@get_data_cb, @seek_cb,
|
|
65
|
+
Integer(channel_count), Integer(sample_rate),
|
|
66
|
+
nil, 0,
|
|
67
|
+
nil,
|
|
68
|
+
)
|
|
69
|
+
raise Error, "sfSoundStream_create returned NULL" if ptr.null?
|
|
70
|
+
|
|
71
|
+
@handle = FFI::AutoPointer.new(ptr, C::Audio.method(:sfSoundStream_destroy))
|
|
72
|
+
|
|
73
|
+
# We re-use a single MemoryPointer for the sample buffer,
|
|
74
|
+
# growing it on demand. CSFML reads from the pointer between
|
|
75
|
+
# callbacks, then asks for the next chunk — by the time we
|
|
76
|
+
# overwrite, CSFML is done with the previous data.
|
|
77
|
+
@sample_buffer = nil
|
|
78
|
+
@sample_buffer_capacity = 0
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# ---- Subclass hooks ------------------------------------------------
|
|
82
|
+
|
|
83
|
+
# Return an Array of Int16 PCM samples (interleaved if multi-channel),
|
|
84
|
+
# or `nil` to stop the stream. Default raises so subclasses must
|
|
85
|
+
# implement it.
|
|
86
|
+
def on_get_data
|
|
87
|
+
raise NoMethodError, "#{self.class} must override #on_get_data"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Called when the user changes the playing offset. Default is a
|
|
91
|
+
# no-op — override if your stream tracks position internally
|
|
92
|
+
# (counters, file offsets, etc.).
|
|
93
|
+
def on_seek(_time); end
|
|
94
|
+
|
|
95
|
+
# ---- Public playback API ------------------------------------------
|
|
96
|
+
|
|
97
|
+
def play = (C::Audio.sfSoundStream_play(@handle); self)
|
|
98
|
+
def pause = (C::Audio.sfSoundStream_pause(@handle); self)
|
|
99
|
+
def stop = (C::Audio.sfSoundStream_stop(@handle); self)
|
|
100
|
+
|
|
101
|
+
def status = C::Audio::STATUSES[C::Audio.sfSoundStream_getStatus(@handle)]
|
|
102
|
+
def playing? = status == :playing
|
|
103
|
+
def paused? = status == :paused
|
|
104
|
+
def stopped? = status == :stopped
|
|
105
|
+
|
|
106
|
+
def channel_count = C::Audio.sfSoundStream_getChannelCount(@handle)
|
|
107
|
+
def sample_rate = C::Audio.sfSoundStream_getSampleRate(@handle)
|
|
108
|
+
|
|
109
|
+
# Cached on the Ruby side; some OpenAL backends (notably the
|
|
110
|
+
# headless null sink we get on Linux CI) don't reliably read
|
|
111
|
+
# the loop flag back through CSFML once it's been set.
|
|
112
|
+
def looping?
|
|
113
|
+
@looping == true
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def looping=(value)
|
|
117
|
+
@looping = !!value
|
|
118
|
+
C::Audio.sfSoundStream_setLooping(@handle, @looping)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def volume = C::Audio.sfSoundStream_getVolume(@handle)
|
|
122
|
+
|
|
123
|
+
def volume=(value)
|
|
124
|
+
C::Audio.sfSoundStream_setVolume(@handle, value.to_f)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def pitch = C::Audio.sfSoundStream_getPitch(@handle)
|
|
128
|
+
|
|
129
|
+
def pitch=(value)
|
|
130
|
+
C::Audio.sfSoundStream_setPitch(@handle, value.to_f)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def playing_offset
|
|
134
|
+
Time.from_native(C::Audio.sfSoundStream_getPlayingOffset(@handle))
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def playing_offset=(value)
|
|
138
|
+
t = value.is_a?(Time) ? value : Time.seconds(value.to_f)
|
|
139
|
+
C::Audio.sfSoundStream_setPlayingOffset(@handle, t.to_native)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def position
|
|
143
|
+
v = C::Audio.sfSoundStream_getPosition(@handle)
|
|
144
|
+
Vector3.new(v[:x], v[:y], v[:z])
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def position=(value)
|
|
148
|
+
v = value.is_a?(Vector3) ? value : Vector3.new(*value)
|
|
149
|
+
packed = C::System::Vector3f.new
|
|
150
|
+
packed[:x] = v.x.to_f; packed[:y] = v.y.to_f; packed[:z] = v.z.to_f
|
|
151
|
+
C::Audio.sfSoundStream_setPosition(@handle, packed)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def attenuation = C::Audio.sfSoundStream_getAttenuation(@handle)
|
|
155
|
+
|
|
156
|
+
def attenuation=(value)
|
|
157
|
+
C::Audio.sfSoundStream_setAttenuation(@handle, value.to_f)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def min_distance = C::Audio.sfSoundStream_getMinDistance(@handle)
|
|
161
|
+
|
|
162
|
+
def min_distance=(value)
|
|
163
|
+
C::Audio.sfSoundStream_setMinDistance(@handle, value.to_f)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def relative_to_listener? = C::Audio.sfSoundStream_isRelativeToListener(@handle)
|
|
167
|
+
|
|
168
|
+
def relative_to_listener=(value)
|
|
169
|
+
C::Audio.sfSoundStream_setRelativeToListener(@handle, !!value)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
attr_reader :handle # :nodoc:
|
|
173
|
+
|
|
174
|
+
private
|
|
175
|
+
|
|
176
|
+
# Bridge between CSFML's chunk struct and our user-facing
|
|
177
|
+
# `#on_get_data`. Runs on the audio thread.
|
|
178
|
+
def _on_get_data_callback(chunk_ptr)
|
|
179
|
+
samples = on_get_data
|
|
180
|
+
chunk = C::Audio::SoundStreamChunk.new(chunk_ptr)
|
|
181
|
+
|
|
182
|
+
if samples.nil?
|
|
183
|
+
chunk[:samples] = FFI::Pointer::NULL
|
|
184
|
+
chunk[:sample_count] = 0
|
|
185
|
+
return false
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
arr = samples.respond_to?(:to_a) ? samples.to_a : samples
|
|
189
|
+
n = arr.length
|
|
190
|
+
|
|
191
|
+
_grow_sample_buffer(n)
|
|
192
|
+
@sample_buffer.write_array_of_int16(arr) if n > 0
|
|
193
|
+
|
|
194
|
+
chunk[:samples] = @sample_buffer
|
|
195
|
+
chunk[:sample_count] = n
|
|
196
|
+
true
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def _grow_sample_buffer(n)
|
|
200
|
+
return if @sample_buffer && @sample_buffer_capacity >= n
|
|
201
|
+
|
|
202
|
+
@sample_buffer_capacity = [n, DEFAULT_CHUNK_FRAMES].max
|
|
203
|
+
@sample_buffer = FFI::MemoryPointer.new(:int16, @sample_buffer_capacity)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
data/lib/sfml/c/audio.rb
CHANGED
|
@@ -12,6 +12,13 @@ module SFML
|
|
|
12
12
|
# sfSoundStatus = { sfStopped, sfPaused, sfPlaying } in that order.
|
|
13
13
|
STATUSES = %i[stopped paused playing].freeze
|
|
14
14
|
|
|
15
|
+
# Plain-old-data struct that mirrors sfSoundSourceCone.
|
|
16
|
+
class SoundSourceCone < FFI::Struct
|
|
17
|
+
layout :inner_angle, :float,
|
|
18
|
+
:outer_angle, :float,
|
|
19
|
+
:outer_gain, :float
|
|
20
|
+
end
|
|
21
|
+
|
|
15
22
|
# ---- SoundBuffer ----
|
|
16
23
|
attach_function :sfSoundBuffer_createFromFile, [:string], :sound_buffer_t
|
|
17
24
|
attach_function :sfSoundBuffer_destroy, [:sound_buffer_t], :void
|
|
@@ -44,6 +51,19 @@ module SFML
|
|
|
44
51
|
attach_function :sfSound_getAttenuation, [:sound_t], :float
|
|
45
52
|
attach_function :sfSound_setRelativeToListener, [:sound_t, :bool], :void
|
|
46
53
|
attach_function :sfSound_isRelativeToListener, [:sound_t], :bool
|
|
54
|
+
attach_function :sfSound_setPlayingOffset, [:sound_t, System::Time.by_value], :void
|
|
55
|
+
attach_function :sfSound_getPlayingOffset, [:sound_t], System::Time.by_value
|
|
56
|
+
attach_function :sfSound_setVelocity, [:sound_t, System::Vector3f.by_value], :void
|
|
57
|
+
attach_function :sfSound_getVelocity, [:sound_t], System::Vector3f.by_value
|
|
58
|
+
attach_function :sfSound_setDopplerFactor, [:sound_t, :float], :void
|
|
59
|
+
attach_function :sfSound_getDopplerFactor, [:sound_t], :float
|
|
60
|
+
attach_function :sfSound_setDirection, [:sound_t, System::Vector3f.by_value], :void
|
|
61
|
+
attach_function :sfSound_getDirection, [:sound_t], System::Vector3f.by_value
|
|
62
|
+
attach_function :sfSound_setCone, [:sound_t, SoundSourceCone.by_value], :void
|
|
63
|
+
attach_function :sfSound_getCone, [:sound_t], SoundSourceCone.by_value
|
|
64
|
+
# void(*)(const float* in, unsigned int* in_count, float* out, unsigned int* out_count, unsigned int channels, void* userData)
|
|
65
|
+
callback :sf_effect_processor, [:pointer, :pointer, :pointer, :pointer, :uint32, :pointer], :void
|
|
66
|
+
attach_function :sfSound_setEffectProcessor, [:sound_t, :sf_effect_processor, :pointer], :void
|
|
47
67
|
|
|
48
68
|
# ---- Music ----
|
|
49
69
|
attach_function :sfMusic_createFromFile, [:string], :music_t
|
|
@@ -68,6 +88,60 @@ module SFML
|
|
|
68
88
|
attach_function :sfMusic_getAttenuation, [:music_t], :float
|
|
69
89
|
attach_function :sfMusic_setRelativeToListener, [:music_t, :bool], :void
|
|
70
90
|
attach_function :sfMusic_isRelativeToListener, [:music_t], :bool
|
|
91
|
+
attach_function :sfMusic_setPlayingOffset, [:music_t, System::Time.by_value], :void
|
|
92
|
+
attach_function :sfMusic_getPlayingOffset, [:music_t], System::Time.by_value
|
|
93
|
+
attach_function :sfMusic_setVelocity, [:music_t, System::Vector3f.by_value], :void
|
|
94
|
+
attach_function :sfMusic_getVelocity, [:music_t], System::Vector3f.by_value
|
|
95
|
+
attach_function :sfMusic_setDopplerFactor, [:music_t, :float], :void
|
|
96
|
+
attach_function :sfMusic_getDopplerFactor, [:music_t], :float
|
|
97
|
+
attach_function :sfMusic_setDirection, [:music_t, System::Vector3f.by_value], :void
|
|
98
|
+
attach_function :sfMusic_getDirection, [:music_t], System::Vector3f.by_value
|
|
99
|
+
attach_function :sfMusic_setCone, [:music_t, SoundSourceCone.by_value], :void
|
|
100
|
+
attach_function :sfMusic_getCone, [:music_t], SoundSourceCone.by_value
|
|
101
|
+
attach_function :sfMusic_setEffectProcessor, [:music_t, :sf_effect_processor, :pointer], :void
|
|
102
|
+
|
|
103
|
+
# ---- SoundStream ----
|
|
104
|
+
# Custom audio source — fills a chunk via a Ruby callback that
|
|
105
|
+
# CSFML invokes from the audio thread. Beware: that callback
|
|
106
|
+
# has to acquire the GVL to run any Ruby code, so don't do
|
|
107
|
+
# heavy work there. Generate samples and return.
|
|
108
|
+
typedef :pointer, :sound_stream_t
|
|
109
|
+
|
|
110
|
+
class SoundStreamChunk < FFI::Struct
|
|
111
|
+
layout :samples, :pointer,
|
|
112
|
+
:sample_count, :uint32
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
callback :sound_stream_get_data, [:pointer, :pointer], :bool
|
|
116
|
+
callback :sound_stream_seek, [System::Time.by_value, :pointer], :void
|
|
117
|
+
|
|
118
|
+
attach_function :sfSoundStream_create,
|
|
119
|
+
[:sound_stream_get_data, :sound_stream_seek,
|
|
120
|
+
:uint32, :uint32, :pointer, :size_t, :pointer],
|
|
121
|
+
:sound_stream_t
|
|
122
|
+
attach_function :sfSoundStream_destroy, [:sound_stream_t], :void
|
|
123
|
+
attach_function :sfSoundStream_play, [:sound_stream_t], :void
|
|
124
|
+
attach_function :sfSoundStream_pause, [:sound_stream_t], :void
|
|
125
|
+
attach_function :sfSoundStream_stop, [:sound_stream_t], :void
|
|
126
|
+
attach_function :sfSoundStream_getChannelCount, [:sound_stream_t], :uint32
|
|
127
|
+
attach_function :sfSoundStream_getSampleRate, [:sound_stream_t], :uint32
|
|
128
|
+
attach_function :sfSoundStream_getStatus, [:sound_stream_t], :int
|
|
129
|
+
attach_function :sfSoundStream_setPlayingOffset, [:sound_stream_t, System::Time.by_value], :void
|
|
130
|
+
attach_function :sfSoundStream_getPlayingOffset, [:sound_stream_t], System::Time.by_value
|
|
131
|
+
attach_function :sfSoundStream_setLooping, [:sound_stream_t, :bool], :void
|
|
132
|
+
attach_function :sfSoundStream_isLooping, [:sound_stream_t], :bool
|
|
133
|
+
attach_function :sfSoundStream_setVolume, [:sound_stream_t, :float], :void
|
|
134
|
+
attach_function :sfSoundStream_getVolume, [:sound_stream_t], :float
|
|
135
|
+
attach_function :sfSoundStream_setPitch, [:sound_stream_t, :float], :void
|
|
136
|
+
attach_function :sfSoundStream_getPitch, [:sound_stream_t], :float
|
|
137
|
+
attach_function :sfSoundStream_setPosition, [:sound_stream_t, System::Vector3f.by_value], :void
|
|
138
|
+
attach_function :sfSoundStream_getPosition, [:sound_stream_t], System::Vector3f.by_value
|
|
139
|
+
attach_function :sfSoundStream_setMinDistance, [:sound_stream_t, :float], :void
|
|
140
|
+
attach_function :sfSoundStream_getMinDistance, [:sound_stream_t], :float
|
|
141
|
+
attach_function :sfSoundStream_setAttenuation, [:sound_stream_t, :float], :void
|
|
142
|
+
attach_function :sfSoundStream_getAttenuation, [:sound_stream_t], :float
|
|
143
|
+
attach_function :sfSoundStream_setRelativeToListener, [:sound_stream_t, :bool], :void
|
|
144
|
+
attach_function :sfSoundStream_isRelativeToListener, [:sound_stream_t], :bool
|
|
71
145
|
|
|
72
146
|
# ---- SoundBufferRecorder ----
|
|
73
147
|
# The simple "record into a SoundBuffer" path. Raw sfSoundRecorder
|
|
@@ -101,6 +175,10 @@ module SFML
|
|
|
101
175
|
attach_function :sfListener_getDirection, [], System::Vector3f.by_value
|
|
102
176
|
attach_function :sfListener_setUpVector, [System::Vector3f.by_value], :void
|
|
103
177
|
attach_function :sfListener_getUpVector, [], System::Vector3f.by_value
|
|
178
|
+
attach_function :sfListener_setVelocity, [System::Vector3f.by_value], :void
|
|
179
|
+
attach_function :sfListener_getVelocity, [], System::Vector3f.by_value
|
|
180
|
+
attach_function :sfListener_setCone, [SoundSourceCone.by_value], :void
|
|
181
|
+
attach_function :sfListener_getCone, [], SoundSourceCone.by_value
|
|
104
182
|
end
|
|
105
183
|
end
|
|
106
184
|
end
|
data/lib/sfml/c/graphics.rb
CHANGED
|
@@ -94,8 +94,17 @@ module SFML
|
|
|
94
94
|
attach_function :sfRenderWindow_setFramerateLimit, [:render_window_t, :uint32], :void
|
|
95
95
|
attach_function :sfRenderWindow_display, [:render_window_t], :void
|
|
96
96
|
attach_function :sfRenderWindow_clear, [:render_window_t, Color.by_value], :void
|
|
97
|
+
attach_function :sfRenderWindow_clearStencil, [:render_window_t, StencilValue.by_value], :void
|
|
98
|
+
attach_function :sfRenderWindow_clearColorAndStencil, [:render_window_t, Color.by_value, StencilValue.by_value], :void
|
|
97
99
|
attach_function :sfRenderWindow_getSize, [:render_window_t], System::Vector2u.by_value
|
|
98
100
|
attach_function :sfRenderWindow_setSize, [:render_window_t, System::Vector2u.by_value], :void
|
|
101
|
+
attach_function :sfRenderWindow_setIcon, [:render_window_t, System::Vector2u.by_value, :pointer], :void
|
|
102
|
+
|
|
103
|
+
typedef :pointer, :vertex_buffer_t
|
|
104
|
+
attach_function :sfRenderWindow_setMinimumSize, [:render_window_t, :pointer], :void
|
|
105
|
+
attach_function :sfRenderWindow_setMaximumSize, [:render_window_t, :pointer], :void
|
|
106
|
+
attach_function :sfRenderWindow_createFromHandle, [:pointer, :pointer], :render_window_t
|
|
107
|
+
attach_function :sfRenderWindow_getNativeHandle, [:render_window_t], :pointer
|
|
99
108
|
|
|
100
109
|
typedef :pointer, :texture_t
|
|
101
110
|
typedef :pointer, :render_texture_t
|
|
@@ -144,6 +153,10 @@ module SFML
|
|
|
144
153
|
[:render_window_t, :text_t, :render_states_t], :void
|
|
145
154
|
attach_function :sfRenderWindow_drawVertexArray,
|
|
146
155
|
[:render_window_t, :vertex_array_t, :render_states_t], :void
|
|
156
|
+
attach_function :sfRenderWindow_drawVertexBuffer,
|
|
157
|
+
[:render_window_t, :vertex_buffer_t, :render_states_t], :void
|
|
158
|
+
attach_function :sfRenderWindow_drawVertexBufferRange,
|
|
159
|
+
[:render_window_t, :vertex_buffer_t, :uint32, :uint32, :render_states_t], :void
|
|
147
160
|
|
|
148
161
|
# Mouse position queries relative to a render-window.
|
|
149
162
|
attach_function :sfMouse_getPositionRenderWindow,
|
|
@@ -151,6 +164,10 @@ module SFML
|
|
|
151
164
|
attach_function :sfMouse_setPositionRenderWindow,
|
|
152
165
|
[System::Vector2i.by_value, :render_window_t], :void
|
|
153
166
|
|
|
167
|
+
# Touch position relative to a render-window.
|
|
168
|
+
attach_function :sfTouch_getPositionRenderWindow,
|
|
169
|
+
[:uint32, :render_window_t], System::Vector2i.by_value
|
|
170
|
+
|
|
154
171
|
# ---- View ----
|
|
155
172
|
attach_function :sfView_create, [], :view_t
|
|
156
173
|
attach_function :sfView_createFromRect, [FloatRect.by_value], :view_t
|
|
@@ -206,6 +223,7 @@ module SFML
|
|
|
206
223
|
attach_function :sfImage_copy, [:image_t], :image_t
|
|
207
224
|
attach_function :sfImage_destroy, [:image_t], :void
|
|
208
225
|
attach_function :sfImage_saveToFile, [:image_t, :string], :bool
|
|
226
|
+
attach_function :sfImage_saveToMemory, [:image_t, :pointer, :string], :bool
|
|
209
227
|
attach_function :sfImage_getSize, [:image_t], System::Vector2u.by_value
|
|
210
228
|
attach_function :sfImage_setPixel, [:image_t, System::Vector2u.by_value, Color.by_value], :void
|
|
211
229
|
attach_function :sfImage_getPixel, [:image_t, System::Vector2u.by_value], Color.by_value
|
|
@@ -324,6 +342,9 @@ module SFML
|
|
|
324
342
|
attach_function :sfRenderTexture_setActive, [:render_texture_t, :bool], :bool
|
|
325
343
|
attach_function :sfRenderTexture_display, [:render_texture_t], :void
|
|
326
344
|
attach_function :sfRenderTexture_clear, [:render_texture_t, Color.by_value], :void
|
|
345
|
+
attach_function :sfRenderTexture_clearStencil, [:render_texture_t, StencilValue.by_value], :void
|
|
346
|
+
attach_function :sfRenderTexture_clearColorAndStencil,
|
|
347
|
+
[:render_texture_t, Color.by_value, StencilValue.by_value], :void
|
|
327
348
|
attach_function :sfRenderTexture_setView, [:render_texture_t, :view_t], :void
|
|
328
349
|
attach_function :sfRenderTexture_getView, [:render_texture_t], :view_t
|
|
329
350
|
attach_function :sfRenderTexture_getDefaultView, [:render_texture_t], :view_t
|
|
@@ -347,6 +368,9 @@ module SFML
|
|
|
347
368
|
attach_function :sfRenderTexture_drawConvexShape, [:render_texture_t, :convex_shape_t, :render_states_t], :void
|
|
348
369
|
attach_function :sfRenderTexture_drawText, [:render_texture_t, :text_t, :render_states_t], :void
|
|
349
370
|
attach_function :sfRenderTexture_drawVertexArray, [:render_texture_t, :vertex_array_t, :render_states_t], :void
|
|
371
|
+
attach_function :sfRenderTexture_drawVertexBuffer, [:render_texture_t, :vertex_buffer_t, :render_states_t], :void
|
|
372
|
+
attach_function :sfRenderTexture_drawVertexBufferRange,
|
|
373
|
+
[:render_texture_t, :vertex_buffer_t, :uint32, :uint32, :render_states_t], :void
|
|
350
374
|
|
|
351
375
|
# ---- Raw primitive drawing (without a VertexArray object) ----
|
|
352
376
|
attach_function :sfRenderWindow_drawPrimitives,
|
|
@@ -374,6 +398,33 @@ module SFML
|
|
|
374
398
|
attach_function :sfShader_setTextureUniform,[:shader_t, :string, :texture_t], :void
|
|
375
399
|
attach_function :sfShader_setCurrentTextureUniform, [:shader_t, :string], :void
|
|
376
400
|
|
|
401
|
+
# ---- VertexBuffer (static GPU vertex buffer) ----
|
|
402
|
+
# USAGE order matches sfVertexBufferUsage in CSFML.
|
|
403
|
+
VERTEX_BUFFER_USAGES = %i[stream dynamic static].freeze
|
|
404
|
+
|
|
405
|
+
attach_function :sfVertexBuffer_create, [:uint32, :int, :int], :vertex_buffer_t
|
|
406
|
+
attach_function :sfVertexBuffer_copy, [:vertex_buffer_t], :vertex_buffer_t
|
|
407
|
+
attach_function :sfVertexBuffer_destroy, [:vertex_buffer_t], :void
|
|
408
|
+
attach_function :sfVertexBuffer_getVertexCount, [:vertex_buffer_t], :uint32
|
|
409
|
+
attach_function :sfVertexBuffer_update, [:vertex_buffer_t, :pointer, :uint32, :uint32], :bool
|
|
410
|
+
attach_function :sfVertexBuffer_updateFromVertexBuffer,
|
|
411
|
+
[:vertex_buffer_t, :vertex_buffer_t], :bool
|
|
412
|
+
attach_function :sfVertexBuffer_swap, [:vertex_buffer_t, :vertex_buffer_t], :void
|
|
413
|
+
attach_function :sfVertexBuffer_getNativeHandle,[:vertex_buffer_t], :uint32
|
|
414
|
+
attach_function :sfVertexBuffer_setPrimitiveType,[:vertex_buffer_t, :int], :void
|
|
415
|
+
attach_function :sfVertexBuffer_getPrimitiveType,[:vertex_buffer_t], :int
|
|
416
|
+
attach_function :sfVertexBuffer_setUsage, [:vertex_buffer_t, :int], :void
|
|
417
|
+
attach_function :sfVertexBuffer_getUsage, [:vertex_buffer_t], :int
|
|
418
|
+
attach_function :sfVertexBuffer_isAvailable, [], :bool
|
|
419
|
+
|
|
420
|
+
# Bulk array uniform setters. The array argument is a packed
|
|
421
|
+
# buffer of N elements (N×{1,2,3,4} floats); the length argument
|
|
422
|
+
# is the *element* count, not the float count.
|
|
423
|
+
attach_function :sfShader_setFloatUniformArray, [:shader_t, :string, :pointer, :size_t], :void
|
|
424
|
+
attach_function :sfShader_setVec2UniformArray, [:shader_t, :string, :pointer, :size_t], :void
|
|
425
|
+
attach_function :sfShader_setVec3UniformArray, [:shader_t, :string, :pointer, :size_t], :void
|
|
426
|
+
attach_function :sfShader_setVec4UniformArray, [:shader_t, :string, :pointer, :size_t], :void
|
|
427
|
+
|
|
377
428
|
# ---- Font ----
|
|
378
429
|
attach_function :sfFont_createFromFile, [:string], :font_t
|
|
379
430
|
attach_function :sfFont_destroy, [:font_t], :void
|
data/lib/sfml/c/network.rb
CHANGED
|
@@ -74,6 +74,110 @@ module SFML
|
|
|
74
74
|
attach_function :sfPacket_append, [:packet_t, :pointer, :size_t], :void
|
|
75
75
|
attach_function :sfPacket_clear, [:packet_t], :void
|
|
76
76
|
attach_function :sfPacket_getData, [:packet_t], :pointer
|
|
77
|
+
|
|
78
|
+
# ---- HTTP ----
|
|
79
|
+
typedef :pointer, :http_t
|
|
80
|
+
typedef :pointer, :http_request_t
|
|
81
|
+
typedef :pointer, :http_response_t
|
|
82
|
+
|
|
83
|
+
# Order matches sfHttpMethod in CSFML 3.
|
|
84
|
+
HTTP_METHODS = %i[get post head put delete].freeze
|
|
85
|
+
|
|
86
|
+
# CSFML returns sfHttpStatus as an int. Most are HTTP status
|
|
87
|
+
# codes; the four sfInvalid*/sfConnectionFailed are SFML-side
|
|
88
|
+
# transport errors above the HTTP status range.
|
|
89
|
+
attach_function :sfHttpRequest_create, [], :http_request_t
|
|
90
|
+
attach_function :sfHttpRequest_destroy, [:http_request_t], :void
|
|
91
|
+
attach_function :sfHttpRequest_setField, [:http_request_t, :string, :string], :void
|
|
92
|
+
attach_function :sfHttpRequest_setMethod, [:http_request_t, :int], :void
|
|
93
|
+
attach_function :sfHttpRequest_setUri, [:http_request_t, :string], :void
|
|
94
|
+
attach_function :sfHttpRequest_setHttpVersion, [:http_request_t, :uint32, :uint32], :void
|
|
95
|
+
attach_function :sfHttpRequest_setBody, [:http_request_t, :string], :void
|
|
96
|
+
|
|
97
|
+
attach_function :sfHttpResponse_destroy, [:http_response_t], :void
|
|
98
|
+
attach_function :sfHttpResponse_getField, [:http_response_t, :string], :string
|
|
99
|
+
attach_function :sfHttpResponse_getStatus, [:http_response_t], :int
|
|
100
|
+
attach_function :sfHttpResponse_getMajorVersion, [:http_response_t], :uint32
|
|
101
|
+
attach_function :sfHttpResponse_getMinorVersion, [:http_response_t], :uint32
|
|
102
|
+
attach_function :sfHttpResponse_getBody, [:http_response_t], :string
|
|
103
|
+
|
|
104
|
+
attach_function :sfHttp_create, [], :http_t
|
|
105
|
+
attach_function :sfHttp_destroy, [:http_t], :void
|
|
106
|
+
attach_function :sfHttp_setHost, [:http_t, :string, :uint16], :void
|
|
107
|
+
# The actual network round-trip — release the GVL so other Ruby
|
|
108
|
+
# threads (timers, audio, even an in-process test server) can run
|
|
109
|
+
# while CSFML is blocked on the socket.
|
|
110
|
+
attach_function :sfHttp_sendRequest,
|
|
111
|
+
[:http_t, :http_request_t, System::Time.by_value],
|
|
112
|
+
:http_response_t,
|
|
113
|
+
blocking: true
|
|
114
|
+
|
|
115
|
+
# ---- SocketSelector ----
|
|
116
|
+
typedef :pointer, :socket_selector_t
|
|
117
|
+
|
|
118
|
+
attach_function :sfSocketSelector_create, [], :socket_selector_t
|
|
119
|
+
attach_function :sfSocketSelector_copy, [:socket_selector_t], :socket_selector_t
|
|
120
|
+
attach_function :sfSocketSelector_destroy, [:socket_selector_t], :void
|
|
121
|
+
attach_function :sfSocketSelector_addTcpListener, [:socket_selector_t, :tcp_listener_t], :void
|
|
122
|
+
attach_function :sfSocketSelector_addTcpSocket, [:socket_selector_t, :tcp_socket_t], :void
|
|
123
|
+
attach_function :sfSocketSelector_addUdpSocket, [:socket_selector_t, :udp_socket_t], :void
|
|
124
|
+
attach_function :sfSocketSelector_removeTcpListener, [:socket_selector_t, :tcp_listener_t], :void
|
|
125
|
+
attach_function :sfSocketSelector_removeTcpSocket, [:socket_selector_t, :tcp_socket_t], :void
|
|
126
|
+
attach_function :sfSocketSelector_removeUdpSocket, [:socket_selector_t, :udp_socket_t], :void
|
|
127
|
+
attach_function :sfSocketSelector_clear, [:socket_selector_t], :void
|
|
128
|
+
attach_function :sfSocketSelector_wait,
|
|
129
|
+
[:socket_selector_t, System::Time.by_value], :bool, blocking: true
|
|
130
|
+
attach_function :sfSocketSelector_isTcpListenerReady, [:socket_selector_t, :tcp_listener_t], :bool
|
|
131
|
+
attach_function :sfSocketSelector_isTcpSocketReady, [:socket_selector_t, :tcp_socket_t], :bool
|
|
132
|
+
attach_function :sfSocketSelector_isUdpSocketReady, [:socket_selector_t, :udp_socket_t], :bool
|
|
133
|
+
|
|
134
|
+
# ---- FTP ----
|
|
135
|
+
typedef :pointer, :ftp_t
|
|
136
|
+
typedef :pointer, :ftp_response_t
|
|
137
|
+
typedef :pointer, :ftp_dir_response_t
|
|
138
|
+
typedef :pointer, :ftp_listing_response_t
|
|
139
|
+
|
|
140
|
+
# Order matches sfFtpTransferMode.
|
|
141
|
+
FTP_TRANSFER_MODES = %i[binary ascii ebcdic].freeze
|
|
142
|
+
|
|
143
|
+
attach_function :sfFtpResponse_destroy, [:ftp_response_t], :void
|
|
144
|
+
attach_function :sfFtpResponse_isOk, [:ftp_response_t], :bool
|
|
145
|
+
attach_function :sfFtpResponse_getStatus, [:ftp_response_t], :int
|
|
146
|
+
attach_function :sfFtpResponse_getMessage, [:ftp_response_t], :string
|
|
147
|
+
|
|
148
|
+
attach_function :sfFtpDirectoryResponse_destroy, [:ftp_dir_response_t], :void
|
|
149
|
+
attach_function :sfFtpDirectoryResponse_isOk, [:ftp_dir_response_t], :bool
|
|
150
|
+
attach_function :sfFtpDirectoryResponse_getStatus, [:ftp_dir_response_t], :int
|
|
151
|
+
attach_function :sfFtpDirectoryResponse_getMessage, [:ftp_dir_response_t], :string
|
|
152
|
+
attach_function :sfFtpDirectoryResponse_getDirectory, [:ftp_dir_response_t], :string
|
|
153
|
+
|
|
154
|
+
attach_function :sfFtpListingResponse_destroy, [:ftp_listing_response_t], :void
|
|
155
|
+
attach_function :sfFtpListingResponse_isOk, [:ftp_listing_response_t], :bool
|
|
156
|
+
attach_function :sfFtpListingResponse_getStatus, [:ftp_listing_response_t], :int
|
|
157
|
+
attach_function :sfFtpListingResponse_getMessage, [:ftp_listing_response_t], :string
|
|
158
|
+
attach_function :sfFtpListingResponse_getCount, [:ftp_listing_response_t], :size_t
|
|
159
|
+
attach_function :sfFtpListingResponse_getName, [:ftp_listing_response_t, :size_t], :string
|
|
160
|
+
|
|
161
|
+
attach_function :sfFtp_create, [], :ftp_t
|
|
162
|
+
attach_function :sfFtp_destroy, [:ftp_t], :void
|
|
163
|
+
attach_function :sfFtp_connect,
|
|
164
|
+
[:ftp_t, IpAddress.by_value, :uint16, System::Time.by_value],
|
|
165
|
+
:ftp_response_t, blocking: true
|
|
166
|
+
attach_function :sfFtp_loginAnonymous, [:ftp_t], :ftp_response_t, blocking: true
|
|
167
|
+
attach_function :sfFtp_login, [:ftp_t, :string, :string], :ftp_response_t, blocking: true
|
|
168
|
+
attach_function :sfFtp_disconnect, [:ftp_t], :ftp_response_t, blocking: true
|
|
169
|
+
attach_function :sfFtp_keepAlive, [:ftp_t], :ftp_response_t, blocking: true
|
|
170
|
+
attach_function :sfFtp_getWorkingDirectory, [:ftp_t], :ftp_dir_response_t, blocking: true
|
|
171
|
+
attach_function :sfFtp_getDirectoryListing, [:ftp_t, :string], :ftp_listing_response_t, blocking: true
|
|
172
|
+
attach_function :sfFtp_changeDirectory, [:ftp_t, :string], :ftp_response_t, blocking: true
|
|
173
|
+
attach_function :sfFtp_parentDirectory, [:ftp_t], :ftp_response_t, blocking: true
|
|
174
|
+
attach_function :sfFtp_createDirectory, [:ftp_t, :string], :ftp_dir_response_t, blocking: true
|
|
175
|
+
attach_function :sfFtp_deleteDirectory, [:ftp_t, :string], :ftp_response_t, blocking: true
|
|
176
|
+
attach_function :sfFtp_renameFile, [:ftp_t, :string, :string], :ftp_response_t, blocking: true
|
|
177
|
+
attach_function :sfFtp_deleteFile, [:ftp_t, :string], :ftp_response_t, blocking: true
|
|
178
|
+
attach_function :sfFtp_download, [:ftp_t, :string, :string, :int], :ftp_response_t, blocking: true
|
|
179
|
+
attach_function :sfFtp_upload, [:ftp_t, :string, :string, :int, :bool], :ftp_response_t, blocking: true
|
|
180
|
+
attach_function :sfFtp_sendCommand, [:ftp_t, :string, :string], :ftp_response_t, blocking: true
|
|
77
181
|
end
|
|
78
182
|
end
|
|
79
183
|
end
|
data/lib/sfml/c/system.rb
CHANGED
|
@@ -38,6 +38,16 @@ module SFML
|
|
|
38
38
|
attach_function :sfClock_reset, [:clock_t], Time.by_value
|
|
39
39
|
|
|
40
40
|
attach_function :sfSleep, [Time.by_value], :void
|
|
41
|
+
|
|
42
|
+
# sfBuffer — opaque growable byte buffer used by APIs like
|
|
43
|
+
# sfImage_saveToMemory to return variable-length binary data
|
|
44
|
+
# without forcing the caller to pre-size an output buffer.
|
|
45
|
+
typedef :pointer, :buffer_t
|
|
46
|
+
|
|
47
|
+
attach_function :sfBuffer_create, [], :buffer_t
|
|
48
|
+
attach_function :sfBuffer_destroy, [:buffer_t], :void
|
|
49
|
+
attach_function :sfBuffer_getSize, [:buffer_t], :size_t
|
|
50
|
+
attach_function :sfBuffer_getData, [:buffer_t], :pointer
|
|
41
51
|
end
|
|
42
52
|
end
|
|
43
53
|
end
|
data/lib/sfml/c/window.rb
CHANGED
|
@@ -104,6 +104,18 @@ module SFML
|
|
|
104
104
|
:joystick_id, :uint32
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
+
class TouchEvent < FFI::Struct
|
|
108
|
+
layout :type, :int,
|
|
109
|
+
:finger, :uint32,
|
|
110
|
+
:position, System::Vector2i
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
class SensorEvent < FFI::Struct
|
|
114
|
+
layout :type, :int,
|
|
115
|
+
:sensor, :int,
|
|
116
|
+
:value, System::Vector3f
|
|
117
|
+
end
|
|
118
|
+
|
|
107
119
|
# sfEvent is a C union. The largest variant (KeyEvent on x86_64: 4+4+4+4
|
|
108
120
|
# = 20 bytes) defines the union size; we allocate a buffer that big and
|
|
109
121
|
# reinterpret per-type. We use a Struct (not Union) here because Ruby
|
|
@@ -156,6 +168,25 @@ module SFML
|
|
|
156
168
|
attach_function :sfJoystick_getIdentification, [:uint32], JoystickIdentification.by_value
|
|
157
169
|
attach_function :sfJoystick_update, [], :void
|
|
158
170
|
|
|
171
|
+
# ---- Touch ----
|
|
172
|
+
attach_function :sfTouch_isDown, [:uint32], :bool
|
|
173
|
+
attach_function :sfTouch_getPosition, [:uint32, :pointer], System::Vector2i.by_value
|
|
174
|
+
|
|
175
|
+
# ---- Sensor ----
|
|
176
|
+
# Order matches sfSensorType in CSFML 3.
|
|
177
|
+
SENSOR_TYPES = %i[
|
|
178
|
+
accelerometer
|
|
179
|
+
gyroscope
|
|
180
|
+
magnetometer
|
|
181
|
+
gravity
|
|
182
|
+
user_acceleration
|
|
183
|
+
orientation
|
|
184
|
+
].freeze
|
|
185
|
+
|
|
186
|
+
attach_function :sfSensor_isAvailable, [:int], :bool
|
|
187
|
+
attach_function :sfSensor_setEnabled, [:int, :bool], :void
|
|
188
|
+
attach_function :sfSensor_getValue, [:int], System::Vector3f.by_value
|
|
189
|
+
|
|
159
190
|
# ---- Bare Window (no rendering) ----
|
|
160
191
|
# SFML 3 splits sf::Window (pure window + GL context) from
|
|
161
192
|
# sf::RenderWindow (window + 2D batcher). The bare variant is
|
|
@@ -181,6 +212,17 @@ module SFML
|
|
|
181
212
|
attach_function :sfWindow_requestFocus, [:raw_window_t], :void
|
|
182
213
|
attach_function :sfWindow_hasFocus, [:raw_window_t], :bool
|
|
183
214
|
attach_function :sfWindow_setActive, [:raw_window_t, :bool], :bool
|
|
215
|
+
attach_function :sfWindow_setIcon, [:raw_window_t, System::Vector2u.by_value, :pointer], :void
|
|
216
|
+
# NULL pointer clears the limit. Pass a Vector2u* to set it.
|
|
217
|
+
attach_function :sfWindow_setMinimumSize, [:raw_window_t, :pointer], :void
|
|
218
|
+
attach_function :sfWindow_setMaximumSize, [:raw_window_t, :pointer], :void
|
|
219
|
+
|
|
220
|
+
# Embed into an existing platform window. The first argument is
|
|
221
|
+
# an OS-specific native handle (HWND on Windows, NSView* on
|
|
222
|
+
# macOS, Window XID on X11). Pass NULL for the ContextSettings
|
|
223
|
+
# to use defaults.
|
|
224
|
+
attach_function :sfWindow_createFromHandle, [:pointer, :pointer], :raw_window_t
|
|
225
|
+
attach_function :sfWindow_getNativeHandle, [:raw_window_t], :pointer
|
|
184
226
|
end
|
|
185
227
|
end
|
|
186
228
|
end
|
data/lib/sfml/graphics/image.rb
CHANGED
|
@@ -96,6 +96,29 @@ module SFML
|
|
|
96
96
|
path
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
+
# Encode the image as `format` ("png", "jpg", "bmp", or "tga") and
|
|
100
|
+
# return the encoded bytes as a Ruby String. Useful for sending
|
|
101
|
+
# screenshots over the network, generating data: URLs, piping into
|
|
102
|
+
# an image-processing library, etc., without touching the disk.
|
|
103
|
+
#
|
|
104
|
+
# png_bytes = img.save_to_memory("png")
|
|
105
|
+
# File.binwrite("out.png", png_bytes)
|
|
106
|
+
def save_to_memory(format)
|
|
107
|
+
buffer = C::System.sfBuffer_create
|
|
108
|
+
raise Error, "sfBuffer_create returned NULL" if buffer.null?
|
|
109
|
+
|
|
110
|
+
begin
|
|
111
|
+
ok = C::Graphics.sfImage_saveToMemory(@handle, buffer, format.to_s)
|
|
112
|
+
raise Error, "Could not encode image as #{format.inspect}" unless ok
|
|
113
|
+
|
|
114
|
+
size = C::System.sfBuffer_getSize(buffer)
|
|
115
|
+
data = C::System.sfBuffer_getData(buffer)
|
|
116
|
+
data.read_bytes(size)
|
|
117
|
+
ensure
|
|
118
|
+
C::System.sfBuffer_destroy(buffer)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
99
122
|
# Replace any pixel matching `color` with that colour at `alpha`
|
|
100
123
|
# opacity — typical use is to turn a fixed background colour
|
|
101
124
|
# transparent: img.mask_color!(SFML::Color.magenta, alpha: 0).
|
|
@@ -17,12 +17,13 @@ module SFML
|
|
|
17
17
|
COORDINATE_TYPES = %i[normalized pixels].freeze
|
|
18
18
|
COORDINATE_INDEX = COORDINATE_TYPES.each_with_index.to_h.freeze
|
|
19
19
|
|
|
20
|
-
attr_reader :blend_mode, :texture, :shader, :coordinate_type
|
|
20
|
+
attr_reader :blend_mode, :stencil_mode, :texture, :shader, :coordinate_type
|
|
21
21
|
|
|
22
|
-
def initialize(blend_mode: nil, texture: nil, shader: nil, coordinate_type: :normalized)
|
|
22
|
+
def initialize(blend_mode: nil, stencil_mode: nil, texture: nil, shader: nil, coordinate_type: :normalized)
|
|
23
23
|
@blend_mode = blend_mode
|
|
24
|
+
@stencil_mode = stencil_mode
|
|
24
25
|
@texture = texture
|
|
25
|
-
@shader = shader
|
|
26
|
+
@shader = shader
|
|
26
27
|
@coordinate_type = coordinate_type
|
|
27
28
|
raise ArgumentError, "unknown coordinate_type: #{coordinate_type.inspect}" unless COORDINATE_INDEX.key?(coordinate_type)
|
|
28
29
|
freeze
|
|
@@ -39,6 +40,7 @@ module SFML
|
|
|
39
40
|
.then { |bytes| buffer.pointer.write_bytes(bytes) }
|
|
40
41
|
|
|
41
42
|
@blend_mode&.populate(buffer[:blend_mode])
|
|
43
|
+
@stencil_mode&.populate(buffer[:stencil_mode])
|
|
42
44
|
buffer[:coordinate_type] = COORDINATE_INDEX[@coordinate_type]
|
|
43
45
|
buffer[:texture] = @texture ? @texture.handle : nil
|
|
44
46
|
buffer[:shader] = @shader ? @shader.handle : nil
|