ray 0.0.0.pre2 → 0.0.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.
- data/.gitignore +1 -0
- data/.rspec +3 -0
- data/README.md +62 -0
- data/Rakefile +33 -23
- data/VERSION +1 -1
- data/ext/audio.c +473 -0
- data/ext/color.c +4 -4
- data/ext/event.c +25 -3
- data/ext/extconf.rb +35 -22
- data/ext/font.c +287 -0
- data/ext/image.c +682 -33
- data/ext/joystick.c +9 -9
- data/ext/ray.c +166 -55
- data/ext/ray.h +120 -9
- data/ext/ray_osx.m +161 -0
- data/ext/rect.c +31 -4
- data/lib/ray/audio.rb +52 -0
- data/lib/ray/color.rb +16 -0
- data/lib/ray/dsl.rb +1 -3
- data/lib/ray/dsl/event.rb +1 -39
- data/lib/ray/dsl/event_listener.rb +38 -0
- data/lib/ray/dsl/event_runner.rb +3 -1
- data/lib/ray/dsl/event_translator.rb +74 -8
- data/lib/ray/dsl/handler.rb +3 -33
- data/lib/ray/dsl/matcher.rb +129 -23
- data/lib/ray/font.rb +108 -0
- data/lib/ray/font_set.rb +37 -0
- data/lib/ray/game.rb +171 -34
- data/lib/ray/helper.rb +43 -5
- data/lib/ray/image.rb +90 -3
- data/lib/ray/image_set.rb +35 -0
- data/lib/ray/joystick.rb +30 -0
- data/lib/ray/music_set.rb +35 -0
- data/lib/ray/ray.rb +17 -9
- data/lib/ray/rect.rb +51 -0
- data/lib/ray/resource_set.rb +92 -0
- data/lib/ray/scene.rb +220 -51
- data/lib/ray/sound_set.rb +35 -0
- data/lib/ray/sprite.rb +184 -0
- data/psp/ext.c +4 -0
- data/samples/hello_world/hello.rb +35 -0
- data/samples/hello_world/hello_dsl.rb +24 -0
- data/samples/pong/pong.rb +128 -0
- data/samples/sokoban/level_1 +7 -0
- data/samples/sokoban/sokoban.rb +370 -0
- data/spec/ray/audio_spec.rb +146 -0
- data/spec/ray/color_spec.rb +13 -0
- data/spec/ray/event_spec.rb +57 -168
- data/spec/ray/font_spec.rb +93 -0
- data/spec/ray/image_set_spec.rb +48 -0
- data/spec/ray/image_spec.rb +130 -44
- data/spec/ray/joystick_spec.rb +13 -9
- data/spec/ray/matcher_spec.rb +32 -55
- data/spec/ray/ray_spec.rb +33 -31
- data/spec/ray/rect_spec.rb +80 -0
- data/spec/ray/resource_set_spec.rb +105 -0
- data/spec/ray/sprite_spec.rb +163 -0
- data/spec/res/VeraMono.ttf +0 -0
- data/spec/res/aqua2.bmp +0 -0
- data/spec/res/pop.wav +0 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +8 -0
- data/yard_ext.rb +91 -0
- metadata +104 -38
- data/bin/ray +0 -5
- data/bin/ray_irb +0 -4
- data/ext/SDLMain.h +0 -17
- data/ext/SDLMain.m +0 -381
- data/lib/ray/config.rb +0 -84
- data/lib/ray/dsl/converter.rb +0 -65
- data/lib/ray/dsl/listener.rb +0 -30
- data/lib/ray/dsl/type.rb +0 -58
- data/spec/ray/config_spec.rb +0 -90
- data/spec/ray/conversion_spec.rb +0 -43
- data/spec/ray/type_spec.rb +0 -17
- data/spec_runner.rb +0 -27
data/.gitignore
CHANGED
data/.rspec
ADDED
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Hello world!
|
2
|
+
## Subclassing Ray::Game or Ray::Scene
|
3
|
+
require 'ray'
|
4
|
+
|
5
|
+
class HelloScene < Ray::Scene
|
6
|
+
scene_name :hello
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@font = font(path_of("VeraMono.ttf"), 12)
|
10
|
+
end
|
11
|
+
|
12
|
+
def render(win)
|
13
|
+
@font.draw("Hello world!", :on => win, :at => [0, 0])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class HelloWorld < Ray::Game
|
18
|
+
def initialize
|
19
|
+
super("Hello world!")
|
20
|
+
|
21
|
+
HelloScene.bind(self)
|
22
|
+
push_scene :hello
|
23
|
+
end
|
24
|
+
|
25
|
+
def register
|
26
|
+
add_hook :quit, method(:exit!)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
HelloWorld.new.run
|
31
|
+
## DSL
|
32
|
+
require 'ray'
|
33
|
+
|
34
|
+
Ray::Game.new("Hello world!") do
|
35
|
+
register do
|
36
|
+
add_hook :quit, method(:exit!)
|
37
|
+
end
|
38
|
+
|
39
|
+
scene :hello do
|
40
|
+
@font = font(path_of("VeraMono.ttf"), 12)
|
41
|
+
|
42
|
+
render do |win|
|
43
|
+
@font.draw("Hello world", :on => win, :at => [0, 0])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
push_scene :hello
|
48
|
+
end
|
49
|
+
# Installation
|
50
|
+
Run the following command:
|
51
|
+
|
52
|
+
gem install ray
|
53
|
+
|
54
|
+
This requires the SDL to be installed. SDL_TTF, SDL_image, SDL_gfx, and
|
55
|
+
SDL_mixer are also needed for several features, though you can install ray
|
56
|
+
without them.
|
57
|
+
# Features
|
58
|
+
* Hides the event loop where registred blocks or methods are run when something
|
59
|
+
happens.
|
60
|
+
* Provides a cache for resources like images, fonts, sounds, ...
|
61
|
+
* Documented, using YARD. You can check the documentation on
|
62
|
+
[rubydoc.info](http://rubydoc.info/github/Mon-Ouie/ray/master/frames)
|
data/Rakefile
CHANGED
@@ -2,22 +2,9 @@
|
|
2
2
|
begin
|
3
3
|
require 'yard'
|
4
4
|
|
5
|
-
class MatcherHandler < YARD::Handlers::Ruby::Base
|
6
|
-
handles method_call(:describe_matcher)
|
7
|
-
|
8
|
-
def process
|
9
|
-
src = statement.parameters.children.first.source[1..-1]
|
10
|
-
MethodObject.new(Proxy.new(nil, "Ray::Matchers"), src) do |o|
|
11
|
-
o.source = statement.source
|
12
|
-
o.docstring = statement.comments
|
13
|
-
o.visibility = :private
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
5
|
YARD::Rake::YardocTask.new do |t|
|
19
6
|
t.files = ['lib/**/*.rb', 'ext/**/*.c', 'psp/*.c']
|
20
|
-
t.options |= ["--private"]
|
7
|
+
t.options |= ["--private", "-e", "./yard_ext.rb"]
|
21
8
|
end
|
22
9
|
rescue LoadError
|
23
10
|
$stderr.puts("YARD is not installed. Please install it " +
|
@@ -30,7 +17,8 @@ begin
|
|
30
17
|
Jeweler::Tasks.new do |s|
|
31
18
|
s.name = "ray"
|
32
19
|
|
33
|
-
s.summary = ""
|
20
|
+
s.summary = "A library to write games (or to play with) in Ruby"
|
21
|
+
s.description = "Written to play with Ruby"
|
34
22
|
s.homepage = "http://github.com/Mon-Ouie/ray"
|
35
23
|
|
36
24
|
s.email = "mon.ouie@gmail.com"
|
@@ -38,20 +26,39 @@ begin
|
|
38
26
|
|
39
27
|
s.files |= FileList["lib/**/*.rb"]
|
40
28
|
s.files |= FileList["ext/**/*.{c,h,m}"]
|
41
|
-
s.files |= FileList["bin/ray{,_irb}"]
|
42
29
|
|
43
|
-
s.
|
30
|
+
s.has_rdoc = "yard"
|
44
31
|
|
45
|
-
s.
|
32
|
+
s.extensions = ["ext/extconf.rb"]
|
33
|
+
|
34
|
+
s.add_development_dependency "jeweler"
|
35
|
+
s.add_development_dependency "yard"
|
36
|
+
s.add_development_dependency "rspec"
|
37
|
+
s.add_development_dependency "psp_task"
|
46
38
|
end
|
47
39
|
rescue LoadError
|
48
40
|
$stderr.puts("Jeweler is not installed. Please install it " +
|
49
41
|
"with the following command: gem intall jeweler")
|
50
42
|
end
|
51
43
|
|
52
|
-
|
53
|
-
|
54
|
-
|
44
|
+
begin
|
45
|
+
begin
|
46
|
+
require 'spec/rake/spectask'
|
47
|
+
|
48
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
49
|
+
t.spec_files = FileList['spec/**/*_spec\.rb']
|
50
|
+
t.fail_on_error = false
|
51
|
+
end
|
52
|
+
rescue LoadError
|
53
|
+
require 'rspec/core/rake_task'
|
54
|
+
|
55
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
56
|
+
t.fail_on_error = false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
rescue LoadError
|
60
|
+
$stderr.puts("RSpec is not installed. Please install it " +
|
61
|
+
"with the following command: gem install rspec")
|
55
62
|
end
|
56
63
|
|
57
64
|
namespace :ext do
|
@@ -95,12 +102,15 @@ begin
|
|
95
102
|
syck/token.c syck/emitter.c syck/handler.c syck/node.c syck/syck.c
|
96
103
|
syck/yaml2byte.c).map { |i| "psp/#{i}" }
|
97
104
|
|
98
|
-
static_libs = ["-
|
105
|
+
static_libs = ["-lSDL_ttf", "-lSDL_mixer", "-lSDL_gfx", "-lSDL_image",
|
106
|
+
"-lSDL", "-lGL", "-lpspvfpu", "-lfreetype", "-lvorbisfile",
|
107
|
+
"-lvorbis", "-lmikmod", "-logg",
|
99
108
|
"-lpspgu", "-lpspaudio", "-lpsprtc", "-lpsphprm", "-lpspwlan",
|
100
109
|
"-lruby", "-lpng", "-ljpeg", "-lz","-lm", "-lc"]
|
101
110
|
|
102
111
|
flags = ["-Wall", "-Wno-unused-parameter", "-D_PSP_ -DHAVE_STRUCT_TIMESPEC",
|
103
|
-
"-
|
112
|
+
"-DHAVE_SDL_SDL_IMAGE_H", "-G0", "-DHAVE_SDL_SDL_ROTOZOOM_H",
|
113
|
+
"-DHAVE_SDL_SDL_TTF_H", "-DHAVE_SDL_SDL_MIXER_H", "-DUSE_RWOPS"]
|
104
114
|
|
105
115
|
begin
|
106
116
|
PSPTask.new do |t|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.1
|
data/ext/audio.c
ADDED
@@ -0,0 +1,473 @@
|
|
1
|
+
#include "ray.h"
|
2
|
+
|
3
|
+
#ifdef HAVE_SDL_MIXER
|
4
|
+
|
5
|
+
VALUE ray_mAudio = Qnil;
|
6
|
+
VALUE ray_cSound = Qnil;
|
7
|
+
VALUE ray_cMusic = Qnil;
|
8
|
+
|
9
|
+
/* @return [Integer] The audio frequency */
|
10
|
+
VALUE ray_audio_frequency() {
|
11
|
+
int freq = 0, channels = 0;
|
12
|
+
uint16_t format = 0;
|
13
|
+
Mix_QuerySpec(&freq, &format, &channels);
|
14
|
+
|
15
|
+
return INT2FIX(freq);
|
16
|
+
}
|
17
|
+
|
18
|
+
/* @return [Integer] The audio format */
|
19
|
+
VALUE ray_audio_format() {
|
20
|
+
int freq = 0, channels = 0;
|
21
|
+
uint16_t format = 0;
|
22
|
+
Mix_QuerySpec(&freq, &format, &channels);
|
23
|
+
|
24
|
+
return INT2FIX(format);
|
25
|
+
}
|
26
|
+
|
27
|
+
/* @return [true, false] true if mono is used */
|
28
|
+
VALUE ray_audio_mono() {
|
29
|
+
int freq = 0, channels = 0;
|
30
|
+
uint16_t format = 0;
|
31
|
+
Mix_QuerySpec(&freq, &format, &channels);
|
32
|
+
|
33
|
+
return channels == 1 ? Qtrue : Qfalse;
|
34
|
+
}
|
35
|
+
|
36
|
+
/* @return [true, false] true if stereo is used */
|
37
|
+
VALUE ray_audio_stereo() {
|
38
|
+
int freq = 0, channels = 0;
|
39
|
+
uint16_t format = 0;
|
40
|
+
Mix_QuerySpec(&freq, &format, &channels);
|
41
|
+
|
42
|
+
return channels == 1 ? Qfalse : Qtrue;
|
43
|
+
}
|
44
|
+
|
45
|
+
/*
|
46
|
+
@return [Float] The volume for the song which is currently being played.
|
47
|
+
0 is the minimum volume, whereas 100 is the maximum.
|
48
|
+
*/
|
49
|
+
VALUE ray_audio_volume(VALUE self) {
|
50
|
+
int volume = Mix_VolumeMusic(-1);
|
51
|
+
return rb_float_new((volume / 128.0f) * 100.0f);
|
52
|
+
}
|
53
|
+
|
54
|
+
/* Sets the volume of the song which is currently being played */
|
55
|
+
VALUE ray_audio_set_volume(VALUE self, VALUE value) {
|
56
|
+
float volume = (float)NUM2DBL(value);
|
57
|
+
Mix_VolumeMusic((int)((volume / 100.0f) * 128.0f));
|
58
|
+
|
59
|
+
return value;
|
60
|
+
}
|
61
|
+
|
62
|
+
/*
|
63
|
+
@overload playing?(channel = nil)
|
64
|
+
@return [true, false] If channel is set, true if something is playing on
|
65
|
+
that channel. If it isn't, true if a music is currently being played.
|
66
|
+
*/
|
67
|
+
VALUE ray_audio_playing(int argc, VALUE *argv, VALUE self) {
|
68
|
+
VALUE channel = Qnil;
|
69
|
+
rb_scan_args(argc, argv, "01", &channel);
|
70
|
+
|
71
|
+
if (NIL_P(channel))
|
72
|
+
return Mix_PlayingMusic() ? Qtrue : Qfalse;
|
73
|
+
return Mix_Playing(NUM2INT(channel)) ? Qtrue: Qfalse;
|
74
|
+
}
|
75
|
+
|
76
|
+
/*
|
77
|
+
@overload stop(channel = nil)
|
78
|
+
If channel is set, stops playback on a channel. Stops playing
|
79
|
+
the current music otherwise.
|
80
|
+
*/
|
81
|
+
VALUE ray_audio_stop(int argc, VALUE *argv, VALUE self) {
|
82
|
+
VALUE channel;
|
83
|
+
rb_scan_args(argc, argv, "01", &channel);
|
84
|
+
|
85
|
+
if (!NIL_P(channel)) {
|
86
|
+
Mix_HaltChannel(NUM2INT(channel));
|
87
|
+
return channel;
|
88
|
+
}
|
89
|
+
|
90
|
+
Mix_HaltMusic();
|
91
|
+
return Qnil;
|
92
|
+
}
|
93
|
+
|
94
|
+
/*
|
95
|
+
@overload pause(channel = nil)
|
96
|
+
If channel is set, pauses a channel. Pauses the current music otherwise.
|
97
|
+
*/
|
98
|
+
VALUE ray_audio_pause(int argc, VALUE *argv, VALUE self) {
|
99
|
+
VALUE channel;
|
100
|
+
rb_scan_args(argc, argv, "01", &channel);
|
101
|
+
|
102
|
+
if (!NIL_P(channel)) {
|
103
|
+
Mix_Pause(NUM2INT(channel));
|
104
|
+
return channel;
|
105
|
+
}
|
106
|
+
|
107
|
+
Mix_PauseMusic();
|
108
|
+
return Qnil;
|
109
|
+
}
|
110
|
+
|
111
|
+
/*
|
112
|
+
@overload resume(channel = nil)
|
113
|
+
If channel is set, resumes a paused channel from pause. Resumes the music
|
114
|
+
otherwise.
|
115
|
+
*/
|
116
|
+
VALUE ray_audio_resume(int argc, VALUE *argv, VALUE self) {
|
117
|
+
VALUE channel;
|
118
|
+
rb_scan_args(argc, argv, "01", &channel);
|
119
|
+
|
120
|
+
if (!NIL_P(channel)) {
|
121
|
+
Mix_Resume(NUM2INT(channel));
|
122
|
+
return channel;
|
123
|
+
}
|
124
|
+
|
125
|
+
Mix_ResumeMusic();
|
126
|
+
return Qnil;
|
127
|
+
}
|
128
|
+
|
129
|
+
/*
|
130
|
+
@overload paused?(channel = nil)
|
131
|
+
@return [true, false] True if the channel is paused. If channel isn't set,
|
132
|
+
returns true if the current music isn't paused.
|
133
|
+
*/
|
134
|
+
VALUE ray_audio_paused(int argc, VALUE *argv, VALUE self) {
|
135
|
+
VALUE channel;
|
136
|
+
rb_scan_args(argc, argv, "01", &channel);
|
137
|
+
|
138
|
+
if (!NIL_P(channel))
|
139
|
+
return Mix_Paused(NUM2INT(channel)) ? Qtrue : Qfalse;
|
140
|
+
return Mix_PausedMusic() ? Qtrue : Qfalse;
|
141
|
+
}
|
142
|
+
|
143
|
+
/*
|
144
|
+
@overload music_pos=(val)
|
145
|
+
Sets the position in the current music. May not be implemented for some
|
146
|
+
formats.
|
147
|
+
*/
|
148
|
+
VALUE ray_audio_set_music_pos(VALUE self, VALUE val) {
|
149
|
+
Mix_SetMusicPosition(NUM2DBL(val));
|
150
|
+
return val;
|
151
|
+
}
|
152
|
+
|
153
|
+
Mix_Chunk *ray_rb2chunk(VALUE object) {
|
154
|
+
if (!RAY_IS_A(object, ray_cSound)) {
|
155
|
+
rb_raise(rb_eTypeError, "Can't convert %s into Ray::Sound",
|
156
|
+
RAY_OBJ_CLASSNAME(object));
|
157
|
+
}
|
158
|
+
|
159
|
+
ray_sound *ptr = NULL;
|
160
|
+
Data_Get_Struct(object, ray_sound, ptr);
|
161
|
+
|
162
|
+
return ptr->sound;
|
163
|
+
}
|
164
|
+
|
165
|
+
void ray_free_sound(ray_sound *sound) {
|
166
|
+
if (sound->sound) Mix_FreeChunk(sound->sound);
|
167
|
+
free(sound);
|
168
|
+
}
|
169
|
+
|
170
|
+
VALUE ray_alloc_sound(VALUE self) {
|
171
|
+
ray_sound *ptr = malloc(sizeof(ray_sound));
|
172
|
+
ptr->sound = NULL;
|
173
|
+
|
174
|
+
VALUE ret = Data_Wrap_Struct(self, 0, ray_free_sound, ptr);
|
175
|
+
|
176
|
+
return ret;
|
177
|
+
}
|
178
|
+
|
179
|
+
void ray_init_sound_with_filename(VALUE self, VALUE filename) {
|
180
|
+
char *c_filename = StringValuePtr(filename);
|
181
|
+
ray_sound *sound = NULL;
|
182
|
+
Data_Get_Struct(self, ray_sound, sound);
|
183
|
+
|
184
|
+
sound->sound = Mix_LoadWAV(c_filename);
|
185
|
+
if (!sound->sound) {
|
186
|
+
rb_raise(rb_eRuntimeError, "Could not load sound (%s)",
|
187
|
+
Mix_GetError());
|
188
|
+
}
|
189
|
+
}
|
190
|
+
|
191
|
+
void ray_init_sound_with_io(VALUE self, VALUE io) {
|
192
|
+
ray_sound *sound = NULL;
|
193
|
+
Data_Get_Struct(self, ray_sound, sound);
|
194
|
+
|
195
|
+
VALUE string = rb_funcall2(io, RAY_METH("read"), 0, NULL);
|
196
|
+
char *content = StringValuePtr(string);
|
197
|
+
SDL_RWops *data = SDL_RWFromMem(content, (int)RSTRING_LEN(string));
|
198
|
+
|
199
|
+
if (!data) {
|
200
|
+
rb_raise(rb_eRuntimeError, "Could not create music data (%s)",
|
201
|
+
SDL_GetError());
|
202
|
+
}
|
203
|
+
|
204
|
+
sound->sound = Mix_LoadWAV_RW(data, 1);
|
205
|
+
if (!sound->sound) {
|
206
|
+
rb_raise(rb_eRuntimeError, "Could not load sound (%s)",
|
207
|
+
Mix_GetError());
|
208
|
+
}
|
209
|
+
}
|
210
|
+
|
211
|
+
/*
|
212
|
+
Creates a new sound from an IO object or a filename.
|
213
|
+
*/
|
214
|
+
VALUE ray_init_sound(VALUE self, VALUE arg) {
|
215
|
+
if (rb_respond_to(arg, RAY_METH("to_str")))
|
216
|
+
ray_init_sound_with_filename(self, rb_String(arg));
|
217
|
+
else if (rb_respond_to(arg, RAY_METH("read")))
|
218
|
+
ray_init_sound_with_io(self, arg);
|
219
|
+
else {
|
220
|
+
rb_raise(rb_eTypeError, "Can't convert %s into String",
|
221
|
+
RAY_OBJ_CLASSNAME(arg));
|
222
|
+
}
|
223
|
+
|
224
|
+
return Qnil;
|
225
|
+
}
|
226
|
+
|
227
|
+
/*
|
228
|
+
@overload play(channel = 0, times = 1)
|
229
|
+
Plays a sound on the given channel a given number of times.
|
230
|
+
@param [Integer, :forever] times How many times the sound should be played.
|
231
|
+
Can also be :forever or 0 to play it forever.
|
232
|
+
*/
|
233
|
+
VALUE ray_sound_play(int argc, VALUE *argv, VALUE self) {
|
234
|
+
VALUE channel, times;
|
235
|
+
rb_scan_args(argc, argv, "02", &channel, ×);
|
236
|
+
|
237
|
+
if (NIL_P(channel)) channel = INT2FIX(0);
|
238
|
+
if (NIL_P(times)) times = INT2FIX(1);
|
239
|
+
|
240
|
+
int c_channel = NUM2INT(channel), c_times = 0;
|
241
|
+
if (times == RAY_SYM("forever"))
|
242
|
+
c_times = 0;
|
243
|
+
else
|
244
|
+
c_times = NUM2INT(times);
|
245
|
+
|
246
|
+
Mix_Chunk *chunk = ray_rb2chunk(self);
|
247
|
+
Mix_PlayChannel(c_channel, chunk, c_times - 1);
|
248
|
+
|
249
|
+
return self;
|
250
|
+
}
|
251
|
+
|
252
|
+
/*
|
253
|
+
@overload fade(duration, channel = 0, times = 1)
|
254
|
+
Same as play, but fades for a given number of a seconds.
|
255
|
+
@param [Float] duration Duration of the fade, in seconds.
|
256
|
+
@see Ray::Sound#play
|
257
|
+
*/
|
258
|
+
VALUE ray_sound_fade(int argc, VALUE *argv, VALUE self) {
|
259
|
+
VALUE duration, channel, times;
|
260
|
+
rb_scan_args(argc, argv, "12", &duration, &channel, ×);
|
261
|
+
|
262
|
+
if (NIL_P(channel)) channel = INT2FIX(0);
|
263
|
+
if (NIL_P(times)) times = INT2FIX(1);
|
264
|
+
|
265
|
+
int c_channel = NUM2INT(channel), c_times = 0;
|
266
|
+
if (times == RAY_SYM("forever"))
|
267
|
+
c_times = 0;
|
268
|
+
else
|
269
|
+
c_times = NUM2INT(times);
|
270
|
+
|
271
|
+
Mix_Chunk *chunk = ray_rb2chunk(self);
|
272
|
+
Mix_FadeInChannel(c_channel, chunk, c_times - 1,
|
273
|
+
(int)(NUM2DBL(duration) * 1000));
|
274
|
+
|
275
|
+
return self;
|
276
|
+
}
|
277
|
+
|
278
|
+
/* @return [Float] Volume of the sound, between 0 and 100. */
|
279
|
+
VALUE ray_sound_volume(VALUE self) {
|
280
|
+
Mix_Chunk *chunk = ray_rb2chunk(self);
|
281
|
+
int volume = Mix_VolumeChunk(chunk, -1);
|
282
|
+
|
283
|
+
return rb_float_new((volume / 128.0f) * 100.0f);
|
284
|
+
}
|
285
|
+
|
286
|
+
/* Sets the volume of the sound. */
|
287
|
+
VALUE ray_sound_set_volume(VALUE self, VALUE value) {
|
288
|
+
Mix_Chunk *chunk = ray_rb2chunk(self);
|
289
|
+
float volume = (float)NUM2DBL(value);
|
290
|
+
Mix_VolumeChunk(chunk, (int)((volume / 100.0f) * 128.0f));
|
291
|
+
|
292
|
+
return value;
|
293
|
+
}
|
294
|
+
|
295
|
+
Mix_Music *ray_rb2music(VALUE object) {
|
296
|
+
if (!RAY_IS_A(object, ray_cMusic)) {
|
297
|
+
rb_raise(rb_eTypeError, "Can't convert %s into Ray::Music",
|
298
|
+
RAY_OBJ_CLASSNAME(object));
|
299
|
+
}
|
300
|
+
|
301
|
+
ray_music *ptr = NULL;
|
302
|
+
Data_Get_Struct(object, ray_music, ptr);
|
303
|
+
|
304
|
+
return ptr->music;
|
305
|
+
}
|
306
|
+
|
307
|
+
void ray_free_music(ray_music *music) {
|
308
|
+
if (music->music) Mix_FreeMusic(music->music);
|
309
|
+
free(music);
|
310
|
+
}
|
311
|
+
|
312
|
+
VALUE ray_alloc_music(VALUE self) {
|
313
|
+
ray_music *ptr = malloc(sizeof(ray_music));
|
314
|
+
ptr->music = NULL;
|
315
|
+
|
316
|
+
VALUE ret = Data_Wrap_Struct(self, 0, ray_free_music, ptr);
|
317
|
+
|
318
|
+
return ret;
|
319
|
+
}
|
320
|
+
|
321
|
+
void ray_init_music_with_filename(VALUE self, VALUE filename) {
|
322
|
+
char *c_filename = StringValuePtr(filename);
|
323
|
+
ray_music *music = NULL;
|
324
|
+
Data_Get_Struct(self, ray_music, music);
|
325
|
+
|
326
|
+
music->music = Mix_LoadMUS(c_filename);
|
327
|
+
if (!music->music) {
|
328
|
+
rb_raise(rb_eRuntimeError, "Could not load music (%s)",
|
329
|
+
Mix_GetError());
|
330
|
+
}
|
331
|
+
}
|
332
|
+
|
333
|
+
void ray_init_music_with_io(VALUE self, VALUE io) {
|
334
|
+
ray_music *music = NULL;
|
335
|
+
Data_Get_Struct(self, ray_music, music);
|
336
|
+
|
337
|
+
VALUE string = rb_funcall2(io, RAY_METH("read"), 0, NULL);
|
338
|
+
char *content = StringValuePtr(string);
|
339
|
+
SDL_RWops *data = SDL_RWFromMem(content, (int)RSTRING_LEN(string));
|
340
|
+
|
341
|
+
if (!data) {
|
342
|
+
rb_raise(rb_eRuntimeError, "Could not create music data (%s)",
|
343
|
+
SDL_GetError());
|
344
|
+
}
|
345
|
+
|
346
|
+
music->music = Mix_LoadMUS_RW(data);
|
347
|
+
if (!music->music) {
|
348
|
+
rb_raise(rb_eRuntimeError, "Could not load music (%s)",
|
349
|
+
Mix_GetError());
|
350
|
+
}
|
351
|
+
|
352
|
+
SDL_FreeRW(data);
|
353
|
+
}
|
354
|
+
|
355
|
+
/*
|
356
|
+
Creates a new music from an IO object or a filename.
|
357
|
+
*/
|
358
|
+
VALUE ray_init_music(VALUE self, VALUE arg) {
|
359
|
+
if (rb_respond_to(arg, RAY_METH("to_str")))
|
360
|
+
ray_init_music_with_filename(self, rb_String(arg));
|
361
|
+
else if (rb_respond_to(arg, RAY_METH("read")))
|
362
|
+
ray_init_music_with_io(self, arg);
|
363
|
+
else {
|
364
|
+
rb_raise(rb_eTypeError, "Can't convert %s into String",
|
365
|
+
RAY_OBJ_CLASSNAME(arg));
|
366
|
+
}
|
367
|
+
|
368
|
+
return Qnil;
|
369
|
+
}
|
370
|
+
|
371
|
+
/* @return [Integer] The type of the music */
|
372
|
+
VALUE ray_music_type(VALUE self) {
|
373
|
+
Mix_Music *music = ray_rb2music(self);
|
374
|
+
Mix_MusicType ret = Mix_GetMusicType(music);
|
375
|
+
|
376
|
+
return INT2FIX(ret);
|
377
|
+
}
|
378
|
+
|
379
|
+
/*
|
380
|
+
@overload play(times = 1)
|
381
|
+
Plays the music a given number of times.
|
382
|
+
@param [Integer, :forever] times How many times the music should be played.
|
383
|
+
Can also be :forever or 0 to play it forever.
|
384
|
+
*/
|
385
|
+
VALUE ray_music_play(int argc, VALUE *argv, VALUE self) {
|
386
|
+
VALUE times;
|
387
|
+
rb_scan_args(argc, argv, "01", ×);
|
388
|
+
|
389
|
+
if (NIL_P(times)) times = INT2FIX(1);
|
390
|
+
|
391
|
+
int c_times = 0;
|
392
|
+
if (times == RAY_SYM("forever"))
|
393
|
+
c_times = 0;
|
394
|
+
else
|
395
|
+
c_times = NUM2INT(times);
|
396
|
+
|
397
|
+
Mix_Music *music = ray_rb2music(self);
|
398
|
+
Mix_PlayMusic(music, c_times);
|
399
|
+
|
400
|
+
return self;
|
401
|
+
}
|
402
|
+
|
403
|
+
/*
|
404
|
+
Document-class: Ray::Music
|
405
|
+
|
406
|
+
Class used to play music. Notice only one music can be played at the
|
407
|
+
same time.
|
408
|
+
*/
|
409
|
+
|
410
|
+
/*
|
411
|
+
Document-class: Ray::Sound
|
412
|
+
|
413
|
+
Class used to represent short sounds. You can play one sound per channel.
|
414
|
+
*/
|
415
|
+
|
416
|
+
void Init_ray_audio() {
|
417
|
+
ray_mAudio = rb_define_module_under(ray_mRay, "Audio");
|
418
|
+
|
419
|
+
rb_define_const(ray_mAudio, "FORMAT_U8", INT2FIX(AUDIO_U8));
|
420
|
+
rb_define_const(ray_mAudio, "FORMAT_S8", INT2FIX(AUDIO_S8));
|
421
|
+
rb_define_const(ray_mAudio, "FORMAT_U16LSB", INT2FIX(AUDIO_U16LSB));
|
422
|
+
rb_define_const(ray_mAudio, "FORMAT_S16LSB", INT2FIX(AUDIO_S16LSB));
|
423
|
+
rb_define_const(ray_mAudio, "FORMAT_U16MSB", INT2FIX(AUDIO_U16MSB));
|
424
|
+
rb_define_const(ray_mAudio, "FORMAT_S16MSB", INT2FIX(AUDIO_S16MSB));
|
425
|
+
rb_define_const(ray_mAudio, "FORMAT_U16", INT2FIX(AUDIO_U16));
|
426
|
+
rb_define_const(ray_mAudio, "FORMAT_S16", INT2FIX(AUDIO_S16));
|
427
|
+
rb_define_const(ray_mAudio, "FORMAT_U16SYS", INT2FIX(AUDIO_U16SYS));
|
428
|
+
rb_define_const(ray_mAudio, "FORMAT_S16SYS", INT2FIX(AUDIO_S16SYS));
|
429
|
+
|
430
|
+
rb_define_module_function(ray_mAudio, "frequency", ray_audio_frequency, 0);
|
431
|
+
rb_define_module_function(ray_mAudio, "format", ray_audio_format, 0);
|
432
|
+
rb_define_module_function(ray_mAudio, "mono?", ray_audio_mono, 0);
|
433
|
+
rb_define_module_function(ray_mAudio, "stereo?", ray_audio_stereo, 0);
|
434
|
+
|
435
|
+
rb_define_module_function(ray_mAudio, "volume", ray_audio_volume, 0);
|
436
|
+
rb_define_module_function(ray_mAudio, "volume=", ray_audio_set_volume, 1);
|
437
|
+
|
438
|
+
rb_define_module_function(ray_mAudio, "stop", ray_audio_stop, -1);
|
439
|
+
rb_define_module_function(ray_mAudio, "pause", ray_audio_pause, -1);
|
440
|
+
rb_define_module_function(ray_mAudio, "resume", ray_audio_resume, -1);
|
441
|
+
rb_define_module_function(ray_mAudio, "paused?", ray_audio_paused, -1);
|
442
|
+
rb_define_module_function(ray_mAudio, "playing?", ray_audio_playing, -1);
|
443
|
+
|
444
|
+
rb_define_module_function(ray_mAudio, "music_pos=", ray_audio_set_music_pos, 1);
|
445
|
+
|
446
|
+
ray_cSound = rb_define_class_under(ray_mRay, "Sound", rb_cObject);
|
447
|
+
rb_define_alloc_func(ray_cSound, ray_alloc_sound);
|
448
|
+
rb_define_method(ray_cSound, "initialize", ray_init_sound, 1);
|
449
|
+
rb_define_method(ray_cSound, "play", ray_sound_play, -1);
|
450
|
+
rb_define_method(ray_cSound, "fade", ray_sound_fade, -1);
|
451
|
+
rb_define_method(ray_cSound, "volume", ray_sound_volume, 0);
|
452
|
+
rb_define_method(ray_cSound, "volume=", ray_sound_set_volume, 1);
|
453
|
+
|
454
|
+
ray_cMusic = rb_define_class_under(ray_mRay, "Music", rb_cObject);
|
455
|
+
rb_define_alloc_func(ray_cMusic, ray_alloc_music);
|
456
|
+
rb_define_method(ray_cMusic, "initialize", ray_init_music, 1);
|
457
|
+
rb_define_method(ray_cMusic, "type", ray_music_type, 0);
|
458
|
+
rb_define_method(ray_cMusic, "play", ray_music_play, -1);
|
459
|
+
|
460
|
+
rb_define_const(ray_cMusic, "TYPE_NONE", INT2FIX(MUS_NONE));
|
461
|
+
rb_define_const(ray_cMusic, "TYPE_CMD", INT2FIX(MUS_CMD));
|
462
|
+
rb_define_const(ray_cMusic, "TYPE_WAV", INT2FIX(MUS_WAV));
|
463
|
+
rb_define_const(ray_cMusic, "TYPE_MOD", INT2FIX(MUS_MOD));
|
464
|
+
rb_define_const(ray_cMusic, "TYPE_MID", INT2FIX(MUS_MID));
|
465
|
+
rb_define_const(ray_cMusic, "TYPE_OGG", INT2FIX(MUS_OGG));
|
466
|
+
rb_define_const(ray_cMusic, "TYPE_MP3", INT2FIX(MUS_MP3));
|
467
|
+
#ifndef PSP
|
468
|
+
rb_define_const(ray_cMusic, "TYPE_MP3_MAD", INT2FIX(MUS_MP3_MAD));
|
469
|
+
rb_define_const(ray_cMusic, "TYPE_FLAC", INT2FIX(MUS_FLAC));
|
470
|
+
#endif
|
471
|
+
}
|
472
|
+
|
473
|
+
#endif
|