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
@@ -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