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
@@ -1,60 +1,60 @@
1
- #ifndef GUARD_ACTIONS_H
2
- #define GUARD_ACTIONS_H
3
-
4
- #include "texplay.h"
5
-
6
- /* used by line_do_action */
7
- typedef struct {
8
- int x, y;
9
- rgba color;
10
- } trace_match;
11
-
12
-
13
- /* lines */
14
- trace_match line_do_action(int, int, int, int, texture_info *, VALUE, sync, bool primary, action_struct * payload);
15
-
16
- /* circles */
17
- void circle_do_action(int, int, int, texture_info *, VALUE, sync, bool primary, action_struct * payload);
18
-
19
- /* pixels */
20
- void pixel_do_action(int, int, texture_info *, VALUE, sync, bool primary, action_struct * payload);
21
-
22
- /* rectangles */
23
- void rect_do_action(int x1, int y1, int x2, int y2, texture_info * tex, VALUE hash_arg,
24
- sync sync_mode, bool primary, action_struct * payload);
25
-
26
- /* flood fill */
27
- void flood_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg, sync sync_mode, bool primary,
28
- action_struct * payload);
29
-
30
- /* glow fill */
31
- void glow_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg, sync sync_mode, bool primary,
32
- action_struct * payload);
33
-
34
- /* scan fill */
35
- void scan_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg,
36
- sync sync_mode, bool primary, action_struct * payload);
37
-
38
- /* polyline */
39
- void polyline_do_action(VALUE points, texture_info * tex, VALUE hash_arg, sync sync_mode, bool primary,
40
- action_struct * payload);
41
-
42
- /* bezier */
43
- void bezier_do_action(VALUE points, texture_info * tex, VALUE hash_arg, sync sync_mode, bool primary,
44
- action_struct * payload);
45
-
46
- /* ngon */
47
- void ngon_do_action(int x, int y, int r, int num_sides, texture_info * tex, VALUE hash_arg,
48
- sync sync_mode, bool primary, action_struct * payload);
49
-
50
-
51
- /* splice */
52
- void splice_do_action(int x0,int y0, int cx1, int cy1, int cx2, int cy2, texture_info * splice_tex,
53
- texture_info * tex, VALUE hash_arg, sync sync_mode,
54
- bool primary, action_struct * payload);
55
-
56
- /* each iterator */
57
- void each_pixel_do_action(int x1, int y1, int x2, int y2, VALUE proc, texture_info * tex, VALUE hash_arg,
58
- sync sync_mode, bool primary, action_struct * payload);
59
-
60
- #endif
1
+ #ifndef GUARD_ACTIONS_H
2
+ #define GUARD_ACTIONS_H
3
+
4
+ #include "texplay.h"
5
+
6
+ /* used by line_do_action */
7
+ typedef struct {
8
+ int x, y;
9
+ rgba color;
10
+ } trace_match;
11
+
12
+
13
+ /* lines */
14
+ trace_match line_do_action(int, int, int, int, texture_info *, VALUE, sync, bool primary, action_struct * payload);
15
+
16
+ /* circles */
17
+ void circle_do_action(int, int, int, texture_info *, VALUE, sync, bool primary, action_struct * payload);
18
+
19
+ /* pixels */
20
+ void pixel_do_action(int, int, texture_info *, VALUE, sync, bool primary, action_struct * payload);
21
+
22
+ /* rectangles */
23
+ void rect_do_action(int x1, int y1, int x2, int y2, texture_info * tex, VALUE hash_arg,
24
+ sync sync_mode, bool primary, action_struct * payload);
25
+
26
+ /* flood fill */
27
+ void flood_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg, sync sync_mode, bool primary,
28
+ action_struct * payload);
29
+
30
+ /* glow fill */
31
+ void glow_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg, sync sync_mode, bool primary,
32
+ action_struct * payload);
33
+
34
+ /* scan fill */
35
+ void scan_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg,
36
+ sync sync_mode, bool primary, action_struct * payload);
37
+
38
+ /* polyline */
39
+ void polyline_do_action(VALUE points, texture_info * tex, VALUE hash_arg, sync sync_mode, bool primary,
40
+ action_struct * payload);
41
+
42
+ /* bezier */
43
+ void bezier_do_action(VALUE points, texture_info * tex, VALUE hash_arg, sync sync_mode, bool primary,
44
+ action_struct * payload);
45
+
46
+ /* ngon */
47
+ void ngon_do_action(int x, int y, int r, int num_sides, texture_info * tex, VALUE hash_arg,
48
+ sync sync_mode, bool primary, action_struct * payload);
49
+
50
+
51
+ /* splice */
52
+ void splice_do_action(int x0,int y0, int cx1, int cy1, int cx2, int cy2, texture_info * splice_tex,
53
+ texture_info * tex, VALUE hash_arg, sync sync_mode,
54
+ bool primary, action_struct * payload);
55
+
56
+ /* each iterator */
57
+ void each_pixel_do_action(int x1, int y1, int x2, int y2, VALUE proc, texture_info * tex, VALUE hash_arg,
58
+ sync sync_mode, bool primary, action_struct * payload);
59
+
60
+ #endif
@@ -1,1186 +1,1125 @@
1
- #include <ruby.h>
2
- #include <stdio.h>
3
- #include <string.h>
4
- #include <ctype.h>
5
- #include <math.h>
6
- #include <stdlib.h>
7
- #include <assert.h>
8
- #include <stdarg.h>
9
-
10
- #ifdef __APPLE__
11
- # include <glut.h>
12
- #else
13
- # include <GL/glut.h>
14
- #endif
15
-
16
- #include "texplay.h"
17
- #include "utils.h"
18
- #include "graphics_utils.h"
19
- #include "bindings.h"
20
- #include "actions.h"
21
- #include "cache.h"
22
- #include "compat.h"
23
-
24
- /* associated with gen_eval */
25
- #include "object2module.h"
26
- #include "gen_eval.h"
27
-
28
- /* syncing mode */
29
- /* lazy_sync = sync at end of paint block */
30
- /* eager_sync = sync immediately (after action) */
31
- /* no_sync = do not sync at all */
32
- sync sync_mode = eager_sync;
33
-
34
- static void
35
- process_x_y_pairs(VALUE image, int num_pairs, VALUE * argv, ...)
36
- {
37
- va_list ap;
38
- int i;
39
- int draw_offset_x;
40
- int draw_offset_y;
41
- VALUE offset_val;
42
-
43
- offset_val = get_image_local(image, DRAW_OFFSET);
44
-
45
- draw_offset_x = NUM2INT(get_from_array(offset_val, 0));
46
- draw_offset_y = NUM2INT(get_from_array(offset_val, 1));
47
-
48
- va_start(ap, argv);
49
- if(is_a_point(argv[0])) {
50
- for(i = 0; i < num_pairs; i++) {
51
- int *x_ptr, *y_ptr;
52
-
53
- x_ptr = va_arg(ap, int*);
54
- y_ptr = va_arg(ap, int*);
55
-
56
- *x_ptr = NUM2INT(rb_funcall(argv[i], rb_intern("x"), 0)) + draw_offset_x;
57
- *y_ptr = NUM2INT(rb_funcall(argv[i], rb_intern("y"), 0)) + draw_offset_y;
58
- }
59
- }
60
- else {
61
- for(i = 0; i < (num_pairs * 2); i+=2) {
62
- int *x_ptr, *y_ptr;
63
-
64
- x_ptr = va_arg(ap, int*);
65
- y_ptr = va_arg(ap, int*);
66
-
67
- *x_ptr = NUM2INT(argv[i]) + draw_offset_x;
68
- *y_ptr = NUM2INT(argv[i + 1]) + draw_offset_y;
69
- }
70
- }
71
- va_end(ap);
72
- }
73
-
74
-
75
- /* singleton methods */
76
-
77
- /* responsible for creating macros */
78
- VALUE
79
- M_create_macro(VALUE self, VALUE method_name)
80
- {
81
- VALUE proc;
82
-
83
- rb_need_block();
84
-
85
- /* convert the block to a proc */
86
- proc = rb_block_proc();
87
-
88
- /* define the method in the TexPlay class so that it is accessible to 'instances' */
89
- rb_funcall(self, rb_intern("define_method"), 2, method_name, proc);
90
-
91
- return Qnil;
92
- }
93
-
94
-
95
- /* responsible for removing macros */
96
- VALUE
97
- M_remove_macro(VALUE self, VALUE method_name)
98
- {
99
-
100
- /* remove the method in the TexPlay class */
101
- rb_funcall(self, rb_intern("remove_method"), 1, method_name);
102
-
103
- return Qnil;
104
- }
105
-
106
- /* responsible for refreshing all entries in cache */
107
- VALUE
108
- M_refresh_cache_all(VALUE self)
109
- {
110
- cache_refresh_all();
111
-
112
- return Qnil;
113
- }
114
-
115
- /* VALUE */
116
- /* M_screenshot(VALUE self, VALUE x, VALUE y, VALUE width, VALUE width) */
117
- /* { */
118
- /* texture_info tex; */
119
- /* int sidelength; */
120
- /* int rb_x = FIX2INT(x); */
121
- /* int rb_y = FIX2INT(y); */
122
- /* int rb_width = FIX2INT(width); */
123
- /* int rb_height = FIX2INT(height); */
124
-
125
- /* VALUE blob = rb_str_new(NULL, 4 * rb_width * rb_height); */
126
-
127
- /* glReadPixels(rb_x, rb_y, rb_width, rb_height, GL_RGBA, GL_UNSIGNED_BYTE, RSTRING_PTR(blob)); */
128
-
129
- /* return blob; */
130
- /* } */
131
-
132
-
133
- /* creates a blank image */
134
- /* VALUE */
135
- /* M_create_blank(VALUE self, VALUE window, VALUE width, VALUE height) */
136
- /* { */
137
- /* VALUE fresh_image; */
138
-
139
- /* fresh_image = create_image(window, NUM2INT(width), NUM2INT(height)); */
140
-
141
- /* return fresh_image; */
142
- /* } */
143
- /** end singleton methods **/
144
-
145
- /* some helper methods */
146
- static void
147
- rb_lazy_bounds_to_image_bounds(VALUE image, image_bounds * bounds)
148
- {
149
- VALUE lazy_bounds;
150
-
151
- lazy_bounds = get_image_local(image, LAZY_BOUNDS);
152
-
153
- Check_Type(lazy_bounds, T_ARRAY);
154
-
155
- bounds->xmin = FIX2INT(get_from_array(lazy_bounds, 0));
156
- bounds->ymin = FIX2INT(get_from_array(lazy_bounds, 1));
157
- bounds->xmax = FIX2INT(get_from_array(lazy_bounds, 2));
158
- bounds->ymax = FIX2INT(get_from_array(lazy_bounds, 3));
159
- }
160
-
161
- static VALUE
162
- parse_sync_mode(VALUE user_sync_mode)
163
- {
164
- sync mode;
165
-
166
- Check_Type(user_sync_mode, T_SYMBOL);
167
-
168
- if(user_sync_mode == string2sym("lazy_sync"))
169
- mode = lazy_sync;
170
- else if(user_sync_mode == string2sym("eager_sync"))
171
- mode = eager_sync;
172
- else if(user_sync_mode == string2sym("no_sync"))
173
- mode = no_sync;
174
- else
175
- rb_raise(rb_eArgError, "unrecognized sync mode: %s\n. Allowable modes are "
176
- ":lazy_sync, :eager_sync, :no_sync.",
177
- sym2string(user_sync_mode));
178
-
179
- return mode;
180
- }
181
- /* end helpers */
182
-
183
- /* entry point for TexPlay paint actions */
184
- VALUE
185
- m_paint(int argc, VALUE * argv, VALUE self)
186
- {
187
- texture_info tex;
188
- VALUE options;
189
- image_bounds bounds;
190
- int arity;
191
-
192
- ADJUST_SELF(self);
193
-
194
- rb_scan_args(argc, argv, "01", &options);
195
-
196
- /* get texture info from image */
197
- get_texture_info(self, &tex);
198
-
199
- /* set default sync_mode to lazy */
200
- sync_mode = lazy_sync;
201
-
202
- /* parse sync_mode, overriding lazy sync mode? */
203
- if(has_optional_hash_arg(options, "sync_mode")) {
204
- VALUE user_sync_mode = get_from_hash(options, "sync_mode");
205
- sync_mode = parse_sync_mode(user_sync_mode);
206
- }
207
-
208
- /* if no block then just sync */
209
- if(!rb_block_given_p()) {
210
-
211
- rb_lazy_bounds_to_image_bounds(self, &bounds);
212
-
213
- create_subtexture_and_sync_to_gl(&bounds, &tex);
214
-
215
- /* reset the LAZY_BOUNDS now we've sync'd */
216
- set_image_local(self, LAZY_BOUNDS, Qnil);
217
-
218
- sync_mode = eager_sync;
219
-
220
- return self;
221
- }
222
-
223
- /* find arity of block */
224
- arity = FIX2INT(rb_funcall(rb_block_proc(), rb_intern("arity"), 0));
225
-
226
- /* yield self if the arity is 1, else gen_eval the block */
227
- switch(arity) {
228
- case -1:
229
- case 0:
230
- rb_gen_eval(0, 0, self);
231
- break;
232
- case 1:
233
- rb_yield(self);
234
- break;
235
- default:
236
- rb_raise(rb_eArgError, "block arity must be either 1 or -1 or 0, received arity of: %d", arity);
237
- }
238
-
239
- /* if lazy sync is selected then sync now..as the paint block has finished executing the draw actions*/
240
- if(sync_mode == lazy_sync) {
241
-
242
- rb_lazy_bounds_to_image_bounds(self, &bounds);
243
-
244
- create_subtexture_and_sync_to_gl(&bounds, &tex);
245
-
246
- /* reset the LAZY_BOUNDS now we've sync'd */
247
- set_image_local(self, LAZY_BOUNDS, Qnil);
248
-
249
- }
250
-
251
- /* now we've finished the paint block we reset the default sync_mode back to eager */
252
- sync_mode = eager_sync;
253
-
254
- return self;
255
- }
256
-
257
- VALUE
258
- m_force_sync(VALUE self, VALUE ary)
259
- {
260
- image_bounds bounds;
261
- texture_info tex;
262
-
263
- ADJUST_SELF(self);
264
-
265
- Check_Type(ary, T_ARRAY);
266
-
267
- get_texture_info(self, &tex);
268
-
269
- bounds.xmin = NUM2INT(get_from_array(ary, 0));
270
- bounds.ymin = NUM2INT(get_from_array(ary, 1));
271
- bounds.xmax = NUM2INT(get_from_array(ary, 2));
272
- bounds.ymax = NUM2INT(get_from_array(ary, 3));
273
-
274
- create_subtexture_and_sync_to_gl(&bounds, &tex);
275
-
276
- return Qnil;
277
- }
278
-
279
- VALUE
280
- m_dup_image(VALUE self)
281
- {
282
- texture_info tex, dup_tex;
283
- VALUE dupped_image;
284
- VALUE window;
285
-
286
- ADJUST_SELF(self);
287
-
288
- get_texture_info(self, &tex);
289
-
290
- window = rb_funcall(self, rb_intern("__window__"), 0);
291
-
292
- /* create a new blank image with the height/width of the current image */
293
- dupped_image = create_image(window, tex.width, tex.height);
294
-
295
- /* get the new image's data */
296
- get_texture_info(dupped_image, &dup_tex);
297
-
298
- /* splice into the new image content from the current image, and sync it to gl */
299
- splice_do_action(0, 0, 0, 0, XMAX_OOB, YMAX_OOB, &tex, &dup_tex, Qnil, eager_sync, true, NULL);
300
-
301
- /* copy across the ivars too! */
302
- rb_copy_generic_ivar(dupped_image, self);
303
-
304
- /* we now have a full dup of the current image, return it */
305
- return dupped_image;
306
- }
307
-
308
- VALUE
309
- m_clone_image(VALUE self)
310
- {
311
- VALUE cloned_image;
312
-
313
- ADJUST_SELF(self);
314
-
315
- cloned_image = m_dup_image(self);
316
-
317
- /* the main diff b/w clone and dup is that clone also dups the singleton */
318
- KLASS_OF(cloned_image) = rb_singleton_class_clone(self);
319
-
320
- return cloned_image;
321
- }
322
-
323
- VALUE
324
- m_user_set_options(VALUE self, VALUE options)
325
- {
326
- ADJUST_SELF(self);
327
-
328
- if(!is_a_hash(options))
329
- rb_raise(rb_eArgError, "only a single hash argument is accepted");
330
-
331
- set_image_local(self, USER_DEFAULTS, options);
332
-
333
- return Qnil;
334
- }
335
-
336
- VALUE
337
- m_user_delete_options(VALUE self)
338
- {
339
-
340
- ADJUST_SELF(self);
341
-
342
- set_image_local(self, USER_DEFAULTS, Qnil);
343
-
344
- return Qnil;
345
- }
346
-
347
- VALUE
348
- m_get_options(VALUE self)
349
- {
350
- ADJUST_SELF(self);
351
-
352
- return get_image_local(self, USER_DEFAULTS);
353
- }
354
-
355
- static void
356
- get_image_chunk_with_size(char * data, texture_info * tex, char * blob)
357
- {
358
- for(int y = 0; y < tex->height; y++)
359
- for(int x = 0; x < tex->width; x++) {
360
- int buf_index = 4 * (x + y * tex->width);
361
-
362
- int offset = calc_pixel_offset(tex, x, y);
363
-
364
- memcpy(blob + buf_index, data + offset, 4);
365
- }
366
- }
367
-
368
-
369
-
370
- VALUE
371
- m_to_blob(VALUE self)
372
- {
373
- texture_info tex;
374
- int sidelength;
375
-
376
- ADJUST_SELF(self);
377
-
378
- get_texture_info(self, &tex);
379
-
380
- glEnable(GL_TEXTURE_2D);
381
- glBindTexture(GL_TEXTURE_2D, tex.tname);
382
-
383
- /* get length of a side, since square texture */
384
- glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &sidelength);
385
-
386
- /* initialize texture data array, mult. by 4 because {rgba} */
387
- char new_array[sidelength * sidelength * 4];
388
-
389
- /* get texture data from video memory */
390
- glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE,(void*)(new_array));
391
-
392
- VALUE blob = rb_str_new(NULL, 4 * tex.width * tex.height);
393
-
394
- get_image_chunk_with_size(new_array, &tex, RSTRING_PTR(blob));
395
-
396
- glDisable(GL_TEXTURE_2D);
397
-
398
- return blob;
399
- }
400
-
401
- /* return the pixel colour for the given x, y */
402
- VALUE
403
- m_getpixel(int argc, VALUE * argv, VALUE self)
404
- {
405
- int x1, y1;
406
- int last = argc - 1;
407
- texture_info tex;
408
- rgba pix;
409
- bool gosu_color_mode = false;
410
- VALUE options;
411
-
412
-
413
- /* change self to hidden self if using gen_eval */
414
- ADJUST_SELF(self);
415
-
416
- process_x_y_pairs(self, 1, argv, &x1, &y1);
417
-
418
- /* get texture info */
419
- get_texture_info(self, &tex);
420
-
421
- options = argv[last];
422
-
423
- if (hash_value_is(options, "color_mode", string2sym("gosu")))
424
- gosu_color_mode = true;
425
-
426
- /* locate the desired pixel; */
427
- pix = get_pixel_color(&tex, x1, y1);
428
-
429
- if(not_a_color(pix))
430
- return Qnil;
431
- else {
432
- if (gosu_color_mode)
433
- return convert_rgba_to_gosu_color(&pix);
434
- else
435
- return convert_rgba_to_rb_color(&pix);
436
- }
437
- }
438
-
439
- /* circle action */
440
- VALUE
441
- m_circle(int argc, VALUE * argv, VALUE self)
442
- {
443
- int x1, y1, r;
444
- int last = argc - 1;
445
- VALUE options;
446
- texture_info tex;
447
-
448
- ADJUST_SELF(self);
449
-
450
- if(argc < 2) rb_raise(rb_eArgError, "circle action needs at least 2 parameter");
451
-
452
- process_x_y_pairs(self, 1, argv, &x1, &y1);
453
-
454
- if(is_a_point(argv[0]))
455
- r = NUM2INT(argv[1]);
456
- else
457
- r = NUM2INT(argv[2]);
458
-
459
- options = argv[last];
460
-
461
- get_texture_info(self, &tex);
462
-
463
- circle_do_action(x1, y1, r, &tex, options, sync_mode, true, NULL);
464
-
465
- return self;
466
- }
467
-
468
- /* ngon */
469
- VALUE
470
- m_ngon(int argc, VALUE * argv, VALUE self)
471
- {
472
- int x1, y1, r, n;
473
- int last = argc - 1;
474
- VALUE options;
475
- texture_info tex;
476
-
477
- ADJUST_SELF(self);
478
-
479
- if(argc < 3) rb_raise(rb_eArgError, "ngon requires at least 3 parameters (x, y, radius, num_sides)");
480
-
481
- process_x_y_pairs(self, 1, argv, &x1, &y1);
482
-
483
- options = argv[last];
484
-
485
- get_texture_info(self, &tex);
486
-
487
- r = NUM2INT(argv[2]);
488
- n = NUM2INT(argv[3]);
489
-
490
- ngon_do_action(x1, y1, r, n, &tex, options, sync_mode, true, NULL);
491
-
492
- return self;
493
- }
494
-
495
-
496
- /* flood fill action */
497
- VALUE
498
- m_flood_fill(int argc, VALUE * argv, VALUE self)
499
- {
500
- int x1, y1;
501
- int last = argc - 1;
502
- VALUE options;
503
- texture_info tex;
504
- bool iter = false, glow = false;
505
-
506
- ADJUST_SELF(self);
507
-
508
- if (argc < 1) rb_raise(rb_eArgError, "flood fill action needs at least 1 parameter");
509
-
510
- process_x_y_pairs(self, 1, argv, &x1, &y1);
511
-
512
- options = argv[last];
513
-
514
- get_texture_info(self, &tex);
515
-
516
- if(is_a_hash(options)) {
517
- if(RTEST(get_from_hash(options, "iter")))
518
- iter = true;
519
- if(RTEST(get_from_hash(options, "glow")))
520
- glow = true;
521
- }
522
-
523
- if(iter) {
524
- flood_fill_do_action(x1, y1, &tex, options, sync_mode, true, NULL);
525
- }
526
- else if(glow) {
527
- glow_fill_do_action(x1, y1, &tex, options, sync_mode, true, NULL);
528
-
529
- }
530
- /* this is the default fill */
531
- else {
532
- scan_fill_do_action(x1, y1, &tex, options, sync_mode, true, NULL);
533
- }
534
-
535
- return self;
536
- }
537
-
538
- static inline VALUE
539
- convert_trace_match_to_ruby_array(trace_match match, bool gosu_color_mode)
540
- {
541
- VALUE ary = rb_ary_new();
542
-
543
- rb_ary_store(ary, 0, INT2FIX(match.x));
544
- rb_ary_store(ary, 1, INT2FIX(match.y));
545
-
546
- if (gosu_color_mode)
547
- rb_ary_store(ary, 2, convert_rgba_to_gosu_color(&match.color));
548
- else
549
- rb_ary_store(ary, 2, convert_rgba_to_rb_color(&match.color));
550
-
551
- return ary;
552
- }
553
-
554
- /* line action */
555
- VALUE
556
- m_line(int argc, VALUE * argv, VALUE self)
557
- {
558
- int x1, y1, x2, y2;
559
- int last = argc - 1;
560
- bool gosu_color_mode = false;
561
- VALUE options;
562
- texture_info tex;
563
- trace_match match;
564
-
565
- ADJUST_SELF(self);
566
-
567
- if(argc < 2) rb_raise(rb_eArgError, "line action needs at least 2 parameters");
568
-
569
- process_x_y_pairs(self, 2, argv, &x1, &y1, &x2, &y2);
570
-
571
- options = argv[last];
572
-
573
- if (hash_value_is(options, "color_mode", string2sym("gosu")))
574
- gosu_color_mode = true;
575
-
576
- get_texture_info(self, &tex);
577
-
578
- match = line_do_action(x1, y1, x2, y2, &tex, options, sync_mode, true, NULL);
579
-
580
- if (has_optional_hash_arg(options, "trace")) {
581
- if (match.x == -9999)
582
- return Qnil;
583
- else
584
- return convert_trace_match_to_ruby_array(match, gosu_color_mode);
585
- }
586
-
587
- return self;
588
- }
589
-
590
- /* box action */
591
- VALUE
592
- m_rect(int argc, VALUE * argv, VALUE self)
593
- {
594
-
595
- int x1, y1, x2, y2;
596
- int last = argc - 1;
597
- VALUE options;
598
- texture_info tex;
599
-
600
- ADJUST_SELF(self);
601
-
602
- if(argc < 2) rb_raise(rb_eArgError, "rect action needs at least 2 parameters");
603
-
604
- process_x_y_pairs(self, 2, argv, &x1, &y1, &x2, &y2);
605
-
606
- options = argv[last];
607
-
608
- get_texture_info(self, &tex);
609
-
610
- rect_do_action(x1, y1, x2, y2, &tex, options, sync_mode, true, NULL);
611
-
612
- return self;
613
- }
614
-
615
-
616
- /* pixel action */
617
- VALUE
618
- m_pixel(int argc, VALUE * argv, VALUE self)
619
- {
620
- int x1, y1;
621
- int last = argc - 1;
622
- VALUE options;
623
- texture_info tex;
624
-
625
- ADJUST_SELF(self);
626
-
627
- if(argc < 1) rb_raise(rb_eArgError, "pixel action needs 1 parameter");
628
-
629
- process_x_y_pairs(self, 1, argv, &x1, &y1);
630
-
631
- options = argv[last];
632
-
633
- get_texture_info(self, &tex);
634
-
635
- pixel_do_action(x1, y1, &tex, options, sync_mode, true, NULL);
636
-
637
- return self;
638
- }
639
-
640
- /* bezier curve */
641
- VALUE
642
- m_bezier(int argc, VALUE * argv, VALUE self)
643
- {
644
- VALUE points = Qnil;
645
- VALUE options = Qnil;
646
- int last = argc - 1;
647
- texture_info tex;
648
-
649
- ADJUST_SELF(self);
650
-
651
- if(argc < 1) rb_raise(rb_eArgError, "bezier action needs at least 1 parameter");
652
-
653
- /* get array of points */
654
- points = argv[0];
655
- Check_Type(points, T_ARRAY);
656
-
657
- options = argv[last];
658
-
659
- get_texture_info(self, &tex);
660
-
661
- bezier_do_action(points, &tex, options, sync_mode, true, NULL);
662
-
663
- return self;
664
- }
665
-
666
- /* bezier curve */
667
- VALUE
668
- m_polyline(int argc, VALUE * argv, VALUE self)
669
- {
670
- VALUE points = Qnil;
671
- VALUE options = Qnil;
672
- int last = argc - 1;
673
- texture_info tex;
674
-
675
- ADJUST_SELF(self);
676
-
677
- if(argc < 1) rb_raise(rb_eArgError, "polyline action needs at least 1 parameter");
678
-
679
- /* get array of points */
680
- points = argv[0];
681
- Check_Type(points, T_ARRAY);
682
-
683
- options = argv[last];
684
-
685
- get_texture_info(self, &tex);
686
-
687
- polyline_do_action(points, &tex, options, sync_mode, true, NULL);
688
-
689
- return self;
690
- }
691
-
692
-
693
-
694
- /* splice action */
695
- VALUE
696
- m_splice(int argc, VALUE * argv, VALUE self)
697
- {
698
- int x0, y0;
699
- int cx1 = 0, cy1 = 0, cx2 = XMAX_OOB, cy2 = YMAX_OOB;
700
- texture_info splice_tex;
701
- int last = argc - 1;
702
- texture_info tex;
703
- VALUE options;
704
-
705
- ADJUST_SELF(self);
706
-
707
- if(argc < 3) rb_raise(rb_eArgError, "splice action needs at least 3 parameters");
708
-
709
- if(!is_gosu_image(argv[0]))
710
- rb_raise(rb_eArgError, "first parameter must be a valid Gosu::Image");
711
-
712
- /* get the splice image */
713
- get_texture_info(argv[0], &splice_tex);
714
-
715
- /* add 1 to argv to skip the Image parameter */
716
- process_x_y_pairs(self, 1, argv + 1, &x0, &y0);
717
-
718
- /* get the hash args */
719
- options = argv[last];
720
-
721
- get_texture_info(self, &tex);
722
-
723
- /* get the crop boundaries */
724
- if(is_a_hash(options))
725
- if(RTEST(get_from_hash(options, "crop"))) {
726
- VALUE c = get_from_hash(options, "crop");
727
- Check_Type(c, T_ARRAY);
728
- cx1 = NUM2INT(get_from_array(c, 0));
729
- cy1 = NUM2INT(get_from_array(c, 1));
730
- cx2 = NUM2INT(get_from_array(c, 2));
731
- cy2 = NUM2INT(get_from_array(c, 3));
732
- }
733
-
734
- splice_do_action(x0, y0, cx1, cy1, cx2, cy2, &splice_tex,
735
- &tex, options, sync_mode, true, NULL);
736
-
737
- return self;
738
- }
739
-
740
-
741
- /* clear action - really just an alias for box */
742
- VALUE
743
- m_clear(int argc, VALUE * argv, VALUE self)
744
- {
745
- VALUE parms[4];
746
-
747
- parms[0] = INT2NUM(0);
748
- parms[1] = INT2NUM(0);
749
- parms[2] = INT2NUM(XMAX_OOB);
750
- parms[3] = INT2NUM(YMAX_OOB);
751
-
752
- // m_box(ARY_SIZE(parms), parms, self);
753
-
754
- return self;
755
- }
756
-
757
- /* offset function */
758
- VALUE
759
- m_offset(int argc, VALUE * argv, VALUE self)
760
- {
761
- char * try_offset;
762
-
763
- ADJUST_SELF(self);
764
-
765
- if(argc == 0)
766
- return get_image_local(self, DRAW_OFFSET);
767
-
768
- switch(TYPE(argv[0])) {
769
-
770
- case T_ARRAY:
771
-
772
- set_image_local(self, DRAW_OFFSET, argv[0]);
773
- break;
774
- case T_SYMBOL:
775
- try_offset = sym2string(argv[0]);
776
-
777
- if(!strcmp("default", try_offset)) {
778
- set_image_local(self, DRAW_OFFSET, Qnil);
779
- }
780
- else {
781
- rb_raise(rb_eArgError, "no such offset defined: %s\n", try_offset);
782
- }
783
-
784
- break;
785
- default:
786
- rb_raise(rb_eArgError, "invalid offset. please use an array or :default.");
787
- }
788
- return Qnil;
789
- }
790
-
791
- /* color change */
792
- VALUE
793
- m_color(int argc, VALUE * argv, VALUE self)
794
- {
795
- VALUE first;
796
- rgba new_color;
797
-
798
- ADJUST_SELF(self);
799
-
800
- /* if no params then return action current color */
801
- if(argc == 0)
802
- return get_image_local(self, IMAGE_COLOR);
803
-
804
- /* otherwise set the action color */
805
- /* NB: we cannot just set image_local_color to 'first' because first may not be an array,
806
- it could also be a symbol */
807
-
808
- first = argv[0];
809
-
810
- new_color = convert_rb_color_to_rgba(first);
811
-
812
- /* im quite sure i DO want to set the color even if it is not_a_color.
813
- why ? consistency only
814
- (NB: not_a_color_v is skipped by the set_pixel_color routine */
815
-
816
- /* if(is_a_color(new_color)) */
817
-
818
- save_rgba_to_image_local_color(self, new_color);
819
-
820
- return Qnil;
821
- }
822
-
823
- /* this function manages all other method calls */
824
- VALUE
825
- m_missing(int argc, VALUE * argv, VALUE self)
826
- {
827
- char * action_name = lowercase(sym2string(argv[0]));
828
-
829
- /* try case insensitive version of action name */
830
- if(rb_respond_to(self, rb_intern(action_name))) {
831
- rb_funcall2(self, rb_intern(action_name), --argc, ++argv);
832
- }
833
- /* still no match? then method does not exist */
834
- else {
835
- rb_raise (rb_eRuntimeError, "unrecognized action: %s\n", action_name);
836
- }
837
-
838
- return self;
839
- }
840
-
841
- /* refreshes the cache */
842
- VALUE
843
- m_cache_refresh(VALUE self)
844
- {
845
- texture_info tex;
846
-
847
- ADJUST_SELF(self);
848
-
849
- get_texture_info(self, &tex);
850
-
851
- cache_refresh_entry(tex.tname);
852
-
853
- return self;
854
- }
855
-
856
- /* check whether img quad is already cached */
857
- VALUE
858
- m_quad_cached(VALUE self)
859
- {
860
- VALUE info, gc_state_off;
861
- int tex_name;
862
- cache_entry * entry;
863
-
864
- ADJUST_SELF(self);
865
-
866
- /* prevent weird segfault bug */
867
- gc_state_off = rb_gc_disable();
868
-
869
- /* ensure gl_tex_info returns non nil */
870
- info = check_for_texture_info(self);
871
-
872
- tex_name = FIX2INT(rb_funcall(info, rb_intern("tex_name"), 0));
873
-
874
- entry = find_in_cache(tex_name);
875
-
876
- /* only enable gc if was enabled on function entry */
877
- if(!gc_state_off) rb_gc_enable();
878
-
879
- return entry ? Qtrue : Qfalse;
880
- }
881
-
882
- /** m_each **/
883
- VALUE
884
- m_each(int argc, VALUE * argv, VALUE self)
885
- {
886
- int x1 = 0, y1 = 0, x2 = XMAX_OOB, y2 = YMAX_OOB;
887
- texture_info tex;
888
- VALUE proc;
889
- VALUE options = Qnil;
890
-
891
- rb_need_block();
892
-
893
- ADJUST_SELF(self);
894
-
895
- get_texture_info(self, &tex);
896
-
897
- if(argc >= 1) {
898
- options = argv[0];
899
- Check_Type(options, T_HASH);
900
- if(RTEST(get_from_hash(options, "region"))) {
901
- VALUE region = get_from_hash(options, "region");
902
- Check_Type(region, T_ARRAY);
903
-
904
- if(RARRAY_LEN(region) < 4)
905
- rb_raise(rb_eArgError, "region requires 4 elements");
906
-
907
- x1 = NUM2INT(get_from_array(region, 0));
908
- y1 = NUM2INT(get_from_array(region, 1));
909
- x2 = NUM2INT(get_from_array(region, 2));
910
- y2 = NUM2INT(get_from_array(region, 3));
911
-
912
- }
913
-
914
- }
915
-
916
- constrain_boundaries(&x1, &y1,
917
- &x2, &y2, tex.width, tex.height);
918
-
919
- proc = rb_block_proc();
920
-
921
- each_pixel_do_action(x1, y1, x2, y2, proc, &tex, options, sync_mode, true, NULL);
922
-
923
- return self;
924
- }
925
- /** end of each **/
926
-
927
- /** turtle drawing functions **/
928
- /* static VALUE */
929
- /* m_turtle_move_to */
930
-
931
- /* VALUE */
932
- /* m_bezier(int argc, VALUE * argv, VALUE self) */
933
- /* { */
934
- /* VALUE points = Qnil; */
935
- /* VALUE options = Qnil; */
936
- /* int last = argc - 1; */
937
- /* texture_info tex; */
938
-
939
- /* ADJUST_SELF(self); */
940
-
941
- /* if(argc < 1) rb_raise(rb_eArgError, "bezier action needs at least 1 parameter"); */
942
-
943
- /* /\* get array of points *\/ */
944
- /* points = argv[0]; */
945
- /* Check_Type(points, T_ARRAY); */
946
-
947
- /* options = argv[last]; */
948
-
949
- /* get_texture_info(self, &tex); */
950
-
951
- /* bezier_do_action(points, &tex, options, sync_mode, true, NULL); */
952
-
953
- /* return self; */
954
- /* } */
955
-
956
- /** end turtle drawing **/
957
-
958
-
959
- /* below is yucky old code that needs to be updated */
960
- /* each_pixel iterator */
961
-
962
-
963
- /* VALUE */
964
- /* m_each(int argc, VALUE * argv, VALUE self) */
965
- /* { */
966
- /* int x0, y0, x1, y1, xbound, ybound, arity; */
967
- /* VALUE options, region, pixel_data[2], yield_vals; */
968
- /* register int x, y; */
969
- /* texture_info tex; */
970
- /* image_bounds bounds; */
971
-
972
- /* rb_need_block(); */
973
-
974
- /* arity = FIX2INT(rb_funcall(rb_block_proc(), rb_intern("arity"), 0)); */
975
- /* if(arity != 1 && arity != 3) */
976
- /* rb_raise(rb_eRuntimeError, "block arity must be either 1 or 3"); */
977
-
978
- /* /\* ADJUST_SELF(self); *\/ */
979
-
980
- /* /\* rb_scan_args(argc, argv, "01", &options); *\/ */
981
-
982
- /* /\* /\\* get texture info *\\/ *\/ */
983
- /* /\* get_texture_info(self, &tex); *\/ */
984
-
985
- /* /\* /\\* default values for region *\\/ *\/ */
986
- /* /\* x0 = 0; y0 = 0; x1 = tex.width; y1 = tex.height; *\/ */
987
-
988
- /* /\* if(has_optional_hash_arg(options, "region")) { *\/ */
989
- /* /\* region = get_from_hash(options, "region"); *\/ */
990
-
991
- /* /\* x0 = NUM2INT(get_from_array(region, 0)); *\/ */
992
- /* /\* y0 = NUM2INT(get_from_array(region, 1)); *\/ */
993
- /* /\* x1 = NUM2INT(get_from_array(region, 2)); *\/ */
994
- /* /\* y1 = NUM2INT(get_from_array(region, 3)); *\/ */
995
-
996
- /* /\* constrain_boundaries(&x0, &y0, &x1, &y1, tex.width, tex.height); *\/ */
997
- /* /\* } *\/ */
998
-
999
- /* /\* /\\* width and height of action *\\/ *\/ */
1000
- /* /\* xbound = x1 - x0; *\/ */
1001
- /* /\* ybound = y1 - y0; *\/ */
1002
-
1003
- /* /\* yield_vals = rb_ary_new(); *\/ */
1004
-
1005
- /* /\* for(y = 0; y < ybound; y++) *\/ */
1006
- /* /\* for(x = 0; x < xbound; x++) { *\/ */
1007
- /* /\* VALUE pixel_color; *\/ */
1008
- /* /\* rgba old_color; *\/ */
1009
-
1010
- /* /\* /\\* adjusted x and y *\\/ *\/ */
1011
- /* /\* register int ax = x + x0, ay = y + y0; *\/ */
1012
-
1013
- /* /\* pixel_data[0] = INT2FIX(ax); *\/ */
1014
- /* /\* pixel_data[1] = INT2FIX(ay); *\/ */
1015
-
1016
- /* /\* pixel_color = m_getpixel(self, INT2FIX(ax), INT2FIX(ay)); *\/ */
1017
-
1018
- /* /\* if(arity == 1) { *\/ */
1019
- /* /\* rb_yield(pixel_color); *\/ */
1020
- /* /\* } *\/ */
1021
- /* /\* else if(arity == 3) { *\/ */
1022
- /* /\* rb_ary_store(yield_vals, 0, pixel_color); *\/ */
1023
- /* /\* rb_ary_store(yield_vals, 1, INT2FIX(x)); *\/ */
1024
- /* /\* rb_ary_store(yield_vals, 2, INT2FIX(y)); *\/ */
1025
-
1026
- /* /\* rb_yield(yield_vals); *\/ */
1027
- /* /\* } *\/ */
1028
-
1029
- /* /\* m_color(1, &pixel_color, self); *\/ */
1030
- /* /\* // process_action(pixel, self, 2, pixel_data, false); *\/ */
1031
- /* /\* // color_struct = old_color; *\/ */
1032
- /* /\* } *\/ */
1033
-
1034
- /* /\* bounds.xmin = x0; *\/ */
1035
- /* /\* bounds.ymin = y0; *\/ */
1036
- /* /\* bounds.xmax = x1; *\/ */
1037
- /* /\* bounds.ymax = y1; *\/ */
1038
-
1039
- /* /\* create_subtexture_and_sync_to_gl(&bounds, &tex); *\/ */
1040
-
1041
- /* /\* return self; *\/ */
1042
- /* /\* } *\/ */
1043
-
1044
- /* /\** end each_pixel algorithm **\/} */
1045
- /* /\** end each_pixel algorithm **\/ */
1046
-
1047
-
1048
- /* /\* VALUE *\/ */
1049
- /* /\* m_lshift(int argc, VALUE * argv, VALUE self) *\/ */
1050
- /* /\* { *\/ */
1051
- /* /\* int y,x, step, yoffset; *\/ */
1052
- /* /\* VALUE options, loop; *\/ */
1053
- /* /\* register int offset; *\/ */
1054
- /* /\* texture_info tex; *\/ */
1055
- /* /\* image_bounds bounds; *\/ */
1056
-
1057
- /* /\* ADJUST_SELF(self); *\/ */
1058
-
1059
- /* /\* rb_scan_args(argc, argv, "01", &options); *\/ */
1060
-
1061
- /* /\* /\\* default values for other params *\\/ *\/ */
1062
- /* /\* step = 1; loop = Qfalse; *\/ */
1063
-
1064
- /* /\* if(TYPE(options) == T_HASH) { *\/ */
1065
- /* /\* step = NUM2INT(get_from_hash(options, "step")); *\/ */
1066
- /* /\* loop = get_from_hash(options, "loop"); *\/ */
1067
- /* /\* } *\/ */
1068
- /* /\* else if(options != Qnil) { *\/ */
1069
- /* /\* rb_raise(rb_eArgError, "argument must be a hash"); *\/ */
1070
- /* /\* } *\/ */
1071
-
1072
- /* /\* /\\* get texture info *\\/ *\/ */
1073
- /* /\* get_texture_info(self, &tex); *\/ */
1074
-
1075
- /* /\* for(y = 0; y < tex.height; y++) { *\/ */
1076
- /* /\* for(x = 0; x < tex.width; x++) { *\/ */
1077
- /* /\* offset = calc_pixel_offset(&tex, x, y); *\/ */
1078
-
1079
- /* /\* if((x + step) < tex.width) { *\/ */
1080
- /* /\* color_copy(tex.td_array + offset + step * 4, tex.td_array + offset); *\/ */
1081
- /* /\* } *\/ */
1082
- /* /\* else { *\/ */
1083
- /* /\* if(loop == Qtrue) { *\/ */
1084
- /* /\* yoffset = calc_pixel_offset(&tex, x + step - tex.width, y); *\/ */
1085
-
1086
- /* /\* color_copy(tex.td_array + yoffset, tex.td_array + offset); *\/ */
1087
- /* /\* } *\/ */
1088
- /* /\* else { *\/ */
1089
-
1090
- /* /\* zero_color(tex.td_array + offset); *\/ */
1091
- /* /\* } *\/ */
1092
- /* /\* } *\/ */
1093
-
1094
- /* /\* } *\/ */
1095
- /* /\* } *\/ */
1096
-
1097
- /* /\* bounds.xmin = 0; *\/ */
1098
- /* /\* bounds.xmax = tex.width; *\/ */
1099
- /* /\* bounds.ymin = 0; *\/ */
1100
- /* /\* bounds.ymax = tex.height; *\/ */
1101
-
1102
- /* /\* create_subtexture_and_sync_to_gl(&bounds, &tex); *\/ */
1103
-
1104
- /* /\* return Qnil; *\/ */
1105
- /* /\* } *\/ */
1106
-
1107
- /* /\* VALUE *\/ */
1108
- /* /\* m_rshift(int argc, VALUE * argv, VALUE self) *\/ */
1109
- /* /\* { *\/ */
1110
- /* /\* int y,x, step, yoffset; *\/ */
1111
- /* /\* VALUE options, loop; *\/ */
1112
- /* /\* register int offset; *\/ */
1113
- /* /\* texture_info tex; *\/ */
1114
- /* /\* image_bounds bounds; *\/ */
1115
-
1116
- /* /\* ADJUST_SELF(self); *\/ */
1117
-
1118
- /* /\* rb_scan_args(argc, argv, "01", &options); *\/ */
1119
-
1120
- /* /\* /\\* default values for other params *\\/ *\/ */
1121
- /* /\* step = 1; loop = Qfalse; *\/ */
1122
-
1123
- /* /\* if(TYPE(options) == T_HASH) { *\/ */
1124
- /* /\* step = NUM2INT(get_from_hash(options, "step")); *\/ */
1125
- /* /\* loop = get_from_hash(options, "loop"); *\/ */
1126
- /* /\* } *\/ */
1127
- /* /\* else if(options != Qnil) { *\/ */
1128
- /* /\* rb_raise(rb_eArgError, "argument must be a hash"); *\/ */
1129
- /* /\* } *\/ */
1130
-
1131
- /* /\* /\\* get texture info *\\/ *\/ */
1132
- /* /\* get_texture_info(self, &tex); *\/ */
1133
-
1134
- /* /\* for(y = 0; y < tex.height; y++) { *\/ */
1135
- /* /\* for(x = tex.width - 1; x > -1; x--) { *\/ */
1136
- /* /\* offset = calc_pixel_offset(&tex, x, y); *\/ */
1137
-
1138
- /* /\* if((x - step) > -1) { *\/ */
1139
- /* /\* color_copy(tex.td_array + offset - step * 4, tex.td_array + offset); *\/ */
1140
- /* /\* } *\/ */
1141
- /* /\* else { *\/ */
1142
- /* /\* if(loop == Qtrue) { *\/ */
1143
- /* /\* yoffset = calc_pixel_offset(&tex, x + tex.width - step, y); *\/ */
1144
- /* /\* color_copy(tex.td_array + yoffset, tex.td_array + offset); *\/ */
1145
- /* /\* } *\/ */
1146
- /* /\* else { *\/ */
1147
- /* /\* zero_color(tex.td_array + offset); *\/ */
1148
- /* /\* } *\/ */
1149
- /* /\* } *\/ */
1150
-
1151
- /* /\* } *\/ */
1152
- /* /\* } *\/ */
1153
-
1154
- /* /\* bounds.xmin = 0; *\/ */
1155
- /* /\* bounds.xmax = tex.width; *\/ */
1156
- /* /\* bounds.ymin = 0; *\/ */
1157
- /* /\* bounds.ymax = tex.height; *\/ */
1158
-
1159
- /* /\* create_subtexture_and_sync_to_gl(&bounds, &tex); *\/ */
1160
-
1161
- /* /\* return Qnil; *\/ */
1162
- /* /\* } *\/ */
1163
-
1164
- /* /\* /\\* special pixel action for image[]= *\\/ *\/ */
1165
- /* /\* VALUE *\/ */
1166
- /* /\* m_special_pixel(int argc, VALUE * argv, VALUE self) *\/ */
1167
- /* /\* { *\/ */
1168
-
1169
- /* /\* rgba old_color; *\/ */
1170
-
1171
- /* /\* ADJUST_SELF(self); *\/ */
1172
-
1173
- /* /\* if(argc < 3) rb_raise(rb_eArgError, "[]= action needs 3 parameters"); *\/ */
1174
-
1175
- /* /\* m_color(1, &argv[2], self); *\/ */
1176
-
1177
- /* /\* m_pixel(2, argv, self); *\/ */
1178
-
1179
- /* /\* // color_struct = old_color; *\/ */
1180
-
1181
-
1182
- /* /\* return Qnil; *\/ */
1183
- /* /\* } *\/ */
1184
-
1185
- /* /\* /\\* instance methods *\\/ *\/ */
1186
-
1
+ #include <ruby.h>
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+ #include <ctype.h>
5
+ #include <math.h>
6
+ #include <stdlib.h>
7
+ #include <assert.h>
8
+ #include <stdarg.h>
9
+
10
+ #ifdef __APPLE__
11
+ # include <glut.h>
12
+ #else
13
+ # include <GL/glut.h>
14
+ #endif
15
+
16
+ #include "texplay.h"
17
+ #include "utils.h"
18
+ #include "graphics_utils.h"
19
+ #include "bindings.h"
20
+ #include "actions.h"
21
+ #include "cache.h"
22
+ #include "compat.h"
23
+
24
+ /* syncing mode */
25
+ /* lazy_sync = sync at end of paint block */
26
+ /* eager_sync = sync immediately (after action) */
27
+ /* no_sync = do not sync at all */
28
+ sync sync_mode = eager_sync;
29
+
30
+ static void
31
+ process_x_y_pairs(VALUE image, int num_pairs, VALUE * argv, ...)
32
+ {
33
+ va_list ap;
34
+ int i;
35
+ int draw_offset_x;
36
+ int draw_offset_y;
37
+ VALUE offset_val;
38
+
39
+ offset_val = get_image_local(image, DRAW_OFFSET);
40
+
41
+ draw_offset_x = NUM2INT(get_from_array(offset_val, 0));
42
+ draw_offset_y = NUM2INT(get_from_array(offset_val, 1));
43
+
44
+ va_start(ap, argv);
45
+ if(is_a_point(argv[0])) {
46
+ for(i = 0; i < num_pairs; i++) {
47
+ int *x_ptr, *y_ptr;
48
+
49
+ x_ptr = va_arg(ap, int*);
50
+ y_ptr = va_arg(ap, int*);
51
+
52
+ *x_ptr = NUM2INT(rb_funcall(argv[i], rb_intern("x"), 0)) + draw_offset_x;
53
+ *y_ptr = NUM2INT(rb_funcall(argv[i], rb_intern("y"), 0)) + draw_offset_y;
54
+ }
55
+ }
56
+ else {
57
+ for(i = 0; i < (num_pairs * 2); i+=2) {
58
+ int *x_ptr, *y_ptr;
59
+
60
+ x_ptr = va_arg(ap, int*);
61
+ y_ptr = va_arg(ap, int*);
62
+
63
+ *x_ptr = NUM2INT(argv[i]) + draw_offset_x;
64
+ *y_ptr = NUM2INT(argv[i + 1]) + draw_offset_y;
65
+ }
66
+ }
67
+ va_end(ap);
68
+ }
69
+
70
+
71
+ /* singleton methods */
72
+
73
+ /* responsible for creating macros */
74
+ VALUE
75
+ M_create_macro(VALUE self, VALUE method_name)
76
+ {
77
+ VALUE proc;
78
+
79
+ rb_need_block();
80
+
81
+ /* convert the block to a proc */
82
+ proc = rb_block_proc();
83
+
84
+ /* define the method in the TexPlay class so that it is accessible to 'instances' */
85
+ rb_funcall(self, rb_intern("define_method"), 2, method_name, proc);
86
+
87
+ return Qnil;
88
+ }
89
+
90
+
91
+ /* responsible for removing macros */
92
+ VALUE
93
+ M_remove_macro(VALUE self, VALUE method_name)
94
+ {
95
+
96
+ /* remove the method in the TexPlay class */
97
+ rb_funcall(self, rb_intern("remove_method"), 1, method_name);
98
+
99
+ return Qnil;
100
+ }
101
+
102
+ /* responsible for refreshing all entries in cache */
103
+ VALUE
104
+ M_refresh_cache_all(VALUE self)
105
+ {
106
+ cache_refresh_all();
107
+
108
+ return Qnil;
109
+ }
110
+
111
+ /* VALUE */
112
+ /* M_screenshot(VALUE self, VALUE x, VALUE y, VALUE width, VALUE width) */
113
+ /* { */
114
+ /* texture_info tex; */
115
+ /* int sidelength; */
116
+ /* int rb_x = FIX2INT(x); */
117
+ /* int rb_y = FIX2INT(y); */
118
+ /* int rb_width = FIX2INT(width); */
119
+ /* int rb_height = FIX2INT(height); */
120
+
121
+ /* VALUE blob = rb_str_new(NULL, 4 * rb_width * rb_height); */
122
+
123
+ /* glReadPixels(rb_x, rb_y, rb_width, rb_height, GL_RGBA, GL_UNSIGNED_BYTE, RSTRING_PTR(blob)); */
124
+
125
+ /* return blob; */
126
+ /* } */
127
+
128
+
129
+ /* creates a blank image */
130
+ /* VALUE */
131
+ /* M_create_blank(VALUE self, VALUE window, VALUE width, VALUE height) */
132
+ /* { */
133
+ /* VALUE fresh_image; */
134
+
135
+ /* fresh_image = create_image(window, NUM2INT(width), NUM2INT(height)); */
136
+
137
+ /* return fresh_image; */
138
+ /* } */
139
+ /** end singleton methods **/
140
+
141
+ /* some helper methods */
142
+ static void
143
+ rb_lazy_bounds_to_image_bounds(VALUE image, image_bounds * bounds)
144
+ {
145
+ VALUE lazy_bounds;
146
+
147
+ lazy_bounds = get_image_local(image, LAZY_BOUNDS);
148
+
149
+ Check_Type(lazy_bounds, T_ARRAY);
150
+
151
+ bounds->xmin = FIX2INT(get_from_array(lazy_bounds, 0));
152
+ bounds->ymin = FIX2INT(get_from_array(lazy_bounds, 1));
153
+ bounds->xmax = FIX2INT(get_from_array(lazy_bounds, 2));
154
+ bounds->ymax = FIX2INT(get_from_array(lazy_bounds, 3));
155
+ }
156
+
157
+ static VALUE
158
+ parse_sync_mode(VALUE user_sync_mode)
159
+ {
160
+ sync mode;
161
+
162
+ Check_Type(user_sync_mode, T_SYMBOL);
163
+
164
+ if(user_sync_mode == string2sym("lazy_sync"))
165
+ mode = lazy_sync;
166
+ else if(user_sync_mode == string2sym("eager_sync"))
167
+ mode = eager_sync;
168
+ else if(user_sync_mode == string2sym("no_sync"))
169
+ mode = no_sync;
170
+ else
171
+ rb_raise(rb_eArgError, "unrecognized sync mode: %s\n. Allowable modes are "
172
+ ":lazy_sync, :eager_sync, :no_sync.",
173
+ sym2string(user_sync_mode));
174
+
175
+ return mode;
176
+ }
177
+ /* end helpers */
178
+
179
+ /* entry point for TexPlay paint actions */
180
+ VALUE
181
+ m_paint(int argc, VALUE * argv, VALUE self)
182
+ {
183
+ texture_info tex;
184
+ VALUE options;
185
+ image_bounds bounds;
186
+ int arity;
187
+
188
+ rb_scan_args(argc, argv, "01", &options);
189
+
190
+ /* get texture info from image */
191
+ get_texture_info(self, &tex);
192
+
193
+ /* set default sync_mode to lazy */
194
+ sync_mode = lazy_sync;
195
+
196
+ /* parse sync_mode, overriding lazy sync mode? */
197
+ if(has_optional_hash_arg(options, "sync_mode")) {
198
+ VALUE user_sync_mode = get_from_hash(options, "sync_mode");
199
+ sync_mode = parse_sync_mode(user_sync_mode);
200
+ }
201
+
202
+ /* if no block then just sync */
203
+ if(!rb_block_given_p()) {
204
+
205
+ rb_lazy_bounds_to_image_bounds(self, &bounds);
206
+
207
+ create_subtexture_and_sync_to_gl(&bounds, &tex);
208
+
209
+ /* reset the LAZY_BOUNDS now we've sync'd */
210
+ set_image_local(self, LAZY_BOUNDS, Qnil);
211
+
212
+ sync_mode = eager_sync;
213
+
214
+ return self;
215
+ }
216
+
217
+ /* find arity of block */
218
+ arity = FIX2INT(rb_funcall(rb_block_proc(), rb_intern("arity"), 0));
219
+
220
+ /* yield self if the arity is 1, else instance_eval the block */
221
+ switch(arity) {
222
+ case -1:
223
+ case 0:
224
+ rb_instace_eval(0, 0, self);
225
+ break;
226
+ case 1:
227
+ rb_yield(self);
228
+ break;
229
+ default:
230
+ rb_raise(rb_eArgError, "block arity must be either 1 or -1 or 0, received arity of: %d", arity);
231
+ }
232
+
233
+ /* if lazy sync is selected then sync now..as the paint block has finished executing the draw actions*/
234
+ if(sync_mode == lazy_sync) {
235
+
236
+ rb_lazy_bounds_to_image_bounds(self, &bounds);
237
+
238
+ create_subtexture_and_sync_to_gl(&bounds, &tex);
239
+
240
+ /* reset the LAZY_BOUNDS now we've sync'd */
241
+ set_image_local(self, LAZY_BOUNDS, Qnil);
242
+
243
+ }
244
+
245
+ /* now we've finished the paint block we reset the default sync_mode back to eager */
246
+ sync_mode = eager_sync;
247
+
248
+ return self;
249
+ }
250
+
251
+ VALUE
252
+ m_force_sync(VALUE self, VALUE ary)
253
+ {
254
+ image_bounds bounds;
255
+ texture_info tex;
256
+
257
+ Check_Type(ary, T_ARRAY);
258
+
259
+ get_texture_info(self, &tex);
260
+
261
+ bounds.xmin = NUM2INT(get_from_array(ary, 0));
262
+ bounds.ymin = NUM2INT(get_from_array(ary, 1));
263
+ bounds.xmax = NUM2INT(get_from_array(ary, 2));
264
+ bounds.ymax = NUM2INT(get_from_array(ary, 3));
265
+
266
+ create_subtexture_and_sync_to_gl(&bounds, &tex);
267
+
268
+ return Qnil;
269
+ }
270
+
271
+ VALUE
272
+ m_dup_image(VALUE self)
273
+ {
274
+ texture_info tex, dup_tex;
275
+ VALUE dupped_image;
276
+ VALUE window;
277
+
278
+ get_texture_info(self, &tex);
279
+
280
+ window = rb_funcall(self, rb_intern("__window__"), 0);
281
+
282
+ /* create a new blank image with the height/width of the current image */
283
+ dupped_image = create_image(window, tex.width, tex.height);
284
+
285
+ /* get the new image's data */
286
+ get_texture_info(dupped_image, &dup_tex);
287
+
288
+ /* splice into the new image content from the current image, and sync it to gl */
289
+ splice_do_action(0, 0, 0, 0, XMAX_OOB, YMAX_OOB, &tex, &dup_tex, Qnil, eager_sync, true, NULL);
290
+
291
+ /* copy across the ivars too! */
292
+ rb_copy_generic_ivar(dupped_image, self);
293
+
294
+ /* we now have a full dup of the current image, return it */
295
+ return dupped_image;
296
+ }
297
+
298
+ VALUE
299
+ m_clone_image(VALUE self)
300
+ {
301
+ VALUE cloned_image;
302
+
303
+ cloned_image = m_dup_image(self);
304
+
305
+ /* the main diff b/w clone and dup is that clone also dups the singleton */
306
+ KLASS_OF(cloned_image) = rb_singleton_class_clone(self);
307
+
308
+ return cloned_image;
309
+ }
310
+
311
+ VALUE
312
+ m_user_set_options(VALUE self, VALUE options)
313
+ {
314
+ if(!is_a_hash(options))
315
+ rb_raise(rb_eArgError, "only a single hash argument is accepted");
316
+
317
+ set_image_local(self, USER_DEFAULTS, options);
318
+
319
+ return Qnil;
320
+ }
321
+
322
+ VALUE
323
+ m_user_delete_options(VALUE self)
324
+ {
325
+
326
+ set_image_local(self, USER_DEFAULTS, Qnil);
327
+
328
+ return Qnil;
329
+ }
330
+
331
+ VALUE
332
+ m_get_options(VALUE self)
333
+ {
334
+ return get_image_local(self, USER_DEFAULTS);
335
+ }
336
+
337
+ static void
338
+ get_image_chunk_with_size(char * data, texture_info * tex, char * blob)
339
+ {
340
+ for(int y = 0; y < tex->height; y++)
341
+ for(int x = 0; x < tex->width; x++) {
342
+ int buf_index = 4 * (x + y * tex->width);
343
+
344
+ int offset = calc_pixel_offset(tex, x, y);
345
+
346
+ memcpy(blob + buf_index, data + offset, 4);
347
+ }
348
+ }
349
+
350
+
351
+
352
+ VALUE
353
+ m_to_blob(VALUE self)
354
+ {
355
+ texture_info tex;
356
+ int sidelength;
357
+
358
+ get_texture_info(self, &tex);
359
+
360
+ glEnable(GL_TEXTURE_2D);
361
+ glBindTexture(GL_TEXTURE_2D, tex.tname);
362
+
363
+ /* get length of a side, since square texture */
364
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &sidelength);
365
+
366
+ /* initialize texture data array, mult. by 4 because {rgba} */
367
+ char new_array[sidelength * sidelength * 4];
368
+
369
+ /* get texture data from video memory */
370
+ glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE,(void*)(new_array));
371
+
372
+ VALUE blob = rb_str_new(NULL, 4 * tex.width * tex.height);
373
+
374
+ get_image_chunk_with_size(new_array, &tex, RSTRING_PTR(blob));
375
+
376
+ glDisable(GL_TEXTURE_2D);
377
+
378
+ return blob;
379
+ }
380
+
381
+ /* return the pixel colour for the given x, y */
382
+ VALUE
383
+ m_getpixel(int argc, VALUE * argv, VALUE self)
384
+ {
385
+ int x1, y1;
386
+ int last = argc - 1;
387
+ texture_info tex;
388
+ rgba pix;
389
+ bool gosu_color_mode = false;
390
+ VALUE options;
391
+
392
+
393
+ process_x_y_pairs(self, 1, argv, &x1, &y1);
394
+
395
+ /* get texture info */
396
+ get_texture_info(self, &tex);
397
+
398
+ options = argv[last];
399
+
400
+ if (hash_value_is(options, "color_mode", string2sym("gosu")))
401
+ gosu_color_mode = true;
402
+
403
+ /* locate the desired pixel; */
404
+ pix = get_pixel_color(&tex, x1, y1);
405
+
406
+ if(not_a_color(pix))
407
+ return Qnil;
408
+ else {
409
+ if (gosu_color_mode)
410
+ return convert_rgba_to_gosu_color(&pix);
411
+ else
412
+ return convert_rgba_to_rb_color(&pix);
413
+ }
414
+ }
415
+
416
+ /* circle action */
417
+ VALUE
418
+ m_circle(int argc, VALUE * argv, VALUE self)
419
+ {
420
+ int x1, y1, r;
421
+ int last = argc - 1;
422
+ VALUE options;
423
+ texture_info tex;
424
+
425
+ if(argc < 2) rb_raise(rb_eArgError, "circle action needs at least 2 parameter");
426
+
427
+ process_x_y_pairs(self, 1, argv, &x1, &y1);
428
+
429
+ if(is_a_point(argv[0]))
430
+ r = NUM2INT(argv[1]);
431
+ else
432
+ r = NUM2INT(argv[2]);
433
+
434
+ options = argv[last];
435
+
436
+ get_texture_info(self, &tex);
437
+
438
+ circle_do_action(x1, y1, r, &tex, options, sync_mode, true, NULL);
439
+
440
+ return self;
441
+ }
442
+
443
+ /* ngon */
444
+ VALUE
445
+ m_ngon(int argc, VALUE * argv, VALUE self)
446
+ {
447
+ int x1, y1, r, n;
448
+ int last = argc - 1;
449
+ VALUE options;
450
+ texture_info tex;
451
+
452
+ if(argc < 3) rb_raise(rb_eArgError, "ngon requires at least 3 parameters (x, y, radius, num_sides)");
453
+
454
+ process_x_y_pairs(self, 1, argv, &x1, &y1);
455
+
456
+ options = argv[last];
457
+
458
+ get_texture_info(self, &tex);
459
+
460
+ r = NUM2INT(argv[2]);
461
+ n = NUM2INT(argv[3]);
462
+
463
+ ngon_do_action(x1, y1, r, n, &tex, options, sync_mode, true, NULL);
464
+
465
+ return self;
466
+ }
467
+
468
+
469
+ /* flood fill action */
470
+ VALUE
471
+ m_flood_fill(int argc, VALUE * argv, VALUE self)
472
+ {
473
+ int x1, y1;
474
+ int last = argc - 1;
475
+ VALUE options;
476
+ texture_info tex;
477
+ bool iter = false, glow = false;
478
+
479
+ if (argc < 1) rb_raise(rb_eArgError, "flood fill action needs at least 1 parameter");
480
+
481
+ process_x_y_pairs(self, 1, argv, &x1, &y1);
482
+
483
+ options = argv[last];
484
+
485
+ get_texture_info(self, &tex);
486
+
487
+ if(is_a_hash(options)) {
488
+ if(RTEST(get_from_hash(options, "iter")))
489
+ iter = true;
490
+ if(RTEST(get_from_hash(options, "glow")))
491
+ glow = true;
492
+ }
493
+
494
+ if(iter) {
495
+ flood_fill_do_action(x1, y1, &tex, options, sync_mode, true, NULL);
496
+ }
497
+ else if(glow) {
498
+ glow_fill_do_action(x1, y1, &tex, options, sync_mode, true, NULL);
499
+
500
+ }
501
+ /* this is the default fill */
502
+ else {
503
+ scan_fill_do_action(x1, y1, &tex, options, sync_mode, true, NULL);
504
+ }
505
+
506
+ return self;
507
+ }
508
+
509
+ static inline VALUE
510
+ convert_trace_match_to_ruby_array(trace_match match, bool gosu_color_mode)
511
+ {
512
+ VALUE ary = rb_ary_new();
513
+
514
+ rb_ary_store(ary, 0, INT2FIX(match.x));
515
+ rb_ary_store(ary, 1, INT2FIX(match.y));
516
+
517
+ if (gosu_color_mode)
518
+ rb_ary_store(ary, 2, convert_rgba_to_gosu_color(&match.color));
519
+ else
520
+ rb_ary_store(ary, 2, convert_rgba_to_rb_color(&match.color));
521
+
522
+ return ary;
523
+ }
524
+
525
+ /* line action */
526
+ VALUE
527
+ m_line(int argc, VALUE * argv, VALUE self)
528
+ {
529
+ int x1, y1, x2, y2;
530
+ int last = argc - 1;
531
+ bool gosu_color_mode = false;
532
+ VALUE options;
533
+ texture_info tex;
534
+ trace_match match;
535
+
536
+ if(argc < 2) rb_raise(rb_eArgError, "line action needs at least 2 parameters");
537
+
538
+ process_x_y_pairs(self, 2, argv, &x1, &y1, &x2, &y2);
539
+
540
+ options = argv[last];
541
+
542
+ if (hash_value_is(options, "color_mode", string2sym("gosu")))
543
+ gosu_color_mode = true;
544
+
545
+ get_texture_info(self, &tex);
546
+
547
+ match = line_do_action(x1, y1, x2, y2, &tex, options, sync_mode, true, NULL);
548
+
549
+ if (has_optional_hash_arg(options, "trace")) {
550
+ if (match.x == -9999)
551
+ return Qnil;
552
+ else
553
+ return convert_trace_match_to_ruby_array(match, gosu_color_mode);
554
+ }
555
+
556
+ return self;
557
+ }
558
+
559
+ /* box action */
560
+ VALUE
561
+ m_rect(int argc, VALUE * argv, VALUE self)
562
+ {
563
+
564
+ int x1, y1, x2, y2;
565
+ int last = argc - 1;
566
+ VALUE options;
567
+ texture_info tex;
568
+
569
+ if(argc < 2) rb_raise(rb_eArgError, "rect action needs at least 2 parameters");
570
+
571
+ process_x_y_pairs(self, 2, argv, &x1, &y1, &x2, &y2);
572
+
573
+ options = argv[last];
574
+
575
+ get_texture_info(self, &tex);
576
+
577
+ rect_do_action(x1, y1, x2, y2, &tex, options, sync_mode, true, NULL);
578
+
579
+ return self;
580
+ }
581
+
582
+
583
+ /* pixel action */
584
+ VALUE
585
+ m_pixel(int argc, VALUE * argv, VALUE self)
586
+ {
587
+ int x1, y1;
588
+ int last = argc - 1;
589
+ VALUE options;
590
+ texture_info tex;
591
+
592
+ if(argc < 1) rb_raise(rb_eArgError, "pixel action needs 1 parameter");
593
+
594
+ process_x_y_pairs(self, 1, argv, &x1, &y1);
595
+
596
+ options = argv[last];
597
+
598
+ get_texture_info(self, &tex);
599
+
600
+ pixel_do_action(x1, y1, &tex, options, sync_mode, true, NULL);
601
+
602
+ return self;
603
+ }
604
+
605
+ /* bezier curve */
606
+ VALUE
607
+ m_bezier(int argc, VALUE * argv, VALUE self)
608
+ {
609
+ VALUE points = Qnil;
610
+ VALUE options = Qnil;
611
+ int last = argc - 1;
612
+ texture_info tex;
613
+
614
+ if(argc < 1) rb_raise(rb_eArgError, "bezier action needs at least 1 parameter");
615
+
616
+ /* get array of points */
617
+ points = argv[0];
618
+ Check_Type(points, T_ARRAY);
619
+
620
+ options = argv[last];
621
+
622
+ get_texture_info(self, &tex);
623
+
624
+ bezier_do_action(points, &tex, options, sync_mode, true, NULL);
625
+
626
+ return self;
627
+ }
628
+
629
+ /* bezier curve */
630
+ VALUE
631
+ m_polyline(int argc, VALUE * argv, VALUE self)
632
+ {
633
+ VALUE points = Qnil;
634
+ VALUE options = Qnil;
635
+ int last = argc - 1;
636
+ texture_info tex;
637
+
638
+ if(argc < 1) rb_raise(rb_eArgError, "polyline action needs at least 1 parameter");
639
+
640
+ /* get array of points */
641
+ points = argv[0];
642
+ Check_Type(points, T_ARRAY);
643
+
644
+ options = argv[last];
645
+
646
+ get_texture_info(self, &tex);
647
+
648
+ polyline_do_action(points, &tex, options, sync_mode, true, NULL);
649
+
650
+ return self;
651
+ }
652
+
653
+
654
+
655
+ /* splice action */
656
+ VALUE
657
+ m_splice(int argc, VALUE * argv, VALUE self)
658
+ {
659
+ int x0, y0;
660
+ int cx1 = 0, cy1 = 0, cx2 = XMAX_OOB, cy2 = YMAX_OOB;
661
+ texture_info splice_tex;
662
+ int last = argc - 1;
663
+ texture_info tex;
664
+ VALUE options;
665
+
666
+ if(argc < 3) rb_raise(rb_eArgError, "splice action needs at least 3 parameters");
667
+
668
+ if(!is_gosu_image(argv[0]))
669
+ rb_raise(rb_eArgError, "first parameter must be a valid Gosu::Image");
670
+
671
+ /* get the splice image */
672
+ get_texture_info(argv[0], &splice_tex);
673
+
674
+ /* add 1 to argv to skip the Image parameter */
675
+ process_x_y_pairs(self, 1, argv + 1, &x0, &y0);
676
+
677
+ /* get the hash args */
678
+ options = argv[last];
679
+
680
+ get_texture_info(self, &tex);
681
+
682
+ /* get the crop boundaries */
683
+ if(is_a_hash(options))
684
+ if(RTEST(get_from_hash(options, "crop"))) {
685
+ VALUE c = get_from_hash(options, "crop");
686
+ Check_Type(c, T_ARRAY);
687
+ cx1 = NUM2INT(get_from_array(c, 0));
688
+ cy1 = NUM2INT(get_from_array(c, 1));
689
+ cx2 = NUM2INT(get_from_array(c, 2));
690
+ cy2 = NUM2INT(get_from_array(c, 3));
691
+ }
692
+
693
+ splice_do_action(x0, y0, cx1, cy1, cx2, cy2, &splice_tex,
694
+ &tex, options, sync_mode, true, NULL);
695
+
696
+ return self;
697
+ }
698
+
699
+
700
+ /* clear action - really just an alias for box */
701
+ VALUE
702
+ m_clear(int argc, VALUE * argv, VALUE self)
703
+ {
704
+ VALUE parms[4];
705
+
706
+ parms[0] = INT2NUM(0);
707
+ parms[1] = INT2NUM(0);
708
+ parms[2] = INT2NUM(XMAX_OOB);
709
+ parms[3] = INT2NUM(YMAX_OOB);
710
+
711
+ // m_box(ARY_SIZE(parms), parms, self);
712
+
713
+ return self;
714
+ }
715
+
716
+ /* offset function */
717
+ VALUE
718
+ m_offset(int argc, VALUE * argv, VALUE self)
719
+ {
720
+ char * try_offset;
721
+
722
+ if(argc == 0)
723
+ return get_image_local(self, DRAW_OFFSET);
724
+
725
+ switch(TYPE(argv[0])) {
726
+
727
+ case T_ARRAY:
728
+
729
+ set_image_local(self, DRAW_OFFSET, argv[0]);
730
+ break;
731
+ case T_SYMBOL:
732
+ try_offset = sym2string(argv[0]);
733
+
734
+ if(!strcmp("default", try_offset)) {
735
+ set_image_local(self, DRAW_OFFSET, Qnil);
736
+ }
737
+ else {
738
+ rb_raise(rb_eArgError, "no such offset defined: %s\n", try_offset);
739
+ }
740
+
741
+ break;
742
+ default:
743
+ rb_raise(rb_eArgError, "invalid offset. please use an array or :default.");
744
+ }
745
+ return Qnil;
746
+ }
747
+
748
+ /* color change */
749
+ VALUE
750
+ m_color(int argc, VALUE * argv, VALUE self)
751
+ {
752
+ VALUE first;
753
+ rgba new_color;
754
+
755
+ /* if no params then return action current color */
756
+ if(argc == 0)
757
+ return get_image_local(self, IMAGE_COLOR);
758
+
759
+ /* otherwise set the action color */
760
+ /* NB: we cannot just set image_local_color to 'first' because first may not be an array,
761
+ it could also be a symbol */
762
+
763
+ first = argv[0];
764
+
765
+ new_color = convert_rb_color_to_rgba(first);
766
+
767
+ /* im quite sure i DO want to set the color even if it is not_a_color.
768
+ why ? consistency only
769
+ (NB: not_a_color_v is skipped by the set_pixel_color routine */
770
+
771
+ /* if(is_a_color(new_color)) */
772
+
773
+ save_rgba_to_image_local_color(self, new_color);
774
+
775
+ return Qnil;
776
+ }
777
+
778
+ /* this function manages all other method calls */
779
+ VALUE
780
+ m_missing(int argc, VALUE * argv, VALUE self)
781
+ {
782
+ char * action_name = lowercase(sym2string(argv[0]));
783
+
784
+ /* try case insensitive version of action name */
785
+ if(rb_respond_to(self, rb_intern(action_name))) {
786
+ rb_funcall2(self, rb_intern(action_name), --argc, ++argv);
787
+ }
788
+ /* still no match? then method does not exist */
789
+ else {
790
+ rb_raise (rb_eRuntimeError, "unrecognized action: %s\n", action_name);
791
+ }
792
+
793
+ return self;
794
+ }
795
+
796
+ /* refreshes the cache */
797
+ VALUE
798
+ m_cache_refresh(VALUE self)
799
+ {
800
+ texture_info tex;
801
+
802
+ get_texture_info(self, &tex);
803
+
804
+ cache_refresh_entry(tex.tname);
805
+
806
+ return self;
807
+ }
808
+
809
+ /* check whether img quad is already cached */
810
+ VALUE
811
+ m_quad_cached(VALUE self)
812
+ {
813
+ VALUE info, gc_state_off;
814
+ int tex_name;
815
+ cache_entry * entry;
816
+
817
+ /* prevent weird segfault bug */
818
+ gc_state_off = rb_gc_disable();
819
+
820
+ /* ensure gl_tex_info returns non nil */
821
+ info = check_for_texture_info(self);
822
+
823
+ tex_name = FIX2INT(rb_funcall(info, rb_intern("tex_name"), 0));
824
+
825
+ entry = find_in_cache(tex_name);
826
+
827
+ /* only enable gc if was enabled on function entry */
828
+ if(!gc_state_off) rb_gc_enable();
829
+
830
+ return entry ? Qtrue : Qfalse;
831
+ }
832
+
833
+ /** m_each **/
834
+ VALUE
835
+ m_each(int argc, VALUE * argv, VALUE self)
836
+ {
837
+ int x1 = 0, y1 = 0, x2 = XMAX_OOB, y2 = YMAX_OOB;
838
+ texture_info tex;
839
+ VALUE proc;
840
+ VALUE options = Qnil;
841
+
842
+ rb_need_block();
843
+
844
+ get_texture_info(self, &tex);
845
+
846
+ if(argc >= 1) {
847
+ options = argv[0];
848
+ Check_Type(options, T_HASH);
849
+ if(RTEST(get_from_hash(options, "region"))) {
850
+ VALUE region = get_from_hash(options, "region");
851
+ Check_Type(region, T_ARRAY);
852
+
853
+ if(RARRAY_LEN(region) < 4)
854
+ rb_raise(rb_eArgError, "region requires 4 elements");
855
+
856
+ x1 = NUM2INT(get_from_array(region, 0));
857
+ y1 = NUM2INT(get_from_array(region, 1));
858
+ x2 = NUM2INT(get_from_array(region, 2));
859
+ y2 = NUM2INT(get_from_array(region, 3));
860
+
861
+ }
862
+
863
+ }
864
+
865
+ constrain_boundaries(&x1, &y1,
866
+ &x2, &y2, tex.width, tex.height);
867
+
868
+ proc = rb_block_proc();
869
+
870
+ each_pixel_do_action(x1, y1, x2, y2, proc, &tex, options, sync_mode, true, NULL);
871
+
872
+ return self;
873
+ }
874
+ /** end of each **/
875
+
876
+ /** turtle drawing functions **/
877
+ /* static VALUE */
878
+ /* m_turtle_move_to */
879
+
880
+ /* VALUE */
881
+ /* m_bezier(int argc, VALUE * argv, VALUE self) */
882
+ /* { */
883
+ /* VALUE points = Qnil; */
884
+ /* VALUE options = Qnil; */
885
+ /* int last = argc - 1; */
886
+ /* texture_info tex; */
887
+
888
+ /* if(argc < 1) rb_raise(rb_eArgError, "bezier action needs at least 1 parameter"); */
889
+
890
+ /* /\* get array of points *\/ */
891
+ /* points = argv[0]; */
892
+ /* Check_Type(points, T_ARRAY); */
893
+
894
+ /* options = argv[last]; */
895
+
896
+ /* get_texture_info(self, &tex); */
897
+
898
+ /* bezier_do_action(points, &tex, options, sync_mode, true, NULL); */
899
+
900
+ /* return self; */
901
+ /* } */
902
+
903
+ /** end turtle drawing **/
904
+
905
+
906
+ /* below is yucky old code that needs to be updated */
907
+ /* each_pixel iterator */
908
+
909
+
910
+ /* VALUE */
911
+ /* m_each(int argc, VALUE * argv, VALUE self) */
912
+ /* { */
913
+ /* int x0, y0, x1, y1, xbound, ybound, arity; */
914
+ /* VALUE options, region, pixel_data[2], yield_vals; */
915
+ /* register int x, y; */
916
+ /* texture_info tex; */
917
+ /* image_bounds bounds; */
918
+
919
+ /* rb_need_block(); */
920
+
921
+ /* arity = FIX2INT(rb_funcall(rb_block_proc(), rb_intern("arity"), 0)); */
922
+ /* if(arity != 1 && arity != 3) */
923
+ /* rb_raise(rb_eRuntimeError, "block arity must be either 1 or 3"); */
924
+
925
+ /* /\* rb_scan_args(argc, argv, "01", &options); *\/ */
926
+
927
+ /* /\* /\\* get texture info *\\/ *\/ */
928
+ /* /\* get_texture_info(self, &tex); *\/ */
929
+
930
+ /* /\* /\\* default values for region *\\/ *\/ */
931
+ /* /\* x0 = 0; y0 = 0; x1 = tex.width; y1 = tex.height; *\/ */
932
+
933
+ /* /\* if(has_optional_hash_arg(options, "region")) { *\/ */
934
+ /* /\* region = get_from_hash(options, "region"); *\/ */
935
+
936
+ /* /\* x0 = NUM2INT(get_from_array(region, 0)); *\/ */
937
+ /* /\* y0 = NUM2INT(get_from_array(region, 1)); *\/ */
938
+ /* /\* x1 = NUM2INT(get_from_array(region, 2)); *\/ */
939
+ /* /\* y1 = NUM2INT(get_from_array(region, 3)); *\/ */
940
+
941
+ /* /\* constrain_boundaries(&x0, &y0, &x1, &y1, tex.width, tex.height); *\/ */
942
+ /* /\* } *\/ */
943
+
944
+ /* /\* /\\* width and height of action *\\/ *\/ */
945
+ /* /\* xbound = x1 - x0; *\/ */
946
+ /* /\* ybound = y1 - y0; *\/ */
947
+
948
+ /* /\* yield_vals = rb_ary_new(); *\/ */
949
+
950
+ /* /\* for(y = 0; y < ybound; y++) *\/ */
951
+ /* /\* for(x = 0; x < xbound; x++) { *\/ */
952
+ /* /\* VALUE pixel_color; *\/ */
953
+ /* /\* rgba old_color; *\/ */
954
+
955
+ /* /\* /\\* adjusted x and y *\\/ *\/ */
956
+ /* /\* register int ax = x + x0, ay = y + y0; *\/ */
957
+
958
+ /* /\* pixel_data[0] = INT2FIX(ax); *\/ */
959
+ /* /\* pixel_data[1] = INT2FIX(ay); *\/ */
960
+
961
+ /* /\* pixel_color = m_getpixel(self, INT2FIX(ax), INT2FIX(ay)); *\/ */
962
+
963
+ /* /\* if(arity == 1) { *\/ */
964
+ /* /\* rb_yield(pixel_color); *\/ */
965
+ /* /\* } *\/ */
966
+ /* /\* else if(arity == 3) { *\/ */
967
+ /* /\* rb_ary_store(yield_vals, 0, pixel_color); *\/ */
968
+ /* /\* rb_ary_store(yield_vals, 1, INT2FIX(x)); *\/ */
969
+ /* /\* rb_ary_store(yield_vals, 2, INT2FIX(y)); *\/ */
970
+
971
+ /* /\* rb_yield(yield_vals); *\/ */
972
+ /* /\* } *\/ */
973
+
974
+ /* /\* m_color(1, &pixel_color, self); *\/ */
975
+ /* /\* // process_action(pixel, self, 2, pixel_data, false); *\/ */
976
+ /* /\* // color_struct = old_color; *\/ */
977
+ /* /\* } *\/ */
978
+
979
+ /* /\* bounds.xmin = x0; *\/ */
980
+ /* /\* bounds.ymin = y0; *\/ */
981
+ /* /\* bounds.xmax = x1; *\/ */
982
+ /* /\* bounds.ymax = y1; *\/ */
983
+
984
+ /* /\* create_subtexture_and_sync_to_gl(&bounds, &tex); *\/ */
985
+
986
+ /* /\* return self; *\/ */
987
+ /* /\* } *\/ */
988
+
989
+ /* /\** end each_pixel algorithm **\/} */
990
+ /* /\** end each_pixel algorithm **\/ */
991
+
992
+
993
+ /* /\* VALUE *\/ */
994
+ /* /\* m_lshift(int argc, VALUE * argv, VALUE self) *\/ */
995
+ /* /\* { *\/ */
996
+ /* /\* int y,x, step, yoffset; *\/ */
997
+ /* /\* VALUE options, loop; *\/ */
998
+ /* /\* register int offset; *\/ */
999
+ /* /\* texture_info tex; *\/ */
1000
+ /* /\* image_bounds bounds; *\/ */
1001
+
1002
+ /* /\* rb_scan_args(argc, argv, "01", &options); *\/ */
1003
+
1004
+ /* /\* /\\* default values for other params *\\/ *\/ */
1005
+ /* /\* step = 1; loop = Qfalse; *\/ */
1006
+
1007
+ /* /\* if(TYPE(options) == T_HASH) { *\/ */
1008
+ /* /\* step = NUM2INT(get_from_hash(options, "step")); *\/ */
1009
+ /* /\* loop = get_from_hash(options, "loop"); *\/ */
1010
+ /* /\* } *\/ */
1011
+ /* /\* else if(options != Qnil) { *\/ */
1012
+ /* /\* rb_raise(rb_eArgError, "argument must be a hash"); *\/ */
1013
+ /* /\* } *\/ */
1014
+
1015
+ /* /\* /\\* get texture info *\\/ *\/ */
1016
+ /* /\* get_texture_info(self, &tex); *\/ */
1017
+
1018
+ /* /\* for(y = 0; y < tex.height; y++) { *\/ */
1019
+ /* /\* for(x = 0; x < tex.width; x++) { *\/ */
1020
+ /* /\* offset = calc_pixel_offset(&tex, x, y); *\/ */
1021
+
1022
+ /* /\* if((x + step) < tex.width) { *\/ */
1023
+ /* /\* color_copy(tex.td_array + offset + step * 4, tex.td_array + offset); *\/ */
1024
+ /* /\* } *\/ */
1025
+ /* /\* else { *\/ */
1026
+ /* /\* if(loop == Qtrue) { *\/ */
1027
+ /* /\* yoffset = calc_pixel_offset(&tex, x + step - tex.width, y); *\/ */
1028
+
1029
+ /* /\* color_copy(tex.td_array + yoffset, tex.td_array + offset); *\/ */
1030
+ /* /\* } *\/ */
1031
+ /* /\* else { *\/ */
1032
+
1033
+ /* /\* zero_color(tex.td_array + offset); *\/ */
1034
+ /* /\* } *\/ */
1035
+ /* /\* } *\/ */
1036
+
1037
+ /* /\* } *\/ */
1038
+ /* /\* } *\/ */
1039
+
1040
+ /* /\* bounds.xmin = 0; *\/ */
1041
+ /* /\* bounds.xmax = tex.width; *\/ */
1042
+ /* /\* bounds.ymin = 0; *\/ */
1043
+ /* /\* bounds.ymax = tex.height; *\/ */
1044
+
1045
+ /* /\* create_subtexture_and_sync_to_gl(&bounds, &tex); *\/ */
1046
+
1047
+ /* /\* return Qnil; *\/ */
1048
+ /* /\* } *\/ */
1049
+
1050
+ /* /\* VALUE *\/ */
1051
+ /* /\* m_rshift(int argc, VALUE * argv, VALUE self) *\/ */
1052
+ /* /\* { *\/ */
1053
+ /* /\* int y,x, step, yoffset; *\/ */
1054
+ /* /\* VALUE options, loop; *\/ */
1055
+ /* /\* register int offset; *\/ */
1056
+ /* /\* texture_info tex; *\/ */
1057
+ /* /\* image_bounds bounds; *\/ */
1058
+
1059
+ /* /\* rb_scan_args(argc, argv, "01", &options); *\/ */
1060
+
1061
+ /* /\* /\\* default values for other params *\\/ *\/ */
1062
+ /* /\* step = 1; loop = Qfalse; *\/ */
1063
+
1064
+ /* /\* if(TYPE(options) == T_HASH) { *\/ */
1065
+ /* /\* step = NUM2INT(get_from_hash(options, "step")); *\/ */
1066
+ /* /\* loop = get_from_hash(options, "loop"); *\/ */
1067
+ /* /\* } *\/ */
1068
+ /* /\* else if(options != Qnil) { *\/ */
1069
+ /* /\* rb_raise(rb_eArgError, "argument must be a hash"); *\/ */
1070
+ /* /\* } *\/ */
1071
+
1072
+ /* /\* /\\* get texture info *\\/ *\/ */
1073
+ /* /\* get_texture_info(self, &tex); *\/ */
1074
+
1075
+ /* /\* for(y = 0; y < tex.height; y++) { *\/ */
1076
+ /* /\* for(x = tex.width - 1; x > -1; x--) { *\/ */
1077
+ /* /\* offset = calc_pixel_offset(&tex, x, y); *\/ */
1078
+
1079
+ /* /\* if((x - step) > -1) { *\/ */
1080
+ /* /\* color_copy(tex.td_array + offset - step * 4, tex.td_array + offset); *\/ */
1081
+ /* /\* } *\/ */
1082
+ /* /\* else { *\/ */
1083
+ /* /\* if(loop == Qtrue) { *\/ */
1084
+ /* /\* yoffset = calc_pixel_offset(&tex, x + tex.width - step, y); *\/ */
1085
+ /* /\* color_copy(tex.td_array + yoffset, tex.td_array + offset); *\/ */
1086
+ /* /\* } *\/ */
1087
+ /* /\* else { *\/ */
1088
+ /* /\* zero_color(tex.td_array + offset); *\/ */
1089
+ /* /\* } *\/ */
1090
+ /* /\* } *\/ */
1091
+
1092
+ /* /\* } *\/ */
1093
+ /* /\* } *\/ */
1094
+
1095
+ /* /\* bounds.xmin = 0; *\/ */
1096
+ /* /\* bounds.xmax = tex.width; *\/ */
1097
+ /* /\* bounds.ymin = 0; *\/ */
1098
+ /* /\* bounds.ymax = tex.height; *\/ */
1099
+
1100
+ /* /\* create_subtexture_and_sync_to_gl(&bounds, &tex); *\/ */
1101
+
1102
+ /* /\* return Qnil; *\/ */
1103
+ /* /\* } *\/ */
1104
+
1105
+ /* /\* /\\* special pixel action for image[]= *\\/ *\/ */
1106
+ /* /\* VALUE *\/ */
1107
+ /* /\* m_special_pixel(int argc, VALUE * argv, VALUE self) *\/ */
1108
+ /* /\* { *\/ */
1109
+
1110
+ /* /\* rgba old_color; *\/ */
1111
+
1112
+ /* /\* if(argc < 3) rb_raise(rb_eArgError, "[]= action needs 3 parameters"); *\/ */
1113
+
1114
+ /* /\* m_color(1, &argv[2], self); *\/ */
1115
+
1116
+ /* /\* m_pixel(2, argv, self); *\/ */
1117
+
1118
+ /* /\* // color_struct = old_color; *\/ */
1119
+
1120
+
1121
+ /* /\* return Qnil; *\/ */
1122
+ /* /\* } *\/ */
1123
+
1124
+ /* /\* /\\* instance methods *\\/ *\/ */
1125
+