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,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
+ }