texplay 0.2.800 → 0.2.900

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 (51) hide show
  1. data/CHANGELOG +138 -119
  2. data/README.markdown +43 -41
  3. data/Rakefile +68 -68
  4. data/examples/common.rb +8 -8
  5. data/examples/example_alpha_blend.rb +31 -31
  6. data/examples/example_bezier.rb +42 -42
  7. data/examples/example_color_control.rb +69 -69
  8. data/examples/example_color_transform.rb +64 -67
  9. data/examples/example_color_transform_circle.rb +65 -0
  10. data/examples/example_dup.rb +75 -75
  11. data/examples/example_each.rb +42 -42
  12. data/examples/example_effect.rb +35 -35
  13. data/examples/example_fill.rb +44 -44
  14. data/examples/example_fill_old.rb +49 -49
  15. data/examples/example_fluent.rb +31 -31
  16. data/examples/example_gen_eval.rb +34 -34
  17. data/examples/example_hash_arguments.rb +47 -47
  18. data/examples/example_light.rb +77 -0
  19. data/examples/example_lsystem.rb +61 -61
  20. data/examples/example_melt.rb +27 -27
  21. data/examples/example_meyet.rb +64 -0
  22. data/examples/example_polyline.rb +43 -43
  23. data/examples/example_scale.rb +29 -29
  24. data/examples/example_simple.rb +48 -38
  25. data/examples/example_sync.rb +60 -60
  26. data/examples/example_trace.rb +1 -1
  27. data/examples/example_turtle.rb +40 -40
  28. data/examples/example_weird.rb +3 -1
  29. data/examples/media/Thumbs.db +0 -0
  30. data/ext/texplay/actions.c +999 -1001
  31. data/ext/texplay/actions.h +60 -60
  32. data/ext/texplay/bindings.c +1162 -1149
  33. data/ext/texplay/bindings.h +46 -46
  34. data/ext/texplay/cache.c +118 -118
  35. data/ext/texplay/cache.h +24 -24
  36. data/ext/texplay/compat.h +27 -27
  37. data/ext/texplay/extconf.rb +28 -28
  38. data/ext/texplay/gen_eval.c +211 -211
  39. data/ext/texplay/gen_eval.h +20 -20
  40. data/ext/texplay/graphics_utils.c +188 -63
  41. data/ext/texplay/graphics_utils.h +0 -1
  42. data/ext/texplay/object2module.c +171 -171
  43. data/ext/texplay/object2module.h +11 -11
  44. data/ext/texplay/texplay.c +169 -169
  45. data/ext/texplay/texplay.h +147 -130
  46. data/ext/texplay/utils.c +816 -752
  47. data/ext/texplay/utils.h +151 -145
  48. data/lib/texplay-contrib.rb +171 -171
  49. data/lib/texplay.rb +162 -137
  50. data/lib/texplay/version.rb +1 -1
  51. metadata +9 -5
