rubygame 2.5.3 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/CREDITS +6 -4
  2. data/NEWS +79 -0
  3. data/README +55 -72
  4. data/ROADMAP +20 -13
  5. data/doc/custom_sdl_load_paths.rdoc +79 -0
  6. data/doc/getting_started.rdoc +65 -36
  7. data/doc/keyboard_symbols.rdoc +243 -0
  8. data/doc/macosx_install.rdoc +49 -35
  9. data/doc/windows_install.rdoc +36 -108
  10. data/lib/rubygame.rb +62 -24
  11. data/lib/rubygame/audio.rb +147 -0
  12. data/lib/rubygame/clock.rb +164 -1
  13. data/lib/rubygame/color.rb +40 -7
  14. data/lib/rubygame/color/models/hsl.rb +1 -1
  15. data/lib/rubygame/color/models/hsv.rb +1 -1
  16. data/lib/rubygame/color/models/rgb.rb +1 -1
  17. data/lib/rubygame/color/palettes/css.rb +1 -3
  18. data/lib/rubygame/color/palettes/x11.rb +1 -2
  19. data/lib/rubygame/constants.rb +297 -0
  20. data/lib/rubygame/deprecated_mixer.rb +555 -0
  21. data/lib/rubygame/event.rb +122 -6
  22. data/lib/rubygame/event_handler.rb +3 -1
  23. data/lib/rubygame/event_hook.rb +6 -2
  24. data/lib/rubygame/event_triggers.rb +1 -1
  25. data/lib/rubygame/events.rb +416 -1
  26. data/lib/rubygame/ftor.rb +1 -7
  27. data/lib/rubygame/gfx.rb +583 -0
  28. data/lib/rubygame/gl.rb +107 -0
  29. data/lib/rubygame/image.rb +140 -0
  30. data/lib/rubygame/joystick.rb +184 -0
  31. data/lib/rubygame/main.rb +82 -0
  32. data/lib/rubygame/mediabag.rb +1 -1
  33. data/lib/rubygame/mixer.rb +30 -0
  34. data/lib/rubygame/music.rb +493 -0
  35. data/lib/rubygame/queue.rb +3 -1
  36. data/lib/rubygame/rect.rb +9 -9
  37. data/lib/rubygame/screen.rb +357 -0
  38. data/lib/rubygame/shared.rb +40 -4
  39. data/lib/rubygame/sound.rb +428 -0
  40. data/lib/rubygame/surface.rb +626 -0
  41. data/lib/rubygame/ttf.rb +311 -0
  42. data/samples/FreeSans.ttf +0 -0
  43. data/samples/README +6 -5
  44. data/samples/demo_draw.rb +1 -1
  45. data/samples/demo_gl.rb +3 -1
  46. data/samples/demo_gl_tex.rb +4 -2
  47. data/samples/demo_rubygame.rb +114 -105
  48. data/samples/demo_sfont.rb +1 -1
  49. data/samples/demo_ttf.rb +3 -1
  50. data/samples/demo_utf8.rb +1 -1
  51. data/samples/image_viewer.rb +118 -0
  52. data/samples/load_and_blit.rb +1 -1
  53. data/samples/rubygame.png +0 -0
  54. metadata +34 -40
  55. data/Rakefile +0 -537
  56. data/doc/extended_readme.rdoc +0 -49
  57. data/ext/body/rubygame_body.so +0 -0
  58. data/ext/rubygame/rubygame_clock.c +0 -301
  59. data/ext/rubygame/rubygame_clock.h +0 -32
  60. data/ext/rubygame/rubygame_event.c +0 -760
  61. data/ext/rubygame/rubygame_event.h +0 -48
  62. data/ext/rubygame/rubygame_event2.c +0 -661
  63. data/ext/rubygame/rubygame_event2.h +0 -29
  64. data/ext/rubygame/rubygame_gfx.c +0 -942
  65. data/ext/rubygame/rubygame_gfx.h +0 -101
  66. data/ext/rubygame/rubygame_gl.c +0 -154
  67. data/ext/rubygame/rubygame_gl.h +0 -32
  68. data/ext/rubygame/rubygame_image.c +0 -252
  69. data/ext/rubygame/rubygame_image.h +0 -41
  70. data/ext/rubygame/rubygame_joystick.c +0 -336
  71. data/ext/rubygame/rubygame_joystick.h +0 -41
  72. data/ext/rubygame/rubygame_main.c +0 -158
  73. data/ext/rubygame/rubygame_main.h +0 -36
  74. data/ext/rubygame/rubygame_mixer.c +0 -1024
  75. data/ext/rubygame/rubygame_mixer.h +0 -36
  76. data/ext/rubygame/rubygame_music.c +0 -1017
  77. data/ext/rubygame/rubygame_music.h +0 -29
  78. data/ext/rubygame/rubygame_screen.c +0 -572
  79. data/ext/rubygame/rubygame_screen.h +0 -45
  80. data/ext/rubygame/rubygame_shared.c +0 -269
  81. data/ext/rubygame/rubygame_shared.h +0 -69
  82. data/ext/rubygame/rubygame_sound.c +0 -863
  83. data/ext/rubygame/rubygame_sound.h +0 -29
  84. data/ext/rubygame/rubygame_surface.c +0 -1153
  85. data/ext/rubygame/rubygame_surface.h +0 -62
  86. data/ext/rubygame/rubygame_ttf.c +0 -599
  87. data/ext/rubygame/rubygame_ttf.h +0 -69
  88. data/samples/keys.rb +0 -52
