rubygame 2.5.3 → 2.6.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.
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
@@ -0,0 +1,428 @@
1
+ #--
2
+ # Rubygame -- Ruby code and bindings to SDL to facilitate game creation
3
+ # Copyright (C) 2004-2009 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
+
22
+ # *IMPORTANT*: this class only exists if SDL_mixer is available!
23
+ # Your code should check "defined?(Rubygame::Sound) != nil" to see if
24
+ # you can use this class, or be prepared to rescue from NameError.
25
+ #
26
+ # Sound holds a sound effect, loaded from an audio file (see #load for
27
+ # supported formats).
28
+ #
29
+ # Sound can #play, #pause/#unpause, #stop, adjust #volume,
30
+ # and #fade_out (you can fade in by passing an option to #play).
31
+ #
32
+ # Sound can create duplicates (with #dup or #clone) in a memory-efficient
33
+ # way -- the new Sound instance refers back to the same audio data,
34
+ # so having 100 duplicates of a sound uses only slightly more memory
35
+ # than having the first sound. Duplicates can different volume levels,
36
+ # too!
37
+ #
38
+ # Sound includes the Rubygame::NamedResource mixin module, which
39
+ # can perform autoloading of sounds on demand, among other things.
40
+ #
41
+ class Rubygame::Sound
42
+
43
+ include Rubygame::NamedResource
44
+
45
+ class << self
46
+
47
+ # Searches each directory in Sound.autoload_dirs for a file with
48
+ # the given filename. If it finds that file, loads it and returns
49
+ # a Sound instance. If it doesn't find the file, returns nil.
50
+ #
51
+ # See Rubygame::NamedResource for more information about this
52
+ # functionality.
53
+ #
54
+ def autoload( filename )
55
+ path = find_file( filename )
56
+
57
+ if( path )
58
+ return load( path )
59
+ else
60
+ return nil
61
+ end
62
+ end
63
+
64
+
65
+ # Load the given audio file.
66
+ # Supported file formats are WAVE, MOD, MIDI, OGG, and MP3.
67
+ #
68
+ # filename:: Full or relative path to the file. (String, required)
69
+ #
70
+ # Returns:: The new Sound instance. (Sound)
71
+ # May raise:: SDLError, if the sound file could not be loaded.
72
+ #
73
+ def load( filename )
74
+ Rubygame.open_audio
75
+
76
+ sound = SDL::Mixer.LoadWAV( filename )
77
+
78
+ if( sound.pointer.null? )
79
+ raise( Rubygame::SDLError, "Could not load Sound file '%s': %s"%
80
+ [filename, SDL.GetError()] )
81
+ end
82
+
83
+ return new( sound )
84
+ end
85
+
86
+ end
87
+
88
+
89
+ # call-seq:
90
+ # new
91
+ #
92
+ # **NOTE**: Don't use this method. Use Sound.load.
93
+ #
94
+ # Raises NotImplementedError.
95
+ #
96
+ def initialize( sound=nil )
97
+ if( sound.instance_of? SDL::Mixer::Chunk )
98
+ @struct = sound
99
+ @volume = 1
100
+ @channel = -1
101
+ else
102
+ raise( NotImplementedError, "Sound.new is not implemented. "+
103
+ "Use Sound.load to load a sound file." )
104
+ end
105
+ end
106
+
107
+
108
+ attr_reader :struct # :nodoc:
109
+ protected :struct
110
+
111
+
112
+ # call-seq:
113
+ # clone( other ) -> sound
114
+ # dup( other ) -> sound
115
+ #
116
+ # Create a copy of the given Sound instance. More efficient than
117
+ # using #load to load the sound file again.
118
+ #
119
+ # other:: An existing Sound instance. (Sound, required)
120
+ #
121
+ # Returns:: The new Sound instance. (Sound)
122
+ #
123
+ # **NOTE**: #clone and #dup do slightly different things; #clone
124
+ # will copy the 'frozen' state of the object, while #dup will create
125
+ # a fresh, un-frozen object.
126
+ #
127
+ def initialize_copy( other )
128
+ @struct = other.struct
129
+ @volume = other.volume
130
+ @channel = -1
131
+ end
132
+
133
+
134
+
135
+ # call-seq:
136
+ # play( options={:fade_in => 0, :repeats => 0, :stop_after => nil} )
137
+ #
138
+ # Play the Sound, optionally fading in, repeating a certain number
139
+ # of times (or forever), and/or stopping automatically after a certain time.
140
+ #
141
+ # See also #pause and #stop.
142
+ #
143
+ # options:: Hash of options, listed below. (Hash, required)
144
+ #
145
+ # :fade_in:: Fade in from silence over the given number of
146
+ # seconds. Default: 0. (Numeric, optional)
147
+ # :repeats:: Repeat the sound the given number of times, or
148
+ # forever (or until stopped) if -1. Default: 0.
149
+ # (Integer, optional)
150
+ # :stop_after:: Automatically stop playing after playing for the given
151
+ # number of seconds. Use nil to disable this behavior.
152
+ # (Numeric or nil, optional)
153
+ #
154
+ #
155
+ # Returns:: The receiver (self).
156
+ # May raise:: SDLError, if the audio device could not be opened, or
157
+ # if the sound file could not be played.
158
+ #
159
+ #
160
+ # **NOTE**: If the sound is already playing (or paused), it will be stopped
161
+ # and played again from the beginning.
162
+ #
163
+ # Example:
164
+ # # Fade in over 2 seconds, play 4 times (1 + 3 repeats),
165
+ # # but stop playing after 5 seconds.
166
+ # sound.play( :fade_in => 2, :repeats => 3, :stop_after => 5 );
167
+ #
168
+ def play( options={} )
169
+
170
+ fade_in = (options[:fade_in] or 0)
171
+ repeats = (options[:repeats] or 0)
172
+ stop_after = (options[:stop_after] or nil)
173
+
174
+
175
+ fade_in =
176
+ if( fade_in < 0 )
177
+ raise ArgumentError, ":fade_in cannot be negative (got %.2f)"%fade_in
178
+ elsif( fade_in < 0.05 )
179
+ # Work-around for a bug with SDL_mixer not working with small
180
+ # non-zero fade-ins
181
+ 0
182
+ else
183
+ (fade_in * 1000).to_i
184
+ end
185
+
186
+
187
+ repeats =
188
+ if( repeats < -1 )
189
+ raise( ArgumentError,
190
+ ":repeats cannot be negative, except -1 (got #{repeats})" )
191
+ else
192
+ repeats
193
+ end
194
+
195
+
196
+ stop_after =
197
+ if( stop_after.nil? )
198
+ -1
199
+ elsif( stop_after < 0 )
200
+ raise( ArgumentError,
201
+ ":stop_after cannot be negative, (got %.2f)"%stop_after )
202
+ else
203
+ (stop_after * 1000).to_i
204
+ end
205
+
206
+
207
+
208
+ Rubygame.open_audio
209
+
210
+
211
+ # If it's already playing on a channel, stop it first.
212
+ if channel_active?
213
+ SDL::Mixer.HaltChannel( @channel )
214
+ end
215
+
216
+
217
+ # Find first available channel
218
+ @channel = SDL::Mixer.GroupAvailable(-1)
219
+
220
+
221
+ if @channel == -1
222
+ # No channels were available, so make one more than there are now.
223
+ # (Mix_AllocateChannels(-1) returns the current number of channels)
224
+ SDL::Mixer.AllocateChannels( SDL::Mixer.AllocateChannels(-1) + 1 )
225
+
226
+ # Try again
227
+ @channel = SDL::Mixer.GroupAvailable(-1)
228
+ end
229
+
230
+
231
+ # Set sound channel volume before we play
232
+ SDL::Mixer.Volume( @channel, (SDL::Mixer::MAX_VOLUME * @volume).to_i )
233
+
234
+
235
+ result =
236
+ if( fade_in <= 0 )
237
+ # Play sound without fading in
238
+ SDL::Mixer.PlayChannelTimed( @channel, @struct, repeats, stop_after )
239
+ else
240
+ # Play sound with fading in
241
+ SDL::Mixer.FadeInChannelTimed( @channel, @struct,
242
+ repeats, fade_in, stop_after )
243
+ end
244
+
245
+
246
+ if( result == -1 )
247
+ raise Rubygame::SDLError, "Could not play Sound: #{SDL.GetError()}"
248
+ end
249
+
250
+
251
+ return self
252
+
253
+ end
254
+
255
+
256
+ # True if the Sound is currently playing (not paused and not stopped).
257
+ # See also #paused? and #stopped?.
258
+ #
259
+ def playing?
260
+ channel_active? and
261
+ SDL::Mixer.Playing(@channel) == 1 and
262
+ SDL::Mixer.Paused(@channel) == 0
263
+ end
264
+
265
+
266
+
267
+ # Pause the Sound. Unlike #stop, it can be unpaused later to resume
268
+ # from where it was paused. See also #unpause and #paused?.
269
+ #
270
+ # Returns:: The receiver (self).
271
+ #
272
+ # **NOTE**: Does nothing if the sound is not currently playing.
273
+ #
274
+ def pause
275
+ if channel_active?
276
+ SDL::Mixer.Pause( @channel )
277
+ end
278
+
279
+ return self
280
+ end
281
+
282
+
283
+ # Unpause the Sound, if it is currently paused. Resumes from
284
+ # where it was paused. See also #pause and #paused?.
285
+ #
286
+ # Returns:: The receiver (self).
287
+ #
288
+ # **NOTE**: Does nothing if the sound is not currently paused.
289
+ #
290
+ def unpause
291
+ if channel_active?
292
+ SDL::Mixer.Resume( @channel )
293
+ end
294
+
295
+ return self
296
+ end
297
+
298
+
299
+ # True if the Sound is currently paused (not playing and not stopped).
300
+ # See also #playing? and #stopped?.
301
+ #
302
+ def paused?
303
+ channel_active? and
304
+ SDL::Mixer.Playing( @channel ) == 1 and
305
+ SDL::Mixer.Paused( @channel ) == 1
306
+ end
307
+
308
+
309
+
310
+ # Stop the Sound. Unlike #pause, the sound must be played again from
311
+ # the beginning, it cannot be resumed from it was stopped.
312
+ #
313
+ # Returns:: The receiver (self).
314
+ #
315
+ # **NOTE**: Does nothing if the sound is not currently playing or paused.
316
+ #
317
+ def stop
318
+ if channel_active?
319
+ SDL::Mixer.HaltChannel( @channel )
320
+ end
321
+
322
+ return self
323
+ end
324
+
325
+
326
+ # True if the Sound is currently stopped (not playing and not paused).
327
+ # See also #playing? and #paused?.
328
+ #
329
+ def stopped?
330
+ (not channel_active?) or (SDL::Mixer.Playing(@channel) == 0)
331
+ end
332
+
333
+
334
+
335
+ # Fade out to silence over the given number of seconds. Once the sound
336
+ # is silent, it is automatically stopped.
337
+ #
338
+ # Returns:: The receiver (self).
339
+ #
340
+ # **NOTE**: If the sound is currently paused, the fade will start,
341
+ # but you won't be able to hear it happening unless you #unpause during
342
+ # the fade.
343
+ #
344
+ # Does nothing if the sound is currently stopped.
345
+ #
346
+ def fade_out( fade_time )
347
+ if( fade_time < 0 )
348
+ raise ArgumentError, "fade time cannot be negative (got %.2f)"%fade_time
349
+ end
350
+
351
+ if channel_active?
352
+ SDL::Mixer.FadeOutChannel( @channel, (fade_time * 1000).to_i )
353
+ end
354
+
355
+ return self
356
+ end
357
+
358
+
359
+ # True if the Sound is currently fading in or out.
360
+ # See also #play and #fade_out.
361
+ #
362
+ # direction:: Check if it is fading :in, :out, or :either.
363
+ # (Symbol, required)
364
+ #
365
+ def fading?( direction=:either )
366
+ return false unless channel_active?
367
+
368
+ case direction
369
+ when :in
370
+ SDL::Mixer.FadingChannel( @channel ) == SDL::Mixer::FADING_IN
371
+ when :out
372
+ SDL::Mixer.FadingChannel( @channel ) == SDL::Mixer::FADING_OUT
373
+ else
374
+ SDL::Mixer.FadingChannel( @channel ) != SDL::Mixer::NO_FADING
375
+ end
376
+ end
377
+
378
+
379
+
380
+ # Return the volume level of the sound.
381
+ # 0.0 is totally silent, 1.0 is full volume.
382
+ #
383
+ # **NOTE**: Ignores fading in or out.
384
+ #
385
+ def volume
386
+ @volume
387
+ end
388
+
389
+
390
+ # Set the new #volume level of the sound.
391
+ # 0.0 is totally silent, 1.0 is full volume.
392
+ # The new volume will be clamped to this range if it is too small or
393
+ # too large.
394
+ #
395
+ # Volume cannot be set while the sound is fading in or out.
396
+ # Be sure to check #fading? or rescue from SDLError when
397
+ # using this method.
398
+ #
399
+ # May raise:: SDLError if the sound is fading in or out.
400
+ #
401
+ def volume=( new_vol )
402
+ # Clamp it to valid range
403
+ new_vol = if new_vol < 0.0; 0.0
404
+ elsif new_vol > 1.0; 1.0
405
+ else; new_vol
406
+ end
407
+
408
+ if channel_active?
409
+ if fading?
410
+ raise Rubygame::SDLError, "cannot set Sound volume while fading"
411
+ else
412
+ SDL::Mixer.Volume( @channel, (SDL::Mixer::MAX_VOLUME * new_vol).to_i )
413
+ end
414
+ end
415
+
416
+ @volume = new_vol
417
+ end
418
+
419
+
420
+ private
421
+
422
+
423
+ def channel_active?
424
+ (@channel != -1) and
425
+ (SDL::Mixer.GetChunk(@channel).pointer == @struct.pointer)
426
+ end
427
+
428
+ end
@@ -0,0 +1,626 @@
1
+ #--
2
+ # Rubygame -- Ruby code and bindings to SDL to facilitate game creation
3
+ # Copyright (C) 2004-2009 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
+
22
+ # Surface represents an image, a block of colored pixels arranged in a
23
+ # 2D grid. You can load image files to a new Surface with #load,
24
+ # or create an empty one with Surface.new and draw shapes on it with
25
+ # #draw_line, #draw_circle, and all the rest.
26
+ #
27
+ # One of the most important Surface concepts is #blit, copying image
28
+ # data from one Surface onto another. By blitting Surfaces onto the
29
+ # Screen (which is a special type of Surface) and then using
30
+ # Screen#update, you can make images appear for the player to see.
31
+ #
32
+ # As of Rubygame 2.3.0, Surface includes the Rubygame::NamedResource
33
+ # mixin module, which can perform autoloading of images on demand,
34
+ # among other things.
35
+ #
36
+ class Rubygame::Surface
37
+
38
+ include Rubygame::NamedResource
39
+
40
+ #--
41
+ #
42
+ # Image loading code is defined in image.rb
43
+ #
44
+ #++
45
+
46
+
47
+ attr_reader :struct # :nodoc:
48
+ protected :struct
49
+
50
+
51
+ # Create and initialize a new Surface object.
52
+ #
53
+ # A Surface is a grid of image data which you blit (i.e. copy) onto other
54
+ # Surfaces. Since the Rubygame display is also a Surface (see the Screen
55
+ # class), Surfaces can be blit to the screen; this is the most common way
56
+ # to display images on the screen.
57
+ #
58
+ # This method may raise SDLError if the SDL video subsystem could
59
+ # not be initialized for some reason.
60
+ #
61
+ # This function takes these arguments:
62
+ # size:: requested surface size; an array of the form [width, height].
63
+ # depth:: requested color depth (in bits per pixel). If depth is 0 (default),
64
+ # automatically choose a color depth: either the depth of the Screen
65
+ # mode (if one has been set), or the greatest color depth available
66
+ # on the system.
67
+ # flags:: an Array or Bitwise-OR'd list of zero or more of the following
68
+ # flags (located in the Rubygame module, e.g. Rubygame::SWSURFACE).
69
+ # This argument may be omitted, in which case the Surface
70
+ # will be a normal software surface (this is not necessarily a bad
71
+ # thing).
72
+ # SWSURFACE:: (default) request a software surface.
73
+ # HWSURFACE:: request a hardware-accelerated surface (using a
74
+ # graphics card), if available. Creates a software
75
+ # surface if hardware surfaces are not available.
76
+ # SRCCOLORKEY:: request a colorkeyed surface. #set_colorkey will
77
+ # also enable colorkey as needed. For a description
78
+ # of colorkeys, see #set_colorkey.
79
+ # SRCALPHA:: request an alpha channel. #set_alpha will
80
+ # also enable alpha. as needed. For a description
81
+ # of alpha, see #alpha.
82
+ #
83
+ def initialize( size, depth=0, flags=[] )
84
+
85
+ # Cheating a bit. First arg can be a SDL::Surface to wrap it.
86
+ #
87
+ if( size.kind_of? SDL::Surface )
88
+ surf = size
89
+ if( surf.pointer.null? )
90
+ raise Rubygame::SDLError, "Surface cannot wrap NULL Surface!"
91
+ else
92
+ @struct = surf
93
+ end
94
+ return
95
+ end
96
+
97
+ unless size.kind_of? Array
98
+ raise TypeError, "Surface size is not an Array: #{size.inspect}"
99
+ end
100
+
101
+ unless size.length == 2 and size.all?{ |n| n.kind_of? Numeric }
102
+ raise ArgumentError, "Invalid Surface size: #{size.inspect}"
103
+ end
104
+
105
+
106
+ pixformat = nil
107
+
108
+ vs = SDL.GetVideoSurface()
109
+
110
+ unless( vs.pointer.null? )
111
+ # Pixel format is retrieved from the video surface.
112
+ pixformat = vs.format
113
+ else
114
+ # We can only get the system color depth when the
115
+ # video system has been initialized.
116
+ if( Rubygame.init_video_system == 0 )
117
+ pixformat = SDL.GetVideoInfo().vfmt
118
+ else
119
+ raise(Rubygame::SDLError,
120
+ "Could not initialize SDL video subsystem.")
121
+ end
122
+ end
123
+
124
+ rmask = pixformat.Rmask
125
+ gmask = pixformat.Gmask
126
+ bmask = pixformat.Bmask
127
+ amask = pixformat.Amask
128
+
129
+ if( depth <= 0 )
130
+ depth = pixformat.BitsPerPixel
131
+ end
132
+
133
+ w, h = size
134
+
135
+ flags = Rubygame.collapse_flags(flags)
136
+
137
+ @struct = SDL.CreateRGBSurface(flags, w, h, depth,
138
+ rmask, gmask, bmask, amask)
139
+ end
140
+
141
+
142
+
143
+ # Return the width (in pixels) of the surface.
144
+ #
145
+ def w
146
+ @struct.w
147
+ end
148
+ alias :width :w
149
+
150
+
151
+ # Return the height (in pixels) of the surface.
152
+ #
153
+ def h
154
+ @struct.h
155
+ end
156
+ alias :height :h
157
+
158
+
159
+ # call-seq:
160
+ # size -> [w,h]
161
+ #
162
+ # Return the surface's width and height (in pixels) in an Array.
163
+ #
164
+ def size
165
+ [@struct.w, @struct.h]
166
+ end
167
+
168
+
169
+ # Return the color depth (in bits per pixel) of the surface.
170
+ #
171
+ def depth
172
+ @struct.format.BitsPerPixel
173
+ end
174
+
175
+
176
+ # Return any flags the surface was initialized with
177
+ # (as a bitwise OR'd integer).
178
+ #
179
+ def flags
180
+ @struct.flags
181
+ end
182
+
183
+
184
+ # call-seq:
185
+ # masks -> [r,g,b,a]
186
+ #
187
+ # Return the color masks [r,g,b,a] of the surface. Almost everyone can
188
+ # ignore this function. Color masks are used to separate an
189
+ # integer representation of a color into its seperate channels.
190
+ #
191
+ def masks
192
+ fmt = @struct.format
193
+ [fmt.Rmask, fmt.Gmask, fmt.Bmask, fmt.Amask]
194
+ end
195
+
196
+
197
+ # Return the per-surface alpha (opacity; non-transparency) of the surface.
198
+ # It can range from 0 (full transparent) to 255 (full opaque).
199
+ #
200
+ def alpha
201
+ @struct.format.alpha
202
+ end
203
+
204
+ # Set the per-surface alpha (opacity; non-transparency) of the surface.
205
+ # You can do the same thing with #alpha= if you don't care about flags.
206
+ #
207
+ # This function takes these arguments:
208
+ # alpha:: requested opacity of the surface. Alpha must be from 0
209
+ # (fully transparent) to 255 (fully opaque).
210
+ # flags:: 0 or Rubygame::SRCALPHA (default). Most people will want the
211
+ # default, in which case this argument can be omitted. For advanced
212
+ # users: this flag affects the surface as described in the docs for
213
+ # the SDL C function, SDL_SetAlpha.
214
+ #
215
+ # Returns self.
216
+ #
217
+ def set_alpha( alpha, flags=Rubygame::SRCALPHA )
218
+ result = SDL.SetAlpha(@struct, flags, alpha.to_i)
219
+ raise Rubygame::SDLError, SDL.GetError() unless result == 0
220
+ return self
221
+ end
222
+
223
+ alias :alpha= :set_alpha
224
+
225
+
226
+ # call-seq:
227
+ # colorkey -> [r,g,b] or nil
228
+ #
229
+ # Return the colorkey of the surface in the form [r,g,b] (or +nil+ if there
230
+ # is no key). The colorkey of a surface is the exact color which will be
231
+ # ignored when the surface is blitted, effectively turning that color
232
+ # transparent. This is often used to make a blue (for example) background
233
+ # on an image seem transparent.
234
+ #
235
+ def colorkey
236
+ if( (@struct.flags & Rubygame::SRCCOLORKEY) == Rubygame::SRCCOLORKEY )
237
+ SDL::GetRGB(@struct.format.colorkey, @struct.format)
238
+ else
239
+ nil
240
+ end
241
+ end
242
+
243
+
244
+ # Set the colorkey of the surface. See Surface#colorkey for a description
245
+ # of colorkeys.
246
+ #
247
+ # This method takes these arguments:
248
+ # color:: color to use as the key, in the form [r,g,b]. Can be +nil+ to
249
+ # un-set the colorkey.
250
+ # flags:: 0 or Rubygame::SRCCOLORKEY (default) or
251
+ # Rubygame::SRCCOLORKEY|Rubygame::SDL_RLEACCEL. Most people will
252
+ # want the default, in which case this argument can be omitted. For
253
+ # advanced users: this flag affects the surface as described in the
254
+ # docs for the SDL C function, SDL_SetColorkey.
255
+ #
256
+ def set_colorkey( color, flags=Rubygame::SRCCOLORKEY )
257
+ if color.nil?
258
+ color, flags = 0, 0
259
+ else
260
+ color = _map_sdl_color( color )
261
+ end
262
+
263
+ result = SDL.SetColorKey(@struct, flags, color)
264
+ raise Rubygame::SDLError, SDL.GetError() unless result == 0
265
+ return self
266
+ end
267
+
268
+ alias :colorkey= :set_colorkey
269
+
270
+
271
+ # Blit (copy) all or part of the surface's image to another surface,
272
+ # at a given position. Returns a Rect representing the area of
273
+ # +target+ which was affected by the blit.
274
+ #
275
+ # This method takes these arguments:
276
+ # target:: the target Surface on which to paste the image.
277
+ # pos:: the coordinates of the top-left corner of the blit.
278
+ # Affects the area of +target+ the image data is /pasted/
279
+ # over. Can also be a Rect or an Array larger than 2, but
280
+ # width and height will be ignored.
281
+ # src_rect:: a Rect representing the area of the source surface to get data
282
+ # from. Affects where the image data is /copied/ from.
283
+ # Can also be an Array of no less than 4 values.
284
+ #
285
+ def blit( target, pos, src_rect=nil )
286
+ unless target.kind_of? Rubygame::Surface
287
+ raise TypeError, "blit target must be a Surface"
288
+ end
289
+
290
+ src_x, src_y, src_w, src_h =
291
+ case src_rect
292
+ when SDL::Rect
293
+ [src_rect.x, src_rect.y, src_rect.w, src_rect.h]
294
+ when Array
295
+ src_rect
296
+ when nil
297
+ [0, 0] + self.size
298
+ end
299
+
300
+ src_rect = SDL::Rect.new([src_x, src_y, src_w, src_h])
301
+ blit_x, blit_y = pos
302
+ blit_rect = SDL::Rect.new([blit_x, blit_y, src_w, src_h])
303
+
304
+ SDL.BlitSurface( @struct, src_rect, target.struct, blit_rect )
305
+
306
+ return Rubygame::Rect.new( blit_rect.to_ary )
307
+ end
308
+
309
+
310
+ # Fill all or part of a Surface with a color.
311
+ #
312
+ # This method takes these arguments:
313
+ # color:: color to fill with, in the form +[r,g,b]+ or +[r,g,b,a]+ (for
314
+ # partially transparent fills).
315
+ # rect:: a Rubygame::Rect representing the area of the surface to fill
316
+ # with color. Omit to fill the entire surface.
317
+ #
318
+ def fill( color, rect=nil )
319
+ unless rect.nil? or rect.kind_of? Array
320
+ raise TypeError, "invalid fill Rect: #{rect.inspect}"
321
+ end
322
+
323
+ color = _map_sdl_color( color )
324
+ rect = SDL::Rect.new( rect.to_ary ) unless rect.nil?
325
+ SDL.FillRect( @struct, rect, color )
326
+ return self
327
+ end
328
+
329
+
330
+ # Return a Rect with the same width and height as the Surface,
331
+ # with topleft = [0,0].
332
+ #
333
+ def make_rect()
334
+ return Rubygame::Rect.new( 0, 0, self.w, self.h )
335
+ end
336
+
337
+
338
+ # call-seq:
339
+ # get_at( [x,y] )
340
+ # get_at( x,y )
341
+ #
342
+ # Return the color [r,g,b,a] (0-255) of the pixel at [x,y].
343
+ # If the Surface does not have a per-pixel alpha channel (i.e. not
344
+ # 32-bit), alpha will always be 255. The Surface's overall alpha
345
+ # value (from #set_alpha) does not affect the returned alpha value.
346
+ #
347
+ # Raises IndexError if the coordinates are out of bounds.
348
+ #
349
+ def get_at( *args )
350
+ x,y = case args.length
351
+ when 1; args[0].to_ary.collect { |n| n.round }
352
+ when 2; [args[0].round, args[1].round]
353
+ else
354
+ raise( ArgumentError,
355
+ "wrong number of arguments (#{args.length} for 1)" )
356
+ end
357
+
358
+ if( x < 0 or x >= @struct.w or y < 0 or y >= @struct.h)
359
+ raise( IndexError, "point [%d,%d] is out of bounds for %dx%d Surface"%\
360
+ [x, y, @struct.w, @struct.h] )
361
+ end
362
+
363
+ SDL.LockSurface(@struct)
364
+
365
+ bpp = @struct.format.BytesPerPixel
366
+ ptr = @struct.pixels + (y * @struct.pitch + x * bpp)
367
+
368
+ pixel =
369
+ case bpp
370
+ when 1
371
+ ptr.get_uint8(0)
372
+ when 2
373
+ ptr.get_uint16(0)
374
+ when 3
375
+ if( FFI::Platform::BYTE_ORDER == FFI::Platform::BIG_ENDIAN )
376
+ (ptr.get_uint8(0) << 16)|(ptr.get_uint8(1) << 8)|ptr.get_uint8(2)
377
+ else
378
+ ptr.get_uint8(0)|(ptr.get_uint8(1) << 8)|(ptr.get_uint8(2) << 16)
379
+ end
380
+ when 4
381
+ ptr.get_uint32(0)
382
+ end
383
+
384
+ SDL.UnlockSurface(@struct)
385
+
386
+ return SDL::GetRGBA(pixel, @struct.format)
387
+ end
388
+
389
+
390
+ # call-seq:
391
+ # set_at( [x,y], color )
392
+ #
393
+ # Set the color of the pixel at [x,y]. If no alpha value is given,
394
+ # or if the Surface does not have a per-pixel alpha channel (i.e. not
395
+ # 32-bit), the pixel will be set at full opacity.
396
+ #
397
+ # color can be one of:
398
+ # * an Array, [r,g,b] or [r,g,b,a] with each component in 0-255.
399
+ # * an instance of Rubygame::ColorRGB, Rubygame::ColorHSV, etc.
400
+ # * the name of a color in Rubygame::Color, as a Symbol or String
401
+ #
402
+ # Raises IndexError if the coordinates are out of bounds.
403
+ #
404
+ def set_at( pos, color )
405
+ x,y = pos.to_ary.collect { |n| n.round }
406
+
407
+ if( x < 0 or x >= @struct.w or y < 0 or y >= @struct.h)
408
+ raise( IndexError, "point [%d,%d] is out of bounds for %dx%d Surface"%\
409
+ [x, y, @struct.w, @struct.h] )
410
+ end
411
+
412
+ color = _map_sdl_color( color )
413
+
414
+ SDL.LockSurface(@struct)
415
+
416
+ bpp = @struct.format.BytesPerPixel
417
+ ptr = @struct.pixels + (y * @struct.pitch + x * bpp)
418
+
419
+ case bpp
420
+ when 1
421
+ ptr.put_uint8(0, color)
422
+ when 2
423
+ ptr.put_uint16(0, color)
424
+ when 3
425
+ if( FFI::Platform::BYTE_ORDER == FFI::Platform::BIG_ENDIAN )
426
+ ptr.put_uint8(0, (color >> 16) & 0xff)
427
+ ptr.put_uint8(1, (color >> 8) & 0xff)
428
+ ptr.put_uint8(2, color & 0xff)
429
+ else
430
+ ptr.put_uint8(0, color & 0xff)
431
+ ptr.put_uint8(1, (color >> 8) & 0xff)
432
+ ptr.put_uint8(2, (color >> 16) & 0xff)
433
+ end
434
+ when 4
435
+ ptr.put_uint32(0, color)
436
+ end
437
+
438
+ SDL.UnlockSurface(@struct)
439
+
440
+ return
441
+ end
442
+
443
+
444
+ # Return a string of pixel data for the Surface. Most users will not
445
+ # need to use this method. If you want to convert a Surface into an
446
+ # OpenGL texture, pass the returned string to the TexImage2D method
447
+ # of the ruby-opengl library. (See samples/demo_gl_tex.rb for an
448
+ # example.)
449
+ #
450
+ # (Please note that the dimensions of OpenGL textures must be powers
451
+ # of 2 (e.g. 64x128, 512x512), so if you want to use a Surface as an
452
+ # OpenGL texture, the Surface's dimensions must also be powers of
453
+ # 2!)
454
+ #
455
+ def pixels
456
+ len = @struct.pitch * @struct.h
457
+ SDL.LockSurface(@struct)
458
+ pix = @struct.pixels.get_bytes(0, len)
459
+ SDL.UnlockSurface(@struct)
460
+ return pix
461
+ end
462
+
463
+
464
+
465
+ # Return the clipping area for this Surface. See also #clip=.
466
+ #
467
+ # The clipping area of a Surface is the only part which can be drawn
468
+ # upon by other Surface's #blits. By default, the clipping area is
469
+ # the entire area of the Surface.
470
+ #
471
+ def clip
472
+ Rubygame::Rect.new( SDL.GetClipRect(@struct).to_ary )
473
+ end
474
+
475
+
476
+ # Set the current clipping area of the Surface. See also #clip.
477
+ #
478
+ # The clipping area of a Surface is the only part which can be drawn
479
+ # upon by other Surface's #blits. The clipping area will be clipped
480
+ # to the edges of the surface so that the clipping area for a
481
+ # Surface can never fall outside the edges of the Surface.
482
+ #
483
+ # By default, the clipping area is the entire area of the Surface.
484
+ # You may set clip to +nil+, which will reset the clipping area to
485
+ # cover the entire Surface.
486
+ #
487
+ def clip=( newclip )
488
+ newclip = case newclip
489
+ when nil, SDL::Rect
490
+ newclip # no change
491
+ when Rubygame::Rect
492
+ newclip.to_sdl
493
+ when Array
494
+ Rubygame::Rect.new(newclip).to_sdl
495
+ end
496
+
497
+ SDL.SetClipRect(@struct, newclip)
498
+ return self
499
+ end
500
+
501
+
502
+
503
+ # Copies the Surface to a new Surface with the pixel format of
504
+ # another Surface, for fast blitting. May raise SDLError if a
505
+ # problem occurs.
506
+ #
507
+ # This method takes these arguments:
508
+ # other:: The Surface to match pixel format against. If +nil+, the
509
+ # display surface (i.e. Screen) is used, if available; if
510
+ # no display surface is available, raises SDLError.
511
+ # flags:: An array of flags to pass when the new Surface is created.
512
+ # See Surface#new.
513
+ #
514
+ def convert( other=nil, flags=nil )
515
+
516
+ if other.nil?
517
+ begin
518
+ other = Rubygame::ScreenFFI.get_surface
519
+ rescue Rubygame::SDLError
520
+ raise( Rubygame::SDLError, "Cannot convert Surface with no target " +
521
+ "given and no Screen made: #{SDL.GetError()}" )
522
+ end
523
+ end
524
+
525
+ flags = Rubygame.collapse_flags(flags)
526
+
527
+ newsurf =
528
+ if( Rubygame.init_video_system() == 0 )
529
+ SDL.ConvertSurface( @struct, other.struct.format, flags )
530
+ else
531
+ nil
532
+ end
533
+
534
+ if( newsurf.nil? or newsurf.pointer.null?)
535
+ raise( Rubygame::SDLError,
536
+ "Could not convert the Surface: #{SDL.GetError()}" )
537
+ end
538
+
539
+ # Wrap it
540
+ return self.class.new( newsurf )
541
+ end
542
+
543
+
544
+
545
+ # Copies the Surface to a new Surface with the pixel format of the
546
+ # display, suitable for fast blitting to the display surface (i.e.
547
+ # Screen). May raise SDLError if a problem occurs.
548
+ #
549
+ # If you want to take advantage of hardware colorkey or alpha blit
550
+ # acceleration, you should set the colorkey and alpha value before
551
+ # calling this function.
552
+ #
553
+ def to_display
554
+ newsurf =
555
+ if( Rubygame.init_video_system() == 0 )
556
+ SDL.DisplayFormat( @struct )
557
+ else
558
+ nil
559
+ end
560
+
561
+ if( newsurf.nil? or newsurf.pointer.null?)
562
+ raise( Rubygame::SDLError,
563
+ "Could not convert the Surface to display format: %s"%\
564
+ SDL.GetError() )
565
+ end
566
+
567
+ # Wrap it
568
+ return self.class.new( newsurf )
569
+ end
570
+
571
+
572
+
573
+ # Like #to_display except the Surface has an extra channel for alpha
574
+ # (i.e. opacity). May raise SDLError if a problem occurs.
575
+ #
576
+ # This function can be used to convert a colorkey to an alpha
577
+ # channel, if the SRCCOLORKEY flag is set on the surface. The
578
+ # generated surface will then be transparent (alpha=0) where the
579
+ # pixels match the colorkey, and opaque (alpha=255) elsewhere.
580
+ #
581
+ def to_display_alpha
582
+ newsurf =
583
+ if( Rubygame.init_video_system() == 0 )
584
+ SDL.DisplayFormatAlpha( @struct )
585
+ else
586
+ nil
587
+ end
588
+
589
+ if( newsurf.nil? or newsurf.pointer.null?)
590
+ raise( Rubygame::SDLError,
591
+ "Could not convert the Surface to display format "+
592
+ "with alpha channel: #{SDL.GetError()}" )
593
+ end
594
+
595
+ # Wrap it
596
+ return self.class.new( newsurf )
597
+ end
598
+
599
+
600
+ # Save the Surface as a Windows Bitmap (BMP) file with the given filename.
601
+ # May raise SDLError if a problem occurs.
602
+ #
603
+ def savebmp( filename )
604
+ result = SDL.SaveBMP( @struct, filename )
605
+ if(result != 0)
606
+ raise( Rubygame::SDLError, "Couldn't save surface to file %s: %s"%\
607
+ [filename, SDL.GetError()] )
608
+ end
609
+ nil
610
+ end
611
+
612
+
613
+ def to_s
614
+ "#<%s:%#.x>"%[self.class.name, self.object_id]
615
+ end
616
+
617
+ alias :inspect :to_s
618
+
619
+
620
+ private
621
+
622
+ def _map_sdl_color( color ) # :nodoc:
623
+ SDL.MapRGBA( @struct.format, *Rubygame::Color.make_sdl_rgba(color) )
624
+ end
625
+
626
+ end