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,978 @@
1
+ /* utils.c */
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+ #include <ctype.h>
5
+ #include <ruby.h>
6
+ #include <stdarg.h>
7
+ #include <assert.h>
8
+ #include <stdlib.h>
9
+ #include <math.h>
10
+ #include "cache.h"
11
+ #include "texplay.h"
12
+ #include "utils.h"
13
+
14
+ #ifdef __APPLE__
15
+ #include <glut.h>
16
+ #else
17
+ #include <GL/glut.h>
18
+ #endif
19
+
20
+ /*
21
+ #define MULT_FLOAT4(X, Y) ({ \
22
+ asm volatile ( \
23
+ "movups (%0), %%xmm0\n\t" \
24
+ "mulps (%1), %%xmm0\n\t" \
25
+ "movups %%xmm0, (%1)" \
26
+ :: "r" (X), "r" (Y)); })
27
+
28
+ #define COPY_FLOAT4(X, Y) ({ \
29
+ asm volatile ( \
30
+ "movups (%0), %%xmm0\n\t" \
31
+ "movups %%xmm0, (%1)" \
32
+ :: "r" (X), "r" (Y)); })
33
+
34
+ */
35
+ /* internal linkage with static duration */
36
+ static const rgba not_a_color_v = { -1.0, -1.0, -1.0, -1.0 };
37
+
38
+ /* utility functions */
39
+ char*
40
+ lowercase(char * string)
41
+ {
42
+ int i = 0;
43
+
44
+ while (string[i]) {
45
+ string[i] = tolower(string[i]);
46
+ i++;
47
+ }
48
+
49
+ return string;
50
+ }
51
+
52
+ char*
53
+ sym2string(VALUE sym)
54
+ {
55
+ return rb_id2name(SYM2ID(sym));
56
+ }
57
+
58
+ VALUE
59
+ string2sym(char * string)
60
+ {
61
+ return ID2SYM(rb_intern(string));
62
+ }
63
+
64
+ bool
65
+ is_a_hash(VALUE try_hash)
66
+ {
67
+ return TYPE(try_hash) == T_HASH;
68
+ }
69
+
70
+ bool
71
+ is_an_array(VALUE try_array)
72
+ {
73
+ return TYPE(try_array) == T_ARRAY;
74
+ }
75
+
76
+ bool is_a_num(VALUE try_num)
77
+ {
78
+ return TYPE(try_num) == T_FIXNUM || TYPE(try_num) == T_FLOAT;
79
+ }
80
+
81
+ VALUE
82
+ get_from_hash(VALUE hash, char * sym)
83
+ {
84
+
85
+ if(TYPE(hash) != T_HASH) rb_raise(rb_eArgError, "hash argument expected");
86
+
87
+ return rb_hash_aref(hash, string2sym(sym));
88
+ }
89
+
90
+ VALUE
91
+ set_hash_value(VALUE hash, char * sym, VALUE val)
92
+ {
93
+ if(TYPE(hash) != T_HASH) rb_raise(rb_eArgError, "hash argument expected");
94
+
95
+ rb_hash_aset(hash, string2sym(sym), val);
96
+
97
+ return val;
98
+ }
99
+
100
+ VALUE
101
+ delete_from_hash(VALUE hash, char * sym)
102
+ {
103
+ if(TYPE(hash) != T_HASH) rb_raise(rb_eArgError, "hash argument expected");
104
+
105
+ return rb_hash_delete(hash, string2sym(sym));
106
+ }
107
+
108
+ /* returns true if 'hash' is a hash and the value mapped to key 'sym' is
109
+ equal to 'val' */
110
+ bool
111
+ hash_value_is(VALUE hash, char * sym, VALUE val)
112
+ {
113
+ if(TYPE(hash) != T_HASH) return false;
114
+
115
+ if(get_from_hash(hash, sym) == val)
116
+ return true;
117
+
118
+ return false;
119
+ }
120
+
121
+ bool
122
+ has_optional_hash_arg(VALUE hash, char * sym)
123
+ {
124
+ if(TYPE(hash) != T_HASH) return false;
125
+
126
+ if(NIL_P(get_from_hash(hash, sym)))
127
+ return false;
128
+
129
+ /* 'hash' is a hash and the sym exists */
130
+ return true;
131
+ }
132
+
133
+ VALUE
134
+ set_array_value(VALUE array, int index, VALUE val)
135
+ {
136
+ if(TYPE(array) != T_ARRAY) rb_raise(rb_eArgError, "array argument expected");
137
+
138
+ rb_ary_store(array, index, val);
139
+
140
+ return val;
141
+ }
142
+
143
+ VALUE
144
+ get_from_array(VALUE array, int index)
145
+ {
146
+
147
+ if(TYPE(array) != T_ARRAY) rb_raise(rb_eArgError, "array argument expected");
148
+
149
+ return rb_ary_entry(array, index);
150
+ }
151
+
152
+
153
+ VALUE
154
+ init_image_local(VALUE image)
155
+ {
156
+ VALUE image_local;
157
+
158
+ if(!is_gosu_image(image))
159
+ rb_raise(rb_eArgError, "not a valid image");
160
+
161
+ /* initialize image_local hash if does not exist */
162
+ if(!is_an_array(rb_iv_get(image, "__image_local__"))) {
163
+ image_local = rb_ary_new();
164
+ rb_iv_set(image, "__image_local__", image_local);
165
+ }
166
+
167
+ image_local = rb_iv_get(image, "__image_local__");
168
+
169
+ return image_local;
170
+ }
171
+
172
+ void
173
+ set_image_local(VALUE image, int name, VALUE val)
174
+ {
175
+ VALUE image_local;
176
+
177
+ image_local = init_image_local(image);
178
+
179
+ set_array_value(image_local, name, val);
180
+ }
181
+
182
+ VALUE
183
+ get_image_local(VALUE image, int name)
184
+ {
185
+ VALUE image_local;
186
+ VALUE val;
187
+
188
+ init_image_local(image);
189
+
190
+ /* this var holds all the image local variables in an array */
191
+ image_local = rb_iv_get(image, "__image_local__");
192
+
193
+ /* a particular image_local variable */
194
+ val = get_from_array(image_local, name);
195
+
196
+ /* if the variable exists then return it */
197
+ if(!NIL_P(val))
198
+ return val;
199
+
200
+ /* otherwise initialize the variable and then return it */
201
+ else {
202
+ switch(name) {
203
+ VALUE init_offset, init_bounds, init_color, init_defaults;
204
+ case DRAW_OFFSET:
205
+ init_offset = rb_ary_new2(2);
206
+ set_array_value(init_offset, 0, INT2FIX(0));
207
+ set_array_value(init_offset, 1, INT2FIX(0));
208
+
209
+ set_array_value(image_local, DRAW_OFFSET, init_offset);
210
+
211
+ return init_offset;
212
+ break;
213
+ case LAZY_BOUNDS:
214
+ init_bounds = rb_ary_new2(4);
215
+ set_array_value(init_bounds, 0, INT2FIX(XMAX_OOB));
216
+ set_array_value(init_bounds, 1, INT2FIX(YMAX_OOB));
217
+ set_array_value(init_bounds, 2, INT2FIX(XMIN_OOB));
218
+ set_array_value(init_bounds, 3, INT2FIX(YMIN_OOB));
219
+
220
+ set_array_value(image_local, LAZY_BOUNDS, init_bounds);
221
+
222
+ return init_bounds;
223
+ break;
224
+ case IMAGE_COLOR:
225
+ init_color = rb_ary_new2(4);
226
+ set_array_value(init_color, 0, rb_float_new(1.0));
227
+ set_array_value(init_color, 1, rb_float_new(1.0));
228
+ set_array_value(init_color, 2, rb_float_new(1.0));
229
+ set_array_value(init_color, 3, rb_float_new(1.0));
230
+
231
+ set_array_value(image_local, IMAGE_COLOR, init_color);
232
+
233
+ return init_color;
234
+ break;
235
+ case USER_DEFAULTS:
236
+ init_defaults = rb_hash_new();
237
+
238
+ set_array_value(image_local, USER_DEFAULTS, init_defaults);
239
+
240
+ return init_defaults;
241
+ break;
242
+ default:
243
+ rb_raise(rb_eArgError, "unrecognized image_local variable number. got %d", name);
244
+ }
245
+ }
246
+
247
+ /* never reached */
248
+ return Qnil;
249
+ }
250
+
251
+ rgba
252
+ convert_image_local_color_to_rgba(VALUE image)
253
+ {
254
+ rgba color;
255
+ VALUE image_local_color = get_image_local(image, IMAGE_COLOR);
256
+
257
+ color.red = NUM2DBL(get_from_array(image_local_color, red));
258
+ color.green = NUM2DBL(get_from_array(image_local_color, green));
259
+ color.blue = NUM2DBL(get_from_array(image_local_color, blue));
260
+ color.alpha = NUM2DBL(get_from_array(image_local_color, alpha));
261
+
262
+ return color;
263
+ }
264
+
265
+ VALUE
266
+ save_rgba_to_image_local_color(VALUE image, rgba color)
267
+ {
268
+ /* abbreviation for image_local_color */
269
+ VALUE ilc = get_image_local(image, IMAGE_COLOR);
270
+
271
+ set_array_value(ilc, 0, rb_float_new(color.red));
272
+ set_array_value(ilc, 1, rb_float_new(color.green));
273
+ set_array_value(ilc, 2, rb_float_new(color.blue));
274
+ set_array_value(ilc, 3, rb_float_new(color.alpha));
275
+
276
+ return ilc;
277
+ }
278
+
279
+ /* if 2nd param is Qnil, then create a blank image with 'width' and 'height
280
+ otherwise, try to use the 2nd param (dup) to create a duplicate image
281
+ */
282
+ VALUE
283
+ create_image(VALUE window, int width, int height)
284
+ {
285
+ VALUE gosu = rb_const_get(rb_cObject, rb_intern("Gosu"));
286
+ VALUE image = rb_const_get(gosu, rb_intern("Image"));
287
+
288
+ VALUE TP = rb_const_get(rb_cObject, rb_intern("TexPlay"));
289
+ VALUE EmptyImageStub = rb_const_get(TP, rb_intern("EmptyImageStub"));
290
+
291
+ VALUE rmagick_img;
292
+ VALUE new_image;
293
+
294
+ rmagick_img = rb_funcall(EmptyImageStub, rb_intern("new"), 2, INT2FIX(width), INT2FIX(height));
295
+
296
+ new_image = rb_funcall(image, rb_intern("new"), 2, window, rmagick_img);
297
+
298
+ return new_image;
299
+ }
300
+
301
+
302
+ bool
303
+ not_a_color(rgba color1)
304
+ {
305
+ return color1.red == -1;
306
+ }
307
+
308
+ bool
309
+ is_a_color(rgba color1)
310
+ {
311
+ return !not_a_color(color1);
312
+ }
313
+
314
+ bool
315
+ cmp_color(rgba color1, rgba color2)
316
+ {
317
+
318
+ return (color1.red == color2.red) && (color1.green == color2.green) && (color1.blue == color2.blue)
319
+ && (color1.alpha == color2.alpha);
320
+ }
321
+
322
+ void
323
+ color_copy(float * source, float * dest)
324
+ {
325
+ //COPY_FLOAT4(source, dest);
326
+ memcpy(dest, source, 4 * sizeof(float));
327
+ }
328
+
329
+ void
330
+ zero_color(float * tex)
331
+ {
332
+ memset(tex, 0, 4 * sizeof(float));
333
+ }
334
+
335
+ rgba
336
+ get_pixel_color_from_chunk(float * chunk, int width, int height, int x, int y)
337
+ {
338
+ rgba my_color;
339
+
340
+ int offset;
341
+
342
+ if(x > (width - 1) || x < 0 || y > (height - 1) || y < 0)
343
+ return not_a_color_v;
344
+
345
+ offset = 4 * (x + y * width);
346
+
347
+ my_color.red = chunk[offset + red];
348
+ my_color.green = chunk[offset + green];
349
+ my_color.blue = chunk[offset + blue];
350
+ my_color.alpha = chunk[offset + alpha];
351
+
352
+ return my_color;
353
+ }
354
+
355
+
356
+ rgba
357
+ get_pixel_color(texture_info * tex, int x, int y)
358
+ {
359
+ rgba my_color;
360
+
361
+ int offset;
362
+
363
+ /* if pixel location is out of range return not_a_color_v */
364
+ if (x > (tex->width - 1) || x < 0 || y > (tex->height - 1) || y < 0)
365
+ return not_a_color_v;
366
+
367
+ offset = calc_pixel_offset(tex, x, y);
368
+
369
+ my_color.red = tex->td_array[offset + red];
370
+ my_color.green = tex->td_array[offset + green];
371
+ my_color.blue = tex->td_array[offset + blue];
372
+ my_color.alpha = tex->td_array[offset + alpha];
373
+
374
+ return my_color;
375
+ }
376
+
377
+ /* return the array where pixel data is stored */
378
+ float*
379
+ get_pixel_data(texture_info * tex, int x, int y)
380
+ {
381
+ int offset = calc_pixel_offset(tex, x, y);
382
+
383
+ return &tex->td_array[offset];
384
+ }
385
+
386
+ /* set the pixel color at (x, y) */
387
+ void
388
+ set_pixel_color(rgba * pixel_color, texture_info * tex, int x, int y)
389
+ {
390
+ float * tex_data;
391
+
392
+ /* should pixel be drawn ? */
393
+ if (x > (tex->width - 1) || x < 0 || y > (tex->height - 1) || y < 0)
394
+ return;
395
+
396
+ /* if not a color then do not draw */
397
+ if(not_a_color(*pixel_color))
398
+ return;
399
+
400
+ tex_data = get_pixel_data(tex, x, y);
401
+
402
+ /* set the pixel color */
403
+ tex_data[red] = pixel_color->red;
404
+ tex_data[green] = pixel_color->green;
405
+ tex_data[blue] = pixel_color->blue;
406
+ tex_data[alpha] = pixel_color->alpha;
407
+ }
408
+
409
+ rgba
410
+ find_color_from_string(char * try_color)
411
+ {
412
+ rgba cur_color;
413
+
414
+ if(!strcmp("red", try_color)) {
415
+ cur_color.red = 1.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
416
+ }
417
+ else if(!strcmp("green", try_color)) {
418
+ cur_color.red = 0.0; cur_color.green = 1.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
419
+ }
420
+ else if(!strcmp("blue", try_color)) {
421
+ cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
422
+ }
423
+ else if(!strcmp("black", try_color)) {
424
+ cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
425
+ }
426
+ else if(!strcmp("white", try_color)) {
427
+ cur_color.red = 1.0; cur_color.green = 1.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
428
+ }
429
+ else if(!strcmp("purple", try_color)) {
430
+ cur_color.red = 1.0; cur_color.green = 0.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
431
+ }
432
+ else if(!strcmp("yellow", try_color)) {
433
+ cur_color.red = 1.0; cur_color.green = 1.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
434
+ }
435
+ else if(!strcmp("cyan", try_color)) {
436
+ cur_color.red = 0.0; cur_color.green = 1.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
437
+ }
438
+ else if(!strcmp("orange", try_color)) {
439
+ cur_color.red = 1.0; cur_color.green = 0.5; cur_color.blue = 0.0; cur_color.alpha = 1.0;
440
+ }
441
+ else if(!strcmp("brown", try_color)) {
442
+ cur_color.red = 0.39; cur_color.green = 0.26; cur_color.blue = 0.13; cur_color.alpha = 1.0;
443
+ }
444
+ else if(!strcmp("turquoise", try_color)) {
445
+ cur_color.red = 0.1; cur_color.green = 0.6; cur_color.blue = 0.8; cur_color.alpha = 1.0;
446
+ }
447
+ else if(!strcmp("tyrian", try_color)) {
448
+ cur_color.red = 0.4; cur_color.green = 0.007; cur_color.blue = 0.235; cur_color.alpha = 1.0;
449
+ }
450
+ else if(!strcmp("alpha", try_color)) {
451
+ cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 0.0;
452
+ }
453
+ else if(!strcmp("none", try_color)) {
454
+ cur_color = not_a_color_v;
455
+ }
456
+ else if(!strcmp("random", try_color) || !strcmp("rand", try_color)) {
457
+ cur_color.red = rand() / (float)RAND_MAX;
458
+ cur_color.green = rand() / (float)RAND_MAX;
459
+ cur_color.blue = rand() / (float)RAND_MAX;
460
+ cur_color.alpha = 1.0;
461
+ }
462
+
463
+ else
464
+ rb_raise(rb_eArgError, "invalid colour specified (no color matches the symbol: %s)\n", try_color);
465
+
466
+ return cur_color;
467
+ }
468
+
469
+ /* convert C color to Ruby color */
470
+ VALUE
471
+ convert_rgba_to_rb_color(rgba * pix)
472
+ {
473
+ /* create a new ruby array to store the pixel data */
474
+ VALUE pix_array = rb_ary_new2(4);
475
+
476
+ /* store the pixel data */
477
+ rb_ary_store(pix_array, red, rb_float_new(pix->red));
478
+ rb_ary_store(pix_array, green, rb_float_new(pix->green));
479
+ rb_ary_store(pix_array, blue, rb_float_new(pix->blue));
480
+ rb_ary_store(pix_array, alpha, rb_float_new(pix->alpha));
481
+
482
+ return pix_array;
483
+ }
484
+
485
+ /* convert Ruby color to C color */
486
+ rgba
487
+ convert_rb_color_to_rgba(VALUE cval)
488
+ {
489
+ rgba my_color;
490
+
491
+ /* current color for actions */
492
+ switch(TYPE(cval)) {
493
+ char * try_color;
494
+ case T_SYMBOL:
495
+ try_color = lowercase(sym2string(cval));
496
+
497
+ my_color = find_color_from_string(try_color);
498
+
499
+ break;
500
+ case T_ARRAY:
501
+ my_color.red = NUM2DBL(rb_ary_entry(cval, red));
502
+ my_color.green = NUM2DBL(rb_ary_entry(cval, green));
503
+ my_color.blue = NUM2DBL(rb_ary_entry(cval, blue));
504
+
505
+ if(NUM2INT(rb_funcall(cval, rb_intern("length"), 0)) > 3)
506
+ my_color.alpha = NUM2DBL(rb_ary_entry(cval, alpha));
507
+ else
508
+ my_color.alpha = 1;
509
+
510
+ break;
511
+ default:
512
+ rb_raise(rb_eArgError, "unsupported argument type for color. Got type 0x%x\n", TYPE(cval) );
513
+ }
514
+
515
+ /* a valid color */
516
+ if(is_a_color(my_color))
517
+ return my_color;
518
+
519
+ /* special condition for when color is taken from outside range of bitmap. Color is just ignored */
520
+ else if(not_a_color(my_color))
521
+ return not_a_color_v;
522
+
523
+ /* anything else should fail */
524
+ else
525
+ rb_raise(rb_eArgError, "invalid colour specified (negative value given)\n");
526
+ }
527
+
528
+ /* error checking functions */
529
+ void
530
+ check_mask(VALUE mask)
531
+ {
532
+ char * try_mask;
533
+
534
+ if(TYPE(mask) != T_ARRAY && TYPE(mask) != T_SYMBOL)
535
+ rb_raise(rb_eArgError, "array or symbol parameter required");
536
+
537
+ /* is it a valid mask symbol? */
538
+ if(TYPE(mask) == T_SYMBOL) {
539
+ try_mask = lowercase(sym2string(mask));
540
+ if(*try_mask == '_') try_mask++;
541
+ if(not_a_color(find_color_from_string(try_mask))) {
542
+ rb_raise(rb_eArgError, "unrecognized mask symbol: %s\n", sym2string(mask));
543
+ }
544
+ }
545
+ }
546
+
547
+ void
548
+ check_image(VALUE image)
549
+ {
550
+ if(!rb_respond_to(image, rb_intern("gl_tex_info")))
551
+ rb_raise(rb_eRuntimeError,"must specify a valid source image");
552
+ }
553
+
554
+ bool
555
+ is_gosu_image(VALUE try_image)
556
+ {
557
+ if(rb_respond_to(try_image, rb_intern("gl_tex_info")))
558
+ return true;
559
+
560
+ return false;
561
+ }
562
+
563
+
564
+ /** cohen-sutherland line clipper **/
565
+ #define outcode int
566
+ const int RIGHT = 8; //1000
567
+ const int TOP = 4; //0100
568
+ const int LEFT = 2; //0010
569
+ const int BOTTOM = 1; //0001
570
+
571
+ //Compute the bit code for a point (x, y) using the clip rectangle
572
+ //bounded diagonally by (xmin, ymin), and (xmax, ymax)
573
+ static outcode
574
+ ComputeOutCode (int x, int y, int xmin, int ymin, int xmax, int ymax)
575
+ {
576
+ outcode code = 0;
577
+ if (y > ymax) //above the clip window
578
+ code |= TOP;
579
+ else if (y < ymin) //below the clip window
580
+ code |= BOTTOM;
581
+ if (x > xmax) //to the right of clip window
582
+ code |= RIGHT;
583
+ else if (x < xmin) //to the left of clip window
584
+ code |= LEFT;
585
+ return code;
586
+ }
587
+
588
+ /** Cohen-Sutherland clipping algorithm clips a line from
589
+ P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with
590
+ diagonal from (xmin, ymin) to (xmax, ymax). **/
591
+ void
592
+ cohen_sutherland_clip (int * x0, int * y0,int * x1, int * y1, int xmin, int ymin,
593
+ int xmax, int ymax)
594
+ {
595
+ //Outcodes for P0, P1, and whatever point lies outside the clip rectangle
596
+ outcode outcode0, outcode1, outcodeOut;
597
+ bool accept = false, done = false;
598
+ int tx0 = *x0, ty0 = *y0, tx1 = *x1, ty1 = *y1;
599
+
600
+ //compute outcodes
601
+ outcode0 = ComputeOutCode (tx0, ty0, xmin, ymin, xmax, ymax);
602
+ outcode1 = ComputeOutCode (tx1, ty1, xmin, ymin, xmax, ymax);
603
+
604
+ do{
605
+ if (!(outcode0 | outcode1)) //logical or is 0. Trivially accept and get out of loop
606
+ {
607
+ accept = true;
608
+ done = true;
609
+ }
610
+ else if (outcode0 & outcode1) //logical and is not 0. Trivially reject and get out of loop
611
+ done = true;
612
+ else
613
+ {
614
+ //failed both tests, so calculate the line segment to clip
615
+ //from an outside point to an intersection with clip edge
616
+ double x, y;
617
+ //At least one endpoint is outside the clip rectangle; pick it.
618
+ outcodeOut = outcode0? outcode0: outcode1;
619
+ //Now find the intersection point;
620
+ //use formulas y = y0 + slope * (x - x0), x = x0 + (1/slope)* (y - y0)
621
+ if (outcodeOut & TOP) //point is above the clip rectangle
622
+ {
623
+ x = tx0 + (tx1 - tx0) * (ymax - ty0)/(ty1 - ty0);
624
+ y = ymax;
625
+ }
626
+ else if (outcodeOut & BOTTOM) //point is below the clip rectangle
627
+ {
628
+ x = tx0 + (tx1 - tx0) * (ymin - ty0)/(ty1 - ty0);
629
+ y = ymin;
630
+ }
631
+ else if (outcodeOut & RIGHT) //point is to the right of clip rectangle
632
+ {
633
+ y = ty0 + (ty1 - ty0) * (xmax - tx0)/(tx1 - tx0);
634
+ x = xmax;
635
+ }
636
+ else //point is to the left of clip rectangle
637
+ {
638
+ y = ty0 + (ty1 - ty0) * (xmin - tx0)/(tx1 - tx0);
639
+ x = xmin;
640
+ }
641
+ //Now we move outside point to intersection point to clip
642
+ //and get ready for next pass.
643
+ if (outcodeOut == outcode0)
644
+ {
645
+ tx0 = x;
646
+ ty0 = y;
647
+ outcode0 = ComputeOutCode (tx0, ty0, xmin, ymin, xmax, ymax);
648
+ }
649
+ else
650
+ {
651
+ tx1 = x;
652
+ ty1 = y;
653
+ outcode1 = ComputeOutCode (tx1, ty1, xmin, ymin, xmax, ymax);
654
+ }
655
+ }
656
+ }while (!done);
657
+
658
+ if (accept)
659
+ {
660
+ *x0 = tx0; *x1 = tx1;
661
+ *y0 = ty0; *y1 = ty1;
662
+ }
663
+
664
+ }
665
+ /** end of cohen-sutherland line clipper **/
666
+
667
+
668
+ void
669
+ constrain_boundaries(int * x0, int * y0, int * x1, int * y1, int width, int height)
670
+ {
671
+ if(*y0 < 0) *y0 = 0;
672
+ if(*y1 < 0) *y1 = 0;
673
+
674
+ if(*x0 < 0) *x0 = 0;
675
+ if(*x1 < 0) *x1 = 0;
676
+
677
+ if(*x0 > (width - 1)) *x0 = width - 1;
678
+ if(*x1 > (width - 1)) *x1 = width - 1;
679
+
680
+ if(*y0 > (height - 1)) *y0 = height - 1;
681
+ if(*y1 > (height - 1)) *y1 = height - 1;
682
+
683
+ if(*y0 > *y1) { SWAP(*y0, *y1); }
684
+ if(*x0 > *x1) { SWAP(*x0, *x1); }
685
+ }
686
+
687
+
688
+ /* returns true if point (x, y) is within bounds designated by rect (x0, y0)-(x1, y1)
689
+ and inner thickness: 'inner'
690
+ */
691
+ bool
692
+ bound_by_rect_and_inner(int x, int y, int x0, int y0, int x1, int y1, int inner)
693
+ {
694
+
695
+ return ((x >= x0) && (x <= x1) && (y >= y0) && (y <= y1)) &&
696
+ !((x >= x0 + inner) && (x <= x1 - inner) && (y >= y0 + inner) && (y <= y1 - inner));
697
+ }
698
+
699
+ /* same as above but excluding inner rectangle */
700
+ bool
701
+ bound_by_rect(int x, int y, int x0, int y0, int x1, int y1)
702
+ {
703
+ return bound_by_rect_and_inner(x, y, x0, y0, x1, y1, OOB_VAL);
704
+ }
705
+
706
+ /* calculate the array offset for a given pixel in action context */
707
+ int
708
+ calc_pixel_offset_for_action(action_struct * cur, texture_info * tex, int x, int y)
709
+ {
710
+ int offset = calc_pixel_offset(tex, x + cur->xmin, y + cur->ymin);
711
+
712
+ return offset;
713
+ }
714
+
715
+ /* calculate the array offset for a given pixel */
716
+ int
717
+ calc_pixel_offset(texture_info * tex, int x, int y)
718
+ {
719
+ int offset = 4 * (tex->firstpixel + x + tex->yincr * y);
720
+
721
+ return offset;
722
+ }
723
+
724
+ /* from Texure.cpp in Gosu Graphics folder */
725
+ unsigned
726
+ max_quad_size(void)
727
+ {
728
+ #ifdef __APPLE__
729
+ return 1024;
730
+ #else
731
+ static unsigned MIN_SIZE = 256, MAX_SIZE = 1024;
732
+
733
+ static unsigned size = 0;
734
+ if (size == 0)
735
+ {
736
+ GLint width = 1;
737
+ size = MIN_SIZE / 2;
738
+ do {
739
+ size *= 2;
740
+ glTexImage2D(GL_PROXY_TEXTURE_2D, 0, 4, size * 2, size * 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
741
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
742
+ } while (width != 0 && size < MAX_SIZE);
743
+ }
744
+
745
+ return size;
746
+ #endif
747
+ }
748
+
749
+ /* ensure gl_tex_info returns non nil */
750
+ VALUE
751
+ check_for_texture_info(VALUE image)
752
+ {
753
+ VALUE info;
754
+
755
+ info = rb_funcall(image, rb_intern("gl_tex_info"), 0);
756
+
757
+ if(NIL_P(info)) {
758
+ VALUE image_name = rb_inspect(image);
759
+ int width = FIX2INT(rb_funcall(image, rb_intern("width"), 0));
760
+ int height = FIX2INT(rb_funcall(image, rb_intern("height"), 0));
761
+
762
+ rb_raise(rb_eException, "Error: gl_tex_info returns nil for %s (%i x %i). Could be caused by "
763
+ "very large image or Gosu bug. Try updating Gosu or use a smaller image. Note: TexPlay should"
764
+ " be able to work with %i x %i images.",
765
+ StringValuePtr(image_name), width, height, max_quad_size() - 2, max_quad_size() - 2);
766
+ }
767
+
768
+ return info;
769
+ }
770
+
771
+ float *
772
+ allocate_texture(int width, int height)
773
+ {
774
+ float * new_texture;
775
+ int mval;
776
+
777
+ mval = 4 * width * height * sizeof(float);
778
+ assert(mval > 0);
779
+
780
+ new_texture = malloc(mval);
781
+
782
+ return (float *)new_texture;
783
+ }
784
+
785
+ /* responsible for syncing a subimage to gl */
786
+ void
787
+ sync_to_gl(int tex_name, int x_offset, int y_offset, int width, int height, void * sub)
788
+ {
789
+ /* set the opengl texture context */
790
+ glEnable(GL_TEXTURE_2D);
791
+ glBindTexture(GL_TEXTURE_2D, tex_name);
792
+
793
+ /* sync subtexture */
794
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x_offset, y_offset, width, height,
795
+ GL_RGBA, GL_FLOAT, sub);
796
+
797
+ glDisable(GL_TEXTURE_2D);
798
+ }
799
+
800
+ void
801
+ create_subtexture_and_sync_to_gl(image_bounds * img_bounds, texture_info * tex)
802
+ {
803
+ /* image vars */
804
+ int xbound, ybound;
805
+ float * sub = NULL;
806
+
807
+ /* make the current action's boundaries sane; left until this point because we only
808
+ know height/width here */
809
+ constrain_boundaries(&img_bounds->xmin, &img_bounds->ymin, &img_bounds->xmax, &img_bounds->ymax,
810
+ tex->width, tex->height);
811
+
812
+ /* helper variables */
813
+ ybound = img_bounds->ymax - img_bounds->ymin + 1;
814
+ xbound = img_bounds->xmax - img_bounds->xmin + 1;
815
+
816
+ sub = get_image_chunk(tex, img_bounds->xmin, img_bounds->ymin, img_bounds->xmax, img_bounds->ymax);
817
+
818
+ sync_to_gl(tex->tname, tex->x_offset + img_bounds->xmin, tex->y_offset + img_bounds->ymin, xbound,
819
+ ybound, (void*)sub);
820
+
821
+ free(sub);
822
+ }
823
+
824
+ float *
825
+ get_image_chunk(texture_info * tex, int xmin, int ymin, int xmax, int ymax)
826
+ {
827
+ int xbound;
828
+ int ybound;
829
+ int x, y;
830
+ float * image_buf = NULL;
831
+
832
+ constrain_boundaries(&xmin, &ymin, &xmax, &ymax, tex->width, tex->height);
833
+
834
+ xbound = xmax - xmin + 1;
835
+ ybound = ymax - ymin + 1;
836
+
837
+ image_buf = allocate_texture(xbound, ybound);
838
+
839
+ for(y = 0; y < ybound; y++)
840
+ for(x = 0; x < xbound; x++) {
841
+ int buf_index = 4 * (x + y * xbound);
842
+
843
+ int offset = calc_pixel_offset(tex, x + xmin, y + ymin);
844
+
845
+ color_copy(tex->td_array + offset, image_buf + buf_index);
846
+ }
847
+
848
+ return image_buf;
849
+ }
850
+
851
+ /* get information from texture */
852
+ void
853
+ get_texture_info(VALUE image, texture_info * tex)
854
+ {
855
+ VALUE info, gc_state_off;
856
+ int toppos, leftpos;
857
+ float top, left;
858
+ cache_entry * entry;
859
+
860
+ /* hack to prevent segfault */
861
+ gc_state_off = rb_gc_disable();
862
+
863
+ tex->width = FIX2INT(rb_funcall(image, rb_intern("width"), 0));
864
+ tex->height = FIX2INT(rb_funcall(image, rb_intern("height"), 0));
865
+
866
+ /* ensure gl_tex_info returns non nil */
867
+ info = check_for_texture_info(image);
868
+
869
+ top = NUM2DBL(rb_funcall(info, rb_intern("top"), 0));
870
+ left = NUM2DBL(rb_funcall(info, rb_intern("left"), 0));
871
+ tex->tname = FIX2INT(rb_funcall(info ,rb_intern("tex_name"),0));
872
+
873
+ /* search for texture in cache (& create if not extant) */
874
+ entry = find_or_create_cache_entry(tex->tname);
875
+
876
+ tex->td_array = entry->tdata;
877
+ tex->yincr = entry->sidelength;
878
+
879
+ /* scratch variables */
880
+ toppos = ROUND(top * entry->sidelength * entry->sidelength);
881
+ leftpos = ROUND(left * entry->sidelength);
882
+
883
+ /* find the first pixel for the image */
884
+ tex->firstpixel = (int)(toppos + leftpos);
885
+
886
+ tex->x_offset = ROUND(left * tex->yincr);
887
+ tex->y_offset = ROUND(top * tex->yincr);
888
+
889
+ /* save the associated Gosu::Image */
890
+ tex->image = image;
891
+
892
+ /* only enable gc if was enabled on function entry */
893
+ if(!gc_state_off) rb_gc_enable();
894
+ }
895
+
896
+ /* point format utilities */
897
+ bool
898
+ is_a_point(VALUE try_point)
899
+ {
900
+ /* if it responds to 'x' it's near enough (technically must respond to x AND y) */
901
+ /* added the is_a_num() check due to WEIRD bug where FIXNUMS were responding to the 'x' method (wtf?) but returning nil when invoked */
902
+ if(rb_respond_to(try_point, rb_intern("x")) && !is_a_num(try_point))
903
+ return true;
904
+
905
+ return false;
906
+ }
907
+
908
+ VALUE
909
+ point_x(VALUE point)
910
+ {
911
+ return rb_funcall(point, rb_intern("x"), 0);
912
+ }
913
+
914
+ VALUE
915
+ point_y(VALUE point)
916
+ {
917
+ return rb_funcall(point, rb_intern("y"), 0);
918
+ }
919
+
920
+ /* mathematical utils, used mainly by bezier curves */
921
+ double
922
+ power(float base, int exp)
923
+ {
924
+ float ans = 1.0;
925
+ if(base == 0.0) {
926
+ if(exp == 0)
927
+ return 1;
928
+ else
929
+ return 0;
930
+ }
931
+ else if(exp == 0) return 1;
932
+ else {
933
+ int k;
934
+ for(k = exp; k >= 1; k--) {
935
+ ans = ans * base;
936
+ }
937
+ return ans;
938
+ }
939
+ }
940
+
941
+ unsigned
942
+ fact(int n)
943
+ {
944
+ if (n == 0 || n == 1) return 1;
945
+ else
946
+ return (n * fact(n - 1));
947
+ }
948
+
949
+ unsigned
950
+ comb(int n, int r)
951
+ {
952
+ /* double temp = fact(n) / (fact(r) * fact(n - r)); */
953
+ /* return temp; */
954
+
955
+ /* nCr is symmetrical about n / 2 */
956
+ if(r > (n / 2))
957
+ r = n - r;
958
+
959
+ return perm(n, r) / fact(r);
960
+ }
961
+
962
+ unsigned
963
+ perm(int n, int r)
964
+ {
965
+ int val = 1;
966
+ int i;
967
+ for(i = n; i > (n - r); i--)
968
+ val *= i;
969
+
970
+ return val;
971
+ }
972
+
973
+ double
974
+ bernstein(int n, int k, float u)
975
+ {
976
+ double temp = comb(n, k) * pow(u, k) * pow(1 - u, n - k);
977
+ return temp;
978
+ }