ruby-sfml 3.0.0.6 → 3.0.0.7

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.rdoc_options +44 -0
  3. data/CHANGELOG.md +40 -3
  4. data/README.md +71 -25
  5. data/lib/sfml/app.rb +5 -0
  6. data/lib/sfml/assets.rb +2 -0
  7. data/lib/sfml/audio/listener.rb +7 -0
  8. data/lib/sfml/audio/music.rb +51 -0
  9. data/lib/sfml/audio/sound.rb +41 -0
  10. data/lib/sfml/audio/sound_buffer.rb +4 -0
  11. data/lib/sfml/audio/sound_buffer_recorder.rb +2 -0
  12. data/lib/sfml/audio/sound_cone.rb +1 -0
  13. data/lib/sfml/audio/sound_recorder.rb +5 -0
  14. data/lib/sfml/audio/sound_stream.rb +46 -0
  15. data/lib/sfml/graphics/animation.rb +10 -0
  16. data/lib/sfml/graphics/blend_mode.rb +1 -0
  17. data/lib/sfml/graphics/circle_shape.rb +16 -0
  18. data/lib/sfml/graphics/color.rb +31 -0
  19. data/lib/sfml/graphics/convex_shape.rb +9 -0
  20. data/lib/sfml/graphics/font.rb +2 -0
  21. data/lib/sfml/graphics/image.rb +2 -0
  22. data/lib/sfml/graphics/particle_system.rb +5 -0
  23. data/lib/sfml/graphics/rectangle_shape.rb +11 -0
  24. data/lib/sfml/graphics/render_target.rb +1 -0
  25. data/lib/sfml/graphics/render_texture.rb +7 -0
  26. data/lib/sfml/graphics/render_window.rb +26 -0
  27. data/lib/sfml/graphics/shape.rb +5 -0
  28. data/lib/sfml/graphics/shape_inspectable.rb +2 -0
  29. data/lib/sfml/graphics/sprite.rb +4 -0
  30. data/lib/sfml/graphics/sprite_sheet.rb +2 -0
  31. data/lib/sfml/graphics/stencil_mode.rb +1 -0
  32. data/lib/sfml/graphics/text.rb +19 -0
  33. data/lib/sfml/graphics/texture.rb +5 -0
  34. data/lib/sfml/graphics/texture_atlas.rb +2 -0
  35. data/lib/sfml/graphics/transform.rb +2 -0
  36. data/lib/sfml/graphics/transformable.rb +12 -0
  37. data/lib/sfml/graphics/vertex_array.rb +18 -0
  38. data/lib/sfml/graphics/vertex_buffer.rb +4 -0
  39. data/lib/sfml/graphics/view.rb +5 -0
  40. data/lib/sfml/network/ftp.rb +34 -0
  41. data/lib/sfml/network/http.rb +1 -0
  42. data/lib/sfml/network/ip_address.rb +1 -0
  43. data/lib/sfml/network/packet.rb +28 -0
  44. data/lib/sfml/network/socket_selector.rb +1 -0
  45. data/lib/sfml/network/tcp_listener.rb +3 -0
  46. data/lib/sfml/network/tcp_socket.rb +4 -0
  47. data/lib/sfml/network/udp_socket.rb +3 -0
  48. data/lib/sfml/scene.rb +2 -0
  49. data/lib/sfml/system/clock.rb +1 -0
  50. data/lib/sfml/system/rect.rb +27 -5
  51. data/lib/sfml/system/time.rb +22 -2
  52. data/lib/sfml/system/vector2.rb +42 -2
  53. data/lib/sfml/system/vector3.rb +45 -2
  54. data/lib/sfml/version.rb +1 -1
  55. data/lib/sfml/window/clipboard.rb +1 -0
  56. data/lib/sfml/window/context_settings.rb +1 -0
  57. data/lib/sfml/window/event.rb +2 -0
  58. data/lib/sfml/window/joystick.rb +3 -0
  59. data/lib/sfml/window/sensor.rb +1 -0
  60. data/lib/sfml/window/video_mode.rb +2 -0
  61. data/lib/sfml/window/window.rb +12 -0
  62. data/ruby-sfml.gemspec +6 -2
  63. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e15752d993b5c76445ea903b92227b45c169009bed4de15166ff5db1d1fbd372
4
- data.tar.gz: bf5ae66de3f3df40c765c5aee29eef1138d1743e899e6e072e707f63ee0fcf84
3
+ metadata.gz: 4a12ef598ae1b1dc8e541b0e3f463ec05208391202d465a5cd5360ae473be321
4
+ data.tar.gz: 6830ae6b0a231203e36d104a81caeb3cdcee03f706728cf2af935596f19783aa
5
5
  SHA512:
