rubygame 2.5.3 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CREDITS +6 -4
- data/NEWS +79 -0
- data/README +55 -72
- data/ROADMAP +20 -13
- data/doc/custom_sdl_load_paths.rdoc +79 -0
- data/doc/getting_started.rdoc +65 -36
- data/doc/keyboard_symbols.rdoc +243 -0
- data/doc/macosx_install.rdoc +49 -35
- data/doc/windows_install.rdoc +36 -108
- data/lib/rubygame.rb +62 -24
- data/lib/rubygame/audio.rb +147 -0
- data/lib/rubygame/clock.rb +164 -1
- data/lib/rubygame/color.rb +40 -7
- data/lib/rubygame/color/models/hsl.rb +1 -1
- data/lib/rubygame/color/models/hsv.rb +1 -1
- data/lib/rubygame/color/models/rgb.rb +1 -1
- data/lib/rubygame/color/palettes/css.rb +1 -3
- data/lib/rubygame/color/palettes/x11.rb +1 -2
- data/lib/rubygame/constants.rb +297 -0
- data/lib/rubygame/deprecated_mixer.rb +555 -0
- data/lib/rubygame/event.rb +122 -6
- data/lib/rubygame/event_handler.rb +3 -1
- data/lib/rubygame/event_hook.rb +6 -2
- data/lib/rubygame/event_triggers.rb +1 -1
- data/lib/rubygame/events.rb +416 -1
- data/lib/rubygame/ftor.rb +1 -7
- data/lib/rubygame/gfx.rb +583 -0
- data/lib/rubygame/gl.rb +107 -0
- data/lib/rubygame/image.rb +140 -0
- data/lib/rubygame/joystick.rb +184 -0
- data/lib/rubygame/main.rb +82 -0
- data/lib/rubygame/mediabag.rb +1 -1
- data/lib/rubygame/mixer.rb +30 -0
- data/lib/rubygame/music.rb +493 -0
- data/lib/rubygame/queue.rb +3 -1
- data/lib/rubygame/rect.rb +9 -9
- data/lib/rubygame/screen.rb +357 -0
- data/lib/rubygame/shared.rb +40 -4
- data/lib/rubygame/sound.rb +428 -0
- data/lib/rubygame/surface.rb +626 -0
- data/lib/rubygame/ttf.rb +311 -0
- data/samples/FreeSans.ttf +0 -0
- data/samples/README +6 -5
- data/samples/demo_draw.rb +1 -1
- data/samples/demo_gl.rb +3 -1
- data/samples/demo_gl_tex.rb +4 -2
- data/samples/demo_rubygame.rb +114 -105
- data/samples/demo_sfont.rb +1 -1
- data/samples/demo_ttf.rb +3 -1
- data/samples/demo_utf8.rb +1 -1
- data/samples/image_viewer.rb +118 -0
- data/samples/load_and_blit.rb +1 -1
- data/samples/rubygame.png +0 -0
- metadata +34 -40
- data/Rakefile +0 -537
- data/doc/extended_readme.rdoc +0 -49
- data/ext/body/rubygame_body.so +0 -0
- data/ext/rubygame/rubygame_clock.c +0 -301
- data/ext/rubygame/rubygame_clock.h +0 -32
- data/ext/rubygame/rubygame_event.c +0 -760
- data/ext/rubygame/rubygame_event.h +0 -48
- data/ext/rubygame/rubygame_event2.c +0 -661
- data/ext/rubygame/rubygame_event2.h +0 -29
- data/ext/rubygame/rubygame_gfx.c +0 -942
- data/ext/rubygame/rubygame_gfx.h +0 -101
- data/ext/rubygame/rubygame_gl.c +0 -154
- data/ext/rubygame/rubygame_gl.h +0 -32
- data/ext/rubygame/rubygame_image.c +0 -252
- data/ext/rubygame/rubygame_image.h +0 -41
- data/ext/rubygame/rubygame_joystick.c +0 -336
- data/ext/rubygame/rubygame_joystick.h +0 -41
- data/ext/rubygame/rubygame_main.c +0 -158
- data/ext/rubygame/rubygame_main.h +0 -36
- data/ext/rubygame/rubygame_mixer.c +0 -1024
- data/ext/rubygame/rubygame_mixer.h +0 -36
- data/ext/rubygame/rubygame_music.c +0 -1017
- data/ext/rubygame/rubygame_music.h +0 -29
- data/ext/rubygame/rubygame_screen.c +0 -572
- data/ext/rubygame/rubygame_screen.h +0 -45
- data/ext/rubygame/rubygame_shared.c +0 -269
- data/ext/rubygame/rubygame_shared.h +0 -69
- data/ext/rubygame/rubygame_sound.c +0 -863
- data/ext/rubygame/rubygame_sound.h +0 -29
- data/ext/rubygame/rubygame_surface.c +0 -1153
- data/ext/rubygame/rubygame_surface.h +0 -62
- data/ext/rubygame/rubygame_ttf.c +0 -599
- data/ext/rubygame/rubygame_ttf.h +0 -69
- 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
|