texplay 0.4.3 → 0.4.4.pre

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