sfml3-rb 0.3.0 → 0.3.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 +25 -0
- data/README.md +36 -13
- data/TODO.md +18 -11
- data/ext/audio/music.c +6 -0
- data/ext/audio/sound.c +43 -4
- data/ext/audio/sound_buffer.c +8 -0
- data/ext/audio/sound_buffer_recorder.c +8 -3
- data/ext/audio/sound_recorder.c +21 -11
- data/ext/audio/sound_source_cone.c +18 -3
- data/ext/audio/sound_stream.c +25 -15
- data/ext/ext.c +4 -0
- data/ext/graphics/blend_mode.c +16 -8
- data/ext/graphics/circle.c +30 -13
- data/ext/graphics/color.c +17 -8
- data/ext/graphics/drawable.c +3 -2
- data/ext/graphics/font.c +6 -0
- data/ext/graphics/glyph.c +7 -0
- data/ext/graphics/image.c +25 -4
- data/ext/graphics/polygon.c +31 -11
- data/ext/graphics/rect.c +16 -8
- data/ext/graphics/rectangle.c +30 -11
- data/ext/graphics/render_state.c +8 -10
- data/ext/graphics/render_texture.c +27 -11
- data/ext/graphics/render_window.c +55 -0
- data/ext/graphics/render_window.h +10 -0
- data/ext/graphics/shader.c +6 -0
- data/ext/graphics/shape.c +23 -16
- data/ext/graphics/sprite.c +34 -10
- data/ext/graphics/stencil_mode.c +16 -8
- data/ext/graphics/target.c +60 -27
- data/ext/graphics/target.h +22 -8
- data/ext/graphics/text.c +33 -13
- data/ext/graphics/texture.c +34 -3
- data/ext/graphics/transformable.c +11 -20
- data/ext/graphics/vertex.c +18 -3
- data/ext/graphics/vertex_array.c +18 -9
- data/ext/graphics/vertex_buffer.c +30 -10
- data/ext/graphics/view.c +16 -10
- data/ext/network/ftp.c +30 -3
- data/ext/network/http.c +23 -6
- data/ext/network/ip_address.c +25 -14
- data/ext/network/packet.c +8 -3
- data/ext/network/socket_selector.c +8 -3
- data/ext/network/tcp_listener.c +8 -3
- data/ext/network/tcp_socket.c +8 -3
- data/ext/network/udp_socket.c +8 -3
- data/ext/system/buffer.c +13 -11
- data/ext/system/clock.c +11 -5
- data/ext/system/input_stream.c +21 -11
- data/ext/system/time.c +17 -13
- data/ext/system/vec2.c +17 -11
- data/ext/system/vec3.c +18 -11
- data/ext/window/context.c +14 -11
- data/ext/window/context_settings.c +16 -4
- data/ext/window/cursor.c +6 -0
- data/ext/window/event.c +15 -25
- data/ext/window/mouse.c +28 -11
- data/ext/window/touch.c +12 -10
- data/ext/window/video_mode.c +16 -25
- data/ext/window/window.c +110 -435
- data/ext/window/window.h +4 -4
- data/ext/window/window_base.c +251 -0
- data/ext/window/window_base.h +43 -0
- data/ext/window/window_base.inc +236 -0
- data/lib/sfml/version.rb +1 -1
- data/sig/audio/sound.rbs +1 -1
- data/sig/audio/sound_buffer_recorder.rbs +1 -1
- data/sig/audio/sound_recorder.rbs +1 -1
- data/sig/audio/sound_source_cone.rbs +1 -1
- data/sig/audio/sound_stream.rbs +1 -1
- data/sig/graphics/blend_mode.rbs +1 -1
- data/sig/graphics/circle.rbs +1 -1
- data/sig/graphics/color.rbs +5 -5
- data/sig/graphics/image.rbs +1 -1
- data/sig/graphics/polygon.rbs +1 -1
- data/sig/graphics/rect.rbs +5 -5
- data/sig/graphics/rectangle.rbs +1 -1
- data/sig/graphics/render_state.rbs +2 -2
- data/sig/graphics/render_target.rbs +18 -0
- data/sig/graphics/render_texture.rbs +4 -2
- data/sig/graphics/render_window.rbs +7 -0
- data/sig/graphics/shape.rbs +1 -1
- data/sig/graphics/sprite.rbs +2 -2
- data/sig/graphics/stencil_mode.rbs +2 -2
- data/sig/graphics/target.rbs +1 -3
- data/sig/graphics/text.rbs +4 -4
- data/sig/graphics/texture.rbs +1 -1
- data/sig/graphics/transformable.rbs +1 -1
- data/sig/graphics/vertex.rbs +4 -4
- data/sig/graphics/vertex_array.rbs +1 -1
- data/sig/graphics/vertex_buffer.rbs +4 -4
- data/sig/graphics/view.rbs +0 -1
- data/sig/network/ftp.rbs +1 -1
- data/sig/network/http.rbs +2 -2
- data/sig/network/ip_address.rbs +1 -1
- data/sig/network/packet.rbs +1 -1
- data/sig/network/socket_selector.rbs +1 -1
- data/sig/network/tcp_listener.rbs +1 -1
- data/sig/network/tcp_socket.rbs +1 -1
- data/sig/network/udp_socket.rbs +1 -1
- data/sig/sfml/version.rbs +3 -0
- data/sig/system/buffer.rbs +1 -1
- data/sig/system/clock.rbs +1 -1
- data/sig/system/input_stream.rbs +1 -1
- data/sig/system/time.rbs +4 -4
- data/sig/system/vec2.rbs +4 -4
- data/sig/system/vec3.rbs +4 -4
- data/sig/window/context.rbs +1 -1
- data/sig/window/context_settings.rbs +1 -1
- data/sig/window/event.rbs +1 -1
- data/sig/window/mouse.rbs +2 -2
- data/sig/window/touch.rbs +1 -1
- data/sig/window/video_mode.rbs +1 -1
- data/sig/window/window.rbs +2 -25
- data/sig/window/window_base.rbs +33 -0
- metadata +11 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f98dbb27451c7780e8dbd1ab1f677a9590d5d42b55db97cad407eee15fdd3ef8
|
|
4
|
+
data.tar.gz: 6ffe42d972c73f477b642ad6e1bfc1e9c4d5585f40bd9a9402bc08dfb03834ef
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7fde721522979c1446f14a18ce2433dcf6c8a1009c40cedb6771926f87a759bee9f44f338a47d8205336e51624ee80d919a18ea7172e9815c434194e814459c9
|
|
7
|
+
data.tar.gz: c2fde3b6034c72f50cf8d480a77bee01f79d505b510ca7b354c618bcf0f694307776d2409c00ab0b173253c3c797b2498e5f0c50cbd94256d902f7f96c816d91
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,31 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.3.1] - 2026-09-19
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
* **`SFML::WindowBase`, `SFML::RenderWindow` and the `SFML::RenderTarget` module**, mirroring
|
|
13
|
+
SFML 3's own hierarchy. `WindowBase` wraps `sfWindowBase` -- an OS window and event queue with
|
|
14
|
+
no OpenGL context -- and is constructible, with `Window` and `RenderWindow` derived from it.
|
|
15
|
+
`Window` keeps its existing `sfRenderWindow` behaviour; `RenderWindow` is the same renderable
|
|
16
|
+
window under the name that also includes `RenderTarget`. `RenderTexture` includes
|
|
17
|
+
`RenderTarget` too, so a drawable's `#draw` now accepts a `RenderWindow` or a `RenderTexture`
|
|
18
|
+
directly (the legacy `Target` still works). The shared window surface is generated once, in
|
|
19
|
+
`ext/window/window_base.inc`.
|
|
20
|
+
* **RBS signatures are now checked against the code.** `sig/**/*.rbs` declares `SFML::VERSION`, and
|
|
21
|
+
a `Steepfile` plus the `steep` development gem add `rake steep` to type-check `lib/` against the
|
|
22
|
+
signatures. `check.yaml` runs both `rake rbs` and `rake steep`, on `main` and on `release/**`
|
|
23
|
+
PRs, which previously ran no workflow at all.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
* `Mouse.position`, `Mouse.set_position` and `Touch.position` dispatch to the
|
|
27
|
+
`*RenderWindow` or `*WindowBase` CSFML entry point depending on whether the argument is a
|
|
28
|
+
Window/RenderWindow or a WindowBase, instead of passing an `sfRenderWindow*` where an
|
|
29
|
+
`sfWindowBase*` is expected.
|
|
30
|
+
* **RBS constructors use `def initialize`.** Every `def self.new` became
|
|
31
|
+
`def initialize: (…) -> void`, the form RubyMine links to `Foo.new` and Steep checks, and which
|
|
32
|
+
matches the C extension, where every constructor is an `initialize`.
|
|
33
|
+
|
|
9
34
|
## [0.3.0] - 2026-09-19
|
|
10
35
|
|
|
11
36
|
### Added
|
data/README.md
CHANGED
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
Ruby bindings for [SFML 3](https://www.sfml-dev.org/), via its C API, [CSFML](https://github.com/SFML/CSFML).
|
|
4
4
|
|
|
5
5
|
[](https://www.ruby-lang.org/)
|
|
6
|
-
[](https://img.shields.io/github/actions/workflow/status/algaves/sfml3.rb/test.yaml?style=flat-square)
|
|
7
|
+
[](https://img.shields.io/github/actions/workflow/status/algaves/sfml3.rb/check.yaml?style=flat-square)
|
|
8
|
+
[](https://algaves.github.io/sfml3.rb/)
|
|
8
9
|
[](https://rubygems.org/gems/sfml3-rb)
|
|
9
10
|
[](https://rubygems.org/gems/sfml3-rb)
|
|
10
11
|
[](LICENSE.md)
|
|
11
12
|
|
|
12
|
-
Latest release: **0.3.
|
|
13
|
+
Latest release: **0.3.1**, bound against **CSFML 3**.
|
|
13
14
|
|
|
14
15
|
## Features
|
|
15
16
|
|
|
@@ -20,10 +21,11 @@ Latest release: **0.3.0**, bound against **CSFML 3**.
|
|
|
20
21
|
* **A source fallback everywhere else**, which downloads and builds the pinned, checksum-verified
|
|
21
22
|
dependencies at install time, so the gem works on macOS, ARM and the BSDs out of the box.
|
|
22
23
|
* **Complete API documentation and types**: every class, module, method and constant is documented
|
|
23
|
-
on [
|
|
24
|
+
on the [docs site](https://algaves.github.io/sfml3.rb/) and covered by RBS signatures shipped in
|
|
24
25
|
the gem.
|
|
25
|
-
* **A close fit to SFML's own model**: classes mirror the C++ types (
|
|
26
|
-
Sound, ...) minus the parts that only exist in C++, like
|
|
26
|
+
* **A close fit to SFML's own model**: classes mirror the C++ types (WindowBase, Window,
|
|
27
|
+
RenderWindow, Texture, Sprite, Sound, ...) minus the parts that only exist in C++, like
|
|
28
|
+
`std::string` and exceptions.
|
|
27
29
|
|
|
28
30
|
## Table of Contents
|
|
29
31
|
|
|
@@ -124,13 +126,30 @@ part of the test suite.
|
|
|
124
126
|
|
|
125
127
|
## Documentation
|
|
126
128
|
|
|
127
|
-
* [API reference](https://
|
|
128
|
-
built from the YARD comments in `ext/**/*.c
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
* [API reference](https://algaves.github.io/sfml3.rb/) — every class, module, method and constant,
|
|
130
|
+
built from the YARD comments in `ext/**/*.c` and deployed to GitHub Pages by CI. The same docs
|
|
131
|
+
are also generated on [RubyDoc.info](https://rubydoc.info/gems/sfml3-rb).
|
|
132
|
+
* RBS type signatures (`sig/**/*.rbs`) describe the whole API, including the native classes, for
|
|
133
|
+
RBS-aware editors. `rake rbs` validates the signatures and `rake steep` type-checks `lib/`
|
|
134
|
+
against them.
|
|
131
135
|
* [CHANGELOG.md](CHANGELOG.md) — what changed in each release.
|
|
132
136
|
* [TODO.md](TODO.md) — module-by-module porting coverage and what is deliberately unbound.
|
|
133
137
|
|
|
138
|
+
### IDE setup (RubyMine)
|
|
139
|
+
|
|
140
|
+
`sig/**/*.rbs` is the only machine-readable description of the API: the native extension cannot be
|
|
141
|
+
introspected, so an editor either reads the signatures or sees nothing. RBS support lives in
|
|
142
|
+
**RubyMine** (and IntelliJ IDEA Ultimate with the Ruby plugin); CLion and other C/C++ IDEs show
|
|
143
|
+
`.rbs` files as plain text.
|
|
144
|
+
|
|
145
|
+
1. Open the project in RubyMine and point **Settings → Languages & Frameworks → Ruby SDK** at the
|
|
146
|
+
interpreter you build against (Ruby 3.1+). Keep the C sources in CLion/clangd.
|
|
147
|
+
2. Run `bundle install` so the `rbs` gem (3.2+) is available to that interpreter.
|
|
148
|
+
3. RubyMine indexes `sig/` automatically; completion, type info (`Ctrl+Shift+P`), parameter info
|
|
149
|
+
and *Navigate → Type Signature* then work for `Window.new` and the rest of the API.
|
|
150
|
+
4. For a full type check, run `steep check` from *Run anything* (`Ctrl` twice); `Steepfile` points
|
|
151
|
+
it at `lib/` and `sig/`.
|
|
152
|
+
|
|
134
153
|
## Development
|
|
135
154
|
|
|
136
155
|
```sh
|
|
@@ -140,6 +159,7 @@ rake test # compile, then run the test suite
|
|
|
140
159
|
rake gem # build the source gem into pkg/
|
|
141
160
|
rake yard # build API docs into doc/
|
|
142
161
|
rake rbs # validate sig/**/*.rbs
|
|
162
|
+
rake steep # type-check lib/ against sig/**/*.rbs
|
|
143
163
|
```
|
|
144
164
|
|
|
145
165
|
`rake githooks:install` points your checkout at the committed `.githooks/` pre-commit hook, which
|
|
@@ -155,9 +175,12 @@ side by side: `core/` (CSFML umbrella header, macros, exceptions, UTF-32 convers
|
|
|
155
175
|
devices), `graphics/` (shapes, Color, Transform, View, Texture, Text, Shader, the render targets),
|
|
156
176
|
`audio/` and `network/`. Includes are subsystem-relative, e.g. `#include "graphics/circle.h"`.
|
|
157
177
|
|
|
158
|
-
|
|
159
|
-
a different macro prefix: `audio/sound_source.inc` (Sound, Music, SoundStream)
|
|
160
|
-
`graphics/render_target.inc` (Window,
|
|
178
|
+
Three `.inc` files hold method bodies shared by several classes and are included once per class
|
|
179
|
+
with a different macro prefix: `audio/sound_source.inc` (Sound, Music, SoundStream),
|
|
180
|
+
`window/window_base.inc` (WindowBase, Window) and `graphics/render_target.inc` (Window,
|
|
181
|
+
RenderTexture). `SFML::RenderWindow < SFML::Window < SFML::WindowBase` and includes the
|
|
182
|
+
`SFML::RenderTarget` module, so a drawable's `#draw` accepts a `RenderWindow` or a
|
|
183
|
+
`RenderTexture` directly; `SFML::Target` remains as the legacy generic wrapper.
|
|
161
184
|
|
|
162
185
|
Note that mkmf flattens object files to their basenames, so every `.c` filename has to stay
|
|
163
186
|
unique across the whole tree — and that `$srcs` is baked into the generated Makefile, so after
|
data/TODO.md
CHANGED
|
@@ -51,9 +51,14 @@ Base module: time, vectors, clocks, streams.
|
|
|
51
51
|
|
|
52
52
|
OpenGL-based windows, events, input handling.
|
|
53
53
|
|
|
54
|
-
- [x] **
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
- [x] **WindowBase** — `SFML::WindowBase` (`ext/window/window_base.c`); wraps `sfWindowBase`, an OS
|
|
55
|
+
window and event queue with no OpenGL context. The methods shared with `Window` are generated
|
|
56
|
+
from `ext/window/window_base.inc`.
|
|
57
|
+
- [x] **Window** — `SFML::Window` (`ext/window/window.c`); wraps `sfRenderWindow` and derives from
|
|
58
|
+
`WindowBase`, overriding every base method with the matching `sfRenderWindow_*` entry point.
|
|
59
|
+
Accepts style, state and `ContextSettings`; exposes min/max size, icon, cursor, native handle,
|
|
60
|
+
settings, display, and the render-target surface. Deliberately still renderable, so existing
|
|
61
|
+
`Window.new(...).clear` code keeps working.
|
|
57
62
|
- [x] **VideoMode** — `SFML::VideoMode` (`ext/window/video_mode.c`); includes `desktop_mode` and
|
|
58
63
|
`fullscreen_modes`
|
|
59
64
|
- [x] **Event** — `SFML::Event` (`ext/window/event.c`, `ext/window/event_name.c`); every payload is
|
|
@@ -87,13 +92,16 @@ OpenGL-based windows, events, input handling.
|
|
|
87
92
|
- [x] **Drawable** — `SFML::Drawable` mixin (`ext/graphics/drawable.c`)
|
|
88
93
|
- [x] **RenderStates** — `SFML::RenderState` (`ext/graphics/render_state.c`); blend mode, stencil
|
|
89
94
|
mode, coordinate type, texture, shader and transform are all settable
|
|
90
|
-
- [x] **RenderTarget** — `SFML::
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
- [x] **RenderTarget** — `SFML::RenderTarget` module (`ext/graphics/target.c`), included by
|
|
96
|
+
`RenderWindow` and `RenderTexture`, so a drawable's `#draw` accepts either directly. The
|
|
97
|
+
methods — `map_pixel_to_coords`, `map_coords_to_pixel`, `push_gl_states`, `pop_gl_states`,
|
|
93
98
|
`reset_gl_states`, `draw_primitives`, `draw_vertex_buffer_range`, `clear_stencil`,
|
|
94
99
|
`clear_color_and_stencil`, `viewport`, `scissor`, `srgb?` — are generated once for both
|
|
95
|
-
`Window` and `RenderTexture` from `ext/graphics/render_target.inc`
|
|
96
|
-
|
|
100
|
+
`Window` and `RenderTexture` from `ext/graphics/render_target.inc`. `SFML::Target` remains
|
|
101
|
+
as the legacy runtime-dispatch wrapper for `Drawable#draw`.
|
|
102
|
+
- [x] **RenderWindow** — `SFML::RenderWindow` (`ext/graphics/render_window.c`); derives from
|
|
103
|
+
`Window` and includes `RenderTarget`. Creation, events and the window surface come from
|
|
104
|
+
`Window` / `WindowBase`.
|
|
97
105
|
- [x] **RenderTexture** — `SFML::RenderTexture` (`ext/graphics/render_texture.c`)
|
|
98
106
|
- [x] **View** — `SFML::View` (`ext/graphics/view.c`); including `View.from_rect` and
|
|
99
107
|
`scissor`/`scissor=`
|
|
@@ -179,9 +187,8 @@ without re-deriving the reasoning each time.
|
|
|
179
187
|
|
|
180
188
|
| Symbols | Why |
|
|
181
189
|
| --- | --- |
|
|
182
|
-
| `sfWindow_
|
|
183
|
-
| `
|
|
184
|
-
| `sfRenderWindow_create`, `sfText_getString`/`setString`, `sfRenderWindow_setTitle`, `sfFtpDirectoryResponse_getDirectory` | Superseded by their `*Unicode` counterparts; the narrow forms decode through the C locale and mangle non-ASCII. |
|
|
190
|
+
| `sfWindow_*` (~26 functions) | A plain `sfWindow` (an OpenGL context with no render-target surface); `SFML::Window` wraps `sfRenderWindow` and `SFML::WindowBase` wraps `sfWindowBase`. |
|
|
191
|
+
| `sfRenderWindow_create`, `sfWindowBase_create`, `sfText_getString`/`setString`, `sfRenderWindow_setTitle`, `sfWindowBase_setTitle`, `sfFtpDirectoryResponse_getDirectory` | Superseded by their `*Unicode` counterparts; the narrow forms decode through the C locale and mangle non-ASCII. |
|
|
185
192
|
| `sfColor_add`/`subtract`/`modulate`/`fromRGB`/`fromRGBA`/`fromInteger`/`toInteger`, `sfIntRect_contains`/`intersects` | Reimplemented directly in C in `color.c` / `rect.c`; the Ruby methods exist. |
|
|
186
193
|
| `sfSprite_getTexture`, `sfText_getFont`, `sf*Shape_getTexture` | The Ruby getters return the cached wrapper object. CSFML returns a non-owning pointer, so re-wrapping it would hand Ruby an object it must not free. |
|
|
187
194
|
| `sfShape_getPoint`, `sfShape_getPointCount` | `SFML::Shape` reads these from the Ruby subclass, which is where they are defined. |
|
data/ext/audio/music.c
CHANGED
|
@@ -216,6 +216,11 @@ static VALUE Music_set_loop_points(VALUE self, VALUE rb_span) {
|
|
|
216
216
|
#undef SS_FN
|
|
217
217
|
#undef SS_METHOD
|
|
218
218
|
|
|
219
|
+
static VALUE Music_alloc(VALUE klass) {
|
|
220
|
+
(void)klass;
|
|
221
|
+
rb_raise(rb_eNotImpError, "use Music.from_file, Music.from_memory or Music.from_stream");
|
|
222
|
+
}
|
|
223
|
+
|
|
219
224
|
/* Document-class: SFML::Music
|
|
220
225
|
* Music streamed from a file, memory buffer or InputStream rather than held
|
|
221
226
|
* fully decoded in memory, so it's suited to long tracks that would be
|
|
@@ -349,6 +354,7 @@ static VALUE Music_set_loop_points(VALUE self, VALUE rb_span) {
|
|
|
349
354
|
*/
|
|
350
355
|
void Init_Music(VALUE rb_mSFML) {
|
|
351
356
|
rb_cMusic = rb_define_class_under(rb_mSFML, "Music", rb_cObject);
|
|
357
|
+
rb_define_alloc_func(rb_cMusic, Music_alloc);
|
|
352
358
|
|
|
353
359
|
rb_define_singleton_method(rb_cMusic, "from_file", Music_from_file, 1);
|
|
354
360
|
rb_define_singleton_method(rb_cMusic, "from_memory", Music_from_memory, 1);
|
data/ext/audio/sound.c
CHANGED
|
@@ -39,7 +39,11 @@ static void Sound_free(void* ptr) {
|
|
|
39
39
|
thread's effect_processor_acquire could reuse the slot number for an
|
|
40
40
|
unrelated new source while this source's callback might still be
|
|
41
41
|
executing against it. */
|
|
42
|
-
|
|
42
|
+
if (sound->source.handle != NULL) {
|
|
43
|
+
rb_thread_call_without_gvl(Sound_destroy_without_gvl, sound->source.handle, RUBY_UBF_IO,
|
|
44
|
+
NULL);
|
|
45
|
+
}
|
|
46
|
+
|
|
43
47
|
effect_processor_release(sound->source.effect_slot);
|
|
44
48
|
free(sound);
|
|
45
49
|
}
|
|
@@ -68,6 +72,25 @@ static VALUE Sound_wrap(VALUE klass, sfSound* handle, VALUE rb_buffer) {
|
|
|
68
72
|
return TypedData_Wrap_Struct(klass, &Sound_data_type, ptr);
|
|
69
73
|
}
|
|
70
74
|
|
|
75
|
+
static VALUE Sound_initialize_copy(VALUE self, VALUE other) {
|
|
76
|
+
(void)other;
|
|
77
|
+
rb_raise(rb_eTypeError, "can't copy a %s", rb_obj_classname(self));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static VALUE Sound_alloc(VALUE klass) {
|
|
81
|
+
Sound* ptr = malloc(sizeof(Sound));
|
|
82
|
+
|
|
83
|
+
if (ptr == NULL) {
|
|
84
|
+
rb_raise(rb_eNoMemError, "failed to allocate sound");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
ptr->source.handle = NULL;
|
|
88
|
+
ptr->source.effect_slot = -1;
|
|
89
|
+
ptr->rb_buffer = Qnil;
|
|
90
|
+
|
|
91
|
+
return TypedData_Wrap_Struct(klass, &Sound_data_type, ptr);
|
|
92
|
+
}
|
|
93
|
+
|
|
71
94
|
/* call-seq:
|
|
72
95
|
* Sound.new(buffer) -> Sound
|
|
73
96
|
*
|
|
@@ -76,12 +99,26 @@ static VALUE Sound_wrap(VALUE klass, sfSound* handle, VALUE rb_buffer) {
|
|
|
76
99
|
* @return [Sound]
|
|
77
100
|
* @raise [ArgumentError] if +buffer+ is not a SoundBuffer
|
|
78
101
|
*/
|
|
79
|
-
static VALUE
|
|
102
|
+
static VALUE Sound_initialize(VALUE self, VALUE rb_buffer) {
|
|
103
|
+
Sound* sound;
|
|
104
|
+
sfSound* handle;
|
|
105
|
+
|
|
80
106
|
if (!rb_obj_is_kind_of(rb_buffer, Get_Klass_SoundBuffer())) {
|
|
81
107
|
raise_invalid_argument_class(Get_Klass_SoundBuffer());
|
|
82
108
|
}
|
|
83
109
|
|
|
84
|
-
|
|
110
|
+
sound = (Sound*)Get_Sound_Struct(self);
|
|
111
|
+
|
|
112
|
+
handle = sfSound_create(Get_SoundBuffer_Struct(rb_buffer));
|
|
113
|
+
|
|
114
|
+
if (handle == NULL) {
|
|
115
|
+
rb_raise(rb_eRuntimeError, "failed to create sound");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
sound->source.handle = handle;
|
|
119
|
+
sound->rb_buffer = rb_buffer;
|
|
120
|
+
|
|
121
|
+
return self;
|
|
85
122
|
}
|
|
86
123
|
|
|
87
124
|
/* call-seq: copy -> Sound
|
|
@@ -289,7 +326,9 @@ static VALUE Sound_set_buffer(VALUE self, VALUE rb_buffer) {
|
|
|
289
326
|
void Init_Sound(VALUE rb_mSFML) {
|
|
290
327
|
rb_cSound = rb_define_class_under(rb_mSFML, "Sound", rb_cObject);
|
|
291
328
|
|
|
292
|
-
|
|
329
|
+
rb_define_alloc_func(rb_cSound, Sound_alloc);
|
|
330
|
+
rb_define_method(rb_cSound, "initialize", Sound_initialize, 1);
|
|
331
|
+
rb_define_private_method(rb_cSound, "initialize_copy", Sound_initialize_copy, 1);
|
|
293
332
|
|
|
294
333
|
rb_define_method(rb_cSound, "copy", Sound_copy, 0);
|
|
295
334
|
rb_define_method(rb_cSound, "buffer", Sound_get_buffer, 0);
|
data/ext/audio/sound_buffer.c
CHANGED
|
@@ -381,6 +381,13 @@ static VALUE SoundBuffer_duration(VALUE self) {
|
|
|
381
381
|
return time_to_rb(sfSoundBuffer_getDuration(Get_SoundBuffer_Struct(self)));
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
+
static VALUE SoundBuffer_alloc(VALUE klass) {
|
|
385
|
+
(void)klass;
|
|
386
|
+
rb_raise(rb_eNotImpError,
|
|
387
|
+
"use SoundBuffer.from_file, SoundBuffer.from_memory, SoundBuffer.from_stream or "
|
|
388
|
+
"SoundBuffer.from_samples");
|
|
389
|
+
}
|
|
390
|
+
|
|
384
391
|
/* Document-class: SFML::SoundBuffer
|
|
385
392
|
* Audio samples held fully decoded in memory, ready to be played through one
|
|
386
393
|
* or more Sound instances (a single buffer may back several simultaneous
|
|
@@ -389,6 +396,7 @@ static VALUE SoundBuffer_duration(VALUE self) {
|
|
|
389
396
|
*/
|
|
390
397
|
void Init_SoundBuffer(VALUE rb_mSFML) {
|
|
391
398
|
rb_cSoundBuffer = rb_define_class_under(rb_mSFML, "SoundBuffer", rb_cObject);
|
|
399
|
+
rb_define_alloc_func(rb_cSoundBuffer, SoundBuffer_alloc);
|
|
392
400
|
|
|
393
401
|
rb_define_singleton_method(rb_cSoundBuffer, "from_file", SoundBuffer_from_file, 1);
|
|
394
402
|
rb_define_singleton_method(rb_cSoundBuffer, "from_memory", SoundBuffer_from_memory, 1);
|
|
@@ -41,6 +41,10 @@ static VALUE SoundBufferRecorder_wrap(VALUE klass, sfSoundBufferRecorder* handle
|
|
|
41
41
|
return TypedData_Wrap_Struct(klass, &SoundBufferRecorder_data_type, ptr);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
static VALUE SoundBufferRecorder_alloc(VALUE klass) {
|
|
45
|
+
return SoundBufferRecorder_wrap(klass, sfSoundBufferRecorder_create());
|
|
46
|
+
}
|
|
47
|
+
|
|
44
48
|
/* call-seq:
|
|
45
49
|
* SoundBufferRecorder.new -> SoundBufferRecorder
|
|
46
50
|
*
|
|
@@ -49,8 +53,8 @@ static VALUE SoundBufferRecorder_wrap(VALUE klass, sfSoundBufferRecorder* handle
|
|
|
49
53
|
* @return [SoundBufferRecorder]
|
|
50
54
|
* @raise [RuntimeError] if no capture device is available
|
|
51
55
|
*/
|
|
52
|
-
static VALUE
|
|
53
|
-
return
|
|
56
|
+
static VALUE SoundBufferRecorder_initialize(VALUE self) {
|
|
57
|
+
return self;
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
/* call-seq:
|
|
@@ -151,7 +155,8 @@ static VALUE SoundBufferRecorder_set_channel_count(VALUE self, VALUE rb_count) {
|
|
|
151
155
|
void Init_SoundBufferRecorder(VALUE rb_mSFML) {
|
|
152
156
|
rb_cSoundBufferRecorder = rb_define_class_under(rb_mSFML, "SoundBufferRecorder", rb_cObject);
|
|
153
157
|
|
|
154
|
-
|
|
158
|
+
rb_define_alloc_func(rb_cSoundBufferRecorder, SoundBufferRecorder_alloc);
|
|
159
|
+
rb_define_method(rb_cSoundBufferRecorder, "initialize", SoundBufferRecorder_initialize, 0);
|
|
155
160
|
|
|
156
161
|
rb_define_method(rb_cSoundBufferRecorder, "start", SoundBufferRecorder_start, 1);
|
|
157
162
|
rb_define_method(rb_cSoundBufferRecorder, "stop", SoundBufferRecorder_stop, 0);
|
data/ext/audio/sound_recorder.c
CHANGED
|
@@ -154,6 +154,23 @@ static void SoundRecorder_on_stop(void* userData) {
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
static VALUE SoundRecorder_alloc(VALUE klass) {
|
|
158
|
+
SoundRecorder* ptr = malloc(sizeof(SoundRecorder));
|
|
159
|
+
VALUE self;
|
|
160
|
+
|
|
161
|
+
if (ptr == NULL) {
|
|
162
|
+
rb_raise(rb_eNoMemError, "failed to allocate sound recorder");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
ptr->rb_self = Qnil;
|
|
166
|
+
ptr->handle = NULL;
|
|
167
|
+
|
|
168
|
+
self = TypedData_Wrap_Struct(klass, &SoundRecorder_data_type, ptr);
|
|
169
|
+
ptr->rb_self = self;
|
|
170
|
+
|
|
171
|
+
return self;
|
|
172
|
+
}
|
|
173
|
+
|
|
157
174
|
/* call-seq:
|
|
158
175
|
* SoundRecorder.new -> SoundRecorder
|
|
159
176
|
*
|
|
@@ -167,21 +184,13 @@ static void SoundRecorder_on_stop(void* userData) {
|
|
|
167
184
|
* @raise [NotImplementedError] if the subclass does not define #on_process
|
|
168
185
|
* @raise [RuntimeError] if no capture device is available
|
|
169
186
|
*/
|
|
170
|
-
static VALUE
|
|
187
|
+
static VALUE SoundRecorder_initialize(VALUE self) {
|
|
171
188
|
SoundRecorder* ptr;
|
|
172
189
|
sfSoundRecorder* handle;
|
|
173
|
-
VALUE self;
|
|
174
|
-
|
|
175
|
-
ptr = malloc(sizeof(SoundRecorder));
|
|
176
|
-
ptr->rb_self = Qnil;
|
|
177
|
-
ptr->handle = NULL;
|
|
178
190
|
|
|
179
|
-
self
|
|
180
|
-
ptr->rb_self = self;
|
|
191
|
+
TypedData_Get_Struct(self, SoundRecorder, &SoundRecorder_data_type, ptr);
|
|
181
192
|
|
|
182
193
|
if (!rb_respond_to(self, rb_intern("on_process"))) {
|
|
183
|
-
/* Ruby already owns the wrapper; SoundRecorder_free handles the NULL
|
|
184
|
-
handle, so let GC clean up after the raise. */
|
|
185
194
|
rb_raise(rb_eNotImpError, "subclass must define #on_process");
|
|
186
195
|
}
|
|
187
196
|
|
|
@@ -360,7 +369,8 @@ static VALUE SoundRecorder_channel_map(VALUE self) {
|
|
|
360
369
|
void Init_SoundRecorder(VALUE rb_mSFML) {
|
|
361
370
|
rb_cSoundRecorder = rb_define_class_under(rb_mSFML, "SoundRecorder", rb_cObject);
|
|
362
371
|
|
|
363
|
-
|
|
372
|
+
rb_define_alloc_func(rb_cSoundRecorder, SoundRecorder_alloc);
|
|
373
|
+
rb_define_method(rb_cSoundRecorder, "initialize", SoundRecorder_initialize, 0);
|
|
364
374
|
rb_define_singleton_method(rb_cSoundRecorder, "available?", SoundRecorder_available, 0);
|
|
365
375
|
rb_define_singleton_method(rb_cSoundRecorder, "available_devices",
|
|
366
376
|
SoundRecorder_available_devices, 0);
|
|
@@ -29,6 +29,18 @@ static VALUE SoundSourceCone_wrap(sfSoundSourceCone cone) {
|
|
|
29
29
|
return TypedData_Wrap_Struct(rb_cSoundSourceCone, &SoundSourceCone_data_type, ptr);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
static VALUE SoundSourceCone_alloc(VALUE klass) {
|
|
33
|
+
SoundSourceCone* ptr = malloc(sizeof(SoundSourceCone));
|
|
34
|
+
|
|
35
|
+
if (ptr == NULL) {
|
|
36
|
+
rb_raise(rb_eNoMemError, "failed to allocate sound source cone");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
ptr->cone = (sfSoundSourceCone){0.0f, 0.0f, 0.0f};
|
|
40
|
+
|
|
41
|
+
return TypedData_Wrap_Struct(klass, &SoundSourceCone_data_type, ptr);
|
|
42
|
+
}
|
|
43
|
+
|
|
32
44
|
/* call-seq:
|
|
33
45
|
* SoundSourceCone.new(inner_angle, outer_angle, outer_gain) -> SoundSourceCone
|
|
34
46
|
*
|
|
@@ -36,12 +48,14 @@ static VALUE SoundSourceCone_wrap(sfSoundSourceCone cone) {
|
|
|
36
48
|
*
|
|
37
49
|
* @return [SoundSourceCone]
|
|
38
50
|
*/
|
|
39
|
-
static VALUE
|
|
51
|
+
static VALUE SoundSourceCone_initialize(VALUE self, VALUE rb_inner, VALUE rb_outer, VALUE rb_gain) {
|
|
40
52
|
sfSoundSourceCone cone = {.innerAngle = (float)NUM2DBL(rb_inner),
|
|
41
53
|
.outerAngle = (float)NUM2DBL(rb_outer),
|
|
42
54
|
.outerGain = (float)NUM2DBL(rb_gain)};
|
|
43
55
|
|
|
44
|
-
|
|
56
|
+
((SoundSourceCone*)Get_SoundSourceCone_Struct(self))->cone = cone;
|
|
57
|
+
|
|
58
|
+
return self;
|
|
45
59
|
}
|
|
46
60
|
|
|
47
61
|
/* call-seq: inner_angle -> Float
|
|
@@ -172,7 +186,8 @@ static VALUE SoundSourceCone_eql(VALUE self, VALUE rb_other) {
|
|
|
172
186
|
void Init_SoundSourceCone(VALUE rb_mSFML) {
|
|
173
187
|
rb_cSoundSourceCone = rb_define_class_under(rb_mSFML, "SoundSourceCone", rb_cObject);
|
|
174
188
|
|
|
175
|
-
|
|
189
|
+
rb_define_alloc_func(rb_cSoundSourceCone, SoundSourceCone_alloc);
|
|
190
|
+
rb_define_method(rb_cSoundSourceCone, "initialize", SoundSourceCone_initialize, 3);
|
|
176
191
|
|
|
177
192
|
rb_define_method(rb_cSoundSourceCone, "inner_angle", SoundSourceCone_get_inner_angle, 0);
|
|
178
193
|
rb_define_method(rb_cSoundSourceCone, "outer_angle", SoundSourceCone_get_outer_angle, 0);
|
data/ext/audio/sound_stream.c
CHANGED
|
@@ -193,6 +193,26 @@ static void SoundStream_on_seek(sfTime time, void* userData) {
|
|
|
193
193
|
run_on_ruby_thread(SoundStream_seek_run, &ctx, SOUND_STREAM_CALLBACK_TIMEOUT_MS);
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
static VALUE SoundStream_alloc(VALUE klass) {
|
|
197
|
+
SoundStream* ptr = malloc(sizeof(SoundStream));
|
|
198
|
+
VALUE self;
|
|
199
|
+
|
|
200
|
+
if (ptr == NULL) {
|
|
201
|
+
rb_raise(rb_eNoMemError, "failed to allocate sound stream");
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
ptr->source.handle = NULL;
|
|
205
|
+
ptr->source.effect_slot = -1;
|
|
206
|
+
ptr->rb_self = Qnil;
|
|
207
|
+
ptr->samples = NULL;
|
|
208
|
+
ptr->samples_capacity = 0;
|
|
209
|
+
|
|
210
|
+
self = TypedData_Wrap_Struct(klass, &SoundStream_data_type, ptr);
|
|
211
|
+
ptr->rb_self = self;
|
|
212
|
+
|
|
213
|
+
return self;
|
|
214
|
+
}
|
|
215
|
+
|
|
196
216
|
/* call-seq:
|
|
197
217
|
* SoundStream.new(channel_count, sample_rate) -> SoundStream
|
|
198
218
|
* SoundStream.new(channel_count, sample_rate, channel_map) -> SoundStream
|
|
@@ -206,14 +226,15 @@ static void SoundStream_on_seek(sfTime time, void* userData) {
|
|
|
206
226
|
* @raise [NotImplementedError] if the subclass does not define #on_get_data
|
|
207
227
|
* @raise [RuntimeError] if the underlying stream could not be created
|
|
208
228
|
*/
|
|
209
|
-
static VALUE
|
|
229
|
+
static VALUE SoundStream_initialize(int argc, VALUE* argv, VALUE self) {
|
|
210
230
|
VALUE rb_channel_count, rb_sample_rate, rb_channel_map;
|
|
211
231
|
sfSoundChannel* channel_map = NULL;
|
|
212
232
|
size_t channel_map_size = 0;
|
|
213
233
|
SoundStream* ptr;
|
|
214
|
-
VALUE self;
|
|
215
234
|
long i;
|
|
216
235
|
|
|
236
|
+
TypedData_Get_Struct(self, SoundStream, &SoundStream_data_type, ptr);
|
|
237
|
+
|
|
217
238
|
rb_scan_args(argc, argv, "21", &rb_channel_count, &rb_sample_rate, &rb_channel_map);
|
|
218
239
|
|
|
219
240
|
if (!NIL_P(rb_channel_map)) {
|
|
@@ -229,19 +250,7 @@ static VALUE SoundStream_new(int argc, VALUE* argv, VALUE klass) {
|
|
|
229
250
|
}
|
|
230
251
|
}
|
|
231
252
|
|
|
232
|
-
ptr = malloc(sizeof(SoundStream));
|
|
233
|
-
ptr->source.handle = NULL;
|
|
234
|
-
ptr->source.effect_slot = -1;
|
|
235
|
-
ptr->rb_self = Qnil;
|
|
236
|
-
ptr->samples = NULL;
|
|
237
|
-
ptr->samples_capacity = 0;
|
|
238
|
-
|
|
239
|
-
self = TypedData_Wrap_Struct(klass, &SoundStream_data_type, ptr);
|
|
240
|
-
ptr->rb_self = self;
|
|
241
|
-
|
|
242
253
|
if (!rb_respond_to(self, rb_intern("on_get_data"))) {
|
|
243
|
-
/* The wrapper is already owned by Ruby; its dfree tolerates a NULL
|
|
244
|
-
handle, so raising here just leaves it to be collected. */
|
|
245
254
|
free(channel_map);
|
|
246
255
|
rb_raise(rb_eNotImpError, "subclass must define #on_get_data");
|
|
247
256
|
}
|
|
@@ -447,7 +456,8 @@ static VALUE SoundStream_channel_map(VALUE self) {
|
|
|
447
456
|
void Init_SoundStream(VALUE rb_mSFML) {
|
|
448
457
|
rb_cSoundStream = rb_define_class_under(rb_mSFML, "SoundStream", rb_cObject);
|
|
449
458
|
|
|
450
|
-
|
|
459
|
+
rb_define_alloc_func(rb_cSoundStream, SoundStream_alloc);
|
|
460
|
+
rb_define_method(rb_cSoundStream, "initialize", SoundStream_initialize, -1);
|
|
451
461
|
|
|
452
462
|
rb_define_method(rb_cSoundStream, "channel_count", SoundStream_channel_count, 0);
|
|
453
463
|
rb_define_method(rb_cSoundStream, "sample_rate", SoundStream_sample_rate, 0);
|
data/ext/ext.c
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
#include "graphics/target.h"
|
|
23
23
|
#include "graphics/render_state.h"
|
|
24
24
|
#include "window/event.h"
|
|
25
|
+
#include "window/window_base.h"
|
|
25
26
|
#include "window/window.h"
|
|
26
27
|
#include "window/keyboard.h"
|
|
27
28
|
#include "window/mouse.h"
|
|
@@ -47,6 +48,7 @@
|
|
|
47
48
|
#include "graphics/font.h"
|
|
48
49
|
#include "graphics/text.h"
|
|
49
50
|
#include "graphics/render_texture.h"
|
|
51
|
+
#include "graphics/render_window.h"
|
|
50
52
|
#include "graphics/shader.h"
|
|
51
53
|
#include "audio/effect_processor.h"
|
|
52
54
|
#include "audio/audio_enums.h"
|
|
@@ -127,7 +129,9 @@ void Init_sfml_ext(void) {
|
|
|
127
129
|
Init_Event(rb_mExt);
|
|
128
130
|
Init_VideoMode(rb_mExt);
|
|
129
131
|
Init_View(rb_mExt);
|
|
132
|
+
Init_WindowBase(rb_mExt);
|
|
130
133
|
Init_Window(rb_mExt);
|
|
134
|
+
Init_RenderWindow(rb_mExt);
|
|
131
135
|
Init_Keyboard(rb_mExt);
|
|
132
136
|
Init_Mouse(rb_mExt);
|
|
133
137
|
Init_Joystick(rb_mExt);
|
data/ext/graphics/blend_mode.c
CHANGED
|
@@ -80,6 +80,18 @@ static sfBlendEquation equation_from_rb(VALUE rb_equation) {
|
|
|
80
80
|
return sfBlendEquationAdd;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
static VALUE BlendMode_alloc(VALUE klass) {
|
|
84
|
+
BlendMode* ptr = malloc(sizeof(BlendMode));
|
|
85
|
+
|
|
86
|
+
if (ptr == NULL) {
|
|
87
|
+
rb_raise(rb_eNoMemError, "failed to allocate blend mode");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
ptr->mode = sfBlendAlpha;
|
|
91
|
+
|
|
92
|
+
return TypedData_Wrap_Struct(klass, &BlendMode_data_type, ptr);
|
|
93
|
+
}
|
|
94
|
+
|
|
83
95
|
/* call-seq:
|
|
84
96
|
* BlendMode.new -> BlendMode(ALPHA)
|
|
85
97
|
* BlendMode.new(color_src_factor, color_dst_factor, color_equation, alpha_src_factor,
|
|
@@ -95,9 +107,7 @@ static sfBlendEquation equation_from_rb(VALUE rb_equation) {
|
|
|
95
107
|
* @return [BlendMode]
|
|
96
108
|
* @raise [ArgumentError] if given an argument count other than 0 or 6
|
|
97
109
|
*/
|
|
98
|
-
static VALUE
|
|
99
|
-
VALUE self;
|
|
100
|
-
BlendMode* ptr;
|
|
110
|
+
static VALUE BlendMode_initialize(int argc, VALUE* argv, VALUE self) {
|
|
101
111
|
sfBlendMode mode = sfBlendAlpha;
|
|
102
112
|
|
|
103
113
|
if (argc == 6) {
|
|
@@ -108,10 +118,7 @@ static VALUE BlendMode_new(int argc, VALUE* argv, VALUE klass) {
|
|
|
108
118
|
raise_invalid_arguments_excepted(6, argc);
|
|
109
119
|
}
|
|
110
120
|
|
|
111
|
-
|
|
112
|
-
ptr->mode = mode;
|
|
113
|
-
|
|
114
|
-
self = TypedData_Wrap_Struct(klass, &BlendMode_data_type, ptr);
|
|
121
|
+
((BlendMode*)Get_BlendMode_Struct(self))->mode = mode;
|
|
115
122
|
|
|
116
123
|
return self;
|
|
117
124
|
}
|
|
@@ -310,7 +317,8 @@ static VALUE BlendMode_eql(VALUE self, VALUE rb_other) {
|
|
|
310
317
|
void Init_BlendMode(VALUE rb_mSFML) {
|
|
311
318
|
rb_cBlendMode = rb_define_class_under(rb_mSFML, "BlendMode", rb_cObject);
|
|
312
319
|
|
|
313
|
-
|
|
320
|
+
rb_define_alloc_func(rb_cBlendMode, BlendMode_alloc);
|
|
321
|
+
rb_define_method(rb_cBlendMode, "initialize", BlendMode_initialize, -1);
|
|
314
322
|
|
|
315
323
|
rb_define_method(rb_cBlendMode, "color_src_factor", BlendMode_get_color_src_factor, 0);
|
|
316
324
|
rb_define_method(rb_cBlendMode, "color_dst_factor", BlendMode_get_color_dst_factor, 0);
|