texplay 0.3.5 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/CHANGELOG +222 -222
  2. data/README.markdown +43 -43
  3. data/Rakefile +3 -99
  4. data/examples/common.rb +18 -18
  5. data/examples/example_alpha_blend.rb +29 -29
  6. data/examples/example_bezier.rb +41 -41
  7. data/examples/example_blank.rb +37 -37
  8. data/examples/example_cache.rb +21 -21
  9. data/examples/example_color_control.rb +69 -69
  10. data/examples/example_color_transform.rb +62 -62
  11. data/examples/example_color_transform_circle.rb +34 -34
  12. data/examples/example_darken.rb +24 -24
  13. data/examples/example_dup.rb +73 -73
  14. data/examples/example_each.rb +39 -39
  15. data/examples/example_effect.rb +34 -34
  16. data/examples/example_fill.rb +43 -43
  17. data/examples/example_fill_old.rb +48 -48
  18. data/examples/example_fluent.rb +29 -29
  19. data/examples/example_font.rb +31 -31
  20. data/examples/example_hash_arguments.rb +46 -46
  21. data/examples/example_ippa.rb +23 -23
  22. data/examples/example_light.rb +75 -75
  23. data/examples/example_light_multiply.rb +18 -18
  24. data/examples/example_lsystem.rb +61 -61
  25. data/examples/example_melt.rb +25 -25
  26. data/examples/example_meyet.rb +62 -62
  27. data/examples/example_polyline.rb +42 -42
  28. data/examples/example_scale.rb +27 -27
  29. data/examples/example_select.rb +36 -36
  30. data/examples/example_select2.rb +25 -25
  31. data/examples/example_simple.rb +46 -46
  32. data/examples/example_splice.rb +26 -26
  33. data/examples/example_sync.rb +59 -59
  34. data/examples/example_tiles.rb +41 -41
  35. data/examples/example_trace.rb +22 -22
  36. data/examples/example_transparent.rb +28 -28
  37. data/examples/example_transparent2.rb +24 -24
  38. data/examples/example_transparent3.rb +20 -20
  39. data/examples/example_turtle.rb +39 -39
  40. data/examples/example_weird.rb +22 -22
  41. data/examples/example_window_render_to_image.rb +41 -41
  42. data/examples/example_window_to_blob.rb +35 -35
  43. data/examples/media/maria.png +0 -0
  44. data/examples/media/rose.bmp +0 -0
  45. data/ext/texplay/actions.c +1006 -1006
  46. data/ext/texplay/actions.h +60 -60
  47. data/ext/texplay/bindings.c +1125 -1186
  48. data/ext/texplay/bindings.h +46 -46
  49. data/ext/texplay/cache.c +118 -118
  50. data/ext/texplay/cache.h +24 -24
  51. data/ext/texplay/compat.h +27 -27
  52. data/ext/texplay/extconf.rb +28 -28
  53. data/ext/texplay/graphics_utils.c +1313 -1313
  54. data/ext/texplay/graphics_utils.h +22 -22
  55. data/ext/texplay/texplay.c +201 -216
  56. data/ext/texplay/texplay.h +153 -153
  57. data/ext/texplay/utils.c +891 -891
  58. data/ext/texplay/utils.h +153 -153
  59. data/lib/texplay-contrib.rb +147 -164
  60. data/lib/texplay.rb +341 -356
  61. data/lib/texplay/alone.rb +20 -20
  62. data/lib/texplay/c_function_docs.rb +178 -190
  63. data/lib/texplay/live.rb +84 -84
  64. data/lib/texplay/version.rb +3 -3
  65. data/live/live.rb +85 -85
  66. data/test/image_spec.rb +45 -45
  67. data/test/texplay_spec.rb +144 -141
  68. metadata +54 -42
  69. data/examples/example_gen_eval.rb +0 -32
  70. data/ext/texplay/gen_eval.c +0 -211
  71. data/ext/texplay/gen_eval.h +0 -20
  72. data/ext/texplay/object2module.c +0 -171
  73. data/ext/texplay/object2module.h +0 -11
