texplay 0.2.800 → 0.2.900

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