ruby-sfml 3.0.0.3 → 3.0.0.4
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 +51 -0
- data/lib/sfml/audio/music.rb +87 -0
- data/lib/sfml/audio/sound.rb +72 -0
- data/lib/sfml/audio/sound_buffer.rb +74 -0
- data/lib/sfml/c/audio.rb +44 -0
- data/lib/sfml/c/graphics.rb +21 -0
- data/lib/sfml/graphics/render_texture.rb +12 -0
- data/lib/sfml/graphics/render_window.rb +16 -0
- data/lib/sfml/graphics/shader.rb +9 -0
- data/lib/sfml/graphics/sprite.rb +32 -0
- data/lib/sfml/graphics/texture.rb +73 -0
- data/lib/sfml/graphics/view.rb +23 -6
- data/lib/sfml/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 02adbbc1dc50cc42127dc845ad9be68829ee07c100cb915e83f15d2e8deb8df7
|
|
4
|
+
data.tar.gz: 59e6cadd1e7a325e70b7ad92b162f7ba3d73035fc482317e3ad0f28d8b7afcb6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: da0f1e034c77f9a78fb202e4e40e90099aafac7fbe5b2261e94bd693e51f937098c5113491f723eefc45acc731f983b39cc6a27e372c81e6391f8b2777aee99e
|
|
7
|
+
data.tar.gz: a494f581e0cf1975c5233705838cc9f29f0f99fe88a793cd580478772c5170a0c440330c40f464947a689849d43b8e2c16b4b247c0cf4350eea5e35616d9ec90
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,57 @@ ruby-sfml's own patch level.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [3.0.0.4] — 2026-05-09
|
|
12
|
+
|
|
13
|
+
### Added — graphics
|
|
14
|
+
|
|
15
|
+
- `Sprite#dup` / `#clone`, `Sprite#texture` (borrowed reference),
|
|
16
|
+
`Sprite#transform`, `Sprite#inverse_transform`.
|
|
17
|
+
- `View#scissor` / `View#scissor=` — normalised [0..1] clip rect
|
|
18
|
+
applied at render time (paired with the existing `viewport` API).
|
|
19
|
+
- `Texture.from_memory(bytes, smooth:, repeated:)` — decode +
|
|
20
|
+
upload a Ruby String of bytes (PNG / JPG / BMP / TGA / …) as a
|
|
21
|
+
texture. Bypasses the disk for embedded assets / network blobs.
|
|
22
|
+
- `Texture#resize(w, h)` — reallocate GPU memory in place.
|
|
23
|
+
- `Texture#swap(other)` — atomically swap GPU memory between two
|
|
24
|
+
textures (cheap double-buffer pattern).
|
|
25
|
+
- `Texture#native_handle` — the OpenGL texture-object name for
|
|
26
|
+
raw GL interop.
|
|
27
|
+
- `Texture#update_from_texture(source, offset:)`,
|
|
28
|
+
`Texture#update_from_render_window(window, offset:)`,
|
|
29
|
+
`Texture#update_from_window(window, offset:)` — copy pixels
|
|
30
|
+
from another GPU texture / from a window's back-buffer / from a
|
|
31
|
+
bare-Window's framebuffer into this texture at `offset`.
|
|
32
|
+
- `RenderWindow#viewport(view = self.view)` and
|
|
33
|
+
`RenderWindow#scissor(view = self.view)` — pixel-space
|
|
34
|
+
`SFML::Rect`s the view actually covers / clips. Same on
|
|
35
|
+
`RenderTexture`.
|
|
36
|
+
- `Shader#set_int_color(name, color)` — uploads a `SFML::Color`
|
|
37
|
+
as a `vec4` uniform (CSFML normalises 0–255 → 0.0–1.0 for you).
|
|
38
|
+
|
|
39
|
+
### Added — audio
|
|
40
|
+
- `Sound#dup` / `#clone`, `Sound#buffer` reader.
|
|
41
|
+
- `Sound#pan` / `#pan=`, `Sound#min_gain`/`#max_gain` (and `=`),
|
|
42
|
+
`Sound#max_distance` (and `=`), `Sound#spatialization_enabled?` /
|
|
43
|
+
`#spatialization_enabled=`,
|
|
44
|
+
`Sound#directional_attenuation_factor` (and `=`) — the full
|
|
45
|
+
remaining 3D-audio surface from CSFML's SoundSource.
|
|
46
|
+
- Same set on `Music`: `pan`, gain clamps, max-distance,
|
|
47
|
+
spatialisation, directional-attenuation.
|
|
48
|
+
- `Music#channel_count`, `Music#sample_rate` — stream introspection.
|
|
49
|
+
- `Music#loop_points` / `#loop_points=` — set the looping window
|
|
50
|
+
inside a track ([offset_time, length_time] pair of `SFML::Time`s).
|
|
51
|
+
- `Music.from_memory(bytes, **opts)` — stream from a Ruby String
|
|
52
|
+
of bytes (in-memory MP3 / OGG / FLAC). Caller's bytes must
|
|
53
|
+
outlive the `Music` (we pin the Ruby buffer).
|
|
54
|
+
- `SoundBuffer.from_memory(bytes)` — decode `.wav` / `.ogg` /
|
|
55
|
+
`.flac` from RAM.
|
|
56
|
+
- `SoundBuffer.from_samples(samples, sample_rate:, channel_count:,
|
|
57
|
+
channel_map:)` — build a buffer from a Ruby Array of int16
|
|
58
|
+
samples. Default channel maps for 1- and 2-channel content.
|
|
59
|
+
- `SoundBuffer#dup`, `SoundBuffer#sample_count`,
|
|
60
|
+
`SoundBuffer#samples` — sample-level introspection.
|
|
61
|
+
|
|
11
62
|
## [3.0.0.3] — 2026-05-09
|
|
12
63
|
|
|
13
64
|
### Added — typography
|
data/lib/sfml/audio/music.rb
CHANGED
|
@@ -9,6 +9,29 @@ module SFML
|
|
|
9
9
|
ptr = C::Audio.sfMusic_createFromFile(path.to_s)
|
|
10
10
|
raise Error, "Could not load music from #{path.inspect}" if ptr.null?
|
|
11
11
|
|
|
12
|
+
_wrap(ptr, opts)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Stream music from a Ruby String of bytes (an in-memory MP3,
|
|
16
|
+
# OGG, FLAC, …). Useful for embedded audio or downloaded
|
|
17
|
+
# tracks that bypass the disk. The bytes must outlive the
|
|
18
|
+
# Music object — SFML keeps a pointer into them.
|
|
19
|
+
def self.from_memory(bytes, **opts)
|
|
20
|
+
raise ArgumentError, "expected a String, got #{bytes.class}" unless bytes.is_a?(String)
|
|
21
|
+
|
|
22
|
+
buf = FFI::MemoryPointer.new(:uint8, bytes.bytesize)
|
|
23
|
+
buf.write_bytes(bytes)
|
|
24
|
+
ptr = C::Audio.sfMusic_createFromMemory(buf, bytes.bytesize)
|
|
25
|
+
raise Error, "sfMusic_createFromMemory returned NULL — unsupported format?" if ptr.null?
|
|
26
|
+
|
|
27
|
+
m = _wrap(ptr, opts)
|
|
28
|
+
m.instance_variable_set(:@_memory_pin, buf) # keep buffer alive
|
|
29
|
+
m
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Internal — finish initialising a Music from an already-built
|
|
33
|
+
# CSFML pointer.
|
|
34
|
+
def self._wrap(ptr, opts)
|
|
12
35
|
m = allocate
|
|
13
36
|
m.send(:_take_ownership, ptr)
|
|
14
37
|
m.instance_variable_set(:@looping, false)
|
|
@@ -17,6 +40,7 @@ module SFML
|
|
|
17
40
|
m.looping = opts[:looping] if opts.key?(:looping)
|
|
18
41
|
m
|
|
19
42
|
end
|
|
43
|
+
private_class_method :_wrap
|
|
20
44
|
|
|
21
45
|
def play = C::Audio.sfMusic_play(@handle)
|
|
22
46
|
def pause = C::Audio.sfMusic_pause(@handle)
|
|
@@ -143,6 +167,69 @@ module SFML
|
|
|
143
167
|
C::Audio.sfMusic_setRelativeToListener(@handle, value ? true : false)
|
|
144
168
|
end
|
|
145
169
|
|
|
170
|
+
# ---- Stream introspection ----
|
|
171
|
+
|
|
172
|
+
def channel_count = C::Audio.sfMusic_getChannelCount(@handle)
|
|
173
|
+
def sample_rate = C::Audio.sfMusic_getSampleRate(@handle)
|
|
174
|
+
|
|
175
|
+
# The portion of the track that loops when `looping = true`.
|
|
176
|
+
# Returns `[offset, length]` of `SFML::Time`s; defaults to the
|
|
177
|
+
# whole track. Set with `loop_points = [Time, Time]`.
|
|
178
|
+
def loop_points
|
|
179
|
+
span = C::Audio.sfMusic_getLoopPoints(@handle)
|
|
180
|
+
[Time.from_native(span[:offset]), Time.from_native(span[:length])]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def loop_points=(value)
|
|
184
|
+
offset_t, length_t = value
|
|
185
|
+
raise ArgumentError, "expected [offset_time, length_time]" unless offset_t && length_t
|
|
186
|
+
|
|
187
|
+
span = C::Audio::TimeSpan.new
|
|
188
|
+
span[:offset][:microseconds] = offset_t.is_a?(Time) ? offset_t.microseconds : Time.seconds(offset_t.to_f).microseconds
|
|
189
|
+
span[:length][:microseconds] = length_t.is_a?(Time) ? length_t.microseconds : Time.seconds(length_t.to_f).microseconds
|
|
190
|
+
C::Audio.sfMusic_setLoopPoints(@handle, span)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# ---- 3D-audio extras (mirror of Sound's) ----
|
|
194
|
+
|
|
195
|
+
def pan = C::Audio.sfMusic_getPan(@handle)
|
|
196
|
+
|
|
197
|
+
def pan=(v)
|
|
198
|
+
C::Audio.sfMusic_setPan(@handle, v.to_f)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def min_gain = C::Audio.sfMusic_getMinGain(@handle)
|
|
202
|
+
|
|
203
|
+
def min_gain=(v)
|
|
204
|
+
C::Audio.sfMusic_setMinGain(@handle, v.to_f)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def max_gain = C::Audio.sfMusic_getMaxGain(@handle)
|
|
208
|
+
|
|
209
|
+
def max_gain=(v)
|
|
210
|
+
C::Audio.sfMusic_setMaxGain(@handle, v.to_f)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def max_distance = C::Audio.sfMusic_getMaxDistance(@handle)
|
|
214
|
+
|
|
215
|
+
def max_distance=(v)
|
|
216
|
+
C::Audio.sfMusic_setMaxDistance(@handle, v.to_f)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def spatialization_enabled? = C::Audio.sfMusic_isSpatializationEnabled(@handle)
|
|
220
|
+
|
|
221
|
+
def spatialization_enabled=(v)
|
|
222
|
+
C::Audio.sfMusic_setSpatializationEnabled(@handle, v ? true : false)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def directional_attenuation_factor
|
|
226
|
+
C::Audio.sfMusic_getDirectionalAttenuationFactor(@handle)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def directional_attenuation_factor=(v)
|
|
230
|
+
C::Audio.sfMusic_setDirectionalAttenuationFactor(@handle, v.to_f)
|
|
231
|
+
end
|
|
232
|
+
|
|
146
233
|
private
|
|
147
234
|
|
|
148
235
|
def _take_ownership(ptr)
|
data/lib/sfml/audio/sound.rb
CHANGED
|
@@ -180,5 +180,77 @@ module SFML
|
|
|
180
180
|
def relative_to_listener=(value)
|
|
181
181
|
C::Audio.sfSound_setRelativeToListener(@handle, value ? true : false)
|
|
182
182
|
end
|
|
183
|
+
|
|
184
|
+
# The buffer this Sound is currently bound to (the one passed
|
|
185
|
+
# to `.new`, or whoever last called `buffer=`). Returns nil
|
|
186
|
+
# if the underlying source has none.
|
|
187
|
+
def buffer
|
|
188
|
+
ptr = C::Audio.sfSound_getBuffer(@handle)
|
|
189
|
+
return nil if ptr.null?
|
|
190
|
+
@buffer # keep Ruby reference alive (the C handle is borrowed from it)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Stereo pan in [-1.0, 1.0]: -1 = full left, 0 = centre, 1 = full right.
|
|
194
|
+
def pan = C::Audio.sfSound_getPan(@handle)
|
|
195
|
+
|
|
196
|
+
def pan=(v)
|
|
197
|
+
C::Audio.sfSound_setPan(@handle, v.to_f)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Output gain clamping. `min_gain` floors the attenuated
|
|
201
|
+
# gain; `max_gain` caps it. Useful when you want a sound to
|
|
202
|
+
# always be at least faintly audible (or never louder than
|
|
203
|
+
# the listener's local SFX volume).
|
|
204
|
+
def min_gain = C::Audio.sfSound_getMinGain(@handle)
|
|
205
|
+
|
|
206
|
+
def min_gain=(v)
|
|
207
|
+
C::Audio.sfSound_setMinGain(@handle, v.to_f)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def max_gain = C::Audio.sfSound_getMaxGain(@handle)
|
|
211
|
+
|
|
212
|
+
def max_gain=(v)
|
|
213
|
+
C::Audio.sfSound_setMaxGain(@handle, v.to_f)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# The distance beyond which the source is fully attenuated.
|
|
217
|
+
def max_distance = C::Audio.sfSound_getMaxDistance(@handle)
|
|
218
|
+
|
|
219
|
+
def max_distance=(v)
|
|
220
|
+
C::Audio.sfSound_setMaxDistance(@handle, v.to_f)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Whether 3D-positional / Doppler / cone math is applied at
|
|
224
|
+
# mix time. Off → the sound plays as a simple stereo source.
|
|
225
|
+
def spatialization_enabled? = C::Audio.sfSound_isSpatializationEnabled(@handle)
|
|
226
|
+
|
|
227
|
+
def spatialization_enabled=(v)
|
|
228
|
+
C::Audio.sfSound_setSpatializationEnabled(@handle, v ? true : false)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Multiplier on the Listener's directional attenuation cone.
|
|
232
|
+
# 0 = source ignores the listener's facing direction (no
|
|
233
|
+
# cone falloff); 1 = full cone effect.
|
|
234
|
+
def directional_attenuation_factor
|
|
235
|
+
C::Audio.sfSound_getDirectionalAttenuationFactor(@handle)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def directional_attenuation_factor=(v)
|
|
239
|
+
C::Audio.sfSound_setDirectionalAttenuationFactor(@handle, v.to_f)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Independent copy — same buffer (buffers are shareable),
|
|
243
|
+
# independent transport state (volume/pan/spatialisation/etc).
|
|
244
|
+
def dup
|
|
245
|
+
ptr = C::Audio.sfSound_copy(@handle)
|
|
246
|
+
raise Error, "sfSound_copy returned NULL" if ptr.null?
|
|
247
|
+
|
|
248
|
+
copy = self.class.allocate
|
|
249
|
+
copy.instance_variable_set(:@handle,
|
|
250
|
+
FFI::AutoPointer.new(ptr, C::Audio.method(:sfSound_destroy)))
|
|
251
|
+
copy.instance_variable_set(:@buffer, @buffer)
|
|
252
|
+
copy
|
|
253
|
+
end
|
|
254
|
+
alias clone dup
|
|
183
255
|
end
|
|
184
256
|
end
|
|
@@ -14,9 +14,83 @@ module SFML
|
|
|
14
14
|
buf
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
# Decode a Ruby String of bytes (.wav, .ogg, .flac, …)
|
|
18
|
+
# straight into a buffer — bypass the disk.
|
|
19
|
+
def self.from_memory(bytes)
|
|
20
|
+
raise ArgumentError, "expected a String, got #{bytes.class}" unless bytes.is_a?(String)
|
|
21
|
+
|
|
22
|
+
buf_p = FFI::MemoryPointer.new(:uint8, bytes.bytesize)
|
|
23
|
+
buf_p.write_bytes(bytes)
|
|
24
|
+
ptr = C::Audio.sfSoundBuffer_createFromMemory(buf_p, bytes.bytesize)
|
|
25
|
+
raise Error, "sfSoundBuffer_createFromMemory returned NULL — unsupported format?" if ptr.null?
|
|
26
|
+
|
|
27
|
+
buf = allocate
|
|
28
|
+
buf.send(:_take_ownership, ptr)
|
|
29
|
+
buf
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Default channel-layout map for the common 1- and 2-channel
|
|
33
|
+
# cases — saves callers from spelling out the SoundChannel
|
|
34
|
+
# enum just to build a mono blip or stereo waveform.
|
|
35
|
+
DEFAULT_CHANNEL_MAPS = {
|
|
36
|
+
1 => [1], # sfSoundChannelMono
|
|
37
|
+
2 => [2, 3], # sfSoundChannelFrontLeft, FrontRight
|
|
38
|
+
}.freeze
|
|
39
|
+
|
|
40
|
+
# Build a buffer from raw 16-bit signed samples. `samples` is
|
|
41
|
+
# an Array of Integers in [-32768, 32767]. The caller specifies
|
|
42
|
+
# `sample_rate` (Hz) and `channel_count` (1 = mono, 2 = stereo).
|
|
43
|
+
# `channel_map` is an Array of `sfSoundChannel` enum values; for
|
|
44
|
+
# 1- and 2-channel content the default mono / front-L+R layout
|
|
45
|
+
# is filled in automatically.
|
|
46
|
+
def self.from_samples(samples, sample_rate:, channel_count:, channel_map: nil)
|
|
47
|
+
arr = samples.to_a.map { |s| Integer(s) }
|
|
48
|
+
buf = FFI::MemoryPointer.new(:int16, arr.length)
|
|
49
|
+
buf.write_array_of_int16(arr)
|
|
50
|
+
|
|
51
|
+
map = channel_map || DEFAULT_CHANNEL_MAPS.fetch(channel_count) do
|
|
52
|
+
raise ArgumentError,
|
|
53
|
+
"no default channel_map for #{channel_count} channels — pass `channel_map: [...]` explicitly"
|
|
54
|
+
end
|
|
55
|
+
map_buf = FFI::MemoryPointer.new(:int, map.length)
|
|
56
|
+
map_buf.write_array_of_int(map.map { |v| Integer(v) })
|
|
57
|
+
|
|
58
|
+
ptr = C::Audio.sfSoundBuffer_createFromSamples(buf, arr.length,
|
|
59
|
+
Integer(channel_count),
|
|
60
|
+
Integer(sample_rate),
|
|
61
|
+
map_buf, map.length)
|
|
62
|
+
raise Error, "sfSoundBuffer_createFromSamples returned NULL" if ptr.null?
|
|
63
|
+
|
|
64
|
+
sb = allocate
|
|
65
|
+
sb.send(:_take_ownership, ptr)
|
|
66
|
+
sb
|
|
67
|
+
end
|
|
68
|
+
|
|
17
69
|
def duration = Time.from_native(C::Audio.sfSoundBuffer_getDuration(@handle))
|
|
18
70
|
def sample_rate = C::Audio.sfSoundBuffer_getSampleRate(@handle)
|
|
19
71
|
def channel_count = C::Audio.sfSoundBuffer_getChannelCount(@handle)
|
|
72
|
+
def sample_count = C::Audio.sfSoundBuffer_getSampleCount(@handle)
|
|
73
|
+
|
|
74
|
+
# The decoded 16-bit signed samples as a Ruby Array of
|
|
75
|
+
# Integers. Heavy — copies every sample. For analysis or
|
|
76
|
+
# custom DSP that needs the raw waveform.
|
|
77
|
+
def samples
|
|
78
|
+
ptr = C::Audio.sfSoundBuffer_getSamples(@handle)
|
|
79
|
+
return [] if ptr.null?
|
|
80
|
+
ptr.read_array_of_int16(sample_count)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Independent copy — same decoded waveform, different
|
|
84
|
+
# underlying memory block.
|
|
85
|
+
def dup
|
|
86
|
+
ptr = C::Audio.sfSoundBuffer_copy(@handle)
|
|
87
|
+
raise Error, "sfSoundBuffer_copy returned NULL" if ptr.null?
|
|
88
|
+
|
|
89
|
+
copy = self.class.allocate
|
|
90
|
+
copy.send(:_take_ownership, ptr)
|
|
91
|
+
copy
|
|
92
|
+
end
|
|
93
|
+
alias clone dup
|
|
20
94
|
|
|
21
95
|
# Write the buffer out to disk. Format is inferred from the file
|
|
22
96
|
# extension (.wav / .ogg / .flac, depends on what CSFML was built
|
data/lib/sfml/c/audio.rb
CHANGED
|
@@ -26,10 +26,31 @@ module SFML
|
|
|
26
26
|
attach_function :sfSoundBuffer_getDuration, [:sound_buffer_t], System::Time.by_value
|
|
27
27
|
attach_function :sfSoundBuffer_getSampleRate, [:sound_buffer_t], :uint32
|
|
28
28
|
attach_function :sfSoundBuffer_getChannelCount,[:sound_buffer_t], :uint32
|
|
29
|
+
attach_function :sfSoundBuffer_copy, [:sound_buffer_t], :sound_buffer_t
|
|
30
|
+
attach_function :sfSoundBuffer_createFromMemory, [:pointer, :size_t], :sound_buffer_t
|
|
31
|
+
attach_function :sfSoundBuffer_createFromSamples,
|
|
32
|
+
[:pointer, :uint64, :uint32, :uint32, :pointer, :size_t], :sound_buffer_t
|
|
33
|
+
attach_function :sfSoundBuffer_getSampleCount, [:sound_buffer_t], :uint64
|
|
34
|
+
attach_function :sfSoundBuffer_getSamples, [:sound_buffer_t], :pointer
|
|
35
|
+
attach_function :sfSoundBuffer_getChannelMap, [:sound_buffer_t, :pointer], :pointer
|
|
29
36
|
|
|
30
37
|
# ---- Sound ----
|
|
31
38
|
attach_function :sfSound_create, [:sound_buffer_t], :sound_t
|
|
39
|
+
attach_function :sfSound_copy, [:sound_t], :sound_t
|
|
32
40
|
attach_function :sfSound_destroy, [:sound_t], :void
|
|
41
|
+
attach_function :sfSound_getBuffer, [:sound_t], :sound_buffer_t
|
|
42
|
+
attach_function :sfSound_setPan, [:sound_t, :float], :void
|
|
43
|
+
attach_function :sfSound_getPan, [:sound_t], :float
|
|
44
|
+
attach_function :sfSound_setMinGain, [:sound_t, :float], :void
|
|
45
|
+
attach_function :sfSound_getMinGain, [:sound_t], :float
|
|
46
|
+
attach_function :sfSound_setMaxGain, [:sound_t, :float], :void
|
|
47
|
+
attach_function :sfSound_getMaxGain, [:sound_t], :float
|
|
48
|
+
attach_function :sfSound_setMaxDistance, [:sound_t, :float], :void
|
|
49
|
+
attach_function :sfSound_getMaxDistance, [:sound_t], :float
|
|
50
|
+
attach_function :sfSound_setSpatializationEnabled, [:sound_t, :bool], :void
|
|
51
|
+
attach_function :sfSound_isSpatializationEnabled, [:sound_t], :bool
|
|
52
|
+
attach_function :sfSound_setDirectionalAttenuationFactor, [:sound_t, :float], :void
|
|
53
|
+
attach_function :sfSound_getDirectionalAttenuationFactor, [:sound_t], :float
|
|
33
54
|
attach_function :sfSound_play, [:sound_t], :void
|
|
34
55
|
attach_function :sfSound_pause, [:sound_t], :void
|
|
35
56
|
attach_function :sfSound_stop, [:sound_t], :void
|
|
@@ -66,8 +87,31 @@ module SFML
|
|
|
66
87
|
attach_function :sfSound_setEffectProcessor, [:sound_t, :sf_effect_processor, :pointer], :void
|
|
67
88
|
|
|
68
89
|
# ---- Music ----
|
|
90
|
+
class TimeSpan < FFI::Struct
|
|
91
|
+
layout :offset, System::Time,
|
|
92
|
+
:length, System::Time
|
|
93
|
+
end
|
|
94
|
+
|
|
69
95
|
attach_function :sfMusic_createFromFile, [:string], :music_t
|
|
96
|
+
attach_function :sfMusic_createFromMemory, [:pointer, :size_t], :music_t
|
|
70
97
|
attach_function :sfMusic_destroy, [:music_t], :void
|
|
98
|
+
attach_function :sfMusic_getChannelCount, [:music_t], :uint32
|
|
99
|
+
attach_function :sfMusic_getSampleRate, [:music_t], :uint32
|
|
100
|
+
attach_function :sfMusic_getChannelMap, [:music_t, :pointer], :pointer
|
|
101
|
+
attach_function :sfMusic_getLoopPoints, [:music_t], TimeSpan.by_value
|
|
102
|
+
attach_function :sfMusic_setLoopPoints, [:music_t, TimeSpan.by_value], :void
|
|
103
|
+
attach_function :sfMusic_setPan, [:music_t, :float], :void
|
|
104
|
+
attach_function :sfMusic_getPan, [:music_t], :float
|
|
105
|
+
attach_function :sfMusic_setMinGain, [:music_t, :float], :void
|
|
106
|
+
attach_function :sfMusic_getMinGain, [:music_t], :float
|
|
107
|
+
attach_function :sfMusic_setMaxGain, [:music_t, :float], :void
|
|
108
|
+
attach_function :sfMusic_getMaxGain, [:music_t], :float
|
|
109
|
+
attach_function :sfMusic_setMaxDistance, [:music_t, :float], :void
|
|
110
|
+
attach_function :sfMusic_getMaxDistance, [:music_t], :float
|
|
111
|
+
attach_function :sfMusic_setSpatializationEnabled, [:music_t, :bool], :void
|
|
112
|
+
attach_function :sfMusic_isSpatializationEnabled, [:music_t], :bool
|
|
113
|
+
attach_function :sfMusic_setDirectionalAttenuationFactor, [:music_t, :float], :void
|
|
114
|
+
attach_function :sfMusic_getDirectionalAttenuationFactor, [:music_t], :float
|
|
71
115
|
attach_function :sfMusic_play, [:music_t], :void
|
|
72
116
|
attach_function :sfMusic_pause, [:music_t], :void
|
|
73
117
|
attach_function :sfMusic_stop, [:music_t], :void
|
data/lib/sfml/c/graphics.rb
CHANGED
|
@@ -121,6 +121,8 @@ module SFML
|
|
|
121
121
|
attach_function :sfRenderWindow_resetGLStates, [:render_window_t], :void
|
|
122
122
|
attach_function :sfRenderWindow_isSrgb, [:render_window_t], :bool
|
|
123
123
|
attach_function :sfRenderWindow_waitEvent, [:render_window_t, System::Time.by_value, :pointer], :bool
|
|
124
|
+
attach_function :sfRenderWindow_getScissor, [:render_window_t, :pointer], IntRect.by_value
|
|
125
|
+
attach_function :sfRenderWindow_getViewport, [:render_window_t, :pointer], IntRect.by_value
|
|
124
126
|
|
|
125
127
|
typedef :pointer, :texture_t
|
|
126
128
|
typedef :pointer, :render_texture_t
|
|
@@ -197,6 +199,8 @@ module SFML
|
|
|
197
199
|
attach_function :sfView_getRotation, [:view_t], :float
|
|
198
200
|
attach_function :sfView_setViewport, [:view_t, FloatRect.by_value], :void
|
|
199
201
|
attach_function :sfView_getViewport, [:view_t], FloatRect.by_value
|
|
202
|
+
attach_function :sfView_setScissor, [:view_t, FloatRect.by_value], :void
|
|
203
|
+
attach_function :sfView_getScissor, [:view_t], FloatRect.by_value
|
|
200
204
|
attach_function :sfView_move, [:view_t, System::Vector2f.by_value], :void
|
|
201
205
|
attach_function :sfView_rotate, [:view_t, :float], :void
|
|
202
206
|
attach_function :sfView_zoom, [:view_t, :float], :void
|
|
@@ -221,7 +225,17 @@ module SFML
|
|
|
221
225
|
attach_function :sfTexture_create, [System::Vector2u.by_value], :texture_t
|
|
222
226
|
attach_function :sfTexture_createFromFile, [:string, :pointer], :texture_t
|
|
223
227
|
attach_function :sfTexture_createFromImage,[:image_t, :pointer], :texture_t
|
|
228
|
+
attach_function :sfTexture_createFromMemory,[:pointer, :size_t, :pointer], :texture_t
|
|
224
229
|
attach_function :sfTexture_copy, [:texture_t], :texture_t
|
|
230
|
+
attach_function :sfTexture_resize, [:texture_t, System::Vector2u.by_value], :bool
|
|
231
|
+
attach_function :sfTexture_swap, [:texture_t, :texture_t], :void
|
|
232
|
+
attach_function :sfTexture_getNativeHandle,[:texture_t], :uint
|
|
233
|
+
attach_function :sfTexture_updateFromTexture,
|
|
234
|
+
[:texture_t, :texture_t, System::Vector2u.by_value], :void
|
|
235
|
+
attach_function :sfTexture_updateFromRenderWindow,
|
|
236
|
+
[:texture_t, :render_window_t, System::Vector2u.by_value], :void
|
|
237
|
+
attach_function :sfTexture_updateFromWindow,
|
|
238
|
+
[:texture_t, :pointer, System::Vector2u.by_value], :void
|
|
225
239
|
attach_function :sfTexture_isSrgb, [:texture_t], :bool
|
|
226
240
|
attach_function :sfTexture_generateMipmap, [:texture_t], :bool
|
|
227
241
|
attach_function :sfTexture_getMaximumSize, [], :uint
|
|
@@ -275,6 +289,10 @@ module SFML
|
|
|
275
289
|
attach_function :sfSprite_setColor, [:sprite_t, Color.by_value], :void
|
|
276
290
|
attach_function :sfSprite_getColor, [:sprite_t], Color.by_value
|
|
277
291
|
attach_function :sfSprite_setTexture, [:sprite_t, :texture_t, :bool], :void
|
|
292
|
+
attach_function :sfSprite_getTexture, [:sprite_t], :texture_t
|
|
293
|
+
attach_function :sfSprite_copy, [:sprite_t], :sprite_t
|
|
294
|
+
attach_function :sfSprite_getTransform, [:sprite_t], Transform.by_value
|
|
295
|
+
attach_function :sfSprite_getInverseTransform, [:sprite_t], Transform.by_value
|
|
278
296
|
|
|
279
297
|
# ---- CircleShape ----
|
|
280
298
|
attach_function :sfCircleShape_create, [], :circle_shape_t
|
|
@@ -385,6 +403,8 @@ module SFML
|
|
|
385
403
|
attach_function :sfRenderTexture_pushGLStates, [:render_texture_t], :void
|
|
386
404
|
attach_function :sfRenderTexture_popGLStates, [:render_texture_t], :void
|
|
387
405
|
attach_function :sfRenderTexture_resetGLStates, [:render_texture_t], :void
|
|
406
|
+
attach_function :sfRenderTexture_getScissor, [:render_texture_t, :view_t], IntRect.by_value
|
|
407
|
+
attach_function :sfRenderTexture_getViewport, [:render_texture_t, :view_t], IntRect.by_value
|
|
388
408
|
|
|
389
409
|
attach_function :sfRenderTexture_mapPixelToCoords,
|
|
390
410
|
[:render_texture_t, System::Vector2i.by_value, :view_t],
|
|
@@ -417,6 +437,7 @@ module SFML
|
|
|
417
437
|
attach_function :sfShader_isAvailable, [], :bool
|
|
418
438
|
attach_function :sfShader_bind, [:shader_t], :void
|
|
419
439
|
attach_function :sfShader_getNativeHandle, [:shader_t], :uint
|
|
440
|
+
attach_function :sfShader_setIntColorUniform, [:shader_t, :string, Color.by_value], :void
|
|
420
441
|
attach_function :sfShader_isGeometryAvailable, [], :bool
|
|
421
442
|
|
|
422
443
|
attach_function :sfShader_setFloatUniform, [:shader_t, :string, :float], :void
|
|
@@ -78,6 +78,18 @@ module SFML
|
|
|
78
78
|
def pop_gl_states = C::Graphics.sfRenderTexture_popGLStates(@handle)
|
|
79
79
|
def reset_gl_states = C::Graphics.sfRenderTexture_resetGLStates(@handle)
|
|
80
80
|
|
|
81
|
+
# Pixel-space viewport / scissor for the given view (defaults
|
|
82
|
+
# to the active view). Same shape as RenderWindow's.
|
|
83
|
+
def viewport(view = self.view)
|
|
84
|
+
raise ArgumentError, "expected a SFML::View" unless view.is_a?(View)
|
|
85
|
+
Rect.from_native(C::Graphics.sfRenderTexture_getViewport(@handle, view.handle))
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def scissor(view = self.view)
|
|
89
|
+
raise ArgumentError, "expected a SFML::View" unless view.is_a?(View)
|
|
90
|
+
Rect.from_native(C::Graphics.sfRenderTexture_getScissor(@handle, view.handle))
|
|
91
|
+
end
|
|
92
|
+
|
|
81
93
|
# The Texture this RenderTexture is rendering into. Borrowed — its
|
|
82
94
|
# lifetime is bounded by `self`. Memoised so repeated calls return
|
|
83
95
|
# the same Ruby wrapper.
|
|
@@ -224,6 +224,22 @@ module SFML
|
|
|
224
224
|
Event.from_native(@event_buffer)
|
|
225
225
|
end
|
|
226
226
|
|
|
227
|
+
# The pixel-space rect a `view` projects onto inside this
|
|
228
|
+
# window. Combines the view's normalised viewport with the
|
|
229
|
+
# window's pixel size.
|
|
230
|
+
def viewport(view = self.view)
|
|
231
|
+
raise ArgumentError, "expected a SFML::View" unless view.is_a?(View)
|
|
232
|
+
Rect.from_native(C::Graphics.sfRenderWindow_getViewport(@handle, view.handle))
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# The pixel-space scissor rect — same idea as `viewport` but
|
|
236
|
+
# for the view's `scissor` property. Pixels outside this rect
|
|
237
|
+
# are clipped before rendering.
|
|
238
|
+
def scissor(view = self.view)
|
|
239
|
+
raise ArgumentError, "expected a SFML::View" unless view.is_a?(View)
|
|
240
|
+
Rect.from_native(C::Graphics.sfRenderWindow_getScissor(@handle, view.handle))
|
|
241
|
+
end
|
|
242
|
+
|
|
227
243
|
# Wrap an existing OS-level window. `handle` is a platform native
|
|
228
244
|
# handle (Integer address or FFI::Pointer). Useful for embedding
|
|
229
245
|
# the renderer inside another framework's window (Qt, Gtk, raw
|
data/lib/sfml/graphics/shader.rb
CHANGED
|
@@ -152,6 +152,15 @@ module SFML
|
|
|
152
152
|
# with raw GL libraries.
|
|
153
153
|
def native_handle = C::Graphics.sfShader_getNativeHandle(@handle)
|
|
154
154
|
|
|
155
|
+
# Set a `vec4` uniform from an integer-channel `SFML::Color`
|
|
156
|
+
# (RGBA 0–255). Equivalent to writing `[c.r/255, ..., c.a/255]`
|
|
157
|
+
# by hand into a vec4 — the CSFML helper does the divide for
|
|
158
|
+
# you.
|
|
159
|
+
def set_int_color(name, color)
|
|
160
|
+
raise ArgumentError, "expected SFML::Color" unless color.is_a?(Color)
|
|
161
|
+
C::Graphics.sfShader_setIntColorUniform(@handle, name.to_s, color.to_native)
|
|
162
|
+
end
|
|
163
|
+
|
|
155
164
|
attr_reader :handle # :nodoc:
|
|
156
165
|
|
|
157
166
|
private
|
data/lib/sfml/graphics/sprite.rb
CHANGED
|
@@ -70,6 +70,38 @@ module SFML
|
|
|
70
70
|
target._draw_native(:Sprite, @handle, states_ptr)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
+
# The Texture this sprite was last bound to. Borrowed — caller
|
|
74
|
+
# is responsible for keeping the source texture alive.
|
|
75
|
+
def texture
|
|
76
|
+
ptr = C::Graphics.sfSprite_getTexture(@handle)
|
|
77
|
+
return nil if ptr.null?
|
|
78
|
+
Texture.send(:_borrow, ptr)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Combined transform (translation + rotation + scale + origin)
|
|
82
|
+
# the renderer applies when drawing this sprite.
|
|
83
|
+
def transform
|
|
84
|
+
C::Graphics.sfSprite_getTransform(@handle)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def inverse_transform
|
|
88
|
+
C::Graphics.sfSprite_getInverseTransform(@handle)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Deep copy — same texture binding (textures are shared GPU
|
|
92
|
+
# objects), independent transform / colour state.
|
|
93
|
+
def dup
|
|
94
|
+
ptr = C::Graphics.sfSprite_copy(@handle)
|
|
95
|
+
raise Error, "sfSprite_copy returned NULL" if ptr.null?
|
|
96
|
+
|
|
97
|
+
copy = self.class.allocate
|
|
98
|
+
copy.instance_variable_set(:@handle,
|
|
99
|
+
FFI::AutoPointer.new(ptr, C::Graphics.method(:sfSprite_destroy)))
|
|
100
|
+
copy.instance_variable_set(:@texture, @texture) # keep source alive
|
|
101
|
+
copy
|
|
102
|
+
end
|
|
103
|
+
alias clone dup
|
|
104
|
+
|
|
73
105
|
attr_reader :handle # :nodoc:
|
|
74
106
|
end
|
|
75
107
|
end
|
|
@@ -31,6 +31,24 @@ module SFML
|
|
|
31
31
|
tex
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
# Decode + upload a Ruby String of bytes (PNG, JPG, BMP, …) as
|
|
35
|
+
# a texture. Useful for embedded assets / network responses
|
|
36
|
+
# that bypass the disk.
|
|
37
|
+
def self.from_memory(bytes, smooth: false, repeated: false)
|
|
38
|
+
raise ArgumentError, "expected a String, got #{bytes.class}" unless bytes.is_a?(String)
|
|
39
|
+
|
|
40
|
+
buf = FFI::MemoryPointer.new(:uint8, bytes.bytesize)
|
|
41
|
+
buf.write_bytes(bytes)
|
|
42
|
+
ptr = C::Graphics.sfTexture_createFromMemory(buf, bytes.bytesize, nil)
|
|
43
|
+
raise Error, "sfTexture_createFromMemory returned NULL — unsupported format?" if ptr.null?
|
|
44
|
+
|
|
45
|
+
tex = allocate
|
|
46
|
+
tex.send(:_take_ownership, ptr)
|
|
47
|
+
tex.smooth = smooth
|
|
48
|
+
tex.repeated = repeated
|
|
49
|
+
tex
|
|
50
|
+
end
|
|
51
|
+
|
|
34
52
|
# Upload a CPU-side SFML::Image to the GPU as a new Texture. Keeps
|
|
35
53
|
# the RGBA byte order and dimensions of the source image.
|
|
36
54
|
def self.from_image(image, smooth: false, repeated: false)
|
|
@@ -123,6 +141,54 @@ module SFML
|
|
|
123
141
|
end
|
|
124
142
|
alias clone dup
|
|
125
143
|
|
|
144
|
+
# Reallocate this texture's GPU memory at a new size. Returns
|
|
145
|
+
# `false` if the GPU rejects the size (driver limit / OOM);
|
|
146
|
+
# the texture's contents become undefined on success.
|
|
147
|
+
def resize(width, height)
|
|
148
|
+
size = C::System::Vector2u.new
|
|
149
|
+
size[:x] = Integer(width); size[:y] = Integer(height)
|
|
150
|
+
C::Graphics.sfTexture_resize(@handle, size)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Atomically swap the GPU memory between two textures —
|
|
154
|
+
# cheaper than `dup` + reassign for double-buffer-style
|
|
155
|
+
# patterns (paint-buffer ⇄ visible-buffer).
|
|
156
|
+
def swap(other)
|
|
157
|
+
raise ArgumentError, "Texture#swap needs a Texture" unless other.is_a?(Texture)
|
|
158
|
+
C::Graphics.sfTexture_swap(@handle, other.handle)
|
|
159
|
+
self
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# The OpenGL texture-object name (a `glGenTextures` ID).
|
|
163
|
+
# Useful when feeding this texture into raw GL calls.
|
|
164
|
+
def native_handle = C::Graphics.sfTexture_getNativeHandle(@handle)
|
|
165
|
+
|
|
166
|
+
# Upload the contents of another texture into this one at
|
|
167
|
+
# `offset` (`[x, y]`). Both textures must remain alive for the
|
|
168
|
+
# duration of the call.
|
|
169
|
+
def update_from_texture(source, offset: [0, 0])
|
|
170
|
+
raise ArgumentError, "expected a Texture" unless source.is_a?(Texture)
|
|
171
|
+
C::Graphics.sfTexture_updateFromTexture(@handle, source.handle, _vec2u(offset))
|
|
172
|
+
self
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Read the back-buffer of a `RenderWindow` into this texture
|
|
176
|
+
# at `offset`. Useful for capturing the rendered scene
|
|
177
|
+
# without re-drawing into a separate `RenderTexture`.
|
|
178
|
+
def update_from_render_window(window, offset: [0, 0])
|
|
179
|
+
raise ArgumentError, "expected a RenderWindow" unless window.is_a?(RenderWindow)
|
|
180
|
+
C::Graphics.sfTexture_updateFromRenderWindow(@handle, window.handle, _vec2u(offset))
|
|
181
|
+
self
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Same as `update_from_render_window` for the bare `Window`
|
|
185
|
+
# (when you're managing GL yourself).
|
|
186
|
+
def update_from_window(window, offset: [0, 0])
|
|
187
|
+
raise ArgumentError, "expected a Window" unless window.is_a?(SFML::Window)
|
|
188
|
+
C::Graphics.sfTexture_updateFromWindow(@handle, window.handle, _vec2u(offset))
|
|
189
|
+
self
|
|
190
|
+
end
|
|
191
|
+
|
|
126
192
|
attr_reader :handle # :nodoc:
|
|
127
193
|
|
|
128
194
|
# Internal — borrow a CSFML-owned `sfTexture*` (e.g. one
|
|
@@ -140,5 +206,12 @@ module SFML
|
|
|
140
206
|
def _take_ownership(ptr)
|
|
141
207
|
@handle = FFI::AutoPointer.new(ptr, C::Graphics.method(:sfTexture_destroy))
|
|
142
208
|
end
|
|
209
|
+
|
|
210
|
+
def _vec2u(value)
|
|
211
|
+
v = C::System::Vector2u.new
|
|
212
|
+
x, y = value.is_a?(Vector2) ? [value.x, value.y] : value
|
|
213
|
+
v[:x] = Integer(x); v[:y] = Integer(y)
|
|
214
|
+
v
|
|
215
|
+
end
|
|
143
216
|
end
|
|
144
217
|
end
|
data/lib/sfml/graphics/view.rb
CHANGED
|
@@ -88,12 +88,20 @@ module SFML
|
|
|
88
88
|
|
|
89
89
|
def viewport=(rect)
|
|
90
90
|
raise ArgumentError, "View#viewport= needs a SFML::Rect" unless rect.is_a?(Rect)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
91
|
+
C::Graphics.sfView_setViewport(@handle, _to_floatrect(rect))
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Scissor rect in normalised [0,1] window coords — pixels
|
|
95
|
+
# *outside* this rect are clipped before rendering. Default
|
|
96
|
+
# `[0, 0, 1, 1]` (no clipping). Use it to render UI inside a
|
|
97
|
+
# sub-region of the window without re-projecting.
|
|
98
|
+
def scissor
|
|
99
|
+
Rect.from_native(C::Graphics.sfView_getScissor(@handle))
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def scissor=(rect)
|
|
103
|
+
raise ArgumentError, "View#scissor= needs a SFML::Rect" unless rect.is_a?(Rect)
|
|
104
|
+
C::Graphics.sfView_setScissor(@handle, _to_floatrect(rect))
|
|
97
105
|
end
|
|
98
106
|
|
|
99
107
|
# Pan the camera by an offset in world units.
|
|
@@ -119,6 +127,15 @@ module SFML
|
|
|
119
127
|
|
|
120
128
|
private
|
|
121
129
|
|
|
130
|
+
def _to_floatrect(rect)
|
|
131
|
+
native = C::Graphics::FloatRect.new
|
|
132
|
+
native[:position][:x] = rect.x.to_f
|
|
133
|
+
native[:position][:y] = rect.y.to_f
|
|
134
|
+
native[:size][:x] = rect.width.to_f
|
|
135
|
+
native[:size][:y] = rect.height.to_f
|
|
136
|
+
native
|
|
137
|
+
end
|
|
138
|
+
|
|
122
139
|
def _vec2(value)
|
|
123
140
|
value.is_a?(Vector2) ? value : Vector2.new(*value)
|
|
124
141
|
end
|
data/lib/sfml/version.rb
CHANGED