data/lib/texplay.rb CHANGED
@@ -1,356 +1,341 @@
1
-
2
- # (C) John Mair 2009, under the MIT licence
3
-
4
- direc = File.expand_path(File.dirname(__FILE__))
5
-
6
- # include gosu first
7
- require 'gosu'
8
- require "#{direc}/texplay/version"
9
-
10
- module TexPlay
11
- RENDER_CLEAR_COLOR = Gosu::Color.new(255, 0, 0, 0)
12
-
13
- class << self
14
- def on_setup(&block)
15
- raise "need a block" if !block
16
- @__init_procs__ ||= []
17
- @__init_procs__.push(block)
18
- end
19
-
20
- def setup(receiver)
21
- if @__init_procs__
22
- @__init_procs__.each do |init_proc|
23
- receiver.instance_eval(&init_proc)
24
- end
25
- end
26
- end
27
-
28
- def create_image(window, width, height, options={})
29
- options = {
30
- :color => :alpha,
31
- :caching => false,
32
- }.merge!(options)
33
-
34
- raise ArgumentError, "Height and width must be positive" if height <= 0 or width <= 0
35
-
36
- img = Gosu::Image.new(window, EmptyImageStub.new(width, height), :caching => options[:caching])
37
-
38
- # this should be a major speedup (avoids both a cache and a sync
39
- # if color is alpha (default)
40
- if options[:color] != :alpha
41
- img.rect 0, 0, img.width - 1, img.height - 1, :color => options[:color], :fill => true
42
- end
43
-
44
- img
45
- end
46
-
47
- alias_method :create_blank_image, :create_image
48
-
49
- # Image can be :tileable, but it will break if it is tileable AND gets modified after creation.
50
- def from_blob(window, blob_data, width, height, options={})
51
- options = {
52
- :caching => false,
53
- :tileable => false,
54
- }.merge!(options)
55
-
56
- raise ArgumentError, "Height and width must be positive (received #{width}x#{height})" if height <= 0 or width <= 0
57
-
58
- expected_size = height * width * 4
59
- if blob_data.size != expected_size
60
- raise ArgumentError, "Blob data is not of the correct size (expected #{expected_size} but received #{blob_data.size} bytes)"
61
- end
62
-
63
- Gosu::Image.new(window, ImageStub.new(blob_data, width, height), options[:tileable], :caching => options[:caching])
64
- end
65
-
66
- def set_options(options = {})
67
- @options.merge!(options)
68
- end
69
-
70
- def get_options
71
- @options
72
- end
73
-
74
- # default values defined here
75
- def set_defaults
76
- @options = {
77
- :caching => :lazy
78
- }
79
- end
80
-
81
- def init
82
- set_defaults
83
- end
84
- end
85
-
86
- module Colors
87
- Red = [1, 0, 0, 1]
88
- Green = [0, 1, 0, 1]
89
- Blue = [0, 0, 1, 1]
90
- Black = [0, 0, 0, 1]
91
- White = [1, 1, 1, 1]
92
- Grey = [0.5, 0.5, 0.5, 1]
93
- Alpha = [0, 0, 0, 0]
94
- Purple = [1, 0, 1, 1]
95
- Yellow = [1, 1, 0, 1]
96
- Cyan = [0, 1, 1, 1]
97
- Orange = [1, 0.5, 0, 1]
98
- Brown = [0.39, 0.26, 0.13, 1]
99
- Turquoise = [1, 0.6, 0.8, 1]
100
- Tyrian = [0.4, 0.007, 0.235, 1]
101
- end
102
- include Colors
103
-
104
- # extra instance methods defined in Ruby
105
-
106
- # Clear an image.
107
- #
108
- # @option options :color (:alpha) Colour of the image.
109
- # @return [Gosu::Image]
110
- def clear(options = {})
111
- options = {
112
- :color => :alpha,
113
- :fill => true
114
- }.merge!(options)
115
-
116
- capture {
117
- rect 0, 0, width - 1, height - 1, options
118
-
119
- self
120
- }
121
- end
122
-
123
- # Used internally to create images from raw binary (blob) data (TexPlay::from_blob).
124
- #
125
- # This object duck-types an RMagick image (#rows, #columns, #to_blob), so that Gosu will import it.
126
- class ImageStub
127
-
128
- # @return [Integer]
129
- attr_reader :rows, :columns
130
-
131
- # The first pixel in the blob will be at the top left hand corner of the created image, since that is the orientation
132
- # of Gosu images.
133
- #
134
- # @param [String] blob_data Raw data string to import. Must be RGBA ordered, (4 * width * height) bytes in length.
135
- # @param [Integer] width Number of pixels wide.
136
- # @param [Integer] height Number of pixels high.
137
- def initialize(blob_data, width, height)
138
- @data, @columns, @rows = blob_data, width, height
139
- end
140
-
141
- # @return [String]
142
- def to_blob
143
- @data
144
- end
145
- end
146
-
147
- # Used internally to create blank images (red/blue/green/alpha all 0) (TexPlay::create_image).
148
- #
149
- # Credit to philomory for this class.
150
- class EmptyImageStub < ImageStub
151
- # @param width (see ImageStub#initialize)
152
- # @param height (see ImageStub#initialize)
153
- def initialize(width, height)
154
- super("\0" * (width * height * 4), width, height)
155
- end
156
- end
157
- end
158
-
159
- # bring in user-defined extensions to TexPlay
160
- begin
161
- if RUBY_VERSION && RUBY_VERSION =~ /1.9/
162
- require "#{direc}/1.9/texplay"
163
- else
164
- require "#{direc}/1.8/texplay"
165
- end
166
- rescue LoadError => e
167
- require 'rbconfig'
168
- dlext = Config::CONFIG['DLEXT']
169
- require "#{direc}/texplay.#{dlext}"
170
- end
171
-
172
- require "#{direc}/texplay-contrib"
173
-
174
- # monkey patching the Gosu::Image class to add image manipulation functionality
175
- module Gosu
176
- class Image
177
-
178
- # bring in the TexPlay image manipulation methods
179
- include TexPlay
180
-
181
- attr_reader :__window__
182
- protected :__window__
183
-
184
- class << self
185
- alias_method :original_new, :new
186
-
187
- def new(*args, &block)
188
-
189
- options = args.last.is_a?(Hash) ? args.pop : {}
190
- # invoke old behaviour
191
- obj = original_new(*args, &block)
192
-
193
- prepare_image(obj, args.first, options)
194
- end
195
-
196
- alias_method :original_from_text, :from_text
197
-
198
- def from_text(*args, &block)
199
-
200
- options = args.last.is_a?(Hash) ? args.pop : {}
201
- # invoke old behaviour
202
- obj = original_from_text(*args, &block)
203
-
204
- prepare_image(obj, args.first, options)
205
- end
206
-
207
- def prepare_image(obj, window, options={})
208
- options = {
209
- :caching => TexPlay.get_options[:caching]
210
- }.merge!(options)
211
-
212
- caching_mode = options[:caching]
213
-
214
- # we can't manipulate large images, so skip them.
215
- if obj.width <= (TexPlay::TP_MAX_QUAD_SIZE) &&
216
- obj.height <= (TexPlay::TP_MAX_QUAD_SIZE)
217
-
218
- if caching_mode
219
- if caching_mode == :lazy
220
-
221
- # only cache if quad already cached (to refresh old data)
222
- # otherwise cache lazily at point of first TexPlay call
223
- obj.refresh_cache if obj.quad_cached?
224
-
225
- else
226
-
227
- # force a cache - this obviates the need for a
228
- # potentialy expensive runtime cache of the image by
229
- # moving the cache to load-time
230
- obj.refresh_cache
231
- end
232
- end
233
- end
234
-
235
- # run custom setup
236
- TexPlay.setup(obj)
237
-
238
- obj.instance_variable_set(:@__window__, window)
239
-
240
- obj
241
- end
242
-
243
- private :prepare_image
244
- end
245
-
246
- alias_method :rows, :height
247
- alias_method :columns, :width
248
- end
249
-
250
- class Window
251
- # Render directly into an existing image, optionally only to a specific region of that image.
252
- #
253
- # Since this operation utilises the window's back buffer, the image (or clipped area, if specified) cannot be larger than the
254
- # window itself. Larger images can be rendered to only in separate sections using :clip_to areas, each no larger
255
- # than the window).
256
- #
257
- # @note *Warning!* This operation will corrupt an area of the screen, at the bottom left corner, equal in size to the image rendered to (or the clipped area), so should be performed in #draw _before_ any other rendering.
258
- #
259
- # @note The final alpha of the image will be 255, regardless of what it started with or what is drawn onto it.
260
- #
261
- # @example
262
- # class Gosu
263
- # class Window
264
- # def draw
265
- # # Always render images before regular drawing to the screen.
266
- # unless @rendered_image
267
- # @rendered_image = TexPlay.create_image(self, 300, 300, :color => :blue)
268
- # render_to_image(@rendered_image) do
269
- # @an_image.draw 0, 0, 0
270
- # @another_image.draw 130, 0, 0
271
- # draw_line(0, 0, Color.new(255, 0, 0, 0), 100, 100, Color.new(255, 0, 0, 0), 0)
272
- # @font.draw("Hello world!", 0, 50, 0)
273
- # end
274
- # end
275
- #
276
- # # Perform regular screen rendering.
277
- # @rendered_image.draw 0, 0
278
- # end
279
- # end
280
- # end
281
- #
282
- #
283
- # @param [Gosu::Image] image Existing image to render onto.
284
- # @option options [Array<Integer>] :clip_to ([0, 0, image.width, image.height]) Area of the image to render into. This area cannot be larger than the window, though the image may be.
285
- # @return [Gosu::Image] The image that has been rendered to.
286
- # @yield to a block that renders to the image.
287
- def render_to_image(image, options = {})
288
- raise ArgumentError, "image parameter must be a Gosu::Image to be rendered to" unless image.is_a? Gosu::Image
289
- raise ArgumentError, "rendering block required" unless block_given?
290
-
291
- options = {
292
- :clip_to => [0, 0, image.width, image.height],
293
- }.merge! options
294
-
295
- texture_info = image.gl_tex_info
296
- tex_name = texture_info.tex_name
297
- x_offset = (texture_info.left * Gosu::MAX_TEXTURE_SIZE).to_i
298
- y_offset = (texture_info.top * Gosu::MAX_TEXTURE_SIZE).to_i
299
-
300
- raise ArgumentError, ":clip_to rectangle must contain exactly 4 elements" unless options[:clip_to].size == 4
301
-
302
- left, top, width, height = *(options[:clip_to].map {|n| n.to_i })
303
-
304
- raise ArgumentError, ":clip_to rectangle cannot be wider or taller than the window" unless width <= self.width and height <= self.height
305
- raise ArgumentError, ":clip_to rectangle width and height must be positive" unless width > 0 and height > 0
306
-
307
- right = left + width - 1
308
- bottom = top + height - 1
309
-
310
- unless (0...image.width).include? left and (0...image.width).include? right and
311
- (0...image.height).include? top and (0...image.height).include? bottom
312
- raise ArgumentError, ":clip_to rectangle out of bounds of the image"
313
- end
314
-
315
- # Since to_texture copies an inverted copy of the screen, what the user renders needs to be inverted first.
316
- scale(1, -1) do
317
- translate(-left, -top - self.height) do
318
- # TODO: Once Gosu is fixed, we can just pass width/height to clip_to
319
- clip_to(left, top, width, height) do
320
- # Draw over the background (which is assumed to be blank) with the original image texture,
321
- # to get us to the base image.
322
- image.draw(0, 0, 0)
323
- flush
324
-
325
- # Allow the user to overwrite the texture.
326
- yield
327
- end
328
-
329
- # Copy the modified texture back from the screen buffer to the image.
330
- to_texture(tex_name, x_offset + left, y_offset + top, 0, 0, width, height)
331
-
332
- # Clear the clipped zone to black again, ready for the regular screen drawing.
333
- # Quad can be a pixel out, so just make sure with a slightly larger shape.
334
- draw_quad(left - 2, top - 2, TexPlay::RENDER_CLEAR_COLOR,
335
- right + 2, top - 2, TexPlay::RENDER_CLEAR_COLOR,
336
- right + 2, bottom + 2, TexPlay::RENDER_CLEAR_COLOR,
337
- left - 2, bottom + 2, TexPlay::RENDER_CLEAR_COLOR)
338
- end
339
- end
340
-
341
- image
342
- end
343
- end
344
- end
345
-
346
- # a bug in ruby 1.8.6 rb_eval_string() means i must define this here (rather than in texplay.c)
347
- class Proc
348
- def __context__
349
- eval('self', self.binding)
350
- end
351
- end
352
-
353
-
354
- # initialize TP (at the moment just setting some default settings)
355
- TexPlay.init
356
-
1
+
2
+ # (C) John Mair 2009, under the MIT licence
3
+
4
+ direc = File.expand_path(File.dirname(__FILE__))
5
+
6
+ # include gosu first
7
+ require 'gosu'
8
+ require "#{direc}/texplay/version"
9
+ require 'texplay/texplay'
10
+
11
+ module TexPlay
12
+ RENDER_CLEAR_COLOR = Gosu::Color.new(255, 0, 0, 0)
13
+
14
+ class << self
15
+ def on_setup(&block)
16
+ raise "need a block" if !block
17
+ @__init_procs__ ||= []
18
+ @__init_procs__.push(block)
19
+ end
20
+
21
+ def setup(receiver)
22
+ if @__init_procs__
23
+ @__init_procs__.each do |init_proc|
24
+ receiver.instance_eval(&init_proc)
25
+ end
26
+ end
27
+ end
28
+
29
+ def create_image(window, width, height, options={})
30
+ options = {
31
+ :color => :alpha,
32
+ :caching => false,
33
+ }.merge!(options)
34
+
35
+ raise ArgumentError, "Height and width must be positive" if height <= 0 or width <= 0
36
+
37
+ img = Gosu::Image.new(window, EmptyImageStub.new(width, height), :caching => options[:caching])
38
+
39
+ # this should be a major speedup (avoids both a cache and a sync
40
+ # if color is alpha (default)
41
+ if options[:color] != :alpha
42
+ img.rect 0, 0, img.width - 1, img.height - 1, :color => options[:color], :fill => true
43
+ end
44
+
45
+ img
46
+ end
47
+
48
+ alias_method :create_blank_image, :create_image
49
+
50
+ # Image can be :tileable, but it will break if it is tileable AND gets modified after creation.
51
+ def from_blob(window, blob_data, width, height, options={})
52
+ options = {
53
+ :caching => false,
54
+ :tileable => false,
55
+ }.merge!(options)
56
+
57
+ raise ArgumentError, "Height and width must be positive (received #{width}x#{height})" if height <= 0 or width <= 0
58
+
59
+ expected_size = height * width * 4
60
+ if blob_data.size != expected_size
61
+ raise ArgumentError, "Blob data is not of the correct size (expected #{expected_size} but received #{blob_data.size} bytes)"
62
+ end
63
+
64
+ Gosu::Image.new(window, ImageStub.new(blob_data, width, height), options[:tileable], :caching => options[:caching])
65
+ end
66
+
67
+ def set_options(options = {})
68
+ @options.merge!(options)
69
+ end
70
+
71
+ def get_options
72
+ @options
73
+ end
74
+
75
+ # default values defined here
76
+ def set_defaults
77
+ @options = {
78
+ :caching => :lazy
79
+ }
80
+ end
81
+
82
+ def init
83
+ set_defaults
84
+ end
85
+ end
86
+
87
+ module Colors
88
+ Red = [1, 0, 0, 1]
89
+ Green = [0, 1, 0, 1]
90
+ Blue = [0, 0, 1, 1]
91
+ Black = [0, 0, 0, 1]
92
+ White = [1, 1, 1, 1]
93
+ Grey = [0.5, 0.5, 0.5, 1]
94
+ Alpha = [0, 0, 0, 0]
95
+ Purple = [1, 0, 1, 1]
96
+ Yellow = [1, 1, 0, 1]
97
+ Cyan = [0, 1, 1, 1]
98
+ Orange = [1, 0.5, 0, 1]
99
+ Brown = [0.39, 0.26, 0.13, 1]
100
+ Turquoise = [1, 0.6, 0.8, 1]
101
+ Tyrian = [0.4, 0.007, 0.235, 1]
102
+ end
103
+ include Colors
104
+
105
+ # extra instance methods defined in Ruby
106
+
107
+ # Clear an image.
108
+ #
109
+ # @option options :color (:alpha) Colour of the image.
110
+ # @return [Gosu::Image]
111
+ def clear(options = {})
112
+ options = {
113
+ :color => :alpha,
114
+ :fill => true
115
+ }.merge!(options)
116
+
117
+ rect 0, 0, width - 1, height - 1, options
118
+ end
119
+
120
+ # Used internally to create images from raw binary (blob) data (TexPlay::from_blob).
121
+ #
122
+ # This object duck-types an RMagick image (#rows, #columns, #to_blob), so that Gosu will import it.
123
+ class ImageStub
124
+
125
+ # @return [Integer]
126
+ attr_reader :rows, :columns
127
+
128
+ # The first pixel in the blob will be at the top left hand corner of the created image, since that is the orientation
129
+ # of Gosu images.
130
+ #
131
+ # @param [String] blob_data Raw data string to import. Must be RGBA ordered, (4 * width * height) bytes in length.
132
+ # @param [Integer] width Number of pixels wide.
133
+ # @param [Integer] height Number of pixels high.
134
+ def initialize(blob_data, width, height)
135
+ @data, @columns, @rows = blob_data, width, height
136
+ end
137
+
138
+ # @return [String]
139
+ def to_blob
140
+ @data
141
+ end
142
+ end
143
+
144
+ # Used internally to create blank images (red/blue/green/alpha all 0) (TexPlay::create_image).
145
+ #
146
+ # Credit to philomory for this class.
147
+ class EmptyImageStub < ImageStub
148
+ # @param width (see ImageStub#initialize)
149
+ # @param height (see ImageStub#initialize)
150
+ def initialize(width, height)
151
+ raise ArgumentError if (width > TexPlay::TP_MAX_QUAD_SIZE || height > TexPlay::TP_MAX_QUAD_SIZE)
152
+ super("\0" * (width * height * 4), width, height)
153
+ end
154
+ end
155
+ end
156
+
157
+ require "#{direc}/texplay-contrib"
158
+
159
+ # monkey patching the Gosu::Image class to add image manipulation functionality
160
+ module Gosu
161
+ class Image
162
+
163
+ # bring in the TexPlay image manipulation methods
164
+ include TexPlay
165
+
166
+ attr_reader :__window__
167
+ protected :__window__
168
+
169
+ class << self
170
+ alias_method :original_new, :new
171
+
172
+ def new(*args, &block)
173
+
174
+ options = args.last.is_a?(Hash) ? args.pop : {}
175
+ # invoke old behaviour
176
+ obj = original_new(*args, &block)
177
+
178
+ prepare_image(obj, args.first, options)
179
+ end
180
+
181
+ alias_method :original_from_text, :from_text
182
+
183
+ def from_text(*args, &block)
184
+
185
+ options = args.last.is_a?(Hash) ? args.pop : {}
186
+ # invoke old behaviour
187
+ obj = original_from_text(*args, &block)
188
+
189
+ prepare_image(obj, args.first, options)
190
+ end
191
+
192
+ def prepare_image(obj, window, options={})
193
+ options = {
194
+ :caching => TexPlay.get_options[:caching]
195
+ }.merge!(options)
196
+
197
+ caching_mode = options[:caching]
198
+
199
+ # we can't manipulate large images, so skip them.
200
+ if obj.width <= (TexPlay::TP_MAX_QUAD_SIZE) &&
201
+ obj.height <= (TexPlay::TP_MAX_QUAD_SIZE)
202
+
203
+ if caching_mode
204
+ if caching_mode == :lazy
205
+
206
+ # only cache if quad already cached (to refresh old data)
207
+ # otherwise cache lazily at point of first TexPlay call
208
+ obj.refresh_cache if obj.quad_cached?
209
+
210
+ else
211
+
212
+ # force a cache - this obviates the need for a
213
+ # potentialy expensive runtime cache of the image by
214
+ # moving the cache to load-time
215
+ obj.refresh_cache
216
+ end
217
+ end
218
+ end
219
+
220
+ # run custom setup
221
+ TexPlay.setup(obj)
222
+
223
+ obj.instance_variable_set(:@__window__, window)
224
+
225
+ obj
226
+ end
227
+
228
+ private :prepare_image
229
+ end
230
+
231
+ alias_method :rows, :height
232
+ alias_method :columns, :width
233
+ end
234
+
235
+ class Window
236
+ # Render directly into an existing image, optionally only to a specific region of that image.
237
+ #
238
+ # Since this operation utilises the window's back buffer, the image (or clipped area, if specified) cannot be larger than the
239
+ # window itself. Larger images can be rendered to only in separate sections using :clip_to areas, each no larger
240
+ # than the window).
241
+ #
242
+ # @note *Warning!* This operation will corrupt an area of the screen, at the bottom left corner, equal in size to the image rendered to (or the clipped area), so should be performed in #draw _before_ any other rendering.
243
+ #
244
+ # @note The final alpha of the image will be 255, regardless of what it started with or what is drawn onto it.
245
+ #
246
+ # @example
247
+ # class Gosu
248
+ # class Window
249
+ # def draw
250
+ # # Always render images before regular drawing to the screen.
251
+ # unless @rendered_image
252
+ # @rendered_image = TexPlay.create_image(self, 300, 300, :color => :blue)
253
+ # render_to_image(@rendered_image) do
254
+ # @an_image.draw 0, 0, 0
255
+ # @another_image.draw 130, 0, 0
256
+ # draw_line(0, 0, Color.new(255, 0, 0, 0), 100, 100, Color.new(255, 0, 0, 0), 0)
257
+ # @font.draw("Hello world!", 0, 50, 0)
258
+ # end
259
+ # end
260
+ #
261
+ # # Perform regular screen rendering.
262
+ # @rendered_image.draw 0, 0
263
+ # end
264
+ # end
265
+ # end
266
+ #
267
+ #
268
+ # @param [Gosu::Image] image Existing image to render onto.
269
+ # @option options [Array<Integer>] :clip_to ([0, 0, image.width, image.height]) Area of the image to render into. This area cannot be larger than the window, though the image may be.
270
+ # @return [Gosu::Image] The image that has been rendered to.
271
+ # @yield to a block that renders to the image.
272
+ def render_to_image(image, options = {})
273
+ raise ArgumentError, "image parameter must be a Gosu::Image to be rendered to" unless image.is_a? Gosu::Image
274
+ raise ArgumentError, "rendering block required" unless block_given?
275
+
276
+ options = {
277
+ :clip_to => [0, 0, image.width, image.height],
278
+ }.merge! options
279
+
280
+ texture_info = image.gl_tex_info
281
+ tex_name = texture_info.tex_name
282
+ x_offset = (texture_info.left * Gosu::MAX_TEXTURE_SIZE).to_i
283
+ y_offset = (texture_info.top * Gosu::MAX_TEXTURE_SIZE).to_i
284
+
285
+ raise ArgumentError, ":clip_to rectangle must contain exactly 4 elements" unless options[:clip_to].size == 4
286
+
287
+ left, top, width, height = *(options[:clip_to].map {|n| n.to_i })
288
+
289
+ raise ArgumentError, ":clip_to rectangle cannot be wider or taller than the window" unless width <= self.width and height <= self.height
290
+ raise ArgumentError, ":clip_to rectangle width and height must be positive" unless width > 0 and height > 0
291
+
292
+ right = left + width - 1
293
+ bottom = top + height - 1
294
+
295
+ unless (0...image.width).include? left and (0...image.width).include? right and
296
+ (0...image.height).include? top and (0...image.height).include? bottom
297
+ raise ArgumentError, ":clip_to rectangle out of bounds of the image"
298
+ end
299
+
300
+ # Since to_texture copies an inverted copy of the screen, what the user renders needs to be inverted first.
301
+ scale(1, -1) do
302
+ translate(-left, -top - self.height) do
303
+ # TODO: Once Gosu is fixed, we can just pass width/height to clip_to
304
+ clip_to(left, top, width, height) do
305
+ # Draw over the background (which is assumed to be blank) with the original image texture,
306
+ # to get us to the base image.
307
+ image.draw(0, 0, 0)
308
+ flush
309
+
310
+ # Allow the user to overwrite the texture.
311
+ yield
312
+ end
313
+
314
+ # Copy the modified texture back from the screen buffer to the image.
315
+ to_texture(tex_name, x_offset + left, y_offset + top, 0, 0, width, height)
316
+
317
+ # Clear the clipped zone to black again, ready for the regular screen drawing.
318
+ # Quad can be a pixel out, so just make sure with a slightly larger shape.
319
+ draw_quad(left - 2, top - 2, TexPlay::RENDER_CLEAR_COLOR,
320
+ right + 2, top - 2, TexPlay::RENDER_CLEAR_COLOR,
321
+ right + 2, bottom + 2, TexPlay::RENDER_CLEAR_COLOR,
322
+ left - 2, bottom + 2, TexPlay::RENDER_CLEAR_COLOR)
323
+ end
324
+ end
325
+
326
+ image
327
+ end
328
+ end
329
+ end
330
+
331
+ # a bug in ruby 1.8.6 rb_eval_string() means i must define this here (rather than in texplay.c)
332
+ class Proc
333
+ def __context__
334
+ eval('self', self.binding)
335
+ end
336
+ end
337
+
338
+
339
+ # initialize TP (at the moment just setting some default settings)
340
+ TexPlay.init
341
+