texplay 0.2.7-x86-mswin32

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