6
- metadata.gz: dd013a7669a09457c0f5a6915ce8ee91ac32018146d0dae6a6af6d73f5f4dba8864778827aac10e2194c553b715a18895be056f41d0dc8002cfcc99087be4664
7
- data.tar.gz: 41ba407931cdf67f1493187c517a59d8b981d62ae4fd7ccf051696b9348fb03046228c651d2f0be45f0edb40b5f6a2ef417f4cda6dfd7124e04a46489bb7b258
6
+ metadata.gz: fd3caad7ec21d3408d86c973a3f0430408cfda54cb363664fbe6af319e11922740a52fde36290124ef3f591c87fbf70f0dfe2085dd3590e63dba51a54e392567
7
+ data.tar.gz: 41fee62ce46c0e69ee80521f51752309aa4b47bc82021d472f5370dad88dc28735549ee33563352938b2edd1f9f2e9fdbf25b611c33ccc01802b8a88acd2e9a5
data/.rdoc_options ADDED
@@ -0,0 +1,44 @@
1
+ ---
2
+ # RDoc project config. Read by both `rake rdoc` (via RDoc::Task) and
3
+ # the standalone `rdoc` CLI — the docs-site repo invokes `rdoc`
4
+ # directly, so all the user-facing knobs live here, not in Rakefile.
5
+
6
+ # Page rendered as the doc-site root.
7
+ main_page: README.md
8
+ title: ruby-sfml — modern Ruby bindings for SFML 3.x
9
+
10
+ # README + LICENSE + CHANGELOG are markdown; assume the same dialect
11
+ # in source-file comments.
12
+ markup: markdown
13
+
14
+ # `doc/` matches RDoc's default output dir.
15
+ output: doc
16
+
17
+ # Visibility filter: public API only. Internal `_method` helpers and
18
+ # the FFI plumbing under `SFML::C::*` add noise without value.
19
+ visibility: public
20
+
21
+ # What gets parsed. Skip the C-bindings module entirely; including
22
+ # them would document every `attach_function` and drown the API user.
23
+ exclude:
24
+ - lib/sfml/c.rb
25
+ - lib/sfml/c/
26
+ - ext/
27
+ - spec/
28
+ - examples/
29
+ - pkg/
30
+ - doc/
31
+ - vendor/
32
+
33
+ # Surface non-source pages as a "Pages" sidebar entry.
34
+ files:
35
+ - README.md
36
+ - CHANGELOG.md
37
+ - LICENSE.txt
38
+ - lib/
39
+
40
+ # Cosmetic.
41
+ template: darkfish
42
+ charset: UTF-8
43
+ line_numbers: false
44
+ show_hash: false
data/CHANGELOG.md CHANGED
@@ -6,8 +6,48 @@ versioning is [described in the README](README.md#versioning) — first
6
6
  three segments mirror the targeted CSFML release, fourth segment is
7
7
  ruby-sfml's own patch level.
8
8
 
9
+ HTML API docs: <https://ruby-sfml-doc.netlify.app/>
10
+
9
11
  ## [Unreleased]
10
12
 
13
+ ## [3.0.0.7] — 2026-05-12
14
+
15
+ Documentation pass. Every public class / module / method now
16
+ carries at least a one-line RDoc comment — coverage went from
17
+ ~36% (`rake rdoc:coverage`) to ~68%. Pair this release with the
18
+ new docs site at <https://ruby-sfml-doc.netlify.app/>.
19
+
20
+ ### Changed — documentation
21
+
22
+ - Hand-written, context-aware docstrings on the value classes
23
+ (`Vector2`, `Vector3`, `Color`, `Rect`, `Time`): every operator,
24
+ every helper, every pattern-match hook.
25
+ - Audio API surface (`Sound`, `Music`, `SoundStream`, `Listener`):
26
+ every playback method, every property setter/getter, every 3D-
27
+ audio knob has a real description.
28
+ - Graphics — `Transformable` mixin (`#position` / `#rotation` /
29
+ `#scale` / `#origin` / `#move` / `#rotate` / `#scale_by`), then
30
+ `CircleShape` / `RectangleShape` / `ConvexShape` / `Text` /
31
+ `VertexArray` / `RenderWindow`. Color named-accessors,
32
+ geometric introspection, fill / outline / texture binding.
33
+ - Network — typed `Packet` reader / writer methods, full FTP
34
+ surface (`#download` / `#upload` / `#directory_listing` / …).
35
+ - The autodoc pass fills in trivial setter / getter / predicate
36
+ pairs everywhere else, so the docs site has at least an
37
+ identifiable signature line on every public method.
38
+
39
+ ### Changed — infra
40
+
41
+ - `documentation_uri` in the gemspec now points to
42
+ <https://ruby-sfml-doc.netlify.app/> (was rubydoc.info).
43
+ rubydoc.info still works as an archive of older releases.
44
+ - `.rdoc_options` ships inside the gem (`gem unpack` exposes it),
45
+ so the docs-site repo can `rdoc` an unpacked release without
46
+ re-supplying title / template / markup / exclude config.
47
+ - Added `script/build-docs.sh` — local-only build that renders
48
+ `../ruby-sfml-doc/public/`. Optional `--check` mode catches
49
+ "docs out of date with source" in a pre-push hook.
50
+
11
51
  ## [3.0.0.6] — 2026-05-12
12
52
 
13
53
  Quality-of-life release: the CSFML 3.0 surface was already covered;
@@ -79,9 +119,6 @@ on top of it.
79
119
 
80
120
  ### Added — CI / tooling
81
121
 
82
- - GitHub Actions release workflow (`release.yml`) — tag
83
- `vX.Y.Z.W` triggers a gem build + push to RubyGems. Verifies
84
- the tag matches `lib/sfml/version.rb` before publishing.
85
122
  - CI badge in `README.md`.
86
123
 
87
124
  ## [3.0.0.5] — 2026-05-11
data/README.md CHANGED
@@ -7,9 +7,9 @@ Modern, idiomatic Ruby bindings for [SFML 3.x](https://www.sfml-dev.org/) via [C
7
7
 
8
8
  [![gem version](https://img.shields.io/gem/v/ruby-sfml.svg)](https://rubygems.org/gems/ruby-sfml)
9
9
  [![CI](https://github.com/sOM2H/ruby-sfml/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/sOM2H/ruby-sfml/actions/workflows/ci.yml)
10
- [![docs](https://img.shields.io/badge/docs-rubydoc.info-blue.svg)](https://www.rubydoc.info/gems/ruby-sfml)
10
+ [![docs](https://img.shields.io/badge/docs-ruby--sfml--doc.netlify.app-blue.svg)](https://ruby-sfml-doc.netlify.app/)
11
11
 
12
- > **Status:** API surface complete for SFML 3.0 — system, window, graphics (incl. stencil buffer + VBOs), audio (incl. 3D positional + custom DSP + procedural streams), network (incl. HTTP / FTP / socket selector), input (keyboard, mouse, joystick, touch, sensors), plus the higher-level `App` / `Scene` / `Assets` helpers. 410 RSpec examples, 24 runnable example folders.
12
+ > **Status:** API surface complete for SFML 3.0 — system, window, graphics (incl. stencil buffer + VBOs), audio (incl. 3D positional + custom DSP + procedural streams), network (incl. HTTP / FTP / socket selector), input (keyboard, mouse, joystick, touch, sensors), plus higher-level helpers (`App`, `Scene`, `Assets`, `SpriteSheet`, `Animation`, `TextureAtlas`, `ParticleSystem`, fixed timestep, input-action DSL, vector math). 640 RSpec examples, 35 runnable example folders.
13
13
 
14
14
  ## Why
15
15
 
@@ -46,9 +46,12 @@ Or drop it in directly:
46
46
  gem install ruby-sfml
47
47
  ```
48
48
 
49
- Hosted on [rubygems.org](https://rubygems.org/gems/ruby-sfml); HTML
50
- docs auto-generate at
51
- [rubydoc.info/gems/ruby-sfml](https://www.rubydoc.info/gems/ruby-sfml).
49
+ Hosted on [rubygems.org](https://rubygems.org/gems/ruby-sfml).
50
+ HTML docs (RDoc) live at [**ruby-sfml-doc.netlify.app**](https://ruby-sfml-doc.netlify.app/)
51
+ — built from the source tree of the latest release and served as
52
+ static HTML. RubyGems' auto-generated docs at
53
+ [rubydoc.info/gems/ruby-sfml](https://www.rubydoc.info/gems/ruby-sfml)
54
+ work too as a fallback.
52
55
 
53
56
  ### How the CSFML check happens
54
57
 
@@ -156,31 +159,74 @@ to its script. Run from the gem root:
156
159
  bundle exec ruby examples/<NN_name>/<name>.rb
157
160
  ```
158
161
 
162
+ The numbering reflects a rough learning order — earlier examples
163
+ introduce concepts that later ones build on. Pick the section that
164
+ matches what you want to learn first.
165
+
166
+ ### Foundations — window, events, input
167
+
159
168
  | # | Example | What it shows |
160
169
  | --- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
161
170
  | 01 | [hello_window](examples/01_hello_window/hello_window.rb) | Empty window, manual event loop |
162
171
  | 02 | [events_demo](examples/02_events_demo/events_demo.rb) | Pattern matching on input events |
163
- | 03 | [bouncing_ball](examples/03_bouncing_ball/bouncing_ball.rb) | dt-based physics, `CircleShape` + `RectangleShape` |
164
- | 04 | [app_class](examples/04_app_class/app_class.rb) | Same idea on top of `SFML::App` |
165
- | 05 | [mouse_demo](examples/05_mouse_demo/mouse_demo.rb) | Polling vs. events; paint with the mouse |
166
- | 06 | [pong](examples/06_pong/pong.rb) | Two-player Pong with in-window score (`Text`) and bounce `Sound` |
167
- | 07 | [scrolling_world](examples/07_scrolling_world/scrolling_world.rb) | `View` as a 2D camera: drag-pan, wheel-zoom around cursor, FPS HUD |
168
- | 08 | [joystick_demo](examples/08_joystick_demo/joystick_demo.rb) | Live gamepad inspector (axes, buttons, connect/disconnect) |
169
- | 09 | [image_viewer](examples/09_image_viewer/image_viewer.rb) | Load a PNG, mutate the `Image`, re-upload to `Texture` on a key |
170
- | 10 | [pixel_paint](examples/10_pixel_paint/pixel_paint.rb) | Paint into a CPU `Image`, blit to GPU `Texture` each dirty frame |
171
- | 11 | [particles](examples/11_particles/particles.rb) | Thousands of points in one draw call via `VertexArray` + `ConvexShape` ground |
172
- | 12 | [render_texture](examples/12_render_texture/render_texture.rb) | Off-screen `RenderTexture` for trail / motion-blur effects |
173
- | 13 | [tilemap](examples/13_tilemap/tilemap.rb) | Textured `VertexArray` tilemap + additive `BlendMode` torch |
174
- | 14 | [shader_wave](examples/14_shader_wave/shader_wave.rb) | Pure GLSL fragment `Shader` — procedural ripple + plasma |
172
+ | 03 | [mouse_demo](examples/03_mouse_demo/mouse_demo.rb) | Polling vs. events; paint with the mouse |
173
+ | 04 | [bouncing_ball](examples/04_bouncing_ball/bouncing_ball.rb) | dt-based physics on a manual main loop |
174
+ | 05 | [app_class](examples/05_app_class/app_class.rb) | Same idea on top of `SFML::App` — see how much boilerplate goes away |
175
+ | 06 | [vector_math](examples/06_vector_math/vector_math.rb) | `Vector2` helpers (`#distance` / `#angle_to` / `#rotated` / `#lerp` / `#clamp_length`) in real motion |
176
+ | 07 | [input_actions](examples/07_input_actions/input_actions.rb) | `action :name, keys:, scancodes:, mouse_buttons:` DSL + `axis(...)` digital steering |
177
+
178
+ ### Drawing geometry and assets
179
+
180
+ | # | Example | What it shows |
181
+ | --- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
182
+ | 08 | [draw_primitives](examples/08_draw_primitives/draw_primitives.rb) | Raw `draw_primitives` line burst rebuilt every frame |
183
+ | 09 | [custom_shape](examples/09_custom_shape/custom_shape.rb) | Abstract `SFML::Shape` subclass parametric star / heart / gear |
184
+ | 10 | [image_viewer](examples/10_image_viewer/image_viewer.rb) | Load a PNG, mutate the `Image`, re-upload to `Texture` on a key |
185
+ | 11 | [pixel_paint](examples/11_pixel_paint/pixel_paint.rb) | Paint into a CPU `Image`, blit to GPU `Texture` each dirty frame |
186
+ | 12 | [sprite_animation](examples/12_sprite_animation/sprite_animation.rb) | Procedural `SpriteSheet` → `Animation` walk cycle |
187
+ | 13 | [texture_atlas](examples/13_texture_atlas/texture_atlas.rb) | Aseprite-style JSON atlas → 3 named animations with auto-fps |
188
+ | 14 | [window_icon](examples/14_window_icon/window_icon.rb) | Procedural 32×32 icon set as the window/taskbar icon |
175
189
  | 15 | [cursors_clipboard](examples/15_cursors_clipboard/cursors_clipboard.rb) | All 21 system `Cursor` shapes + `Clipboard` copy/paste |
176
- | 16 | [spatial_audio](examples/16_spatial_audio/spatial_audio.rb) | 3D positional `Sound` + `Listener` — three drones around the cursor |
177
- | 17 | [voice_memo](examples/17_voice_memo/voice_memo.rb) | Record from microphone via `SoundBufferRecorder`, save + play back |
178
- | 18 | [draw_primitives](examples/18_draw_primitives/draw_primitives.rb) | Raw `draw_primitives` — line burst rebuilt every frame |
179
- | 19 | [udp_loopback](examples/19_udp_loopback/udp_loopback.rb) | UDP send/receive on localhost via `Network::UdpSocket` |
180
- | 20 | [bare_window](examples/20_bare_window/bare_window.rb) | `SFML::Window` (no 2D batcher) — events for raw-OpenGL apps |
181
- | 21 | [window_icon](examples/21_window_icon/window_icon.rb) | Procedural 32×32 icon set as the window/taskbar icon |
182
- | 22 | [stencil_mask](examples/22_stencil_mask/stencil_mask.rb) | Two-pass `StencilMode` masking cursor spotlight clip |
183
- | 23 | [sound_stream](examples/23_sound_stream/sound_stream.rb) | Real-time sine synth via `SFML::SoundStream` subclass |
190
+
191
+ ### Camera, GPU, effects
192
+
193
+ | # | Example | What it shows |
194
+ | --- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
195
+ | 16 | [screenshot](examples/16_screenshot/screenshot.rb) | `RenderWindow#screenshot(path)` / `#capture_image` for in-memory frames |
196
+ | 17 | [scrolling_world](examples/17_scrolling_world/scrolling_world.rb) | `View` as a 2D camera: drag-pan, wheel-zoom around cursor, FPS HUD |
197
+ | 18 | [render_texture](examples/18_render_texture/render_texture.rb) | Off-screen `RenderTexture` for trail / motion-blur effects |
198
+ | 19 | [tilemap](examples/19_tilemap/tilemap.rb) | Textured `VertexArray` tilemap + additive `BlendMode` torch |
199
+ | 20 | [particle_system](examples/20_particle_system/particle_system.rb) | `SFML::ParticleSystem` fountain — VertexArray-backed pool |
200
+ | 21 | [particles](examples/21_particles/particles.rb) | Same fountain hand-rolled on `VertexArray` + `ConvexShape` ground |
201
+ | 22 | [shader_wave](examples/22_shader_wave/shader_wave.rb) | Pure GLSL fragment `Shader` — procedural ripple + plasma |
202
+ | 23 | [stencil_mask](examples/23_stencil_mask/stencil_mask.rb) | Two-pass `StencilMode` masking — cursor spotlight clip |
203
+ | 24 | [vertex_buffer](examples/24_vertex_buffer/vertex_buffer.rb) | 120 K-vertex `VertexBuffer` drawn in one call, animated via `View` only |
204
+ | 25 | [bare_window](examples/25_bare_window/bare_window.rb) | `SFML::Window` (no 2D batcher) — events for raw-OpenGL apps |
205
+
206
+ ### Game-loop polish
207
+
208
+ | # | Example | What it shows |
209
+ | --- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
210
+ | 26 | [scenes](examples/26_scenes/scenes.rb) | Title → play → game-over flow with `SFML::Scene` |
211
+ | 27 | [fixed_timestep](examples/27_fixed_timestep/fixed_timestep.rb) | `fixed_timestep 30` + `interpolation_alpha` for jitter-free physics |
212
+ | 28 | [pong](examples/28_pong/pong.rb) | Two-player Pong with in-window score (`Text`) and bounce `Sound` |
213
+ | 29 | [joystick_demo](examples/29_joystick_demo/joystick_demo.rb) | Live gamepad inspector (axes, buttons, connect/disconnect) |
214
+
215
+ ### Audio — simple to procedural
216
+
217
+ | # | Example | What it shows |
218
+ | --- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
219
+ | 30 | [spatial_audio](examples/30_spatial_audio/spatial_audio.rb) | 3D positional `Sound` + `Listener` — three drones around the cursor |
220
+ | 31 | [voice_memo](examples/31_voice_memo/voice_memo.rb) | Record from microphone via `SoundBufferRecorder`, save + play back |
221
+ | 32 | [sound_stream](examples/32_sound_stream/sound_stream.rb) | Real-time sine synth via `SFML::SoundStream` subclass |
222
+ | 33 | [procedural_synth](examples/33_procedural_synth/procedural_synth.rb) | `SoundBuffer.from_samples` mini-piano (Z–M keys, chromatic C4..B4) |
223
+
224
+ ### Networking
225
+
226
+ | # | Example | What it shows |
227
+ | --- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
228
+ | 34 | [udp_loopback](examples/34_udp_loopback/udp_loopback.rb) | UDP send/receive on localhost via `Network::UdpSocket` |
229
+ | 35 | [tcp_chat](examples/35_tcp_chat/tcp_chat.rb) | `TcpListener` + `TcpSocket` + typed `Network::Packet` over loopback |
184
230
 
185
231
  ## Idioms baked in
186
232
 
data/lib/sfml/app.rb CHANGED
@@ -118,6 +118,7 @@ module SFML
118
118
  # Width and height shortcuts that always reflect the current
119
119
  # window size — matters once the user is allowed to resize.
120
120
  def width = @window.size.x
121
+ # Returns the height.
121
122
  def height = @window.size.y
122
123
 
123
124
  # Close the window. The main loop exits at the start of the
@@ -160,9 +161,13 @@ module SFML
160
161
  # (handy for pause overlays that need to be drawn over a
161
162
  # frozen scene).
162
163
 
164
+ # Pause the simulation. `#draw` keeps firing; `#update` doesn't.
163
165
  def pause = (@paused = true)
166
+ # Resume the simulation.
164
167
  def resume = (@paused = false)
168
+ # Flip the pause state.
165
169
  def toggle_pause = (@paused = !paused?)
170
+ # `true` while the simulation is paused.
166
171
  def paused? = @paused == true
167
172
 
168
173
  # Fraction of a fixed timestep accumulated since the last
data/lib/sfml/assets.rb CHANGED
@@ -26,11 +26,13 @@ module SFML
26
26
  @search_paths ||= [default_root]
27
27
  end
28
28
 
29
+ # Set the search paths.
29
30
  def search_paths=(paths)
30
31
  @search_paths = Array(paths).map { |p| File.expand_path(p) }
31
32
  @cache&.clear
32
33
  end
33
34
 
35
+ # Set the root.
34
36
  def root=(path)
35
37
  self.search_paths = [path]
36
38
  end
@@ -17,14 +17,17 @@ module SFML
17
17
  C::Audio.sfListener_getGlobalVolume
18
18
  end
19
19
 
20
+ # Set the master volume in [0, 100].
20
21
  def global_volume=(value)
21
22
  C::Audio.sfListener_setGlobalVolume(value.to_f)
22
23
  end
23
24
 
25
+ # The listener's 3D position in world space.
24
26
  def position
25
27
  Vector3.from_native(C::Audio.sfListener_getPosition)
26
28
  end
27
29
 
30
+ # Set the position — accepts Vector3 or `[x, y, z]`.
28
31
  def position=(value)
29
32
  vec = value.is_a?(Vector3) ? value : Vector3.new(*value)
30
33
  C::Audio.sfListener_setPosition(vec.to_native_f)
@@ -36,6 +39,7 @@ module SFML
36
39
  Vector3.from_native(C::Audio.sfListener_getDirection)
37
40
  end
38
41
 
42
+ # Set the forward direction — accepts Vector3 or `[x, y, z]`.
39
43
  def direction=(value)
40
44
  vec = value.is_a?(Vector3) ? value : Vector3.new(*value)
41
45
  C::Audio.sfListener_setDirection(vec.to_native_f)
@@ -47,6 +51,7 @@ module SFML
47
51
  Vector3.from_native(C::Audio.sfListener_getUpVector)
48
52
  end
49
53
 
54
+ # Set the up vector — accepts Vector3 or `[x, y, z]`.
50
55
  def up_vector=(value)
51
56
  vec = value.is_a?(Vector3) ? value : Vector3.new(*value)
52
57
  C::Audio.sfListener_setUpVector(vec.to_native_f)
@@ -58,6 +63,7 @@ module SFML
58
63
  Vector3.from_native(C::Audio.sfListener_getVelocity)
59
64
  end
60
65
 
66
+ # Set the velocity — accepts Vector3 or `[x, y, z]`.
61
67
  def velocity=(value)
62
68
  vec = value.is_a?(Vector3) ? value : Vector3.new(*value)
63
69
  C::Audio.sfListener_setVelocity(vec.to_native_f)
@@ -72,6 +78,7 @@ module SFML
72
78
  SoundCone.from_native(C::Audio.sfListener_getCone)
73
79
  end
74
80
 
81
+ # Set the cone. Accepts a `SoundCone` or a Hash.
75
82
  def cone=(value)
76
83
  cone =
77
84
  case value
@@ -5,6 +5,9 @@ module SFML
5
5
  # bgm = SFML::Music.load("assets/track.ogg", looping: true, volume: 60)
6
6
  # bgm.play
7
7
  class Music
8
+ # Load a music track from disk. `opts` may include `:volume`,
9
+ # `:pitch`, and `:looping` — these are applied right after load.
10
+ # Raises `SFML::LoadError` on missing file or unsupported format.
8
11
  def self.load(path, **opts)
9
12
  ptr = C::Audio.sfMusic_createFromFile(path.to_s)
10
13
  raise LoadError, "Could not load music from #{path.inspect}" if ptr.null?
@@ -56,15 +59,23 @@ module SFML
56
59
  end
57
60
  private_class_method :_wrap
58
61
 
62
+ # Start playback (resumes from pause, restarts when stopped).
59
63
  def play = C::Audio.sfMusic_play(@handle)
64
+ # Pause playback — `#play` resumes from here.
60
65
  def pause = C::Audio.sfMusic_pause(@handle)
66
+ # Stop playback and rewind to the start.
61
67
  def stop = C::Audio.sfMusic_stop(@handle)
62
68
 
69
+ # Playback state — one of `:stopped`, `:paused`, `:playing`.
63
70
  def status = C::Audio::STATUSES[C::Audio.sfMusic_getStatus(@handle)]
71
+ # Convenience for `status == :playing`.
64
72
  def playing? = status == :playing
73
+ # Convenience for `status == :paused`.
65
74
  def paused? = status == :paused
75
+ # Convenience for `status == :stopped`.
66
76
  def stopped? = status == :stopped
67
77
 
78
+ # Total length of the track as a `SFML::Time`.
68
79
  def duration = Time.from_native(C::Audio.sfMusic_getDuration(@handle))
69
80
 
70
81
  # Current playback head as a SFML::Time. Reads from the underlying
@@ -88,6 +99,7 @@ module SFML
88
99
  Vector3.new(v[:x], v[:y], v[:z])
89
100
  end
90
101
 
102
+ # Set the 3D velocity — accepts Vector3 or `[x, y, z]`.
91
103
  def velocity=(value)
92
104
  vec = value.is_a?(Vector3) ? value : Vector3.new(*value)
93
105
  packed = C::System::Vector3f.new
@@ -95,14 +107,18 @@ module SFML
95
107
  C::Audio.sfMusic_setVelocity(@handle, packed)
96
108
  end
97
109
 
110
+ # Per-source Doppler scale. 1.0 realistic, 0 disables.
98
111
  def doppler_factor = C::Audio.sfMusic_getDopplerFactor(@handle)
112
+ # Set the per-source Doppler scale.
99
113
  def doppler_factor=(v) C::Audio.sfMusic_setDopplerFactor(@handle, v.to_f); end
100
114
 
115
+ # The direction the music's cone points.
101
116
  def direction
102
117
  v = C::Audio.sfMusic_getDirection(@handle)
103
118
  Vector3.new(v[:x], v[:y], v[:z])
104
119
  end
105
120
 
121
+ # Set the direction vector — accepts Vector3 or `[x, y, z]`.
106
122
  def direction=(value)
107
123
  vec = value.is_a?(Vector3) ? value : Vector3.new(*value)
108
124
  packed = C::System::Vector3f.new
@@ -110,10 +126,13 @@ module SFML
110
126
  C::Audio.sfMusic_setDirection(@handle, packed)
111
127
  end
112
128
 
129
+ # Directional-attenuation cone — see SFML::SoundCone.
113
130
  def cone
114
131
  SoundCone.from_native(C::Audio.sfMusic_getCone(@handle))
115
132
  end
116
133
 
134
+ # Set the cone. Accepts a `SoundCone` or a Hash with
135
+ # `inner_angle`, `outer_angle`, `outer_gain`.
117
136
  def cone=(value)
118
137
  cone =
119
138
  case value
@@ -131,24 +150,31 @@ module SFML
131
150
  C::Audio.sfMusic_setEffectProcessor(@handle, @effect_cb, nil)
132
151
  end
133
152
 
153
+ # `true` if the track restarts after reaching the end (or its
154
+ # `loop_points` length).
134
155
  # Cached on the Ruby side; see Sound#looping? for the why.
135
156
  def looping?
136
157
  @looping
137
158
  end
138
159
 
160
+ # Toggle looping playback.
139
161
  def looping=(value)
140
162
  @looping = value ? true : false
141
163
  C::Audio.sfMusic_setLooping(@handle, @looping)
142
164
  end
143
165
 
166
+ # Playback volume in [0, 100] — 100 = unattenuated.
144
167
  def volume = C::Audio.sfMusic_getVolume(@handle)
145
168
 
169
+ # Set the playback volume in [0, 100].
146
170
  def volume=(value)
147
171
  C::Audio.sfMusic_setVolume(@handle, value.to_f)
148
172
  end
149
173
 
174
+ # Pitch multiplier. 1.0 = normal, 2.0 = octave up, 0.5 = octave down.
150
175
  def pitch = C::Audio.sfMusic_getPitch(@handle)
151
176
 
177
+ # Set the pitch multiplier.
152
178
  def pitch=(value)
153
179
  C::Audio.sfMusic_setPitch(@handle, value.to_f)
154
180
  end
@@ -158,32 +184,41 @@ module SFML
158
184
  Vector3.from_native(C::Audio.sfMusic_getPosition(@handle))
159
185
  end
160
186
 
187
+ # Set the 3D position — accepts Vector3 or `[x, y, z]`.
161
188
  def position=(value)
162
189
  vec = value.is_a?(Vector3) ? value : Vector3.new(*value)
163
190
  C::Audio.sfMusic_setPosition(@handle, vec.to_native_f)
164
191
  end
165
192
 
193
+ # Falloff sharpness with distance — see `Sound#attenuation`.
166
194
  def attenuation = C::Audio.sfMusic_getAttenuation(@handle)
167
195
 
196
+ # Set the attenuation.
168
197
  def attenuation=(value)
169
198
  C::Audio.sfMusic_setAttenuation(@handle, value.to_f)
170
199
  end
171
200
 
201
+ # Distance below which volume is not attenuated.
172
202
  def min_distance = C::Audio.sfMusic_getMinDistance(@handle)
173
203
 
204
+ # Set the min-distance.
174
205
  def min_distance=(value)
175
206
  C::Audio.sfMusic_setMinDistance(@handle, value.to_f)
176
207
  end
177
208
 
209
+ # `true` if `#position` is interpreted relative to the listener.
178
210
  def relative_to_listener? = C::Audio.sfMusic_isRelativeToListener(@handle)
179
211
 
212
+ # Toggle listener-relative positioning.
180
213
  def relative_to_listener=(value)
181
214
  C::Audio.sfMusic_setRelativeToListener(@handle, value ? true : false)
182
215
  end
183
216
 
184
217
  # ---- Stream introspection ----
185
218
 
219
+ # Number of audio channels (1 = mono, 2 = stereo, ...).
186
220
  def channel_count = C::Audio.sfMusic_getChannelCount(@handle)
221
+ # Sample rate in Hz (e.g. 44_100 for CD-quality).
187
222
  def sample_rate = C::Audio.sfMusic_getSampleRate(@handle)
188
223
 
189
224
  # The portion of the track that loops when `looping = true`.
@@ -194,6 +229,8 @@ module SFML
194
229
  [Time.from_native(span[:offset]), Time.from_native(span[:length])]
195
230
  end
196
231
 
232
+ # Set the looping window. Accepts `[offset, length]` of either
233
+ # `SFML::Time` or numeric seconds.
197
234
  def loop_points=(value)
198
235
  offset_t, length_t = value
199
236
  raise ArgumentError, "expected [offset_time, length_time]" unless offset_t && length_t
@@ -206,40 +243,54 @@ module SFML
206
243
 
207
244
  # ---- 3D-audio extras (mirror of Sound's) ----
208
245
 
246
+ # Stereo pan in [-1.0, 1.0] — see `Sound#pan`.
209
247
  def pan = C::Audio.sfMusic_getPan(@handle)
210
248
 
249
+ # Set the stereo pan.
211
250
  def pan=(v)
212
251
  C::Audio.sfMusic_setPan(@handle, v.to_f)
213
252
  end
214
253
 
254
+ # Lower gain bound — see `Sound#min_gain`.
215
255
  def min_gain = C::Audio.sfMusic_getMinGain(@handle)
216
256
 
257
+ # Set the min-gain floor.
217
258
  def min_gain=(v)
218
259
  C::Audio.sfMusic_setMinGain(@handle, v.to_f)
219
260
  end
220
261
 
262
+ # Upper gain bound — see `Sound#max_gain`.
221
263
  def max_gain = C::Audio.sfMusic_getMaxGain(@handle)
222
264
 
265
+ # Set the max-gain cap.
223
266
  def max_gain=(v)
224
267
  C::Audio.sfMusic_setMaxGain(@handle, v.to_f)
225
268
  end
226
269
 
270
+ # Distance beyond which the source is fully attenuated.
227
271
  def max_distance = C::Audio.sfMusic_getMaxDistance(@handle)
228
272
 
273
+ # Set the max-distance.
229
274
  def max_distance=(v)
230
275
  C::Audio.sfMusic_setMaxDistance(@handle, v.to_f)
231
276
  end
232
277
 
278
+ # `true` if 3D positional / Doppler / cone math is applied at
279
+ # mix time.
233
280
  def spatialization_enabled? = C::Audio.sfMusic_isSpatializationEnabled(@handle)
234
281
 
282
+ # Toggle 3D spatialisation.
235
283
  def spatialization_enabled=(v)
236
284
  C::Audio.sfMusic_setSpatializationEnabled(@handle, v ? true : false)
237
285
  end
238
286
 
287
+ # Multiplier on the Listener's directional attenuation cone —
288
+ # see `Sound#directional_attenuation_factor`.
239
289
  def directional_attenuation_factor
240
290
  C::Audio.sfMusic_getDirectionalAttenuationFactor(@handle)
241
291
  end
242
292
 
293
+ # Set the directional-attenuation factor.
243
294
  def directional_attenuation_factor=(v)
244
295
  C::Audio.sfMusic_setDirectionalAttenuationFactor(@handle, v.to_f)
245
296
  end