texplay 0.2.7-x86-mswin32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+