data/ext/texplay/utils.c CHANGED
@@ -1,752 +1,816 @@
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
- /* external linkage with static duration */
36
- 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
-
280
-
281
- bool
282
- not_a_color(rgba color1)
283
- {
284
- return color1.red == -1;
285
- }
286
-
287
- bool
288
- is_a_color(rgba color1)
289
- {
290
- return !not_a_color(color1);
291
- }
292
-
293
- bool
294
- cmp_color(rgba color1, rgba color2)
295
- {
296
-
297
- return (color1.red == color2.red) && (color1.green == color2.green) && (color1.blue == color2.blue)
298
- && (color1.alpha == color2.alpha);
299
- }
300
-
301
- void
302
- color_copy(float * source, float * dest)
303
- {
304
- //COPY_FLOAT4(source, dest);
305
- memcpy(dest, source, 4 * sizeof(float));
306
- }
307
-
308
- void
309
- zero_color(float * tex)
310
- {
311
- memset(tex, 0, 4 * sizeof(float));
312
- }
313
-
314
- rgba
315
- find_color_from_string(char * try_color)
316
- {
317
- rgba cur_color;
318
-
319
- if(!strcmp("red", try_color)) {
320
- cur_color.red = 1.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
321
- }
322
- else if(!strcmp("green", try_color)) {
323
- cur_color.red = 0.0; cur_color.green = 1.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
324
- }
325
- else if(!strcmp("blue", try_color)) {
326
- cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
327
- }
328
- else if(!strcmp("black", try_color)) {
329
- cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
330
- }
331
- else if(!strcmp("white", try_color)) {
332
- cur_color.red = 1.0; cur_color.green = 1.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
333
- }
334
- else if(!strcmp("purple", try_color)) {
335
- cur_color.red = 1.0; cur_color.green = 0.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
336
- }
337
- else if(!strcmp("yellow", try_color)) {
338
- cur_color.red = 1.0; cur_color.green = 1.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
339
- }
340
- else if(!strcmp("cyan", try_color)) {
341
- cur_color.red = 0.0; cur_color.green = 1.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
342
- }
343
- else if(!strcmp("orange", try_color)) {
344
- cur_color.red = 1.0; cur_color.green = 0.5; cur_color.blue = 0.0; cur_color.alpha = 1.0;
345
- }
346
- else if(!strcmp("brown", try_color)) {
347
- cur_color.red = 0.39; cur_color.green = 0.26; cur_color.blue = 0.13; cur_color.alpha = 1.0;
348
- }
349
- else if(!strcmp("turquoise", try_color)) {
350
- cur_color.red = 0.1; cur_color.green = 0.6; cur_color.blue = 0.8; cur_color.alpha = 1.0;
351
- }
352
- else if(!strcmp("tyrian", try_color)) {
353
- cur_color.red = 0.4; cur_color.green = 0.007; cur_color.blue = 0.235; cur_color.alpha = 1.0;
354
- }
355
- else if(!strcmp("alpha", try_color)) {
356
- cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 0.0;
357
- }
358
- else if(!strcmp("none", try_color)) {
359
- cur_color = not_a_color_v;
360
- }
361
- else if(!strcmp("random", try_color) || !strcmp("rand", try_color)) {
362
- cur_color.red = rand() / (float)RAND_MAX;
363
- cur_color.green = rand() / (float)RAND_MAX;
364
- cur_color.blue = rand() / (float)RAND_MAX;
365
- cur_color.alpha = 1.0;
366
- }
367
-
368
- else
369
- rb_raise(rb_eArgError, "invalid colour specified (no color matches the symbol: %s)\n", try_color);
370
-
371
- return cur_color;
372
- }
373
-
374
- /* convert C color to Ruby color */
375
- VALUE
376
- convert_rgba_to_rb_color(rgba * pix)
377
- {
378
- /* create a new ruby array to store the pixel data */
379
- VALUE pix_array = rb_ary_new2(4);
380
-
381
- /* store the pixel data */
382
- rb_ary_store(pix_array, red, rb_float_new(pix->red));
383
- rb_ary_store(pix_array, green, rb_float_new(pix->green));
384
- rb_ary_store(pix_array, blue, rb_float_new(pix->blue));
385
- rb_ary_store(pix_array, alpha, rb_float_new(pix->alpha));
386
-
387
- return pix_array;
388
- }
389
-
390
- /* convert Ruby color to C color */
391
- rgba
392
- convert_rb_color_to_rgba(VALUE cval)
393
- {
394
- rgba my_color;
395
-
396
- /* current color for actions */
397
- switch(TYPE(cval)) {
398
- char * try_color;
399
- case T_SYMBOL:
400
- try_color = lowercase(sym2string(cval));
401
-
402
- my_color = find_color_from_string(try_color);
403
-
404
- break;
405
- case T_ARRAY:
406
- my_color.red = NUM2DBL(rb_ary_entry(cval, red));
407
- my_color.green = NUM2DBL(rb_ary_entry(cval, green));
408
- my_color.blue = NUM2DBL(rb_ary_entry(cval, blue));
409
-
410
- if(NUM2INT(rb_funcall(cval, rb_intern("length"), 0)) > 3)
411
- my_color.alpha = NUM2DBL(rb_ary_entry(cval, alpha));
412
- else
413
- my_color.alpha = 1;
414
-
415
- break;
416
- default:
417
- rb_raise(rb_eArgError, "unsupported argument type for color. Got type 0x%x\n", TYPE(cval) );
418
- }
419
-
420
- /* a valid color */
421
- if(is_a_color(my_color))
422
- return my_color;
423
-
424
- /* special condition for when color is taken from outside range of bitmap. Color is just ignored */
425
- else if(not_a_color(my_color))
426
- return not_a_color_v;
427
-
428
- /* anything else should fail */
429
- else
430
- rb_raise(rb_eArgError, "invalid colour specified (negative value given)\n");
431
- }
432
-
433
- /* error checking functions */
434
- void
435
- check_mask(VALUE mask)
436
- {
437
- char * try_mask;
438
-
439
- if(TYPE(mask) != T_ARRAY && TYPE(mask) != T_SYMBOL)
440
- rb_raise(rb_eArgError, "array or symbol parameter required");
441
-
442
- /* is it a valid mask symbol? */
443
- if(TYPE(mask) == T_SYMBOL) {
444
- try_mask = lowercase(sym2string(mask));
445
- if(*try_mask == '_') try_mask++;
446
- if(not_a_color(find_color_from_string(try_mask))) {
447
- rb_raise(rb_eArgError, "unrecognized mask symbol: %s\n", sym2string(mask));
448
- }
449
- }
450
- }
451
-
452
- void
453
- check_image(VALUE image)
454
- {
455
- if(!rb_respond_to(image, rb_intern("gl_tex_info")))
456
- rb_raise(rb_eRuntimeError,"must specify a valid source image");
457
- }
458
-
459
- bool
460
- is_gosu_image(VALUE try_image)
461
- {
462
- if(rb_respond_to(try_image, rb_intern("gl_tex_info")))
463
- return true;
464
-
465
- return false;
466
- }
467
-
468
-
469
- /** cohen-sutherland line clipper **/
470
- #define outcode int
471
- const int RIGHT = 8; //1000
472
- const int TOP = 4; //0100
473
- const int LEFT = 2; //0010
474
- const int BOTTOM = 1; //0001
475
-
476
- //Compute the bit code for a point (x, y) using the clip rectangle
477
- //bounded diagonally by (xmin, ymin), and (xmax, ymax)
478
- static outcode
479
- ComputeOutCode (int x, int y, int xmin, int ymin, int xmax, int ymax)
480
- {
481
- outcode code = 0;
482
- if (y > ymax) //above the clip window
483
- code |= TOP;
484
- else if (y < ymin) //below the clip window
485
- code |= BOTTOM;
486
- if (x > xmax) //to the right of clip window
487
- code |= RIGHT;
488
- else if (x < xmin) //to the left of clip window
489
- code |= LEFT;
490
- return code;
491
- }
492
-
493
- /** Cohen-Sutherland clipping algorithm clips a line from
494
- P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with
495
- diagonal from (xmin, ymin) to (xmax, ymax). **/
496
- void
497
- cohen_sutherland_clip (int * x0, int * y0,int * x1, int * y1, int xmin, int ymin,
498
- int xmax, int ymax)
499
- {
500
- //Outcodes for P0, P1, and whatever point lies outside the clip rectangle
501
- outcode outcode0, outcode1, outcodeOut;
502
- bool accept = false, done = false;
503
- int tx0 = *x0, ty0 = *y0, tx1 = *x1, ty1 = *y1;
504
-
505
- //compute outcodes
506
- outcode0 = ComputeOutCode (tx0, ty0, xmin, ymin, xmax, ymax);
507
- outcode1 = ComputeOutCode (tx1, ty1, xmin, ymin, xmax, ymax);
508
-
509
- do{
510
- if (!(outcode0 | outcode1)) //logical or is 0. Trivially accept and get out of loop
511
- {
512
- accept = true;
513
- done = true;
514
- }
515
- else if (outcode0 & outcode1) //logical and is not 0. Trivially reject and get out of loop
516
- done = true;
517
- else
518
- {
519
- //failed both tests, so calculate the line segment to clip
520
- //from an outside point to an intersection with clip edge
521
- double x, y;
522
- //At least one endpoint is outside the clip rectangle; pick it.
523
- outcodeOut = outcode0? outcode0: outcode1;
524
- //Now find the intersection point;
525
- //use formulas y = y0 + slope * (x - x0), x = x0 + (1/slope)* (y - y0)
526
- if (outcodeOut & TOP) //point is above the clip rectangle
527
- {
528
- x = tx0 + (tx1 - tx0) * (ymax - ty0)/(ty1 - ty0);
529
- y = ymax;
530
- }
531
- else if (outcodeOut & BOTTOM) //point is below the clip rectangle
532
- {
533
- x = tx0 + (tx1 - tx0) * (ymin - ty0)/(ty1 - ty0);
534
- y = ymin;
535
- }
536
- else if (outcodeOut & RIGHT) //point is to the right of clip rectangle
537
- {
538
- y = ty0 + (ty1 - ty0) * (xmax - tx0)/(tx1 - tx0);
539
- x = xmax;
540
- }
541
- else //point is to the left of clip rectangle
542
- {
543
- y = ty0 + (ty1 - ty0) * (xmin - tx0)/(tx1 - tx0);
544
- x = xmin;
545
- }
546
- //Now we move outside point to intersection point to clip
547
- //and get ready for next pass.
548
- if (outcodeOut == outcode0)
549
- {
550
- tx0 = x;
551
- ty0 = y;
552
- outcode0 = ComputeOutCode (tx0, ty0, xmin, ymin, xmax, ymax);
553
- }
554
- else
555
- {
556
- tx1 = x;
557
- ty1 = y;
558
- outcode1 = ComputeOutCode (tx1, ty1, xmin, ymin, xmax, ymax);
559
- }
560
- }
561
- }while (!done);
562
-
563
- if (accept)
564
- {
565
- *x0 = tx0; *x1 = tx1;
566
- *y0 = ty0; *y1 = ty1;
567
- }
568
-
569
- }
570
- /** end of cohen-sutherland line clipper **/
571
-
572
-
573
- void
574
- constrain_boundaries(int * x0, int * y0, int * x1, int * y1, int width, int height)
575
- {
576
- if(*y0 < 0) *y0 = 0;
577
- if(*y1 < 0) *y1 = 0;
578
-
579
- if(*x0 < 0) *x0 = 0;
580
- if(*x1 < 0) *x1 = 0;
581
-
582
- if(*x0 > (width - 1)) *x0 = width - 1;
583
- if(*x1 > (width - 1)) *x1 = width - 1;
584
-
585
- if(*y0 > (height - 1)) *y0 = height - 1;
586
- if(*y1 > (height - 1)) *y1 = height - 1;
587
-
588
- if(*y0 > *y1) { SWAP(*y0, *y1); }
589
- if(*x0 > *x1) { SWAP(*x0, *x1); }
590
- }
591
-
592
-
593
- /* returns true if point (x, y) is within bounds designated by rect (x0, y0)-(x1, y1)
594
- and inner thickness: 'inner'
595
- */
596
- bool
597
- bound_by_rect_and_inner(int x, int y, int x0, int y0, int x1, int y1, int inner)
598
- {
599
-
600
- return ((x >= x0) && (x <= x1) && (y >= y0) && (y <= y1)) &&
601
- !((x >= x0 + inner) && (x <= x1 - inner) && (y >= y0 + inner) && (y <= y1 - inner));
602
- }
603
-
604
- /* same as above but excluding inner rectangle */
605
- bool
606
- bound_by_rect(int x, int y, int x0, int y0, int x1, int y1)
607
- {
608
- return bound_by_rect_and_inner(x, y, x0, y0, x1, y1, OOB_VAL);
609
- }
610
-
611
- /* calculate the array offset for a given pixel in action context */
612
- int
613
- calc_pixel_offset_for_action(action_struct * cur, texture_info * tex, int x, int y)
614
- {
615
- int offset = calc_pixel_offset(tex, x + cur->xmin, y + cur->ymin);
616
-
617
- return offset;
618
- }
619
-
620
- /* calculate the array offset for a given pixel */
621
- int
622
- calc_pixel_offset(texture_info * tex, int x, int y)
623
- {
624
- int offset = 4 * (tex->firstpixel + x + tex->yincr * y);
625
-
626
- return offset;
627
- }
628
-
629
- /* NEWEST version that solves segfault on linux, temporarily
630
- out of action due to unavailability of MAX_TEXTURE_SIZE constant
631
- in ruby 1.8 */
632
- /*
633
- unsigned
634
- max_quad_size(void)
635
- {
636
-
637
- static unsigned size = 0;
638
-
639
- if (size == 0) {
640
- VALUE gosu = rb_const_get(rb_cObject, rb_intern("Gosu"));
641
- VALUE rb_size = rb_const_get(gosu, rb_intern("MAX_TEXTURE_SIZE"));
642
-
643
- size = FIX2INT(rb_size);
644
- }
645
-
646
- return size;
647
- }
648
- */
649
-
650
- /* old version for quick update */
651
- unsigned
652
- max_quad_size(void)
653
- {
654
- #ifdef __APPLE__
655
- return 1024;
656
- #else
657
- static unsigned MIN_SIZE = 256, MAX_SIZE = 1024;
658
-
659
- static unsigned size = 0;
660
- if (size == 0)
661
- {
662
- GLint width = 1;
663
- size = MIN_SIZE / 2;
664
- do {
665
- size *= 2;
666
- glTexImage2D(GL_PROXY_TEXTURE_2D, 0, 4, size * 2, size * 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
667
- glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
668
- } while (width != 0 && size < MAX_SIZE);
669
- }
670
-
671
- return size;
672
- #endif
673
- }
674
-
675
- /* point format utilities */
676
- bool
677
- is_a_point(VALUE try_point)
678
- {
679
- /* if it responds to 'x' it's near enough (technically must respond to x AND y) */
680
- /* added the is_a_num() check due to WEIRD bug where FIXNUMS were responding to the 'x' method (wtf?) but returning nil when invoked */
681
- if(rb_respond_to(try_point, rb_intern("x")) && !is_a_num(try_point))
682
- return true;
683
-
684
- return false;
685
- }
686
-
687
- VALUE
688
- point_x(VALUE point)
689
- {
690
- return rb_funcall(point, rb_intern("x"), 0);
691
- }
692
-
693
- VALUE
694
- point_y(VALUE point)
695
- {
696
- return rb_funcall(point, rb_intern("y"), 0);
697
- }
698
-
699
- /* mathematical utils, used mainly by bezier curves */
700
- double
701
- power(float base, int exp)
702
- {
703
- float ans = 1.0;
704
- if(base == 0.0) {
705
- if(exp == 0)
706
- return 1;
707
- else
708
- return 0;
709
- }
710
- else if(exp == 0) return 1;
711
- else {
712
- for(int k = exp; k >= 1; k--) {
713
- ans = ans * base;
714
- }
715
- return ans;
716
- }
717
- }
718
-
719
- unsigned
720
- fact(int n)
721
- {
722
- if (n == 0 || n == 1) return 1;
723
- else
724
- return (n * fact(n - 1));
725
- }
726
-
727
- unsigned
728
- comb(int n, int r)
729
- {
730
- /* nCr is symmetrical about n / 2 */
731
- if(r > (n / 2))
732
- r = n - r;
733
-
734
- return perm(n, r) / fact(r);
735
- }
736
-
737
- unsigned
738
- perm(int n, int r)
739
- {
740
- int val = 1;
741
- for(int i = n; i > (n - r); i--)
742
- val *= i;
743
-
744
- return val;
745
- }
746
-
747
- double
748
- bernstein(int n, int k, float u)
749
- {
750
- double temp = comb(n, k) * pow(u, k) * pow(1 - u, n - k);
751
- return temp;
752
- }
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
+ /* external linkage with static duration */
36
+ 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
+
280
+
281
+ bool
282
+ not_a_color(rgba color1)
283
+ {
284
+ return color1.red == -1;
285
+ }
286
+
287
+ bool
288
+ is_a_color(rgba color1)
289
+ {
290
+ return !not_a_color(color1);
291
+ }
292
+
293
+ bool
294
+ is_rb_raw_color(VALUE cval)
295
+ {
296
+ return TYPE(cval) == T_ARRAY &&
297
+ is_a_num(get_from_array(cval, 0)) &&
298
+ is_a_num(get_from_array(cval, 1)) &&
299
+ is_a_num(get_from_array(cval, 2)) &&
300
+ is_a_num(get_from_array(cval, 3));
301
+ }
302
+
303
+ bool
304
+ not_rb_raw_color(VALUE cval)
305
+ {
306
+ return TYPE(cval) != T_ARRAY ||
307
+ !is_a_num(get_from_array(cval, 0));
308
+ }
309
+
310
+
311
+ bool
312
+ cmp_color(rgba color1, rgba color2)
313
+ {
314
+
315
+ return (color1.red == color2.red) && (color1.green == color2.green) && (color1.blue == color2.blue)
316
+ && (color1.alpha == color2.alpha);
317
+ }
318
+
319
+ void
320
+ color_copy(float * source, float * dest)
321
+ {
322
+ //COPY_FLOAT4(source, dest);
323
+ memcpy(dest, source, 4 * sizeof(float));
324
+ }
325
+
326
+ void
327
+ zero_color(float * tex)
328
+ {
329
+ memset(tex, 0, 4 * sizeof(float));
330
+ }
331
+
332
+ rgba
333
+ find_color_from_string(char * try_color)
334
+ {
335
+ rgba cur_color;
336
+
337
+ if(!strcmp("red", try_color)) {
338
+ cur_color.red = 1.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
339
+ }
340
+ else if(!strcmp("green", try_color)) {
341
+ cur_color.red = 0.0; cur_color.green = 1.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
342
+ }
343
+ else if(!strcmp("blue", try_color)) {
344
+ cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
345
+ }
346
+ else if(!strcmp("black", try_color)) {
347
+ cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
348
+ }
349
+ else if(!strcmp("white", try_color)) {
350
+ cur_color.red = 1.0; cur_color.green = 1.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
351
+ }
352
+ else if(!strcmp("purple", try_color)) {
353
+ cur_color.red = 1.0; cur_color.green = 0.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
354
+ }
355
+ else if(!strcmp("yellow", try_color)) {
356
+ cur_color.red = 1.0; cur_color.green = 1.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
357
+ }
358
+ else if(!strcmp("cyan", try_color)) {
359
+ cur_color.red = 0.0; cur_color.green = 1.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
360
+ }
361
+ else if(!strcmp("orange", try_color)) {
362
+ cur_color.red = 1.0; cur_color.green = 0.5; cur_color.blue = 0.0; cur_color.alpha = 1.0;
363
+ }
364
+ else if(!strcmp("brown", try_color)) {
365
+ cur_color.red = 0.39; cur_color.green = 0.26; cur_color.blue = 0.13; cur_color.alpha = 1.0;
366
+ }
367
+ else if(!strcmp("turquoise", try_color)) {
368
+ cur_color.red = 0.1; cur_color.green = 0.6; cur_color.blue = 0.8; cur_color.alpha = 1.0;
369
+ }
370
+ else if(!strcmp("tyrian", try_color)) {
371
+ cur_color.red = 0.4; cur_color.green = 0.007; cur_color.blue = 0.235; cur_color.alpha = 1.0;
372
+ }
373
+ else if(!strcmp("alpha", try_color)) {
374
+ cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 0.0;
375
+ }
376
+ else if(!strcmp("none", try_color)) {
377
+ cur_color = not_a_color_v;
378
+ }
379
+ else if(!strcmp("random", try_color) || !strcmp("rand", try_color)) {
380
+ cur_color.red = rand() / (float)RAND_MAX;
381
+ cur_color.green = rand() / (float)RAND_MAX;
382
+ cur_color.blue = rand() / (float)RAND_MAX;
383
+ cur_color.alpha = 1.0;
384
+ }
385
+
386
+ else
387
+ rb_raise(rb_eArgError, "invalid colour specified (no color matches the symbol: %s)\n", try_color);
388
+
389
+ return cur_color;
390
+ }
391
+
392
+ rgba
393
+ convert_gosu_to_rgba_color(VALUE gcolor)
394
+ {
395
+
396
+ return (rgba) {
397
+ FIX2INT(rb_funcall(gcolor, rb_intern("red"), 0)) / 255.0,
398
+ FIX2INT(rb_funcall(gcolor, rb_intern("green"), 0)) / 255.0,
399
+ FIX2INT(rb_funcall(gcolor, rb_intern("blue"), 0)) / 255.0,
400
+ FIX2INT(rb_funcall(gcolor, rb_intern("alpha"), 0)) / 255.0
401
+ };
402
+ }
403
+
404
+
405
+ /* convert C color to Ruby color */
406
+ VALUE
407
+ convert_rgba_to_rb_color(rgba * pix)
408
+ {
409
+ /* create a new ruby array to store the pixel data */
410
+ VALUE pix_array = rb_ary_new2(4);
411
+
412
+ /* store the pixel data */
413
+ rb_ary_store(pix_array, red, rb_float_new(pix->red));
414
+ rb_ary_store(pix_array, green, rb_float_new(pix->green));
415
+ rb_ary_store(pix_array, blue, rb_float_new(pix->blue));
416
+ rb_ary_store(pix_array, alpha, rb_float_new(pix->alpha));
417
+
418
+ return pix_array;
419
+ }
420
+
421
+ /* convert C color to gosu color */
422
+ VALUE
423
+ convert_rgba_to_gosu_color(rgba * pix)
424
+ {
425
+ VALUE gosu_color_class = 0;
426
+
427
+ if (gosu_color_class == 0) {
428
+ VALUE gosu_class = rb_const_get(rb_cObject, rb_intern("Gosu"));
429
+ gosu_color_class = rb_const_get(gosu_class, rb_intern("Color"));
430
+ }
431
+
432
+ VALUE gosu_color = rb_funcall(gosu_color_class, rb_intern("new"), 0);
433
+
434
+ rb_funcall(gosu_color, rb_intern("red="), 1, INT2FIX(pix->red * 255));
435
+ rb_funcall(gosu_color, rb_intern("green="), 1, INT2FIX(pix->green * 255));
436
+ rb_funcall(gosu_color, rb_intern("blue="), 1, INT2FIX(pix->blue * 255));
437
+ rb_funcall(gosu_color, rb_intern("alpha="), 1, INT2FIX(pix->alpha * 255));
438
+
439
+ return gosu_color;
440
+ }
441
+
442
+
443
+
444
+ /* convert Ruby color to C color */
445
+ rgba
446
+ convert_rb_color_to_rgba(VALUE cval)
447
+ {
448
+ rgba my_color;
449
+
450
+ if (is_gosu_color(cval)) return convert_gosu_to_rgba_color(cval);
451
+
452
+ /* current color for actions */
453
+ switch(TYPE(cval)) {
454
+ char * try_color;
455
+ case T_SYMBOL:
456
+ try_color = lowercase(sym2string(cval));
457
+
458
+ my_color = find_color_from_string(try_color);
459
+
460
+ break;
461
+ case T_ARRAY:
462
+ my_color.red = NUM2DBL(rb_ary_entry(cval, red));
463
+ my_color.green = NUM2DBL(rb_ary_entry(cval, green));
464
+ my_color.blue = NUM2DBL(rb_ary_entry(cval, blue));
465
+
466
+ if(NUM2INT(rb_funcall(cval, rb_intern("length"), 0)) > 3)
467
+ my_color.alpha = NUM2DBL(rb_ary_entry(cval, alpha));
468
+ else
469
+ my_color.alpha = 1;
470
+
471
+ break;
472
+ default:
473
+ rb_raise(rb_eArgError, "unsupported argument type for color. Got type 0x%x\n", TYPE(cval) );
474
+ }
475
+
476
+ /* a valid color */
477
+ if(is_a_color(my_color))
478
+ return my_color;
479
+
480
+ /* special condition for when color is taken from outside range of bitmap. Color is just ignored */
481
+ else if(not_a_color(my_color))
482
+ return not_a_color_v;
483
+
484
+ /* anything else should fail */
485
+ else
486
+ rb_raise(rb_eArgError, "invalid colour specified (negative value given)\n");
487
+ }
488
+
489
+ /* error checking functions */
490
+ void
491
+ check_mask(VALUE mask)
492
+ {
493
+ char * try_mask;
494
+
495
+ if(TYPE(mask) != T_ARRAY && TYPE(mask) != T_SYMBOL)
496
+ rb_raise(rb_eArgError, "array or symbol parameter required");
497
+
498
+ /* is it a valid mask symbol? */
499
+ if(TYPE(mask) == T_SYMBOL) {
500
+ try_mask = lowercase(sym2string(mask));
501
+ if(*try_mask == '_') try_mask++;
502
+ if(not_a_color(find_color_from_string(try_mask))) {
503
+ rb_raise(rb_eArgError, "unrecognized mask symbol: %s\n", sym2string(mask));
504
+ }
505
+ }
506
+ }
507
+
508
+ void
509
+ check_image(VALUE image)
510
+ {
511
+ if(!rb_respond_to(image, rb_intern("gl_tex_info")))
512
+ rb_raise(rb_eRuntimeError,"must specify a valid source image");
513
+ }
514
+
515
+ bool
516
+ is_gosu_image(VALUE try_image)
517
+ {
518
+ if(rb_respond_to(try_image, rb_intern("gl_tex_info")))
519
+ return true;
520
+
521
+ return false;
522
+ }
523
+
524
+ bool
525
+ is_gosu_color(VALUE try_color)
526
+ {
527
+ if(rb_respond_to(try_color, rb_intern("red")))
528
+ return true;
529
+
530
+ return false;
531
+ }
532
+
533
+
534
+
535
+ /** cohen-sutherland line clipper **/
536
+ #define outcode int
537
+ const int RIGHT = 8; //1000
538
+ const int TOP = 4; //0100
539
+ const int LEFT = 2; //0010
540
+ const int BOTTOM = 1; //0001
541
+
542
+ //Compute the bit code for a point (x, y) using the clip rectangle
543
+ //bounded diagonally by (xmin, ymin), and (xmax, ymax)
544
+ static outcode
545
+ ComputeOutCode (int x, int y, int xmin, int ymin, int xmax, int ymax)
546
+ {
547
+ outcode code = 0;
548
+ if (y > ymax) //above the clip window
549
+ code |= TOP;
550
+ else if (y < ymin) //below the clip window
551
+ code |= BOTTOM;
552
+ if (x > xmax) //to the right of clip window
553
+ code |= RIGHT;
554
+ else if (x < xmin) //to the left of clip window
555
+ code |= LEFT;
556
+ return code;
557
+ }
558
+
559
+ /** Cohen-Sutherland clipping algorithm clips a line from
560
+ P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with
561
+ diagonal from (xmin, ymin) to (xmax, ymax). **/
562
+ void
563
+ cohen_sutherland_clip (int * x0, int * y0,int * x1, int * y1, int xmin, int ymin,
564
+ int xmax, int ymax)
565
+ {
566
+ //Outcodes for P0, P1, and whatever point lies outside the clip rectangle
567
+ outcode outcode0, outcode1, outcodeOut;
568
+ bool accept = false, done = false;
569
+ int tx0 = *x0, ty0 = *y0, tx1 = *x1, ty1 = *y1;
570
+
571
+ //compute outcodes
572
+ outcode0 = ComputeOutCode (tx0, ty0, xmin, ymin, xmax, ymax);
573
+ outcode1 = ComputeOutCode (tx1, ty1, xmin, ymin, xmax, ymax);
574
+
575
+ do{
576
+ if (!(outcode0 | outcode1)) //logical or is 0. Trivially accept and get out of loop
577
+ {
578
+ accept = true;
579
+ done = true;
580
+ }
581
+ else if (outcode0 & outcode1) //logical and is not 0. Trivially reject and get out of loop
582
+ done = true;
583
+ else
584
+ {
585
+ //failed both tests, so calculate the line segment to clip
586
+ //from an outside point to an intersection with clip edge
587
+ double x, y;
588
+ //At least one endpoint is outside the clip rectangle; pick it.
589
+ outcodeOut = outcode0? outcode0: outcode1;
590
+ //Now find the intersection point;
591
+ //use formulas y = y0 + slope * (x - x0), x = x0 + (1/slope)* (y - y0)
592
+ if (outcodeOut & TOP) //point is above the clip rectangle
593
+ {
594
+ x = tx0 + (tx1 - tx0) * (ymax - ty0)/(ty1 - ty0);
595
+ y = ymax;
596
+ }
597
+ else if (outcodeOut & BOTTOM) //point is below the clip rectangle
598
+ {
599
+ x = tx0 + (tx1 - tx0) * (ymin - ty0)/(ty1 - ty0);
600
+ y = ymin;
601
+ }
602
+ else if (outcodeOut & RIGHT) //point is to the right of clip rectangle
603
+ {
604
+ y = ty0 + (ty1 - ty0) * (xmax - tx0)/(tx1 - tx0);
605
+ x = xmax;
606
+ }
607
+ else //point is to the left of clip rectangle
608
+ {
609
+ y = ty0 + (ty1 - ty0) * (xmin - tx0)/(tx1 - tx0);
610
+ x = xmin;
611
+ }
612
+ //Now we move outside point to intersection point to clip
613
+ //and get ready for next pass.
614
+ if (outcodeOut == outcode0)
615
+ {
616
+ tx0 = x;
617
+ ty0 = y;
618
+ outcode0 = ComputeOutCode (tx0, ty0, xmin, ymin, xmax, ymax);
619
+ }
620
+ else
621
+ {
622
+ tx1 = x;
623
+ ty1 = y;
624
+ outcode1 = ComputeOutCode (tx1, ty1, xmin, ymin, xmax, ymax);
625
+ }
626
+ }
627
+ }while (!done);
628
+
629
+ if (accept)
630
+ {
631
+ *x0 = tx0; *x1 = tx1;
632
+ *y0 = ty0; *y1 = ty1;
633
+ }
634
+
635
+ }
636
+ /** end of cohen-sutherland line clipper **/
637
+
638
+
639
+ void
640
+ constrain_boundaries(int * x0, int * y0, int * x1, int * y1, int width, int height)
641
+ {
642
+ if(*y0 < 0) *y0 = 0;
643
+ if(*y1 < 0) *y1 = 0;
644
+
645
+ if(*x0 < 0) *x0 = 0;
646
+ if(*x1 < 0) *x1 = 0;
647
+
648
+ if(*x0 > (width - 1)) *x0 = width - 1;
649
+ if(*x1 > (width - 1)) *x1 = width - 1;
650
+
651
+ if(*y0 > (height - 1)) *y0 = height - 1;
652
+ if(*y1 > (height - 1)) *y1 = height - 1;
653
+
654
+ if(*y0 > *y1) { SWAP(*y0, *y1); }
655
+ if(*x0 > *x1) { SWAP(*x0, *x1); }
656
+ }
657
+
658
+
659
+ /* returns true if point (x, y) is within bounds designated by rect (x0, y0)-(x1, y1)
660
+ and inner thickness: 'inner'
661
+ */
662
+ bool
663
+ bound_by_rect_and_inner(int x, int y, int x0, int y0, int x1, int y1, int inner)
664
+ {
665
+
666
+ return ((x >= x0) && (x <= x1) && (y >= y0) && (y <= y1)) &&
667
+ !((x >= x0 + inner) && (x <= x1 - inner) && (y >= y0 + inner) && (y <= y1 - inner));
668
+ }
669
+
670
+ /* same as above but excluding inner rectangle */
671
+ bool
672
+ bound_by_rect(int x, int y, int x0, int y0, int x1, int y1)
673
+ {
674
+ return bound_by_rect_and_inner(x, y, x0, y0, x1, y1, OOB_VAL);
675
+ }
676
+
677
+ /* calculate the array offset for a given pixel in action context */
678
+ int
679
+ calc_pixel_offset_for_action(action_struct * cur, texture_info * tex, int x, int y)
680
+ {
681
+ int offset = calc_pixel_offset(tex, x + cur->xmin, y + cur->ymin);
682
+
683
+ return offset;
684
+ }
685
+
686
+ /* calculate the array offset for a given pixel */
687
+ int
688
+ calc_pixel_offset(texture_info * tex, int x, int y)
689
+ {
690
+ int offset = 4 * (tex->firstpixel + x + tex->yincr * y);
691
+
692
+ return offset;
693
+ }
694
+
695
+ /* NEWEST version that solves segfault on linux, back
696
+ in action due to availability of MAX_TEXTURE_SIZE constant
697
+ in ruby 1.8 */
698
+ unsigned
699
+ max_quad_size(void)
700
+ {
701
+
702
+ static unsigned size = 0;
703
+
704
+ if (size == 0) {
705
+ VALUE gosu = rb_const_get(rb_cObject, rb_intern("Gosu"));
706
+ VALUE rb_size = rb_const_get(gosu, rb_intern("MAX_TEXTURE_SIZE"));
707
+
708
+ size = FIX2INT(rb_size);
709
+ }
710
+
711
+ return size;
712
+ }
713
+
714
+ /* old version for quick update, OUT OF ACTIONN */
715
+ /* unsigned */
716
+ /* max_quad_size(void) */
717
+ /* { */
718
+ /* #ifdef __APPLE__ */
719
+ /* return 1024; */
720
+ /* #else */
721
+ /* static unsigned MIN_SIZE = 256, MAX_SIZE = 1024; */
722
+
723
+ /* static unsigned size = 0; */
724
+ /* if (size == 0) */
725
+ /* { */
726
+ /* GLint width = 1; */
727
+ /* size = MIN_SIZE / 2; */
728
+ /* do { */
729
+ /* size *= 2; */
730
+ /* glTexImage2D(GL_PROXY_TEXTURE_2D, 0, 4, size * 2, size * 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); */
731
+ /* glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); */
732
+ /* } while (width != 0 && size < MAX_SIZE); */
733
+ /* } */
734
+
735
+ /* return size; */
736
+ /* #endif */
737
+ /* } */
738
+
739
+ /* point format utilities */
740
+ bool
741
+ is_a_point(VALUE try_point)
742
+ {
743
+ /* if it responds to 'x' it's near enough (technically must respond to x AND y) */
744
+ /* added the is_a_num() check due to WEIRD bug where FIXNUMS were responding to the 'x' method (wtf?) but returning nil when invoked */
745
+ if(rb_respond_to(try_point, rb_intern("x")) && !is_a_num(try_point))
746
+ return true;
747
+
748
+ return false;
749
+ }
750
+
751
+ VALUE
752
+ point_x(VALUE point)
753
+ {
754
+ return rb_funcall(point, rb_intern("x"), 0);
755
+ }
756
+
757
+ VALUE
758
+ point_y(VALUE point)
759
+ {
760
+ return rb_funcall(point, rb_intern("y"), 0);
761
+ }
762
+
763
+ /* mathematical utils, used mainly by bezier curves */
764
+ double
765
+ power(float base, int exp)
766
+ {
767
+ float ans = 1.0;
768
+ if(base == 0.0) {
769
+ if(exp == 0)
770
+ return 1;
771
+ else
772
+ return 0;
773
+ }
774
+ else if(exp == 0) return 1;
775
+ else {
776
+ for(int k = exp; k >= 1; k--) {
777
+ ans = ans * base;
778
+ }
779
+ return ans;
780
+ }
781
+ }
782
+
783
+ unsigned
784
+ fact(int n)
785
+ {
786
+ if (n == 0 || n == 1) return 1;
787
+ else
788
+ return (n * fact(n - 1));
789
+ }
790
+
791
+ unsigned
792
+ comb(int n, int r)
793
+ {
794
+ /* nCr is symmetrical about n / 2 */
795
+ if(r > (n / 2))
796
+ r = n - r;
797
+
798
+ return perm(n, r) / fact(r);
799
+ }
800
+
801
+ unsigned
802
+ perm(int n, int r)
803
+ {
804
+ int val = 1;
805
+ for(int i = n; i > (n - r); i--)
806
+ val *= i;
807
+
808
+ return val;
809
+ }
810
+
811
+ double
812
+ bernstein(int n, int k, float u)
813
+ {
814
+ double temp = comb(n, k) * pow(u, k) * pow(1 - u, n - k);
815
+ return temp;
816
+ }