@@ -1,45 +0,0 @@
1
- /*
2
- * Rubygame -- Ruby code and bindings to SDL to facilitate game creation
3
- * Copyright (C) 2004-2007 John Croisant
4
- *
5
- * This library is free software; you can redistribute it and/or
6
- * modify it under the terms of the GNU Lesser General Public
7
- * License as published by the Free Software Foundation; either
8
- * version 2.1 of the License, or (at your option) any later version.
9
- *
10
- * This library is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
- * Lesser General Public License for more details.
14
- *
15
- * You should have received a copy of the GNU Lesser General Public
16
- * License along with this library; if not, write to the Free Software
17
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
- *
19
- */
20
-
21
- #ifndef _RUBYGAME_SCREEN_H
22
- #define _RUBYGAME_SCREEN_H
23
-
24
- extern void Rubygame_Init_Screen();
25
-
26
- extern VALUE cScreen;
27
-
28
- extern VALUE rbgm_screen_setmode(int, VALUE*, VALUE);
29
- extern VALUE rbgm_screen_getsurface(VALUE);
30
-
31
- extern VALUE rbgm_screen_getresolution(VALUE);
32
-
33
- extern VALUE rbgm_screen_getcaption(VALUE);
34
- extern VALUE rbgm_screen_setcaption(VALUE, VALUE);
35
-
36
- extern VALUE rbgm_screen_seticon(VALUE, VALUE);
37
-
38
- extern VALUE rbgm_screen_update(int, VALUE*, VALUE);
39
- extern VALUE rbgm_screen_updaterects(VALUE, VALUE);
40
- extern VALUE rbgm_screen_flip(VALUE);
41
-
42
- extern VALUE rbgm_screen_getshowcursor(VALUE);
43
- extern VALUE rbgm_screen_setshowcursor(VALUE, VALUE);
44
-
45
- #endif
@@ -1,269 +0,0 @@
1
- /*
2
- * Code that is common to all Rubygame modules.
3
- *--
4
- * Rubygame -- Ruby code and bindings to SDL to facilitate game creation
5
- * Copyright (C) 2004-2007 John Croisant
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
- *++
21
- */
22
-
23
- #include "rubygame_shared.h"
24
-
25
- VALUE mRubygame;
26
- VALUE cSurface;
27
- VALUE cRect;
28
- VALUE eSDLError;
29
- VALUE mNamedResource;
30
-
31
-
32
- SDL_Rect *make_rect(int, int, int, int);
33
- SDL_Color make_sdl_color(VALUE);
34
- int init_video_system();
35
- void Init_rubygame_shared();
36
-
37
- SDL_Rect *make_rect(int x, int y, int w, int h)
38
- {
39
- SDL_Rect *rect;
40
- rect = (SDL_Rect *) malloc(sizeof(SDL_Rect));
41
- rect->x = x;
42
- rect->y = y;
43
- rect->w = w;
44
- rect->h = h;
45
- return rect;
46
- }
47
-
48
- /* Returns a symbol from the given char* string */
49
- VALUE make_symbol(char *string)
50
- {
51
- return ID2SYM(rb_intern(string));
52
- }
53
-
54
- /* Returns a char* string from the given symbol */
55
- char *unmake_symbol(VALUE symbol)
56
- {
57
- return (char *)rb_id2name( SYM2ID(symbol) );
58
- }
59
-
60
-
61
- /* Lowercase, change spaces to underscores, and convert to symbol.
62
- * Equivalent to: str.downcase!.gsub!(" ","_").intern
63
- */
64
- VALUE sanitized_symbol(char *string)
65
- {
66
- VALUE str = rb_str_new2(string);
67
-
68
- rb_funcall( str, rb_intern("downcase!"), 0 );
69
- rb_funcall( str, rb_intern("gsub!"), 2, rb_str_new2(" "), rb_str_new2("_") );
70
- return rb_funcall( str, rb_intern("intern"), 0 );
71
- }
72
-
73
- /* Take either nil, Numeric or an Array of Numerics, returns Uint32. */
74
- Uint32 collapse_flags(VALUE vflags)
75
- {
76
- Uint32 flags = 0;
77
- int i;
78
-
79
- if( RTEST(vflags) )
80
- {
81
- switch( TYPE(vflags) ){
82
- case T_ARRAY: {
83
- int len = RARRAY_LEN(vflags);
84
- for(i=0; i < len; i++)
85
- {
86
- flags |= NUM2UINT( rb_ary_entry( vflags,i ) );
87
- }
88
- break;
89
- }
90
- case T_BIGNUM: {
91
- flags = rb_big2uint( vflags );
92
- break;
93
- }
94
- case T_FIXNUM: {
95
- flags = NUM2UINT( vflags );
96
- break;
97
- }
98
- default: {
99
- rb_raise(rb_eArgError,"Wrong type for argument `flags' (wanted Number or Array).");
100
- }
101
- }
102
- }
103
-
104
- return flags;
105
- }
106
-
107
- VALUE convert_to_array(VALUE val)
108
- {
109
- VALUE v = rb_check_array_type(val);
110
- if( TYPE(v) != T_ARRAY )
111
- {
112
- rb_raise(rb_eTypeError, "can't convert %s into Array",
113
- rb_obj_classname(val));
114
- }
115
- return v;
116
- }
117
-
118
- /* Takes a Color, Array, or color name (Symbol or String).
119
- * Returns an RGBA Array, or raises eTypeError if it can't.
120
- */
121
- VALUE convert_color(VALUE color)
122
- {
123
- if( rb_respond_to(color, rb_intern("to_sdl_rgba_ary")) )
124
- {
125
- return rb_funcall( color, rb_intern("to_sdl_rgba_ary"), 0 );
126
- }
127
- else if( rb_respond_to(color, rb_intern("to_ary")) )
128
- {
129
- return convert_to_array( color );
130
- }
131
- else if( TYPE(color) == T_SYMBOL || TYPE(color) == T_STRING )
132
- {
133
- VALUE mColor = rb_const_get( mRubygame, rb_intern("Color") );
134
- return convert_color( rb_funcall( mColor, rb_intern("[]"), 1, color) );
135
- }
136
- else
137
- {
138
- rb_raise(rb_eTypeError, "unsupported type %s for color",
139
- rb_obj_classname(color));
140
- }
141
- }
142
-
143
- SDL_Color make_sdl_color(VALUE vcolor)
144
- {
145
- SDL_Color color;
146
- vcolor = convert_color(vcolor);
147
- extract_rgb_u8_as_u8(vcolor, &(color.r), &(color.g), &(color.b));
148
- return color;
149
- }
150
-
151
- void extract_rgb_u8_as_u8(VALUE color, Uint8 *r, Uint8 *g, Uint8 *b)
152
- {
153
- *r = NUM2UINT(rb_ary_entry(color, 0));
154
- *g = NUM2UINT(rb_ary_entry(color, 1));
155
- *b = NUM2UINT(rb_ary_entry(color, 2));
156
- }
157
-
158
- void extract_rgba_u8_as_u8(VALUE color, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a)
159
- {
160
- *r = NUM2UINT(rb_ary_entry(color, 0));
161
- *g = NUM2UINT(rb_ary_entry(color, 1));
162
- *b = NUM2UINT(rb_ary_entry(color, 2));
163
-
164
- if( RARRAY_LEN(color) > 3 )
165
- {
166
- *a = NUM2UINT(rb_ary_entry(color, 3));
167
- }
168
- else
169
- {
170
- *a = 255;
171
- }
172
- }
173
-
174
-
175
-
176
- /* --
177
- *
178
- * Issues a deprecation warning for the given feature/method.
179
- *
180
- * ++
181
- */
182
- void rg_deprecated( char *feature, char *version )
183
- {
184
- rb_warning( "%s is DEPRECATED and will be removed in Rubygame %s! "
185
- "Please see the docs for more information.",
186
- feature, version );
187
- }
188
-
189
-
190
-
191
- /* --
192
- *
193
- * call-seq:
194
- * init_video_system() -> int
195
- *
196
- * Initialize SDL's video subsystem.
197
- * Return 0 (zero) on success, non-zero on failure.
198
- *
199
- * If it has already been initialized, return 0 immediately.
200
- *
201
- * ++
202
- */
203
- int init_video_system()
204
- {
205
- if( SDL_WasInit(SDL_INIT_VIDEO) == 0 )
206
- {
207
- return SDL_Init(SDL_INIT_VIDEO);
208
- }
209
- else
210
- {
211
- return 0;
212
- }
213
- }
214
-
215
- /* --
216
- *
217
- * Includes the Rubygame::NamedResource mixin in the given class
218
- * and performs the `included' callback.
219
- *
220
- * ++
221
- */
222
- void rg_include_named_resource( VALUE klass )
223
- {
224
- /* Include the mixin, and manually perform the 'included' callback. */
225
- rb_include_module( klass, mNamedResource );
226
- rb_funcall( mNamedResource, rb_intern("included"), 1, klass );
227
- }
228
-
229
-
230
- void Init_rubygame_shared()
231
- {
232
-
233
- mRubygame = rb_define_module("Rubygame");
234
-
235
- /* Rubygame::Surface class */
236
- if( !rb_const_defined(mRubygame,rb_intern("Surface")) )
237
- {
238
- cSurface = rb_define_class_under(mRubygame,"Surface",rb_cObject);
239
- }
240
- else
241
- {
242
- cSurface = rb_const_get(mRubygame,rb_intern("Surface"));
243
- }
244
-
245
- /* Rubygame::SDLError class */
246
- if( !rb_const_defined(mRubygame,rb_intern("SDLError")))
247
- {
248
- /* Indicates that an SDL function did not execute properly. */
249
- eSDLError = rb_define_class_under(mRubygame,"SDLError",rb_eStandardError);
250
- }
251
- else
252
- {
253
- eSDLError = rb_const_get(mRubygame,rb_intern("SDLError"));
254
- }
255
-
256
- /* Rubygame::VERSIONS hash table */
257
- if( !rb_const_defined(mRubygame, rb_intern("VERSIONS")))
258
- {
259
- /* A Hash containing the version s of rubygame and it's
260
- * compile-time dependencies. */
261
- rb_define_const(mRubygame,"VERSIONS",rb_hash_new());
262
- }
263
-
264
-
265
- /* Rubygame::NamedResource mixin. See named_resource.rb. */
266
- rb_require("rubygame/named_resource");
267
- mNamedResource = rb_const_get(mRubygame, rb_intern("NamedResource"));
268
-
269
- }
@@ -1,69 +0,0 @@
1
- /*
2
- * Rubygame -- Ruby code and bindings to SDL to facilitate game creation
3
- * Copyright (C) 2004-2007 John Croisant
4
- *
5
- * This library is free software; you can redistribute it and/or
6
- * modify it under the terms of the GNU Lesser General Public
7
- * License as published by the Free Software Foundation; either
8
- * version 2.1 of the License, or (at your option) any later version.
9
- *
10
- * This library is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
- * Lesser General Public License for more details.
14
- *
15
- * You should have received a copy of the GNU Lesser General Public
16
- * License along with this library; if not, write to the Free Software
17
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
- *
19
- */
20
-
21
- #ifndef _RUBYGAME_SHARED_H
22
- #define _RUBYGAME_SHARED_H
23
-
24
- #include <SDL.h>
25
- #include <ruby.h>
26
- #include <stdio.h>
27
-
28
- /* General */
29
- extern VALUE mRubygame;
30
- extern VALUE eSDLError;
31
- extern VALUE cSurface;
32
- extern VALUE cRect;
33
- extern VALUE mNamedResource;
34
-
35
- extern SDL_Rect *make_rect(int, int, int, int);
36
- extern VALUE make_symbol(char *);
37
- extern char *unmake_symbol(VALUE);
38
- extern VALUE sanitized_symbol(char *);
39
- extern Uint32 collapse_flags(VALUE);
40
- extern VALUE convert_to_array(VALUE);
41
-
42
- extern VALUE convert_color(VALUE);
43
- extern SDL_Color make_sdl_color(VALUE);
44
- extern void extract_rgb_u8_as_u8(VALUE, Uint8*, Uint8*, Uint8*);
45
- extern void extract_rgba_u8_as_u8(VALUE, Uint8*, Uint8*, Uint8*, Uint8*);
46
-
47
- extern void rg_deprecated( char *feature, char *version );
48
-
49
- /* Properly includes the Rubygame::NamedResource mixin in the klass */
50
- extern void rg_include_named_resource( VALUE klass );
51
-
52
- extern int init_video_system();
53
- extern void Init_rubygame_shared();
54
-
55
- /* Apparently it is not desirable to define these functions when
56
- * using Micrsoft Visual C.
57
- */
58
- #ifndef _MSC_VER
59
-
60
- static inline int max(int a, int b) {
61
- return a > b ? a : b;
62
- }
63
- static inline int min(int a, int b) {
64
- return a > b ? b : a;
65
- }
66
-
67
- #endif
68
-
69
- #endif
@@ -1,863 +0,0 @@
1
- /*
2
- * Interface to SDL_mixer sound playback and mixing.
3
- *--
4
- * Rubygame -- Ruby code and bindings to SDL to facilitate game creation
5
- * Copyright (C) 2004-2008 John Croisant
6
- *
7
- * This library is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU Lesser General Public
9
- * License as published by the Free Software Foundation; either
10
- * version 2.1 of the License, or (at your option) any later version.
11
- *
12
- * This library is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
- * Lesser General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU Lesser General Public
18
- * License along with this library; if not, write to the Free Software
19
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
- *++
21
- */
22
-
23
- #include "SDL_mixer.h"
24
- #include "rubygame_shared.h"
25
- #include "rubygame_mixer.h"
26
-
27
- VALUE cSound;
28
-
29
- /* A pointer to a Mix_Chunk, with a reference count.
30
- * Allows re-use of sound data, then freeing memory when
31
- * there are no references to it.
32
- */
33
- typedef struct RG_WrapChunk {
34
- /* 'private' */
35
- Mix_Chunk *chunk;
36
- int ref_count;
37
- } RG_WrapChunk;
38
-
39
-
40
- /* The struct that the Sound class wraps. Stores a
41
- * pointer to a RG_WrapChunk and important attributes
42
- * of the Sound like its volume and channel it's
43
- * playing on.
44
- */
45
- typedef struct RG_Sound {
46
- /* 'public' */
47
- float volume;
48
-
49
- /* 'private' */
50
- RG_WrapChunk *wrap;
51
- int channel;
52
- } RG_Sound;
53
-
54
-
55
-
56
-
57
- /* Allocate/initialize the memory for a RG_WrapChunk and return a pointer. */
58
- static RG_WrapChunk* _rg_wrapchunk_alloc()
59
- {
60
- RG_WrapChunk *wrap;
61
- wrap = ALLOC(RG_WrapChunk);
62
-
63
- wrap->chunk = NULL;
64
- wrap->ref_count = 0;
65
-
66
- return wrap;
67
- }
68
-
69
- /* Load a Mix_Chunk from a file and assign it to the RG_WrapChunk. */
70
- static int _rg_wrapchunk_load( RG_WrapChunk *wrap, char *file )
71
- {
72
- /* Open audio if it's not already. Return -1 if it failed. */
73
- if( ensure_open_audio() != 0 )
74
- {
75
- return -1;
76
- }
77
-
78
- wrap->chunk = Mix_LoadWAV( file );
79
-
80
- if( !(wrap->chunk) )
81
- return -1;
82
- else
83
- return 0;
84
- }
85
-
86
- /* Make a copy of the other's Mix_Chunk audio data, and assign
87
- * it to the RG_WrapChunk.
88
- */
89
- static void _rg_wrapchunk_deepcopy( RG_WrapChunk *wrap, RG_WrapChunk *other )
90
- {
91
- *(wrap->chunk) = *(other->chunk);
92
- }
93
-
94
-
95
- /* Free the memory used by the RG_WrapChunk */
96
- static void _rg_wrapchunk_free( RG_WrapChunk *wrap )
97
- {
98
- Mix_FreeChunk( wrap->chunk );
99
- wrap->chunk = NULL;
100
- free(wrap);
101
- }
102
-
103
-
104
-
105
-
106
- /* Associate a RG_WrapChunk with a RG_Sound. Handles reference counts. */
107
- static inline void _rg_sound_associate( RG_Sound *sound, RG_WrapChunk *wrap )
108
- {
109
- sound->wrap = wrap;
110
- sound->wrap->ref_count += 1;
111
- }
112
-
113
- /* Deassociate the RG_Sound's WrapChunk. Handles reference counts. */
114
- static inline void _rg_sound_deassociate( RG_Sound *sound )
115
- {
116
- sound->wrap->ref_count -= 1;
117
- sound->wrap = NULL;
118
- }
119
-
120
- /* Allocate/initialize the memory for a RG_Sound return a pointer. */
121
- static RG_Sound* _rg_sound_alloc()
122
- {
123
- RG_Sound *sound;
124
- sound = ALLOC(RG_Sound);
125
-
126
- sound->wrap = NULL;
127
- sound->volume = 1.f;
128
- sound->channel = -1;
129
-
130
- return sound;
131
- }
132
-
133
-
134
- /* Free the memory used by the Sound, and possibly the memory
135
- * used by the WrapChunk it refers to.
136
- */
137
- static void _rg_sound_free( RG_Sound *sound )
138
- {
139
- RG_WrapChunk *wrap = sound->wrap;
140
-
141
- _rg_sound_deassociate( sound );
142
-
143
- free(sound);
144
-
145
- /* If the WrapChunk has no more referrers, free it too. */
146
- if( wrap->ref_count <= 0 )
147
- {
148
- _rg_wrapchunk_free( wrap );
149
- }
150
- }
151
-
152
-
153
- /* Load a new Sound from a file. */
154
- static int _rg_sound_load( RG_Sound *sound, char *file )
155
- {
156
- RG_WrapChunk *wrap = _rg_wrapchunk_alloc();
157
-
158
- int result = _rg_wrapchunk_load( wrap, file );
159
-
160
- _rg_sound_associate( sound, wrap );
161
-
162
- return result;
163
- }
164
-
165
-
166
- /* Make a shallow copy of the given Sound; the new Sound points to
167
- * the same audio data in memory as the old one. Also copies
168
- * user-visible attributes (e.g. volume).
169
- */
170
- static void _rg_sound_copy( RG_Sound *sound, RG_Sound *other )
171
- {
172
- _rg_sound_associate( sound, other->wrap );
173
-
174
- sound->volume = other->volume;
175
- sound->channel = -1;
176
- }
177
-
178
-
179
- /* Make a new Sound with a copy of the audio from an existing Sound */
180
- static void _rg_sound_deepcopy( RG_Sound *sound, RG_Sound *other )
181
- {
182
- RG_WrapChunk *wrap = _rg_wrapchunk_alloc();
183
- _rg_wrapchunk_deepcopy( wrap, other->wrap );
184
-
185
- _rg_sound_associate( sound, wrap );
186
-
187
- sound->volume = other->volume;
188
- sound->channel = -1;
189
- }
190
-
191
-
192
- /* Check that the given channel is (still) loaded with the given chunk. */
193
- static int _rg_sound_channel_check( RG_Sound *sound )
194
- {
195
- /* channel is unset, so it doesn't belong. */
196
- if( sound->channel == -1 )
197
- {
198
- return 0;
199
- }
200
-
201
- Mix_Chunk *chan_chunk = Mix_GetChunk(sound->channel);
202
-
203
- /* Check that the channel chunk is the same as the given one */
204
- return ( sound->wrap->chunk == chan_chunk );
205
- }
206
-
207
-
208
- /* Play the sound, fading in, repeating, and stopping as specified.
209
- * fade_in and stop_after are in milliseconds!
210
- */
211
- static int _rg_sound_play( RG_Sound *sound,
212
- int fade_in, int repeats, int stop_after )
213
- {
214
-
215
- /* Open audio if it's not already. Return -1 if it failed. */
216
- if( ensure_open_audio() != 0 )
217
- {
218
- return -1;
219
- }
220
-
221
- /* If it's already playing on a channel, stop it first. */
222
- if( _rg_sound_channel_check(sound) )
223
- {
224
- Mix_HaltChannel( sound->channel );
225
- }
226
-
227
- /* Find first available channel */
228
- sound->channel = Mix_GroupAvailable(-1);
229
-
230
- if( sound->channel == -1 )
231
- {
232
- /* No channels were available, so make one more than there are now.
233
- * (Mix_AllocateChannels(-1) returns the current number of channels)
234
- */
235
- Mix_AllocateChannels( Mix_AllocateChannels(-1) + 1 );
236
-
237
- /* Try again. */
238
- sound->channel = Mix_GroupAvailable(-1);
239
- }
240
-
241
- /* Set its volume before we play */
242
- Mix_Volume( sound->channel, (int)(MIX_MAX_VOLUME * sound->volume) );
243
-
244
-
245
- if( fade_in <= 0 )
246
- {
247
- /* Play sound without fading in */
248
- return Mix_PlayChannelTimed( sound->channel, sound->wrap->chunk,
249
- repeats, stop_after );
250
- }
251
- else
252
- {
253
- /* Play sound with fading in */
254
- return Mix_FadeInChannelTimed( sound->channel, sound->wrap->chunk,
255
- repeats, fade_in, stop_after );
256
- }
257
- }
258
-
259
-
260
- /* Ruby allocation function. */
261
- static VALUE rg_sound_alloc( VALUE klass )
262
- {
263
- RG_Sound *sound = _rg_sound_alloc();
264
- return Data_Wrap_Struct(klass, 0, _rg_sound_free, sound);
265
- }
266
-
267
-
268
-
269
- /*
270
- * call-seq:
271
- * load( filename ) -> sound
272
- *
273
- * Load the given audio file.
274
- * Supported file formats are WAV, AIFF, RIFF, OGG (Ogg Vorbis), and
275
- * VOC (SoundBlaster).
276
- *
277
- * filename:: Full or relative path to the file. (String, required)
278
- *
279
- * Returns:: The new Sound instance. (Sound)
280
- * May raise:: SDLError, if the sound file could not be loaded.
281
- *
282
- */
283
- static VALUE rg_sound_load( VALUE klass, VALUE filename )
284
- {
285
- RG_Sound *sound;
286
-
287
- VALUE s = rg_sound_alloc( cSound );
288
-
289
- Data_Get_Struct( s, RG_Sound, sound );
290
-
291
- char *file = StringValuePtr( filename );
292
-
293
- int result = _rg_sound_load( sound, file );
294
-
295
- if( result == -1 )
296
- {
297
- rb_raise(eSDLError, "Could not load Sound file '%s': %s",
298
- file, Mix_GetError());
299
- }
300
-
301
- return s;
302
- }
303
-
304
-
305
- /*
306
- * call-seq:
307
- * Sound.autoload( filename ) -> Surface or nil
308
- *
309
- * Searches each directory in Sound.autoload_dirs for a file with
310
- * the given filename. If it finds that file, loads it and returns
311
- * a Sound instance. If it doesn't find the file, returns nil.
312
- *
313
- * See Rubygame::NamedResource for more information about this
314
- * functionality.
315
- *
316
- */
317
- VALUE rg_sound_autoload( VALUE klass, VALUE namev )
318
- {
319
- VALUE pathv = rb_funcall( klass, rb_intern("find_file"), 1, namev );
320
-
321
- if( RTEST(pathv) )
322
- {
323
- return rg_sound_load( klass, pathv );
324
- }
325
- else
326
- {
327
- return Qnil;
328
- }
329
- }
330
-
331
-
332
- /*
333
- *
334
- * call-seq:
335
- * new
336
- *
337
- * **NOTE**: Don't use this method. Use Sound.load.
338
- *
339
- * This method is not implemented. (In the future, it might be
340
- * used to create a new Sound with blank audio data.)
341
- *
342
- * Raises NotImplementedError.
343
- *
344
- */
345
- static VALUE rg_sound_new( int argc, VALUE *ARGV, VALUE self )
346
- {
347
- rb_raise(rb_eNotImpError, "Sound.new is not implemented yet. Use Sound.load to load a sound file.");
348
- }
349
-
350
-
351
- /*
352
- * call-seq:
353
- * clone( other ) -> sound
354
- * dup( other ) -> sound
355
- *
356
- * Create a copy of the given Sound instance. Much more memory-efficient
357
- * than using #load to load the sound file again.
358
- *
359
- * other:: An existing Sound instance. (Sound, required)
360
- *
361
- * Returns:: The new Sound instance. (Sound)
362
- *
363
- * **NOTE**: #clone and #dup do slightly different things; #clone will copy
364
- * the 'frozen' state of the object, while #dup will create a fresh, un-frozen
365
- * object.
366
- *
367
- */
368
- static VALUE rg_sound_initialize_copy( VALUE self, VALUE other )
369
- {
370
- RG_Sound *soundA, *soundB;
371
- Data_Get_Struct(self, RG_Sound, soundA);
372
- Data_Get_Struct(other, RG_Sound, soundB);
373
-
374
- _rg_sound_copy( soundA, soundB );
375
-
376
- return self;
377
- }
378
-
379
-
380
-
381
-
382
- /*
383
- * call-seq:
384
- * play( options={} ) -> self
385
- *
386
- * Play the Sound, optionally fading in, repeating a certain number of
387
- * times (or forever), and/or stopping automatically after a certain time.
388
- *
389
- * See also #pause and #stop.
390
- *
391
- * options:: Hash of options, listed below. (Hash, required)
392
- *
393
- * :fade_in:: Fade in from silence over the given number of seconds.
394
- * (Numeric)
395
- * :repeats:: Repeat the sound the given number of times, or forever
396
- * (or until stopped) if -1. (Integer)
397
- * :stop_after:: Automatically stop playing after playing for the given
398
- * number of seconds. (Numeric)
399
- *
400
- * Returns:: The receiver (self).
401
- * May raise:: SDLError, if the sound file could not be played.
402
- *
403
- * **NOTE**: If the sound is already playing (or paused), it will be stopped
404
- * and played again from the beginning.
405
- *
406
- * Example:
407
- * # Fade in over 2 seconds, play 4 times (1 + 3 repeats),
408
- * # but stop playing after 5 seconds.
409
- * sound.play( :fade_in => 2, :repeats => 3, :stop_after => 5 );
410
- *
411
- */
412
- static VALUE rg_sound_play( int argc, VALUE *argv, VALUE self )
413
- {
414
- RG_Sound *sound;
415
- Data_Get_Struct(self, RG_Sound, sound);
416
-
417
- VALUE options;
418
- rb_scan_args(argc, argv, "01", &options);
419
-
420
- int fade_in = 0;
421
- int repeats = 0;
422
- int stop_after = -1;
423
-
424
- /* If we got some options */
425
- if( RTEST(options) )
426
- {
427
- /* Make sure options is a Hash table */
428
- if( TYPE(options) != T_HASH )
429
- {
430
- rb_raise(rb_eTypeError, "wrong argument type %s (expected Hash)",
431
- rb_obj_classname(options));
432
- }
433
-
434
- VALUE temp;
435
-
436
- temp = rb_hash_aref(options, make_symbol("fade_in"));
437
- if( RTEST(temp) )
438
- {
439
- fade_in = (int)(1000 * NUM2DBL( temp ));
440
- }
441
-
442
- temp = rb_hash_aref(options, make_symbol("repeats"));
443
- if( RTEST(temp) )
444
- {
445
- repeats = NUM2INT(temp);
446
- }
447
-
448
- temp = rb_hash_aref(options, make_symbol("stop_after"));
449
- if( RTEST(temp) )
450
- {
451
- stop_after = (int)(1000 * NUM2DBL( temp ));
452
- }
453
-
454
- }
455
-
456
- int result = _rg_sound_play( sound, fade_in, repeats, stop_after );
457
-
458
- if( result == -1 )
459
- {
460
- rb_raise(eSDLError, "Could not play Sound: %s", Mix_GetError());
461
- }
462
-
463
- return self;
464
- }
465
-
466
-
467
- /*
468
- * call-seq:
469
- * playing? -> true or false
470
- *
471
- * True if the Sound is currently playing (not paused or stopped).
472
- * See also #paused? and #stopped?.
473
- *
474
- */
475
- static VALUE rg_sound_playingp( VALUE self )
476
- {
477
- RG_Sound *sound;
478
- Data_Get_Struct(self, RG_Sound, sound);
479
-
480
- int channel = sound->channel;
481
-
482
- /* Make sure the sound actually belongs to the channel */
483
- if( _rg_sound_channel_check(sound) )
484
- {
485
- /* Return true if it's playing, but not paused. */
486
- if( Mix_Playing(channel) && !Mix_Paused(channel) )
487
- {
488
- return Qtrue;
489
- }
490
- else
491
- {
492
- return Qfalse;
493
- }
494
- }
495
- else
496
- {
497
- return Qfalse;
498
- }
499
- }
500
-
501
-
502
-
503
- /*
504
- * call-seq:
505
- * pause -> self
506
- *
507
- * Pause the Sound. Unlike #stop, it can be unpaused later to resume
508
- * from where it was paused. See also #unpause and #paused?.
509
- *
510
- * Returns:: The receiver (self).
511
- *
512
- * **NOTE**: Does nothing if the sound is not currently playing.
513
- *
514
- */
515
- static VALUE rg_sound_pause( VALUE self )
516
- {
517
- RG_Sound *sound;
518
- Data_Get_Struct(self, RG_Sound, sound);
519
-
520
- int channel = sound->channel;
521
-
522
- /* Make sure the sound actually belongs to the channel */
523
- if( _rg_sound_channel_check(sound) )
524
- {
525
- Mix_Pause( channel );
526
- }
527
-
528
- return self;
529
- }
530
-
531
-
532
- /*
533
- * call-seq:
534
- * unpause -> self
535
- *
536
- * Unpause the Sound, if it is currently paused. Resumes from
537
- * where it was paused. See also #pause and #paused?.
538
- *
539
- * Returns:: The receiver (self).
540
- *
541
- * **NOTE**: Does nothing if the sound is not currently paused.
542
- *
543
- */
544
- static VALUE rg_sound_unpause( VALUE self )
545
- {
546
- RG_Sound *sound;
547
- Data_Get_Struct(self, RG_Sound, sound);
548
-
549
- int channel = sound->channel;
550
-
551
- /* Make sure the sound actually belongs to the channel */
552
- if( _rg_sound_channel_check(sound) )
553
- {
554
- Mix_Resume( channel );
555
- }
556
-
557
- return self;
558
- }
559
-
560
-
561
- /*
562
- * call-seq:
563
- * paused? -> true or false
564
- *
565
- * True if the Sound is currently paused (not playing or stopped).
566
- * See also #playing? and #stopped?.
567
- *
568
- */
569
- static VALUE rg_sound_pausedp( VALUE self )
570
- {
571
- RG_Sound *sound;
572
- Data_Get_Struct(self, RG_Sound, sound);
573
-
574
- int channel = sound->channel;
575
-
576
- /* Make sure the sound actually belongs to the channel */
577
- if( _rg_sound_channel_check(sound) )
578
- {
579
- /* Return true if it's "playing" (not stopped), as well as paused. */
580
- if( Mix_Playing(channel) && Mix_Paused(channel) )
581
- {
582
- return Qtrue;
583
- }
584
- else
585
- {
586
- return Qfalse;
587
- }
588
- }
589
- else
590
- {
591
- return Qfalse;
592
- }
593
- }
594
-
595
-
596
-
597
- /*
598
- * call-seq:
599
- * stop -> self
600
- *
601
- * Stop the Sound. Unlike #pause, the sound must be played again from
602
- * the beginning, it cannot be resumed from it was stopped.
603
- *
604
- * Returns:: The receiver (self).
605
- *
606
- * **NOTE**: Does nothing if the sound is not currently playing or paused.
607
- *
608
- */
609
- static VALUE rg_sound_stop( VALUE self )
610
- {
611
- RG_Sound *sound;
612
- Data_Get_Struct(self, RG_Sound, sound);
613
-
614
- int channel = sound->channel;
615
-
616
- /* Make sure the sound actually belongs to the channel */
617
- if( _rg_sound_channel_check(sound) )
618
- {
619
- Mix_HaltChannel( channel );
620
- }
621
-
622
- return self;
623
- }
624
-
625
-
626
- /*
627
- * call-seq:
628
- * stopped? -> true or false
629
- *
630
- * True if the Sound is currently stopped (not playing or paused).
631
- * See also #playing? and #paused?.
632
- *
633
- */
634
- static VALUE rg_sound_stoppedp( VALUE self )
635
- {
636
- RG_Sound *sound;
637
- Data_Get_Struct(self, RG_Sound, sound);
638
-
639
- int channel = sound->channel;
640
-
641
- /* Make sure the sound actually belongs to the channel */
642
- if( _rg_sound_channel_check(sound) )
643
- {
644
- /* Return true if it's not playing. */
645
- if( !Mix_Playing(channel) )
646
- {
647
- return Qtrue;
648
- }
649
- else
650
- {
651
- return Qfalse;
652
- }
653
- }
654
- else
655
- {
656
- /* If it's not on a channel... it can't be playing! */
657
- return Qtrue;
658
- }
659
- }
660
-
661
-
662
- /*
663
- * call-seq:
664
- * fade_out( fade_time ) -> self
665
- *
666
- * Fade out to silence over the given number of seconds. Once the sound
667
- * is silent, it is automatically stopped.
668
- *
669
- * Returns:: The receiver (self).
670
- *
671
- * **NOTE**: If the sound is currently paused, the fade will start,
672
- * but you won't be able to hear it happening unless you #unpause during
673
- * the fade. Does nothing if the sound is currently stopped.
674
- *
675
- */
676
- static VALUE rg_sound_fadeout( VALUE self, VALUE fade_time )
677
- {
678
- RG_Sound *sound;
679
- Data_Get_Struct(self, RG_Sound, sound);
680
-
681
- int channel = sound->channel;
682
- int fade_ms = (int)(1000 * NUM2DBL(fade_time));
683
-
684
- /* Make sure the sound actually belongs to the channel */
685
- if( _rg_sound_channel_check(sound) )
686
- {
687
- Mix_FadeOutChannel( channel, fade_ms );
688
- }
689
-
690
- return self;
691
- }
692
-
693
-
694
- /*
695
- * call-seq:
696
- * fading?( direction=:either ) -> true or false
697
- *
698
- * True if the Sound is currently fading in or out.
699
- * See also #play and #fade_out.
700
- *
701
- * direction:: Check if it is fading :in, :out, or :either.
702
- * (Symbol, required)
703
- *
704
- */
705
- static VALUE rg_sound_fadingp( int argc, VALUE *argv, VALUE self )
706
- {
707
- RG_Sound *sound;
708
- Data_Get_Struct(self, RG_Sound, sound);
709
-
710
- VALUE vdirection;
711
- rb_scan_args(argc, argv, "01", &vdirection);
712
-
713
- int direction;
714
- int channel = sound->channel;
715
-
716
- /* If it's not actually on a channel, return false right away. */
717
- if( !(_rg_sound_channel_check(sound)) )
718
- {
719
- return Qfalse;
720
- }
721
-
722
- if( RTEST(vdirection) )
723
- {
724
- if( make_symbol("in") == vdirection )
725
- {
726
- return ( (Mix_FadingChannel(channel) == MIX_FADING_IN) ? Qtrue : Qfalse );
727
- }
728
-
729
- else if( make_symbol("out") == vdirection )
730
- {
731
- return ( (Mix_FadingChannel(channel) == MIX_FADING_OUT) ? Qtrue : Qfalse );
732
- }
733
-
734
- else if( make_symbol("either") == vdirection )
735
- {
736
- return ( (Mix_FadingChannel(channel) != MIX_NO_FADING) ? Qtrue : Qfalse );
737
- }
738
- }
739
-
740
- /* default */
741
- return ( (Mix_FadingChannel(channel) != MIX_NO_FADING) ? Qtrue : Qfalse );
742
- }
743
-
744
-
745
-
746
- /*
747
- * call-seq:
748
- * volume -> vol
749
- *
750
- * Return the volume level of the sound.
751
- * 0.0 is totally silent, 1.0 is full volume.
752
- *
753
- * **NOTE**: Ignores fading in or out.
754
- *
755
- */
756
- static VALUE rg_sound_getvolume( VALUE self )
757
- {
758
- RG_Sound *sound;
759
- Data_Get_Struct(self, RG_Sound, sound);
760
-
761
- return rb_float_new(sound->volume);
762
- }
763
-
764
-
765
- /*
766
- * call-seq:
767
- * volume = new_vol
768
- *
769
- * Set the new #volume level of the sound.
770
- * 0.0 is totally silent, 1.0 is full volume.
771
- *
772
- * Volume cannot be set while the sound is fading in or out.
773
- * Be sure to check #fading? or rescue from SDLError when
774
- * using this method.
775
- *
776
- * May raise:: SDLError if the sound is fading in or out.
777
- *
778
- */
779
- static VALUE rg_sound_setvolume( VALUE self, VALUE volume )
780
- {
781
- RG_Sound *sound;
782
- Data_Get_Struct(self, RG_Sound, sound);
783
-
784
- /* Change channel volume if Sound is currently assigned to a channel */
785
- if( _rg_sound_channel_check(sound) )
786
- {
787
- /* But only if it's not fading right now. */
788
- if( Mix_FadingChannel(sound->channel) == MIX_NO_FADING )
789
- {
790
- sound->volume = NUM2DBL(volume);
791
- Mix_Volume( sound->channel, (int)(MIX_MAX_VOLUME * sound->volume) );
792
- }
793
- else
794
- {
795
- rb_raise(eSDLError, "cannot set Sound volume while fading");
796
- }
797
- }
798
- else
799
- {
800
- /* Save it for later. */
801
- sound->volume = NUM2DBL(volume);
802
- }
803
-
804
- return volume;
805
- }
806
-
807
-
808
- void Rubygame_Init_Sound()
809
- {
810
- #if 0
811
- mRubygame = rb_define_module("Rubygame");
812
- #endif
813
-
814
- /*
815
- * **IMPORTANT**: Sound is only available if Rubygame was compiled
816
- * with SDL_mixer support!
817
- *
818
- * Sound holds a sound effect, loaded from an audio file (see #load for
819
- * supported formats).
820
- *
821
- * Sound can #play, #pause/#unpause, #stop, adjust #volume,
822
- * and #fade_out (you can fade in by passing an option to #play).
823
- *
824
- * Sound can create duplicates (with #dup or #clone) in a memory-efficient
825
- * way -- the new Sound instance refers back to the same audio data,
826
- * so having 100 duplicates of a sound uses only slightly more memory
827
- * than having the first sound. Duplicates can different volume levels,
828
- * too!
829
- *
830
- * Sound includes the Rubygame::NamedResource mixin module, which
831
- * can perform autoloading of sounds on demand, among other things.
832
- *
833
- */
834
- cSound = rb_define_class_under(mRubygame,"Sound",rb_cObject);
835
-
836
- /* Include the Rubygame::NamedResource mixin module. */
837
- rg_include_named_resource(cSound);
838
-
839
- rb_define_alloc_func( cSound, rg_sound_alloc );
840
-
841
- rb_define_singleton_method( cSound, "new", rg_sound_new, -1 );
842
- rb_define_singleton_method( cSound, "load", rg_sound_load, 1 );
843
-
844
- rb_define_singleton_method( cSound, "autoload", rg_sound_autoload, 1 );
845
-
846
- rb_define_method( cSound, "initialize_copy", rg_sound_initialize_copy, 1 );
847
-
848
- rb_define_method( cSound, "play", rg_sound_play, -1 );
849
- rb_define_method( cSound, "playing?", rg_sound_playingp, 0 );
850
-
851
- rb_define_method( cSound, "pause", rg_sound_pause, 0 );
852
- rb_define_method( cSound, "unpause", rg_sound_unpause, 0 );
853
- rb_define_method( cSound, "paused?", rg_sound_pausedp, 0 );
854
-
855
- rb_define_method( cSound, "stop", rg_sound_stop, 0 );
856
- rb_define_method( cSound, "stopped?", rg_sound_stoppedp, 0 );
857
-
858
- rb_define_method( cSound, "fade_out", rg_sound_fadeout, 1 );
859
- rb_define_method( cSound, "fading?", rg_sound_fadingp, -1 );
860
-
861
- rb_define_method( cSound, "volume", rg_sound_getvolume, 0 );
862
- rb_define_method( cSound, "volume=", rg_sound_setvolume, 1 );
863
- }