rgame 0.1.0
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 +7 -0
- data/LICENSE +26 -0
- data/README.md +406 -0
- data/docs/api/README.md +167 -0
- data/docs/api/app.md +192 -0
- data/docs/api/assets.md +426 -0
- data/docs/api/audio.md +208 -0
- data/docs/api/components.md +321 -0
- data/docs/api/drawing.md +330 -0
- data/docs/api/game.md +99 -0
- data/docs/api/images.md +118 -0
- data/docs/api/input.md +179 -0
- data/docs/api/internals.md +110 -0
- data/docs/api/scene_graph.md +159 -0
- data/docs/api/signals.md +142 -0
- data/docs/api/systems.md +98 -0
- data/docs/api/text.md +116 -0
- data/docs/api/toolbox.md +240 -0
- data/docs/api/values.md +101 -0
- data/ext/README.md +225 -0
- data/ext/rgame_core/app/app.c +721 -0
- data/ext/rgame_core/app/app_gl.h +64 -0
- data/ext/rgame_core/app/frame_loop.c +42 -0
- data/ext/rgame_core/app/frame_loop.h +54 -0
- data/ext/rgame_core/audio/audio.c +466 -0
- data/ext/rgame_core/audio/audio_internal.h +45 -0
- data/ext/rgame_core/audio/vorbis_decoder.c +282 -0
- data/ext/rgame_core/audio/vorbis_decoder.h +45 -0
- data/ext/rgame_core/example.rb +188 -0
- data/ext/rgame_core/extconf.rb +167 -0
- data/ext/rgame_core/graphics/backend.c +52 -0
- data/ext/rgame_core/graphics/backend.h +64 -0
- data/ext/rgame_core/graphics/canvas.c +247 -0
- data/ext/rgame_core/graphics/canvas.h +143 -0
- data/ext/rgame_core/graphics/clip.c +87 -0
- data/ext/rgame_core/graphics/clip.h +89 -0
- data/ext/rgame_core/graphics/draw_queue.c +216 -0
- data/ext/rgame_core/graphics/draw_queue.h +174 -0
- data/ext/rgame_core/graphics/gl_backend.c +122 -0
- data/ext/rgame_core/graphics/gl_backend.h +43 -0
- data/ext/rgame_core/graphics/image.c +304 -0
- data/ext/rgame_core/graphics/image_internal.h +30 -0
- data/ext/rgame_core/graphics/primitives.c +189 -0
- data/ext/rgame_core/graphics/primitives.h +111 -0
- data/ext/rgame_core/graphics/recording.c +119 -0
- data/ext/rgame_core/graphics/recording.h +88 -0
- data/ext/rgame_core/graphics/texture.c +181 -0
- data/ext/rgame_core/graphics/texture.h +165 -0
- data/ext/rgame_core/graphics/transform.c +128 -0
- data/ext/rgame_core/graphics/transform.h +106 -0
- data/ext/rgame_core/include/rgame/core.h +577 -0
- data/ext/rgame_core/input/device_slots.c +103 -0
- data/ext/rgame_core/input/device_slots.h +93 -0
- data/ext/rgame_core/input/gamepad.c +145 -0
- data/ext/rgame_core/input/gamepad.h +63 -0
- data/ext/rgame_core/input/input.c +109 -0
- data/ext/rgame_core/input/input.h +99 -0
- data/ext/rgame_core/ruby/audio_ext.c +321 -0
- data/ext/rgame_core/ruby/core_ext.c +513 -0
- data/ext/rgame_core/ruby/core_ext.h +51 -0
- data/ext/rgame_core/ruby/font_ext.c +168 -0
- data/ext/rgame_core/ruby/image_ext.c +230 -0
- data/ext/rgame_core/ruby/recording_ext.c +186 -0
- data/ext/rgame_core/ruby/renderer_ext.c +376 -0
- data/ext/rgame_core/text/atlas.c +59 -0
- data/ext/rgame_core/text/atlas.h +85 -0
- data/ext/rgame_core/text/font.c +281 -0
- data/ext/rgame_core/text/font.h +139 -0
- data/ext/rgame_core/text/font_atlas.c +385 -0
- data/ext/rgame_core/text/font_internal.h +47 -0
- data/ext/rgame_core/text/glyph_cache.c +142 -0
- data/ext/rgame_core/text/glyph_cache.h +89 -0
- data/ext/rgame_core/vendor/README.md +159 -0
- data/ext/rgame_core/vendor/miniaudio.h +95864 -0
- data/ext/rgame_core/vendor/miniaudio_impl.c +62 -0
- data/ext/rgame_core/vendor/stb_image.h +7988 -0
- data/ext/rgame_core/vendor/stb_image_impl.c +31 -0
- data/ext/rgame_core/vendor/stb_truetype.h +5079 -0
- data/ext/rgame_core/vendor/stb_truetype_impl.c +23 -0
- data/ext/rgame_core/vendor/stb_vorbis.c +5584 -0
- data/ext/rgame_core/vendor/stb_vorbis_impl.c +29 -0
- data/ext/rgame_util/color.c +19 -0
- data/ext/rgame_util/color.h +60 -0
- data/ext/rgame_util/color_ext.c +156 -0
- data/ext/rgame_util/extconf.rb +27 -0
- data/ext/rgame_util/tensor.c +186 -0
- data/ext/rgame_util/util_ext.c +27 -0
- data/ext/rgame_util/util_ext.h +16 -0
- data/lib/rgame/boot.rb +13 -0
- data/lib/rgame/core/app.rb +82 -0
- data/lib/rgame/core/asset_manager.rb +224 -0
- data/lib/rgame/core/audio.rb +124 -0
- data/lib/rgame/core/font.rb +49 -0
- data/lib/rgame/core/gamepad.rb +55 -0
- data/lib/rgame/core/image.rb +55 -0
- data/lib/rgame/core/input.rb +77 -0
- data/lib/rgame/core/nine_slice.rb +163 -0
- data/lib/rgame/core/recording.rb +52 -0
- data/lib/rgame/core/renderer.rb +363 -0
- data/lib/rgame/core/sprite_sheet.rb +108 -0
- data/lib/rgame/core/tile_map_renderer.rb +160 -0
- data/lib/rgame/core/ui_atlas.rb +86 -0
- data/lib/rgame/core.rb +24 -0
- data/lib/rgame/engine/actor.rb +53 -0
- data/lib/rgame/engine/animation_set.rb +49 -0
- data/lib/rgame/engine/animator.rb +44 -0
- data/lib/rgame/engine/audio_bus.rb +24 -0
- data/lib/rgame/engine/audio_director.rb +29 -0
- data/lib/rgame/engine/body.rb +49 -0
- data/lib/rgame/engine/cached_label.rb +33 -0
- data/lib/rgame/engine/camera.rb +33 -0
- data/lib/rgame/engine/camera_view.rb +28 -0
- data/lib/rgame/engine/circle_collider.rb +32 -0
- data/lib/rgame/engine/collision_box.rb +34 -0
- data/lib/rgame/engine/collision_system.rb +44 -0
- data/lib/rgame/engine/component.rb +30 -0
- data/lib/rgame/engine/components/action_trigger.rb +41 -0
- data/lib/rgame/engine/components/animated_sprite.rb +63 -0
- data/lib/rgame/engine/components/character_body.rb +70 -0
- data/lib/rgame/engine/components/circle_collider.rb +44 -0
- data/lib/rgame/engine/components/collision_world.rb +103 -0
- data/lib/rgame/engine/components/despawn_offscreen.rb +26 -0
- data/lib/rgame/engine/components/path_follow.rb +84 -0
- data/lib/rgame/engine/components/player_controller.rb +24 -0
- data/lib/rgame/engine/components/pool.rb +53 -0
- data/lib/rgame/engine/components/screen_wrap.rb +27 -0
- data/lib/rgame/engine/components/sprite.rb +31 -0
- data/lib/rgame/engine/components/targeting.rb +54 -0
- data/lib/rgame/engine/components/thrust_controller.rb +65 -0
- data/lib/rgame/engine/components/tile_world.rb +68 -0
- data/lib/rgame/engine/components/timer.rb +75 -0
- data/lib/rgame/engine/components/velocity.rb +27 -0
- data/lib/rgame/engine/components/wander_controller.rb +60 -0
- data/lib/rgame/engine/debug_overlay.rb +106 -0
- data/lib/rgame/engine/i18n.rb +97 -0
- data/lib/rgame/engine/input/action_mapper.rb +46 -0
- data/lib/rgame/engine/input/actions.rb +41 -0
- data/lib/rgame/engine/input/player_controller.rb +14 -0
- data/lib/rgame/engine/matrix.rb +32 -0
- data/lib/rgame/engine/node2d.rb +271 -0
- data/lib/rgame/engine/path.rb +78 -0
- data/lib/rgame/engine/pool.rb +51 -0
- data/lib/rgame/engine/resettable.rb +67 -0
- data/lib/rgame/engine/scene/scene_stack.rb +65 -0
- data/lib/rgame/engine/signal.rb +75 -0
- data/lib/rgame/engine/spatial_hash.rb +71 -0
- data/lib/rgame/engine/tile_collision.rb +78 -0
- data/lib/rgame/engine/tile_map.rb +149 -0
- data/lib/rgame/engine/tileset.rb +101 -0
- data/lib/rgame/engine/timer.rb +51 -0
- data/lib/rgame/engine.rb +68 -0
- data/lib/rgame/fonts/LiberationSans-Regular.ttf +0 -0
- data/lib/rgame/fonts/OFL.txt +102 -0
- data/lib/rgame/game.rb +129 -0
- data/lib/rgame/util/color.rb +27 -0
- data/lib/rgame/util/controls.rb +107 -0
- data/lib/rgame/util/tensor.rb +12 -0
- data/lib/rgame/util.rb +8 -0
- data/lib/rgame/version.rb +12 -0
- data/lib/rgame.rb +20 -0
- metadata +215 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* audio_ext.c — the Ruby bindings for RGame::Core::Audio, ::Sample and ::Song.
|
|
3
|
+
*
|
|
4
|
+
* audio = RGame::Core::Audio.new
|
|
5
|
+
* hit = RGame::Core::Sample.new(audio, 'assets/hit.ogg')
|
|
6
|
+
* hit.play
|
|
7
|
+
*
|
|
8
|
+
* music = RGame::Core::Song.new(audio, 'assets/theme.ogg')
|
|
9
|
+
* music.play(looping: true)
|
|
10
|
+
*
|
|
11
|
+
* Three classes in one file, unlike the one-class-per-file rule the rest of the
|
|
12
|
+
* extension follows. They share a single wrapping shape — a C handle plus a
|
|
13
|
+
* marked reference to the device it belongs to — and a Sample or a Song apart
|
|
14
|
+
* from its Audio is not a thing. Splitting them would triplicate the TypedData
|
|
15
|
+
* boilerplate to separate ninety lines that are read together.
|
|
16
|
+
*
|
|
17
|
+
* All three are thin: audio.c does the work, and the interesting parts of that
|
|
18
|
+
* are miniaudio's. What this file adds is turning a NULL return into an
|
|
19
|
+
* exception that names the file, and keeping the device reachable for as long
|
|
20
|
+
* as any sound made from it.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
#include "ruby/core_ext.h"
|
|
24
|
+
|
|
25
|
+
#include "audio/audio_internal.h"
|
|
26
|
+
#include "rgame/core.h"
|
|
27
|
+
|
|
28
|
+
/* ------------------------------------------------------------------------- *
|
|
29
|
+
* Audio — the device
|
|
30
|
+
* ------------------------------------------------------------------------- */
|
|
31
|
+
|
|
32
|
+
static void audio_free(void *ptr) {
|
|
33
|
+
rgame_audio_destroy((rgame_audio *)ptr);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static const rb_data_type_t audio_data_type = {
|
|
37
|
+
.wrap_struct_name = "rgame_audio",
|
|
38
|
+
.function = {
|
|
39
|
+
.dmark = NULL, /* no Ruby objects inside */
|
|
40
|
+
.dfree = audio_free,
|
|
41
|
+
.dsize = NULL,
|
|
42
|
+
},
|
|
43
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
static VALUE cAudio;
|
|
47
|
+
static VALUE cSample;
|
|
48
|
+
static VALUE cSong;
|
|
49
|
+
|
|
50
|
+
static rgame_audio *audio_unwrap(VALUE self) {
|
|
51
|
+
rgame_audio *audio;
|
|
52
|
+
TypedData_Get_Struct(self, rgame_audio, &audio_data_type, audio);
|
|
53
|
+
if (!audio) {
|
|
54
|
+
rb_raise(rb_eRuntimeError, "audio device is not initialized");
|
|
55
|
+
}
|
|
56
|
+
return audio;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static VALUE audio_alloc(VALUE klass) {
|
|
60
|
+
return TypedData_Wrap_Struct(klass, &audio_data_type, NULL);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static VALUE audio_initialize(VALUE self) {
|
|
64
|
+
char error[256] = {0};
|
|
65
|
+
rgame_audio *audio = rgame_audio_create(error, sizeof(error));
|
|
66
|
+
if (!audio) {
|
|
67
|
+
rb_raise(rb_eRuntimeError, "%s", error);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
RTYPEDDATA_DATA(self) = audio;
|
|
71
|
+
return self;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static VALUE audio_volume(VALUE self) {
|
|
75
|
+
return DBL2NUM((double)rgame_audio_volume(audio_unwrap(self)));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static VALUE audio_set_volume(VALUE self, VALUE volume) {
|
|
79
|
+
rgame_audio_set_volume(audio_unwrap(self), (float)NUM2DBL(volume));
|
|
80
|
+
return volume;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* Which sound system is in use — "PulseAudio", "ALSA", "Null". A game with no
|
|
84
|
+
* sound hardware gets "Null" and plays silently rather than failing, so this is
|
|
85
|
+
* how it would find out. */
|
|
86
|
+
static VALUE audio_backend(VALUE self) {
|
|
87
|
+
return rb_str_new_cstr(rgame_audio_backend(audio_unwrap(self)));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static VALUE audio_inspect(VALUE self) {
|
|
91
|
+
rgame_audio *audio;
|
|
92
|
+
TypedData_Get_Struct(self, rgame_audio, &audio_data_type, audio);
|
|
93
|
+
if (!audio) {
|
|
94
|
+
return rb_sprintf("#<%" PRIsVALUE " (uninitialized)>", rb_obj_class(self));
|
|
95
|
+
}
|
|
96
|
+
return rb_sprintf("#<%" PRIsVALUE " %s>", rb_obj_class(self),
|
|
97
|
+
rgame_audio_backend(audio));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/*
|
|
101
|
+
* Audio.debug_live_sounds — how many samples and songs are alive.
|
|
102
|
+
*
|
|
103
|
+
* Test-only, and named so. A leaked sound is silent in every sense: nothing
|
|
104
|
+
* sounds wrong, nothing is slower, and memory grows across an hour of play.
|
|
105
|
+
* The image and font sides have the same counter for the same reason.
|
|
106
|
+
*/
|
|
107
|
+
static VALUE audio_s_debug_live_sounds(VALUE klass) {
|
|
108
|
+
(void)klass;
|
|
109
|
+
return LONG2NUM(rgame_audio_live_sounds());
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* ------------------------------------------------------------------------- *
|
|
113
|
+
* Sample and Song — one shape, two payloads
|
|
114
|
+
* ------------------------------------------------------------------------- */
|
|
115
|
+
|
|
116
|
+
/*
|
|
117
|
+
* Both wrap a C handle plus the Ruby Audio it came from. Marking the device is
|
|
118
|
+
* what stops the collector taking it first: the sound is a voice inside that
|
|
119
|
+
* device's mixer, and freeing the mixer out from under it would be a crash at
|
|
120
|
+
* an unpredictable moment.
|
|
121
|
+
*/
|
|
122
|
+
typedef struct {
|
|
123
|
+
void *handle; /* rgame_sample * or rgame_song * */
|
|
124
|
+
VALUE audio;
|
|
125
|
+
} rgame_sound_ref;
|
|
126
|
+
|
|
127
|
+
static void sound_ref_mark(void *ptr) {
|
|
128
|
+
rb_gc_mark(((rgame_sound_ref *)ptr)->audio);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
static size_t sound_ref_size(const void *ptr) {
|
|
132
|
+
(void)ptr;
|
|
133
|
+
return sizeof(rgame_sound_ref);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
static void sample_ref_free(void *ptr) {
|
|
137
|
+
rgame_sound_ref *ref = ptr;
|
|
138
|
+
rgame_sample_destroy((rgame_sample *)ref->handle); /* NULL-safe */
|
|
139
|
+
xfree(ref);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
static void song_ref_free(void *ptr) {
|
|
143
|
+
rgame_sound_ref *ref = ptr;
|
|
144
|
+
rgame_song_destroy((rgame_song *)ref->handle);
|
|
145
|
+
xfree(ref);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static const rb_data_type_t sample_data_type = {
|
|
149
|
+
.wrap_struct_name = "rgame_sample",
|
|
150
|
+
.function = { .dmark = sound_ref_mark, .dfree = sample_ref_free, .dsize = sound_ref_size },
|
|
151
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
static const rb_data_type_t song_data_type = {
|
|
155
|
+
.wrap_struct_name = "rgame_song",
|
|
156
|
+
.function = { .dmark = sound_ref_mark, .dfree = song_ref_free, .dsize = sound_ref_size },
|
|
157
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
static VALUE sound_alloc(VALUE klass, const rb_data_type_t *type) {
|
|
161
|
+
rgame_sound_ref *ref;
|
|
162
|
+
VALUE object = TypedData_Make_Struct(klass, rgame_sound_ref, type, ref);
|
|
163
|
+
ref->handle = NULL;
|
|
164
|
+
ref->audio = Qnil;
|
|
165
|
+
return object;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static VALUE sample_alloc(VALUE klass) {
|
|
169
|
+
return sound_alloc(klass, &sample_data_type);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
static VALUE song_alloc(VALUE klass) {
|
|
173
|
+
return sound_alloc(klass, &song_data_type);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
static rgame_sound_ref *sound_unwrap(VALUE self, const rb_data_type_t *type) {
|
|
177
|
+
rgame_sound_ref *ref;
|
|
178
|
+
TypedData_Get_Struct(self, rgame_sound_ref, type, ref);
|
|
179
|
+
if (!ref->handle) {
|
|
180
|
+
rb_raise(rb_eRuntimeError, "sound is not initialized");
|
|
181
|
+
}
|
|
182
|
+
return ref;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* Shared by both constructors: unwrap the device, load, raise on failure with
|
|
186
|
+
* the file named. `load` differs; nothing else does. */
|
|
187
|
+
static VALUE sound_initialize(VALUE self, VALUE audio, VALUE path, const rb_data_type_t *type,
|
|
188
|
+
void *(*load)(rgame_audio *, const char *, char *, size_t),
|
|
189
|
+
VALUE error_class) {
|
|
190
|
+
rgame_sound_ref *ref;
|
|
191
|
+
TypedData_Get_Struct(self, rgame_sound_ref, type, ref);
|
|
192
|
+
|
|
193
|
+
/* Raises TypeError on anything that is not an Audio, so there is no
|
|
194
|
+
* separate check to keep in step. */
|
|
195
|
+
rgame_audio *device;
|
|
196
|
+
TypedData_Get_Struct(audio, rgame_audio, &audio_data_type, device);
|
|
197
|
+
|
|
198
|
+
const char *path_str = StringValueCStr(path);
|
|
199
|
+
|
|
200
|
+
char error[256] = {0};
|
|
201
|
+
void *handle = load(device, path_str, error, sizeof(error));
|
|
202
|
+
if (!handle) {
|
|
203
|
+
rb_raise(error_class, "%s", error);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
ref->handle = handle;
|
|
207
|
+
ref->audio = audio;
|
|
208
|
+
return self;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* The two loaders, wrapped so their signatures match sound_initialize's. */
|
|
212
|
+
static void *load_sample(rgame_audio *audio, const char *path, char *err, size_t err_size) {
|
|
213
|
+
return rgame_sample_load(audio, path, err, err_size);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
static void *load_song(rgame_audio *audio, const char *path, char *err, size_t err_size) {
|
|
217
|
+
return rgame_song_load(audio, path, err, err_size);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* --- Sample --- */
|
|
221
|
+
|
|
222
|
+
static VALUE sample_initialize(VALUE self, VALUE audio, VALUE path) {
|
|
223
|
+
return sound_initialize(self, audio, path, &sample_data_type, load_sample,
|
|
224
|
+
rb_const_get(cSample, rb_intern("LoadError")));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/*
|
|
228
|
+
* #play — start another voice.
|
|
229
|
+
*
|
|
230
|
+
* Deliberately not "restart": playing a sample while it is already sounding
|
|
231
|
+
* layers a second voice over the first, which is what makes rapid footsteps or
|
|
232
|
+
* gunfire sound right. A Song does the opposite.
|
|
233
|
+
*/
|
|
234
|
+
static VALUE sample_play(VALUE self) {
|
|
235
|
+
rgame_sample_play((rgame_sample *)sound_unwrap(self, &sample_data_type)->handle);
|
|
236
|
+
return self;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
static VALUE sample_volume(VALUE self) {
|
|
240
|
+
return DBL2NUM(
|
|
241
|
+
(double)rgame_sample_volume((rgame_sample *)sound_unwrap(self, &sample_data_type)->handle));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
static VALUE sample_set_volume(VALUE self, VALUE volume) {
|
|
245
|
+
rgame_sample_set_volume((rgame_sample *)sound_unwrap(self, &sample_data_type)->handle,
|
|
246
|
+
(float)NUM2DBL(volume));
|
|
247
|
+
return volume;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* --- Song --- */
|
|
251
|
+
|
|
252
|
+
static VALUE song_initialize(VALUE self, VALUE audio, VALUE path) {
|
|
253
|
+
return sound_initialize(self, audio, path, &song_data_type, load_song,
|
|
254
|
+
rb_const_get(cSong, rb_intern("LoadError")));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* #play_looping(true/false) — the raw form; Song#play in
|
|
258
|
+
* lib/rgame/core/audio.rb is the one with the keyword. */
|
|
259
|
+
static VALUE song_play(VALUE self, VALUE looping) {
|
|
260
|
+
rgame_song_play((rgame_song *)sound_unwrap(self, &song_data_type)->handle,
|
|
261
|
+
RTEST(looping) ? 1 : 0);
|
|
262
|
+
return self;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
static VALUE song_stop(VALUE self) {
|
|
266
|
+
rgame_song_stop((rgame_song *)sound_unwrap(self, &song_data_type)->handle);
|
|
267
|
+
return self;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
static VALUE song_playing_p(VALUE self) {
|
|
271
|
+
return rgame_song_playing((rgame_song *)sound_unwrap(self, &song_data_type)->handle) ? Qtrue
|
|
272
|
+
: Qfalse;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
static VALUE song_looping_p(VALUE self) {
|
|
276
|
+
return rgame_song_looping((rgame_song *)sound_unwrap(self, &song_data_type)->handle) ? Qtrue
|
|
277
|
+
: Qfalse;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
static VALUE song_volume(VALUE self) {
|
|
281
|
+
return DBL2NUM(
|
|
282
|
+
(double)rgame_song_volume((rgame_song *)sound_unwrap(self, &song_data_type)->handle));
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
static VALUE song_set_volume(VALUE self, VALUE volume) {
|
|
286
|
+
rgame_song_set_volume((rgame_song *)sound_unwrap(self, &song_data_type)->handle,
|
|
287
|
+
(float)NUM2DBL(volume));
|
|
288
|
+
return volume;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
void rgame_init_audio(VALUE mCore) {
|
|
292
|
+
cAudio = rb_define_class_under(mCore, "Audio", rb_cObject);
|
|
293
|
+
rb_define_alloc_func(cAudio, audio_alloc);
|
|
294
|
+
rb_define_method(cAudio, "initialize", audio_initialize, 0);
|
|
295
|
+
rb_define_method(cAudio, "volume", audio_volume, 0);
|
|
296
|
+
rb_define_method(cAudio, "volume=", audio_set_volume, 1);
|
|
297
|
+
rb_define_method(cAudio, "backend", audio_backend, 0);
|
|
298
|
+
rb_define_method(cAudio, "inspect", audio_inspect, 0);
|
|
299
|
+
rb_define_singleton_method(cAudio, "debug_live_sounds", audio_s_debug_live_sounds, 0);
|
|
300
|
+
|
|
301
|
+
cSample = rb_define_class_under(mCore, "Sample", rb_cObject);
|
|
302
|
+
/* A file that cannot be read or is not a sound the engine knows — an
|
|
303
|
+
* everyday condition, so it gets a name a game can rescue. */
|
|
304
|
+
rb_define_class_under(cSample, "LoadError", rb_eStandardError);
|
|
305
|
+
rb_define_alloc_func(cSample, sample_alloc);
|
|
306
|
+
rb_define_method(cSample, "initialize", sample_initialize, 2);
|
|
307
|
+
rb_define_method(cSample, "play", sample_play, 0);
|
|
308
|
+
rb_define_method(cSample, "volume", sample_volume, 0);
|
|
309
|
+
rb_define_method(cSample, "volume=", sample_set_volume, 1);
|
|
310
|
+
|
|
311
|
+
cSong = rb_define_class_under(mCore, "Song", rb_cObject);
|
|
312
|
+
rb_define_class_under(cSong, "LoadError", rb_eStandardError);
|
|
313
|
+
rb_define_alloc_func(cSong, song_alloc);
|
|
314
|
+
rb_define_method(cSong, "initialize", song_initialize, 2);
|
|
315
|
+
rb_define_method(cSong, "play_looping", song_play, 1);
|
|
316
|
+
rb_define_method(cSong, "stop", song_stop, 0);
|
|
317
|
+
rb_define_method(cSong, "playing?", song_playing_p, 0);
|
|
318
|
+
rb_define_method(cSong, "looping?", song_looping_p, 0);
|
|
319
|
+
rb_define_method(cSong, "volume", song_volume, 0);
|
|
320
|
+
rb_define_method(cSong, "volume=", song_set_volume, 1);
|
|
321
|
+
}
|