texplay 0.2.800 → 0.2.900

Sign up to get free protection for your applications and to get access to all the features.
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
+ }