texplay 0.4.3 → 0.4.4.pre

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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +225 -222
  3. data/README.markdown +48 -48
  4. data/Rakefile +16 -16
  5. data/examples/common.rb +18 -18
  6. data/examples/example_alpha_blend.rb +29 -29
  7. data/examples/example_bezier.rb +41 -41
  8. data/examples/example_blank.rb +37 -37
  9. data/examples/example_cache.rb +21 -21
  10. data/examples/example_color_control.rb +69 -69
  11. data/examples/example_color_transform.rb +62 -62
  12. data/examples/example_color_transform_circle.rb +34 -34
  13. data/examples/example_darken.rb +24 -24
  14. data/examples/example_dup.rb +73 -73
  15. data/examples/example_each.rb +39 -39
  16. data/examples/example_effect.rb +34 -34
  17. data/examples/example_fill.rb +43 -43
  18. data/examples/example_fill_old.rb +48 -48
  19. data/examples/example_fluent.rb +29 -29
  20. data/examples/example_font.rb +31 -31
  21. data/examples/example_hash_arguments.rb +46 -46
  22. data/examples/example_ippa.rb +23 -23
  23. data/examples/example_light.rb +75 -75
  24. data/examples/example_light_multiply.rb +18 -18
  25. data/examples/example_lsystem.rb +61 -61
  26. data/examples/example_melt.rb +25 -25
  27. data/examples/example_meyet.rb +62 -62
  28. data/examples/example_polyline.rb +42 -42
  29. data/examples/example_scale.rb +27 -27
  30. data/examples/example_select.rb +36 -36
  31. data/examples/example_select2.rb +25 -25
  32. data/examples/example_simple.rb +46 -46
  33. data/examples/example_splice.rb +26 -26
  34. data/examples/example_sync.rb +59 -59
  35. data/examples/example_tiles.rb +41 -41
  36. data/examples/example_trace.rb +22 -22
  37. data/examples/example_transparent.rb +28 -28
  38. data/examples/example_transparent2.rb +24 -24
  39. data/examples/example_transparent3.rb +20 -20
  40. data/examples/example_turtle.rb +39 -39
  41. data/examples/example_weird.rb +22 -22
  42. data/examples/example_window_render_to_image.rb +41 -41
  43. data/examples/example_window_to_blob.rb +35 -35
  44. data/examples/media/maria.png +0 -0
  45. data/examples/media/rose.bmp +0 -0
  46. data/ext/texplay/actions.c +1011 -1006
  47. data/ext/texplay/actions.h +60 -60
  48. data/ext/texplay/bindings.c +1130 -1125
  49. data/ext/texplay/bindings.h +46 -46
  50. data/ext/texplay/cache.c +123 -118
  51. data/ext/texplay/cache.h +24 -24
  52. data/ext/texplay/compat.h +21 -27
  53. data/ext/texplay/extconf.rb +38 -38
  54. data/ext/texplay/graphics_utils.c +1318 -1313
  55. data/ext/texplay/graphics_utils.h +22 -22
  56. data/ext/texplay/texplay.c +206 -201
  57. data/ext/texplay/texplay.h +153 -153
  58. data/ext/texplay/utils.c +896 -891
  59. data/ext/texplay/utils.h +153 -153
  60. data/lib/texplay-contrib.rb +147 -147
  61. data/lib/texplay.rb +347 -347
  62. data/lib/texplay/alone.rb +20 -20
  63. data/lib/texplay/c_function_docs.rb +178 -178
  64. data/lib/texplay/live.rb +84 -84
  65. data/lib/texplay/version.rb +3 -3
  66. data/live/live.rb +85 -85
  67. data/test/image_spec.rb +45 -45
  68. data/test/texplay_spec.rb +144 -144
  69. metadata +42 -52
  70. data/lib/texplay/1.8/texplay.so +0 -0
  71. data/lib/texplay/1.9/texplay.so +0 -0
@@ -1,153 +1,153 @@
1
- /* texplay.h (C) John Mair 2008
2
- * This program is distributed under the terms of the MIT License
3
- *
4
- *
5
- * */
6
-
7
- #ifndef GUARD_TEXPLAY_H
8
- #define GUARD_TEXPLAY_H
9
-
10
- #include <ruby.h>
11
-
12
- /* #defines */
13
- #define OOB_VAL 9999
14
- #define XMAX_OOB OOB_VAL
15
- #define YMAX_OOB OOB_VAL
16
- #define XMIN_OOB -OOB_VAL
17
- #define YMIN_OOB -OOB_VAL
18
- #define RGBA_LIST_SIZE 100
19
- #define PI 3.14159265358979
20
-
21
- /* macros */
22
- #define SWAP(X, Y) {(X) ^= (Y); (Y) ^= (X); (X) ^= (Y);}
23
- #define ROUND(X) (int)((X) + 0.5)
24
- #define ARY_SIZE(X) sizeof(X) / sizeof(*X)
25
- #define SGN(X) ((X) >= 0 ? 1 : -1)
26
- #define MAX(X, Y) ((X) > (Y)) ? (X) :(Y)
27
- #define MIN(X, Y) ((X) < (Y)) ? (X) : (Y)
28
- #define ABS(X) ((X) >= 0 ? (X) : -(X))
29
-
30
- /* enums */
31
- typedef enum e_bool {
32
- false, true
33
- } bool;
34
-
35
- typedef enum e_color {
36
- red, green, blue, alpha
37
- } color_t;
38
-
39
- typedef enum e_sync_mode {
40
- lazy_sync, eager_sync, no_sync
41
- } sync;
42
-
43
-
44
- typedef enum {
45
- clear, copy, noop,
46
- set, copy_inverted,
47
- invert, and_reverse, and,
48
- or, nand, nor, xor,
49
- equiv, and_inverted,
50
- or_inverted, additive,
51
- multiply, screen, overlay,
52
- darken, lighten, color_dodge,
53
- color_burn, hard_light, soft_light,
54
- difference, exclusion
55
- } draw_mode;
56
-
57
- typedef enum {
58
- source, dest, source_with_fixed_alpha, dest_with_fixed_alpha
59
- } alpha_blend_mode_t;
60
-
61
- /* structs */
62
- typedef struct s_rgba {
63
- float red, green, blue, alpha;
64
- } rgba;
65
-
66
- typedef struct {
67
- rgba colors[RGBA_LIST_SIZE];
68
- int size;
69
- } rgba_list;
70
-
71
-
72
- /* stores image data */
73
- typedef struct {
74
- int width, height;
75
- float top, left;
76
- int tname;
77
- float * td_array;
78
- int yincr, firstpixel;
79
- int x_offset, y_offset;
80
- VALUE image;
81
- } texture_info;
82
-
83
-
84
- /* convenience macro */
85
- #define IMAGE_BOUNDS(X) ((image_bounds *) (X))
86
- typedef struct {
87
- int xmin;
88
- int ymin;
89
- int xmax;
90
- int ymax;
91
- } image_bounds;
92
-
93
-
94
- typedef struct action_struct {
95
- int xmin, ymin, xmax, ymax;
96
- sync sync_mode;
97
-
98
- /* pointer to associated texture */
99
- /* a bit of a kludge having this here
100
- since it's only being used by convert_image_local_color_to_rgba */
101
- texture_info * tex;
102
-
103
- VALUE hash_arg;
104
-
105
- /* action color */
106
- rgba color;
107
-
108
- /* pen data */
109
- struct {
110
-
111
- /* color control, dynamic */
112
- bool has_color_control_proc;
113
- VALUE color_control_proc;
114
- int color_control_arity;
115
-
116
- /* color control, static */
117
- bool has_color_control_transform;
118
- rgba color_mult;
119
- rgba color_add;
120
-
121
- /* texture fill */
122
- bool has_source_texture;
123
- texture_info source_tex;
124
-
125
- /* lerp */
126
- bool has_lerp;
127
- float lerp;
128
-
129
- /* alpha blend */
130
- bool alpha_blend;
131
- alpha_blend_mode_t alpha_blend_mode;
132
-
133
- /* drawing mode */
134
- bool has_drawing_mode;
135
- draw_mode drawing_mode;
136
-
137
- /* tolerance */
138
- bool has_tolerance;
139
- float tolerance;
140
-
141
- /* color selection */
142
- bool has_color_select;
143
- rgba_list source_select;
144
- rgba_list source_ignore;
145
- rgba_list dest_select;
146
- rgba_list dest_ignore;
147
-
148
- } pen;
149
-
150
- } action_struct;
151
-
152
-
153
- #endif
1
+ /* texplay.h (C) John Mair 2008
2
+ * This program is distributed under the terms of the MIT License
3
+ *
4
+ *
5
+ * */
6
+
7
+ #ifndef GUARD_TEXPLAY_H
8
+ #define GUARD_TEXPLAY_H
9
+
10
+ #include <ruby.h>
11
+
12
+ /* #defines */
13
+ #define OOB_VAL 9999
14
+ #define XMAX_OOB OOB_VAL
15
+ #define YMAX_OOB OOB_VAL
16
+ #define XMIN_OOB -OOB_VAL
17
+ #define YMIN_OOB -OOB_VAL
18
+ #define RGBA_LIST_SIZE 100
19
+ #define PI 3.14159265358979
20
+
21
+ /* macros */
22
+ #define SWAP(X, Y) {(X) ^= (Y); (Y) ^= (X); (X) ^= (Y);}
23
+ #define ROUND(X) (int)((X) + 0.5)
24
+ #define ARY_SIZE(X) sizeof(X) / sizeof(*X)
25
+ #define SGN(X) ((X) >= 0 ? 1 : -1)
26
+ #define MAX(X, Y) ((X) > (Y)) ? (X) :(Y)
27
+ #define MIN(X, Y) ((X) < (Y)) ? (X) : (Y)
28
+ #define ABS(X) ((X) >= 0 ? (X) : -(X))
29
+
30
+ /* enums */
31
+ typedef enum e_bool {
32
+ false, true
33
+ } bool;
34
+
35
+ typedef enum e_color {
36
+ red, green, blue, alpha
37
+ } color_t;
38
+
39
+ typedef enum e_sync_mode {
40
+ lazy_sync, eager_sync, no_sync
41
+ } sync_;
42
+
43
+
44
+ typedef enum {
45
+ clear, copy, noop,
46
+ set, copy_inverted,
47
+ invert, and_reverse, and,
48
+ or, nand, nor, xor,
49
+ equiv, and_inverted,
50
+ or_inverted, additive,
51
+ multiply, screen, overlay,
52
+ darken, lighten, color_dodge,
53
+ color_burn, hard_light, soft_light,
54
+ difference, exclusion
55
+ } draw_mode;
56
+
57
+ typedef enum {
58
+ source, dest, source_with_fixed_alpha, dest_with_fixed_alpha
59
+ } alpha_blend_mode_t;
60
+
61
+ /* structs */
62
+ typedef struct s_rgba {
63
+ float red, green, blue, alpha;
64
+ } rgba;
65
+
66
+ typedef struct {
67
+ rgba colors[RGBA_LIST_SIZE];
68
+ int size;
69
+ } rgba_list;
70
+
71
+
72
+ /* stores image data */
73
+ typedef struct {
74
+ int width, height;
75
+ float top, left;
76
+ int tname;
77
+ float * td_array;
78
+ int yincr, firstpixel;
79
+ int x_offset, y_offset;
80
+ VALUE image;
81
+ } texture_info;
82
+
83
+
84
+ /* convenience macro */
85
+ #define IMAGE_BOUNDS(X) ((image_bounds *) (X))
86
+ typedef struct {
87
+ int xmin;
88
+ int ymin;
89
+ int xmax;
90
+ int ymax;
91
+ } image_bounds;
92
+
93
+
94
+ typedef struct action_struct {
95
+ int xmin, ymin, xmax, ymax;
96
+ sync_ sync_mode;
97
+
98
+ /* pointer to associated texture */
99
+ /* a bit of a kludge having this here
100
+ since it's only being used by convert_image_local_color_to_rgba */
101
+ texture_info * tex;
102
+
103
+ VALUE hash_arg;
104
+
105
+ /* action color */
106
+ rgba color;
107
+
108
+ /* pen data */
109
+ struct {
110
+
111
+ /* color control, dynamic */
112
+ bool has_color_control_proc;
113
+ VALUE color_control_proc;
114
+ int color_control_arity;
115
+
116
+ /* color control, static */
117
+ bool has_color_control_transform;
118
+ rgba color_mult;
119
+ rgba color_add;
120
+
121
+ /* texture fill */
122
+ bool has_source_texture;
123
+ texture_info source_tex;
124
+
125
+ /* lerp */
126
+ bool has_lerp;
127
+ float lerp;
128
+
129
+ /* alpha blend */
130
+ bool alpha_blend;
131
+ alpha_blend_mode_t alpha_blend_mode;
132
+
133
+ /* drawing mode */
134
+ bool has_drawing_mode;
135
+ draw_mode drawing_mode;
136
+
137
+ /* tolerance */
138
+ bool has_tolerance;
139
+ float tolerance;
140
+
141
+ /* color selection */
142
+ bool has_color_select;
143
+ rgba_list source_select;
144
+ rgba_list source_ignore;
145
+ rgba_list dest_select;
146
+ rgba_list dest_ignore;
147
+
148
+ } pen;
149
+
150
+ } action_struct;
151
+
152
+
153
+ #endif
@@ -1,891 +1,896 @@
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
- bool
280
- not_a_color(rgba color1)
281
- {
282
- return color1.red == -1 || color1.green == -1 ||
283
- color1.blue == -1 || color1.alpha == -1;
284
- }
285
-
286
- bool
287
- is_a_color(rgba color1)
288
- {
289
- return !not_a_color(color1);
290
- }
291
-
292
- bool
293
- is_rb_raw_color(VALUE cval)
294
- {
295
- return TYPE(cval) == T_ARRAY &&
296
- is_a_num(get_from_array(cval, 0)) &&
297
- is_a_num(get_from_array(cval, 1)) &&
298
- is_a_num(get_from_array(cval, 2)) &&
299
- is_a_num(get_from_array(cval, 3));
300
- }
301
-
302
- bool
303
- not_rb_raw_color(VALUE cval)
304
- {
305
- return TYPE(cval) != T_ARRAY ||
306
- !is_a_num(get_from_array(cval, 0));
307
- }
308
-
309
- /** cmp_color related functions **/
310
- static bool
311
- is_transparent_color(rgba color1)
312
- {
313
- return color1.red == -666 && color1.green == -666 && color1.blue == -666 &&
314
- color1.alpha == -666;
315
- }
316
-
317
- static bool
318
- special_cmp_color(rgba color1, rgba color2)
319
- {
320
- if (is_transparent_color(color1))
321
- return color2.alpha == 0;
322
- else if (is_transparent_color(color2))
323
- return color1.alpha == 0;
324
- else
325
- return false;
326
- }
327
-
328
- static bool
329
- special_cmp_color_with_tolerance(rgba color1, rgba color2, float tolerance)
330
- {
331
- if (is_transparent_color(color1))
332
- return (color2.alpha) <= tolerance;
333
- else if (is_transparent_color(color2))
334
- return color1.alpha <= tolerance;
335
- else
336
- return false;
337
- }
338
-
339
-
340
- static float
341
- color_distance_squared(rgba c1, rgba c2)
342
- {
343
- return (c1.red - c2.red) * (c1.red - c2.red) +
344
- (c1.green - c2.green) * (c1.green - c2.green) +
345
- (c1.blue - c2.blue) * (c1.blue - c2.blue) +
346
- (c1.alpha - c2.alpha) * (c1.alpha - c2.alpha);
347
- }
348
-
349
-
350
- bool
351
- cmp_color_with_tolerance(rgba color1, rgba color2, float tolerance)
352
- {
353
- if (color1.red < 0 || color2.red < 0)
354
- return special_cmp_color_with_tolerance(color1, color2, tolerance);
355
-
356
- return color_distance_squared(color1, color2) <= (tolerance * tolerance);
357
- }
358
-
359
- bool
360
- cmp_color(rgba color1, rgba color2)
361
- {
362
- if (color1.red < 0 || color2.red < 0)
363
- return special_cmp_color(color1, color2);
364
-
365
- return (color1.red == color2.red) && (color1.green == color2.green) && (color1.blue == color2.blue)
366
- && (color1.alpha == color2.alpha);
367
- }
368
-
369
-
370
- /*** these functions are UNSAFE ***/
371
- void
372
- color_copy(float * source, float * dest)
373
- {
374
- //COPY_FLOAT4(source, dest);
375
- memcpy(dest, source, 4 * sizeof(float));
376
- }
377
-
378
- void
379
- zero_color(float * tex)
380
- {
381
- memset(tex, 0, 4 * sizeof(float));
382
- }
383
- /*** ***/
384
-
385
- rgba
386
- find_color_from_string(char * try_color)
387
- {
388
- rgba cur_color;
389
-
390
- if(!strcmp("red", try_color)) {
391
- cur_color.red = 1.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
392
- }
393
- else if(!strcmp("green", try_color)) {
394
- cur_color.red = 0.0; cur_color.green = 1.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
395
- }
396
- else if(!strcmp("blue", try_color)) {
397
- cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
398
- }
399
- else if(!strcmp("black", try_color)) {
400
- cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
401
- }
402
- else if(!strcmp("white", try_color)) {
403
- cur_color.red = 1.0; cur_color.green = 1.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
404
- }
405
- else if(!strcmp("purple", try_color)) {
406
- cur_color.red = 1.0; cur_color.green = 0.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
407
- }
408
- else if(!strcmp("yellow", try_color)) {
409
- cur_color.red = 1.0; cur_color.green = 1.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
410
- }
411
- else if(!strcmp("cyan", try_color)) {
412
- cur_color.red = 0.0; cur_color.green = 1.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
413
- }
414
- else if(!strcmp("orange", try_color)) {
415
- cur_color.red = 1.0; cur_color.green = 0.5; cur_color.blue = 0.0; cur_color.alpha = 1.0;
416
- }
417
- else if(!strcmp("brown", try_color)) {
418
- cur_color.red = 0.39; cur_color.green = 0.26; cur_color.blue = 0.13; cur_color.alpha = 1.0;
419
- }
420
- else if(!strcmp("turquoise", try_color)) {
421
- cur_color.red = 0.1; cur_color.green = 0.6; cur_color.blue = 0.8; cur_color.alpha = 1.0;
422
- }
423
- else if(!strcmp("tyrian", try_color)) {
424
- cur_color.red = 0.4; cur_color.green = 0.007; cur_color.blue = 0.235; cur_color.alpha = 1.0;
425
- }
426
- else if(!strcmp("alpha", try_color)) {
427
- cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 0.0;
428
- }
429
- else if(!strcmp("transparent", try_color)) {
430
- cur_color.red = -666; cur_color.green = -666; cur_color.blue = -666; cur_color.alpha = -666;
431
- }
432
- else if(!strcmp("none", try_color)) {
433
- cur_color = not_a_color_v;
434
- }
435
- else if(!strcmp("random", try_color) || !strcmp("rand", try_color)) {
436
- cur_color.red = rand() / (float)RAND_MAX;
437
- cur_color.green = rand() / (float)RAND_MAX;
438
- cur_color.blue = rand() / (float)RAND_MAX;
439
- cur_color.alpha = 1.0;
440
- }
441
-
442
- else
443
- rb_raise(rb_eArgError, "invalid colour specified (no color matches the symbol: %s)\n", try_color);
444
-
445
- return cur_color;
446
- }
447
-
448
- rgba
449
- convert_gosu_to_rgba_color(VALUE gcolor)
450
- {
451
-
452
- return (rgba) {
453
- FIX2INT(rb_funcall(gcolor, rb_intern("red"), 0)) / 255.0,
454
- FIX2INT(rb_funcall(gcolor, rb_intern("green"), 0)) / 255.0,
455
- FIX2INT(rb_funcall(gcolor, rb_intern("blue"), 0)) / 255.0,
456
- FIX2INT(rb_funcall(gcolor, rb_intern("alpha"), 0)) / 255.0
457
- };
458
- }
459
-
460
-
461
- /* convert C color to Ruby color */
462
- VALUE
463
- convert_rgba_to_rb_color(rgba * pix)
464
- {
465
- if (not_a_color(*pix)) return Qnil;
466
-
467
- /* create a new ruby array to store the pixel data */
468
- VALUE pix_array = rb_ary_new2(4);
469
-
470
- /* store the pixel data */
471
- rb_ary_store(pix_array, red, rb_float_new(pix->red));
472
- rb_ary_store(pix_array, green, rb_float_new(pix->green));
473
- rb_ary_store(pix_array, blue, rb_float_new(pix->blue));
474
- rb_ary_store(pix_array, alpha, rb_float_new(pix->alpha));
475
-
476
- return pix_array;
477
- }
478
-
479
- /* convert C color to gosu color */
480
- VALUE
481
- convert_rgba_to_gosu_color(rgba * pix)
482
- {
483
- if (not_a_color(*pix)) return Qnil;
484
-
485
- VALUE gosu_color = rb_funcall(gosu_color_class(), rb_intern("new"), 0);
486
-
487
- rb_funcall(gosu_color, rb_intern("red="), 1, INT2FIX(pix->red * 255));
488
- rb_funcall(gosu_color, rb_intern("green="), 1, INT2FIX(pix->green * 255));
489
- rb_funcall(gosu_color, rb_intern("blue="), 1, INT2FIX(pix->blue * 255));
490
- rb_funcall(gosu_color, rb_intern("alpha="), 1, INT2FIX(pix->alpha * 255));
491
-
492
- return gosu_color;
493
- }
494
-
495
- VALUE
496
- gosu_color_class()
497
- {
498
- static VALUE gcolor_class = 0;
499
-
500
- if (gcolor_class == 0) {
501
- VALUE gosu_class = rb_const_get(rb_cObject, rb_intern("Gosu"));
502
- gcolor_class = rb_const_get(gosu_class, rb_intern("Color"));
503
- }
504
-
505
- return gcolor_class;
506
- }
507
-
508
- /* convert Ruby color to C color */
509
- rgba
510
- convert_rb_color_to_rgba(VALUE cval)
511
- {
512
- rgba my_color;
513
-
514
- if (is_gosu_color(cval)) return convert_gosu_to_rgba_color(cval);
515
-
516
- /* current color for actions */
517
- switch(TYPE(cval)) {
518
- char * try_color;
519
- case T_SYMBOL:
520
- try_color = lowercase(sym2string(cval));
521
-
522
- my_color = find_color_from_string(try_color);
523
-
524
- break;
525
- case T_ARRAY:
526
- my_color.red = NUM2DBL(rb_ary_entry(cval, red));
527
- my_color.green = NUM2DBL(rb_ary_entry(cval, green));
528
- my_color.blue = NUM2DBL(rb_ary_entry(cval, blue));
529
-
530
- if(NUM2INT(rb_funcall(cval, rb_intern("length"), 0)) > 3)
531
- my_color.alpha = NUM2DBL(rb_ary_entry(cval, alpha));
532
- else
533
- my_color.alpha = 1;
534
-
535
- break;
536
-
537
- /* hex literals */
538
- case T_FIXNUM:
539
- case T_BIGNUM:
540
- return convert_gosu_to_rgba_color(rb_funcall(gosu_color_class(),
541
- rb_intern("new"), 1, cval));
542
- break;
543
-
544
- default:
545
- rb_raise(rb_eArgError, "unsupported argument type for color. Got type 0x%x\n", TYPE(cval) );
546
- }
547
-
548
- /* a valid color */
549
- if(is_a_color(my_color))
550
- return my_color;
551
-
552
- /* special condition for when color is taken from outside range of bitmap. Color is just ignored */
553
- else if(not_a_color(my_color))
554
- return not_a_color_v;
555
-
556
- /* anything else should fail */
557
- else
558
- rb_raise(rb_eArgError, "invalid colour specified (negative value given)\n");
559
- }
560
-
561
- /* error checking functions */
562
- void
563
- check_mask(VALUE mask)
564
- {
565
- char * try_mask;
566
-
567
- if(TYPE(mask) != T_ARRAY && TYPE(mask) != T_SYMBOL)
568
- rb_raise(rb_eArgError, "array or symbol parameter required");
569
-
570
- /* is it a valid mask symbol? */
571
- if(TYPE(mask) == T_SYMBOL) {
572
- try_mask = lowercase(sym2string(mask));
573
- if(*try_mask == '_') try_mask++;
574
- if(not_a_color(find_color_from_string(try_mask))) {
575
- rb_raise(rb_eArgError, "unrecognized mask symbol: %s\n", sym2string(mask));
576
- }
577
- }
578
- }
579
-
580
- void
581
- check_image(VALUE image)
582
- {
583
- if(!rb_respond_to(image, rb_intern("gl_tex_info")))
584
- rb_raise(rb_eRuntimeError,"must specify a valid source image");
585
- }
586
-
587
- bool
588
- is_gosu_image(VALUE try_image)
589
- {
590
- if(rb_respond_to(try_image, rb_intern("gl_tex_info")))
591
- return true;
592
-
593
- return false;
594
- }
595
-
596
- bool
597
- is_gosu_color(VALUE try_color)
598
- {
599
- if(rb_respond_to(try_color, rb_intern("red")))
600
- return true;
601
-
602
- return false;
603
- }
604
-
605
-
606
-
607
- /** cohen-sutherland line clipper **/
608
- #define outcode int
609
- const int RIGHT = 8; //1000
610
- const int TOP = 4; //0100
611
- const int LEFT = 2; //0010
612
- const int BOTTOM = 1; //0001
613
-
614
- //Compute the bit code for a point (x, y) using the clip rectangle
615
- //bounded diagonally by (xmin, ymin), and (xmax, ymax)
616
- static outcode
617
- ComputeOutCode (int x, int y, int xmin, int ymin, int xmax, int ymax)
618
- {
619
- outcode code = 0;
620
- if (y > ymax) //above the clip window
621
- code |= TOP;
622
- else if (y < ymin) //below the clip window
623
- code |= BOTTOM;
624
- if (x > xmax) //to the right of clip window
625
- code |= RIGHT;
626
- else if (x < xmin) //to the left of clip window
627
- code |= LEFT;
628
- return code;
629
- }
630
-
631
- /** Cohen-Sutherland clipping algorithm clips a line from
632
- P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with
633
- diagonal from (xmin, ymin) to (xmax, ymax). **/
634
- void
635
- cohen_sutherland_clip (int * x0, int * y0,int * x1, int * y1, int xmin, int ymin,
636
- int xmax, int ymax)
637
- {
638
- //Outcodes for P0, P1, and whatever point lies outside the clip rectangle
639
- outcode outcode0, outcode1, outcodeOut;
640
- bool accept = false, done = false;
641
- int tx0 = *x0, ty0 = *y0, tx1 = *x1, ty1 = *y1;
642
-
643
- //compute outcodes
644
- outcode0 = ComputeOutCode (tx0, ty0, xmin, ymin, xmax, ymax);
645
- outcode1 = ComputeOutCode (tx1, ty1, xmin, ymin, xmax, ymax);
646
-
647
- do{
648
- if (!(outcode0 | outcode1)) //logical or is 0. Trivially accept and get out of loop
649
- {
650
- accept = true;
651
- done = true;
652
- }
653
- else if (outcode0 & outcode1) //logical and is not 0. Trivially reject and get out of loop
654
- done = true;
655
- else
656
- {
657
- //failed both tests, so calculate the line segment to clip
658
- //from an outside point to an intersection with clip edge
659
- double x, y;
660
- //At least one endpoint is outside the clip rectangle; pick it.
661
- outcodeOut = outcode0? outcode0: outcode1;
662
- //Now find the intersection point;
663
- //use formulas y = y0 + slope * (x - x0), x = x0 + (1/slope)* (y - y0)
664
- if (outcodeOut & TOP) //point is above the clip rectangle
665
- {
666
- x = tx0 + (tx1 - tx0) * (ymax - ty0)/(ty1 - ty0);
667
- y = ymax;
668
- }
669
- else if (outcodeOut & BOTTOM) //point is below the clip rectangle
670
- {
671
- x = tx0 + (tx1 - tx0) * (ymin - ty0)/(ty1 - ty0);
672
- y = ymin;
673
- }
674
- else if (outcodeOut & RIGHT) //point is to the right of clip rectangle
675
- {
676
- y = ty0 + (ty1 - ty0) * (xmax - tx0)/(tx1 - tx0);
677
- x = xmax;
678
- }
679
- else //point is to the left of clip rectangle
680
- {
681
- y = ty0 + (ty1 - ty0) * (xmin - tx0)/(tx1 - tx0);
682
- x = xmin;
683
- }
684
- //Now we move outside point to intersection point to clip
685
- //and get ready for next pass.
686
- if (outcodeOut == outcode0)
687
- {
688
- tx0 = x;
689
- ty0 = y;
690
- outcode0 = ComputeOutCode (tx0, ty0, xmin, ymin, xmax, ymax);
691
- }
692
- else
693
- {
694
- tx1 = x;
695
- ty1 = y;
696
- outcode1 = ComputeOutCode (tx1, ty1, xmin, ymin, xmax, ymax);
697
- }
698
- }
699
- }while (!done);
700
-
701
- if (accept)
702
- {
703
- *x0 = tx0; *x1 = tx1;
704
- *y0 = ty0; *y1 = ty1;
705
- }
706
-
707
- }
708
- /** end of cohen-sutherland line clipper **/
709
-
710
-
711
- void
712
- constrain_boundaries(int * x0, int * y0, int * x1, int * y1, int width, int height)
713
- {
714
- if(*y0 < 0) *y0 = 0;
715
- if(*y1 < 0) *y1 = 0;
716
-
717
- if(*x0 < 0) *x0 = 0;
718
- if(*x1 < 0) *x1 = 0;
719
-
720
- if(*x0 > (width - 1)) *x0 = width - 1;
721
- if(*x1 > (width - 1)) *x1 = width - 1;
722
-
723
- if(*y0 > (height - 1)) *y0 = height - 1;
724
- if(*y1 > (height - 1)) *y1 = height - 1;
725
-
726
- if(*y0 > *y1) { SWAP(*y0, *y1); }
727
- if(*x0 > *x1) { SWAP(*x0, *x1); }
728
- }
729
-
730
-
731
- /* returns true if point (x, y) is within bounds designated by rect (x0, y0)-(x1, y1)
732
- and inner thickness: 'inner'
733
- */
734
- bool
735
- bound_by_rect_and_inner(int x, int y, int x0, int y0, int x1, int y1, int inner)
736
- {
737
-
738
- return ((x >= x0) && (x <= x1) && (y >= y0) && (y <= y1)) &&
739
- !((x >= x0 + inner) && (x <= x1 - inner) && (y >= y0 + inner) && (y <= y1 - inner));
740
- }
741
-
742
- /* same as above but excluding inner rectangle */
743
- bool
744
- bound_by_rect(int x, int y, int x0, int y0, int x1, int y1)
745
- {
746
- return bound_by_rect_and_inner(x, y, x0, y0, x1, y1, OOB_VAL);
747
- }
748
-
749
- /* calculate the array offset for a given pixel in action context */
750
- int
751
- calc_pixel_offset_for_action(action_struct * cur, texture_info * tex, int x, int y)
752
- {
753
- int offset = calc_pixel_offset(tex, x + cur->xmin, y + cur->ymin);
754
-
755
- return offset;
756
- }
757
-
758
- /* calculate the array offset for a given pixel */
759
- int
760
- calc_pixel_offset(texture_info * tex, int x, int y)
761
- {
762
- int offset = 4 * (tex->firstpixel + x + tex->yincr * y);
763
-
764
- return offset;
765
- }
766
-
767
- /* NEWEST version that solves segfault on linux, back
768
- in action due to availability of MAX_TEXTURE_SIZE constant
769
- in ruby 1.8 */
770
- unsigned
771
- max_quad_size(void)
772
- {
773
- #if 1
774
- return 1024;
775
- #endif
776
-
777
- static unsigned size = 0;
778
-
779
- if (size == 0) {
780
- VALUE gosu = rb_const_get(rb_cObject, rb_intern("Gosu"));
781
- VALUE rb_size = rb_const_get(gosu, rb_intern("MAX_TEXTURE_SIZE"));
782
-
783
- size = FIX2INT(rb_size);
784
- }
785
-
786
- return size;
787
- }
788
-
789
- /* old version for quick update, OUT OF ACTIONN */
790
- /* unsigned */
791
- /* max_quad_size(void) */
792
- /* { */
793
- /* #ifdef __APPLE__ */
794
- /* return 1024; */
795
- /* #else */
796
- /* static unsigned MIN_SIZE = 256, MAX_SIZE = 1024; */
797
-
798
- /* static unsigned size = 0; */
799
- /* if (size == 0) */
800
- /* { */
801
- /* GLint width = 1; */
802
- /* size = MIN_SIZE / 2; */
803
- /* do { */
804
- /* size *= 2; */
805
- /* glTexImage2D(GL_PROXY_TEXTURE_2D, 0, 4, size * 2, size * 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); */
806
- /* glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); */
807
- /* } while (width != 0 && size < MAX_SIZE); */
808
- /* } */
809
-
810
- /* return size; */
811
- /* #endif */
812
- /* } */
813
-
814
- /* point format utilities */
815
- bool
816
- is_a_point(VALUE try_point)
817
- {
818
- /* if it responds to 'x' it's near enough (technically must respond to x AND y) */
819
- /* added the is_a_num() check due to WEIRD bug where FIXNUMS were responding to the 'x' method (wtf?) but returning nil when invoked */
820
- if(rb_respond_to(try_point, rb_intern("x")) && !is_a_num(try_point))
821
- return true;
822
-
823
- return false;
824
- }
825
-
826
- VALUE
827
- point_x(VALUE point)
828
- {
829
- return rb_funcall(point, rb_intern("x"), 0);
830
- }
831
-
832
- VALUE
833
- point_y(VALUE point)
834
- {
835
- return rb_funcall(point, rb_intern("y"), 0);
836
- }
837
-
838
- /* mathematical utils, used mainly by bezier curves */
839
- double
840
- power(float base, int exp)
841
- {
842
- float ans = 1.0;
843
- if(base == 0.0) {
844
- if(exp == 0)
845
- return 1;
846
- else
847
- return 0;
848
- }
849
- else if(exp == 0) return 1;
850
- else {
851
- for(int k = exp; k >= 1; k--) {
852
- ans = ans * base;
853
- }
854
- return ans;
855
- }
856
- }
857
-
858
- unsigned
859
- fact(int n)
860
- {
861
- if (n == 0 || n == 1) return 1;
862
- else
863
- return (n * fact(n - 1));
864
- }
865
-
866
- unsigned
867
- comb(int n, int r)
868
- {
869
- /* nCr is symmetrical about n / 2 */
870
- if(r > (n / 2))
871
- r = n - r;
872
-
873
- return perm(n, r) / fact(r);
874
- }
875
-
876
- unsigned
877
- perm(int n, int r)
878
- {
879
- int val = 1;
880
- for(int i = n; i > (n - r); i--)
881
- val *= i;
882
-
883
- return val;
884
- }
885
-
886
- double
887
- bernstein(int n, int k, float u)
888
- {
889
- double temp = comb(n, k) * pow(u, k) * pow(1 - u, n - k);
890
- return temp;
891
- }
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 <AvailabilityMacros.h>
16
+ #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
17
+ # include <GLUT/glut.h>
18
+ #else
19
+ # include <GL/glut.h>
20
+ #endif
21
+ #else
22
+ # include <GL/glut.h>
23
+ #endif
24
+
25
+ /*
26
+ #define MULT_FLOAT4(X, Y) ({ \
27
+ asm volatile ( \
28
+ "movups (%0), %%xmm0\n\t" \
29
+ "mulps (%1), %%xmm0\n\t" \
30
+ "movups %%xmm0, (%1)" \
31
+ :: "r" (X), "r" (Y)); })
32
+
33
+ #define COPY_FLOAT4(X, Y) ({ \
34
+ asm volatile ( \
35
+ "movups (%0), %%xmm0\n\t" \
36
+ "movups %%xmm0, (%1)" \
37
+ :: "r" (X), "r" (Y)); })
38
+
39
+ */
40
+ /* external linkage with static duration */
41
+ const rgba not_a_color_v = { -1.0, -1.0, -1.0, -1.0 };
42
+
43
+ /* utility functions */
44
+ char*
45
+ lowercase(char * string)
46
+ {
47
+ int i = 0;
48
+
49
+ while (string[i]) {
50
+ string[i] = tolower(string[i]);
51
+ i++;
52
+ }
53
+
54
+ return string;
55
+ }
56
+
57
+ char*
58
+ sym2string(VALUE sym)
59
+ {
60
+ return rb_id2name(SYM2ID(sym));
61
+ }
62
+
63
+ VALUE
64
+ string2sym(char * string)
65
+ {
66
+ return ID2SYM(rb_intern(string));
67
+ }
68
+
69
+ bool
70
+ is_a_hash(VALUE try_hash)
71
+ {
72
+ return TYPE(try_hash) == T_HASH;
73
+ }
74
+
75
+ bool
76
+ is_an_array(VALUE try_array)
77
+ {
78
+ return TYPE(try_array) == T_ARRAY;
79
+ }
80
+
81
+ bool is_a_num(VALUE try_num)
82
+ {
83
+ return TYPE(try_num) == T_FIXNUM || TYPE(try_num) == T_FLOAT;
84
+ }
85
+
86
+ VALUE
87
+ get_from_hash(VALUE hash, char * sym)
88
+ {
89
+
90
+ if(TYPE(hash) != T_HASH) rb_raise(rb_eArgError, "hash argument expected");
91
+
92
+ return rb_hash_aref(hash, string2sym(sym));
93
+ }
94
+
95
+ VALUE
96
+ set_hash_value(VALUE hash, char * sym, VALUE val)
97
+ {
98
+ if(TYPE(hash) != T_HASH) rb_raise(rb_eArgError, "hash argument expected");
99
+
100
+ rb_hash_aset(hash, string2sym(sym), val);
101
+
102
+ return val;
103
+ }
104
+
105
+ VALUE
106
+ delete_from_hash(VALUE hash, char * sym)
107
+ {
108
+ if(TYPE(hash) != T_HASH) rb_raise(rb_eArgError, "hash argument expected");
109
+
110
+ return rb_hash_delete(hash, string2sym(sym));
111
+ }
112
+
113
+ /* returns true if 'hash' is a hash and the value mapped to key 'sym' is
114
+ equal to 'val' */
115
+ bool
116
+ hash_value_is(VALUE hash, char * sym, VALUE val)
117
+ {
118
+ if(TYPE(hash) != T_HASH) return false;
119
+
120
+ if(get_from_hash(hash, sym) == val)
121
+ return true;
122
+
123
+ return false;
124
+ }
125
+
126
+ bool
127
+ has_optional_hash_arg(VALUE hash, char * sym)
128
+ {
129
+ if(TYPE(hash) != T_HASH) return false;
130
+
131
+ if(NIL_P(get_from_hash(hash, sym)))
132
+ return false;
133
+
134
+ /* 'hash' is a hash and the sym exists */
135
+ return true;
136
+ }
137
+
138
+ VALUE
139
+ set_array_value(VALUE array, int index, VALUE val)
140
+ {
141
+ if(TYPE(array) != T_ARRAY) rb_raise(rb_eArgError, "array argument expected");
142
+
143
+ rb_ary_store(array, index, val);
144
+
145
+ return val;
146
+ }
147
+
148
+ VALUE
149
+ get_from_array(VALUE array, int index)
150
+ {
151
+
152
+ if(TYPE(array) != T_ARRAY) rb_raise(rb_eArgError, "array argument expected");
153
+
154
+ return rb_ary_entry(array, index);
155
+ }
156
+
157
+
158
+ VALUE
159
+ init_image_local(VALUE image)
160
+ {
161
+ VALUE image_local;
162
+
163
+ if(!is_gosu_image(image))
164
+ rb_raise(rb_eArgError, "not a valid image");
165
+
166
+ /* initialize image_local hash if does not exist */
167
+ if(!is_an_array(rb_iv_get(image, "__image_local__"))) {
168
+ image_local = rb_ary_new();
169
+ rb_iv_set(image, "__image_local__", image_local);
170
+ }
171
+
172
+ image_local = rb_iv_get(image, "__image_local__");
173
+
174
+ return image_local;
175
+ }
176
+
177
+ void
178
+ set_image_local(VALUE image, int name, VALUE val)
179
+ {
180
+ VALUE image_local;
181
+
182
+ image_local = init_image_local(image);
183
+
184
+ set_array_value(image_local, name, val);
185
+ }
186
+
187
+ VALUE
188
+ get_image_local(VALUE image, int name)
189
+ {
190
+ VALUE image_local;
191
+ VALUE val;
192
+
193
+ init_image_local(image);
194
+
195
+ /* this var holds all the image local variables in an array */
196
+ image_local = rb_iv_get(image, "__image_local__");
197
+
198
+ /* a particular image_local variable */
199
+ val = get_from_array(image_local, name);
200
+
201
+ /* if the variable exists then return it */
202
+ if(!NIL_P(val))
203
+ return val;
204
+
205
+ /* otherwise initialize the variable and then return it */
206
+ else {
207
+ switch(name) {
208
+ VALUE init_offset, init_bounds, init_color, init_defaults;
209
+ case DRAW_OFFSET:
210
+ init_offset = rb_ary_new2(2);
211
+ set_array_value(init_offset, 0, INT2FIX(0));
212
+ set_array_value(init_offset, 1, INT2FIX(0));
213
+
214
+ set_array_value(image_local, DRAW_OFFSET, init_offset);
215
+
216
+ return init_offset;
217
+ break;
218
+ case LAZY_BOUNDS:
219
+ init_bounds = rb_ary_new2(4);
220
+ set_array_value(init_bounds, 0, INT2FIX(XMAX_OOB));
221
+ set_array_value(init_bounds, 1, INT2FIX(YMAX_OOB));
222
+ set_array_value(init_bounds, 2, INT2FIX(XMIN_OOB));
223
+ set_array_value(init_bounds, 3, INT2FIX(YMIN_OOB));
224
+
225
+ set_array_value(image_local, LAZY_BOUNDS, init_bounds);
226
+
227
+ return init_bounds;
228
+ break;
229
+ case IMAGE_COLOR:
230
+ init_color = rb_ary_new2(4);
231
+ set_array_value(init_color, 0, rb_float_new(1.0));
232
+ set_array_value(init_color, 1, rb_float_new(1.0));
233
+ set_array_value(init_color, 2, rb_float_new(1.0));
234
+ set_array_value(init_color, 3, rb_float_new(1.0));
235
+
236
+ set_array_value(image_local, IMAGE_COLOR, init_color);
237
+
238
+ return init_color;
239
+ break;
240
+ case USER_DEFAULTS:
241
+ init_defaults = rb_hash_new();
242
+
243
+ set_array_value(image_local, USER_DEFAULTS, init_defaults);
244
+
245
+ return init_defaults;
246
+ break;
247
+ default:
248
+ rb_raise(rb_eArgError, "unrecognized image_local variable number. got %d", name);
249
+ }
250
+ }
251
+
252
+ /* never reached */
253
+ return Qnil;
254
+ }
255
+
256
+ rgba
257
+ convert_image_local_color_to_rgba(VALUE image)
258
+ {
259
+ rgba color;
260
+ VALUE image_local_color = get_image_local(image, IMAGE_COLOR);
261
+
262
+ color.red = NUM2DBL(get_from_array(image_local_color, red));
263
+ color.green = NUM2DBL(get_from_array(image_local_color, green));
264
+ color.blue = NUM2DBL(get_from_array(image_local_color, blue));
265
+ color.alpha = NUM2DBL(get_from_array(image_local_color, alpha));
266
+
267
+ return color;
268
+ }
269
+
270
+ VALUE
271
+ save_rgba_to_image_local_color(VALUE image, rgba color)
272
+ {
273
+ /* abbreviation for image_local_color */
274
+ VALUE ilc = get_image_local(image, IMAGE_COLOR);
275
+
276
+ set_array_value(ilc, 0, rb_float_new(color.red));
277
+ set_array_value(ilc, 1, rb_float_new(color.green));
278
+ set_array_value(ilc, 2, rb_float_new(color.blue));
279
+ set_array_value(ilc, 3, rb_float_new(color.alpha));
280
+
281
+ return ilc;
282
+ }
283
+
284
+ bool
285
+ not_a_color(rgba color1)
286
+ {
287
+ return color1.red == -1 || color1.green == -1 ||
288
+ color1.blue == -1 || color1.alpha == -1;
289
+ }
290
+
291
+ bool
292
+ is_a_color(rgba color1)
293
+ {
294
+ return !not_a_color(color1);
295
+ }
296
+
297
+ bool
298
+ is_rb_raw_color(VALUE cval)
299
+ {
300
+ return TYPE(cval) == T_ARRAY &&
301
+ is_a_num(get_from_array(cval, 0)) &&
302
+ is_a_num(get_from_array(cval, 1)) &&
303
+ is_a_num(get_from_array(cval, 2)) &&
304
+ is_a_num(get_from_array(cval, 3));
305
+ }
306
+
307
+ bool
308
+ not_rb_raw_color(VALUE cval)
309
+ {
310
+ return TYPE(cval) != T_ARRAY ||
311
+ !is_a_num(get_from_array(cval, 0));
312
+ }
313
+
314
+ /** cmp_color related functions **/
315
+ static bool
316
+ is_transparent_color(rgba color1)
317
+ {
318
+ return color1.red == -666 && color1.green == -666 && color1.blue == -666 &&
319
+ color1.alpha == -666;
320
+ }
321
+
322
+ static bool
323
+ special_cmp_color(rgba color1, rgba color2)
324
+ {
325
+ if (is_transparent_color(color1))
326
+ return color2.alpha == 0;
327
+ else if (is_transparent_color(color2))
328
+ return color1.alpha == 0;
329
+ else
330
+ return false;
331
+ }
332
+
333
+ static bool
334
+ special_cmp_color_with_tolerance(rgba color1, rgba color2, float tolerance)
335
+ {
336
+ if (is_transparent_color(color1))
337
+ return (color2.alpha) <= tolerance;
338
+ else if (is_transparent_color(color2))
339
+ return color1.alpha <= tolerance;
340
+ else
341
+ return false;
342
+ }
343
+
344
+
345
+ static float
346
+ color_distance_squared(rgba c1, rgba c2)
347
+ {
348
+ return (c1.red - c2.red) * (c1.red - c2.red) +
349
+ (c1.green - c2.green) * (c1.green - c2.green) +
350
+ (c1.blue - c2.blue) * (c1.blue - c2.blue) +
351
+ (c1.alpha - c2.alpha) * (c1.alpha - c2.alpha);
352
+ }
353
+
354
+
355
+ bool
356
+ cmp_color_with_tolerance(rgba color1, rgba color2, float tolerance)
357
+ {
358
+ if (color1.red < 0 || color2.red < 0)
359
+ return special_cmp_color_with_tolerance(color1, color2, tolerance);
360
+
361
+ return color_distance_squared(color1, color2) <= (tolerance * tolerance);
362
+ }
363
+
364
+ bool
365
+ cmp_color(rgba color1, rgba color2)
366
+ {
367
+ if (color1.red < 0 || color2.red < 0)
368
+ return special_cmp_color(color1, color2);
369
+
370
+ return (color1.red == color2.red) && (color1.green == color2.green) && (color1.blue == color2.blue)
371
+ && (color1.alpha == color2.alpha);
372
+ }
373
+
374
+
375
+ /*** these functions are UNSAFE ***/
376
+ void
377
+ color_copy(float * source, float * dest)
378
+ {
379
+ //COPY_FLOAT4(source, dest);
380
+ memcpy(dest, source, 4 * sizeof(float));
381
+ }
382
+
383
+ void
384
+ zero_color(float * tex)
385
+ {
386
+ memset(tex, 0, 4 * sizeof(float));
387
+ }
388
+ /*** ***/
389
+
390
+ rgba
391
+ find_color_from_string(char * try_color)
392
+ {
393
+ rgba cur_color;
394
+
395
+ if(!strcmp("red", try_color)) {
396
+ cur_color.red = 1.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
397
+ }
398
+ else if(!strcmp("green", try_color)) {
399
+ cur_color.red = 0.0; cur_color.green = 1.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
400
+ }
401
+ else if(!strcmp("blue", try_color)) {
402
+ cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
403
+ }
404
+ else if(!strcmp("black", try_color)) {
405
+ cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
406
+ }
407
+ else if(!strcmp("white", try_color)) {
408
+ cur_color.red = 1.0; cur_color.green = 1.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
409
+ }
410
+ else if(!strcmp("purple", try_color)) {
411
+ cur_color.red = 1.0; cur_color.green = 0.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
412
+ }
413
+ else if(!strcmp("yellow", try_color)) {
414
+ cur_color.red = 1.0; cur_color.green = 1.0; cur_color.blue = 0.0; cur_color.alpha = 1.0;
415
+ }
416
+ else if(!strcmp("cyan", try_color)) {
417
+ cur_color.red = 0.0; cur_color.green = 1.0; cur_color.blue = 1.0; cur_color.alpha = 1.0;
418
+ }
419
+ else if(!strcmp("orange", try_color)) {
420
+ cur_color.red = 1.0; cur_color.green = 0.5; cur_color.blue = 0.0; cur_color.alpha = 1.0;
421
+ }
422
+ else if(!strcmp("brown", try_color)) {
423
+ cur_color.red = 0.39; cur_color.green = 0.26; cur_color.blue = 0.13; cur_color.alpha = 1.0;
424
+ }
425
+ else if(!strcmp("turquoise", try_color)) {
426
+ cur_color.red = 0.1; cur_color.green = 0.6; cur_color.blue = 0.8; cur_color.alpha = 1.0;
427
+ }
428
+ else if(!strcmp("tyrian", try_color)) {
429
+ cur_color.red = 0.4; cur_color.green = 0.007; cur_color.blue = 0.235; cur_color.alpha = 1.0;
430
+ }
431
+ else if(!strcmp("alpha", try_color)) {
432
+ cur_color.red = 0.0; cur_color.green = 0.0; cur_color.blue = 0.0; cur_color.alpha = 0.0;
433
+ }
434
+ else if(!strcmp("transparent", try_color)) {
435
+ cur_color.red = -666; cur_color.green = -666; cur_color.blue = -666; cur_color.alpha = -666;
436
+ }
437
+ else if(!strcmp("none", try_color)) {
438
+ cur_color = not_a_color_v;
439
+ }
440
+ else if(!strcmp("random", try_color) || !strcmp("rand", try_color)) {
441
+ cur_color.red = rand() / (float)RAND_MAX;
442
+ cur_color.green = rand() / (float)RAND_MAX;
443
+ cur_color.blue = rand() / (float)RAND_MAX;
444
+ cur_color.alpha = 1.0;
445
+ }
446
+
447
+ else
448
+ rb_raise(rb_eArgError, "invalid colour specified (no color matches the symbol: %s)\n", try_color);
449
+
450
+ return cur_color;
451
+ }
452
+
453
+ rgba
454
+ convert_gosu_to_rgba_color(VALUE gcolor)
455
+ {
456
+
457
+ return (rgba) {
458
+ FIX2INT(rb_funcall(gcolor, rb_intern("red"), 0)) / 255.0,
459
+ FIX2INT(rb_funcall(gcolor, rb_intern("green"), 0)) / 255.0,
460
+ FIX2INT(rb_funcall(gcolor, rb_intern("blue"), 0)) / 255.0,
461
+ FIX2INT(rb_funcall(gcolor, rb_intern("alpha"), 0)) / 255.0
462
+ };
463
+ }
464
+
465
+
466
+ /* convert C color to Ruby color */
467
+ VALUE
468
+ convert_rgba_to_rb_color(rgba * pix)
469
+ {
470
+ if (not_a_color(*pix)) return Qnil;
471
+
472
+ /* create a new ruby array to store the pixel data */
473
+ VALUE pix_array = rb_ary_new2(4);
474
+
475
+ /* store the pixel data */
476
+ rb_ary_store(pix_array, red, rb_float_new(pix->red));
477
+ rb_ary_store(pix_array, green, rb_float_new(pix->green));
478
+ rb_ary_store(pix_array, blue, rb_float_new(pix->blue));
479
+ rb_ary_store(pix_array, alpha, rb_float_new(pix->alpha));
480
+
481
+ return pix_array;
482
+ }
483
+
484
+ /* convert C color to gosu color */
485
+ VALUE
486
+ convert_rgba_to_gosu_color(rgba * pix)
487
+ {
488
+ if (not_a_color(*pix)) return Qnil;
489
+
490
+ VALUE gosu_color = rb_funcall(gosu_color_class(), rb_intern("new"), 0);
491
+
492
+ rb_funcall(gosu_color, rb_intern("red="), 1, INT2FIX(pix->red * 255));
493
+ rb_funcall(gosu_color, rb_intern("green="), 1, INT2FIX(pix->green * 255));
494
+ rb_funcall(gosu_color, rb_intern("blue="), 1, INT2FIX(pix->blue * 255));
495
+ rb_funcall(gosu_color, rb_intern("alpha="), 1, INT2FIX(pix->alpha * 255));
496
+
497
+ return gosu_color;
498
+ }
499
+
500
+ VALUE
501
+ gosu_color_class()
502
+ {
503
+ static VALUE gcolor_class = 0;
504
+
505
+ if (gcolor_class == 0) {
506
+ VALUE gosu_class = rb_const_get(rb_cObject, rb_intern("Gosu"));
507
+ gcolor_class = rb_const_get(gosu_class, rb_intern("Color"));
508
+ }
509
+
510
+ return gcolor_class;
511
+ }
512
+
513
+ /* convert Ruby color to C color */
514
+ rgba
515
+ convert_rb_color_to_rgba(VALUE cval)
516
+ {
517
+ rgba my_color;
518
+
519
+ if (is_gosu_color(cval)) return convert_gosu_to_rgba_color(cval);
520
+
521
+ /* current color for actions */
522
+ switch(TYPE(cval)) {
523
+ char * try_color;
524
+ case T_SYMBOL:
525
+ try_color = lowercase(sym2string(cval));
526
+
527
+ my_color = find_color_from_string(try_color);
528
+
529
+ break;
530
+ case T_ARRAY:
531
+ my_color.red = NUM2DBL(rb_ary_entry(cval, red));
532
+ my_color.green = NUM2DBL(rb_ary_entry(cval, green));
533
+ my_color.blue = NUM2DBL(rb_ary_entry(cval, blue));
534
+
535
+ if(NUM2INT(rb_funcall(cval, rb_intern("length"), 0)) > 3)
536
+ my_color.alpha = NUM2DBL(rb_ary_entry(cval, alpha));
537
+ else
538
+ my_color.alpha = 1;
539
+
540
+ break;
541
+
542
+ /* hex literals */
543
+ case T_FIXNUM:
544
+ case T_BIGNUM:
545
+ return convert_gosu_to_rgba_color(rb_funcall(gosu_color_class(),
546
+ rb_intern("new"), 1, cval));
547
+ break;
548
+
549
+ default:
550
+ rb_raise(rb_eArgError, "unsupported argument type for color. Got type 0x%x\n", TYPE(cval) );
551
+ }
552
+
553
+ /* a valid color */
554
+ if(is_a_color(my_color))
555
+ return my_color;
556
+
557
+ /* special condition for when color is taken from outside range of bitmap. Color is just ignored */
558
+ else if(not_a_color(my_color))
559
+ return not_a_color_v;
560
+
561
+ /* anything else should fail */
562
+ else
563
+ rb_raise(rb_eArgError, "invalid colour specified (negative value given)\n");
564
+ }
565
+
566
+ /* error checking functions */
567
+ void
568
+ check_mask(VALUE mask)
569
+ {
570
+ char * try_mask;
571
+
572
+ if(TYPE(mask) != T_ARRAY && TYPE(mask) != T_SYMBOL)
573
+ rb_raise(rb_eArgError, "array or symbol parameter required");
574
+
575
+ /* is it a valid mask symbol? */
576
+ if(TYPE(mask) == T_SYMBOL) {
577
+ try_mask = lowercase(sym2string(mask));
578
+ if(*try_mask == '_') try_mask++;
579
+ if(not_a_color(find_color_from_string(try_mask))) {
580
+ rb_raise(rb_eArgError, "unrecognized mask symbol: %s\n", sym2string(mask));
581
+ }
582
+ }
583
+ }
584
+
585
+ void
586
+ check_image(VALUE image)
587
+ {
588
+ if(!rb_respond_to(image, rb_intern("gl_tex_info")))
589
+ rb_raise(rb_eRuntimeError,"must specify a valid source image");
590
+ }
591
+
592
+ bool
593
+ is_gosu_image(VALUE try_image)
594
+ {
595
+ if(rb_respond_to(try_image, rb_intern("gl_tex_info")))
596
+ return true;
597
+
598
+ return false;
599
+ }
600
+
601
+ bool
602
+ is_gosu_color(VALUE try_color)
603
+ {
604
+ if(rb_respond_to(try_color, rb_intern("red")))
605
+ return true;
606
+
607
+ return false;
608
+ }
609
+
610
+
611
+
612
+ /** cohen-sutherland line clipper **/
613
+ #define outcode int
614
+ const int RIGHT = 8; //1000
615
+ const int TOP = 4; //0100
616
+ const int LEFT = 2; //0010
617
+ const int BOTTOM = 1; //0001
618
+
619
+ //Compute the bit code for a point (x, y) using the clip rectangle
620
+ //bounded diagonally by (xmin, ymin), and (xmax, ymax)
621
+ static outcode
622
+ ComputeOutCode (int x, int y, int xmin, int ymin, int xmax, int ymax)
623
+ {
624
+ outcode code = 0;
625
+ if (y > ymax) //above the clip window
626
+ code |= TOP;
627
+ else if (y < ymin) //below the clip window
628
+ code |= BOTTOM;
629
+ if (x > xmax) //to the right of clip window
630
+ code |= RIGHT;
631
+ else if (x < xmin) //to the left of clip window
632
+ code |= LEFT;
633
+ return code;
634
+ }
635
+
636
+ /** Cohen-Sutherland clipping algorithm clips a line from
637
+ P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with
638
+ diagonal from (xmin, ymin) to (xmax, ymax). **/
639
+ void
640
+ cohen_sutherland_clip (int * x0, int * y0,int * x1, int * y1, int xmin, int ymin,
641
+ int xmax, int ymax)
642
+ {
643
+ //Outcodes for P0, P1, and whatever point lies outside the clip rectangle
644
+ outcode outcode0, outcode1, outcodeOut;
645
+ bool accept = false, done = false;
646
+ int tx0 = *x0, ty0 = *y0, tx1 = *x1, ty1 = *y1;
647
+
648
+ //compute outcodes
649
+ outcode0 = ComputeOutCode (tx0, ty0, xmin, ymin, xmax, ymax);
650
+ outcode1 = ComputeOutCode (tx1, ty1, xmin, ymin, xmax, ymax);
651
+
652
+ do{
653
+ if (!(outcode0 | outcode1)) //logical or is 0. Trivially accept and get out of loop
654
+ {
655
+ accept = true;
656
+ done = true;
657
+ }
658
+ else if (outcode0 & outcode1) //logical and is not 0. Trivially reject and get out of loop
659
+ done = true;
660
+ else
661
+ {
662
+ //failed both tests, so calculate the line segment to clip
663
+ //from an outside point to an intersection with clip edge
664
+ double x, y;
665
+ //At least one endpoint is outside the clip rectangle; pick it.
666
+ outcodeOut = outcode0? outcode0: outcode1;
667
+ //Now find the intersection point;
668
+ //use formulas y = y0 + slope * (x - x0), x = x0 + (1/slope)* (y - y0)
669
+ if (outcodeOut & TOP) //point is above the clip rectangle
670
+ {
671
+ x = tx0 + (tx1 - tx0) * (ymax - ty0)/(ty1 - ty0);
672
+ y = ymax;
673
+ }
674
+ else if (outcodeOut & BOTTOM) //point is below the clip rectangle
675
+ {
676
+ x = tx0 + (tx1 - tx0) * (ymin - ty0)/(ty1 - ty0);
677
+ y = ymin;
678
+ }
679
+ else if (outcodeOut & RIGHT) //point is to the right of clip rectangle
680
+ {
681
+ y = ty0 + (ty1 - ty0) * (xmax - tx0)/(tx1 - tx0);
682
+ x = xmax;
683
+ }
684
+ else //point is to the left of clip rectangle
685
+ {
686
+ y = ty0 + (ty1 - ty0) * (xmin - tx0)/(tx1 - tx0);
687
+ x = xmin;
688
+ }
689
+ //Now we move outside point to intersection point to clip
690
+ //and get ready for next pass.
691
+ if (outcodeOut == outcode0)
692
+ {
693
+ tx0 = x;
694
+ ty0 = y;
695
+ outcode0 = ComputeOutCode (tx0, ty0, xmin, ymin, xmax, ymax);
696
+ }
697
+ else
698
+ {
699
+ tx1 = x;
700
+ ty1 = y;
701
+ outcode1 = ComputeOutCode (tx1, ty1, xmin, ymin, xmax, ymax);
702
+ }
703
+ }
704
+ }while (!done);
705
+
706
+ if (accept)
707
+ {
708
+ *x0 = tx0; *x1 = tx1;
709
+ *y0 = ty0; *y1 = ty1;
710
+ }
711
+
712
+ }
713
+ /** end of cohen-sutherland line clipper **/
714
+
715
+
716
+ void
717
+ constrain_boundaries(int * x0, int * y0, int * x1, int * y1, int width, int height)
718
+ {
719
+ if(*y0 < 0) *y0 = 0;
720
+ if(*y1 < 0) *y1 = 0;
721
+
722
+ if(*x0 < 0) *x0 = 0;
723
+ if(*x1 < 0) *x1 = 0;
724
+
725
+ if(*x0 > (width - 1)) *x0 = width - 1;
726
+ if(*x1 > (width - 1)) *x1 = width - 1;
727
+
728
+ if(*y0 > (height - 1)) *y0 = height - 1;
729
+ if(*y1 > (height - 1)) *y1 = height - 1;
730
+
731
+ if(*y0 > *y1) { SWAP(*y0, *y1); }
732
+ if(*x0 > *x1) { SWAP(*x0, *x1); }
733
+ }
734
+
735
+
736
+ /* returns true if point (x, y) is within bounds designated by rect (x0, y0)-(x1, y1)
737
+ and inner thickness: 'inner'
738
+ */
739
+ bool
740
+ bound_by_rect_and_inner(int x, int y, int x0, int y0, int x1, int y1, int inner)
741
+ {
742
+
743
+ return ((x >= x0) && (x <= x1) && (y >= y0) && (y <= y1)) &&
744
+ !((x >= x0 + inner) && (x <= x1 - inner) && (y >= y0 + inner) && (y <= y1 - inner));
745
+ }
746
+
747
+ /* same as above but excluding inner rectangle */
748
+ bool
749
+ bound_by_rect(int x, int y, int x0, int y0, int x1, int y1)
750
+ {
751
+ return bound_by_rect_and_inner(x, y, x0, y0, x1, y1, OOB_VAL);
752
+ }
753
+
754
+ /* calculate the array offset for a given pixel in action context */
755
+ int
756
+ calc_pixel_offset_for_action(action_struct * cur, texture_info * tex, int x, int y)
757
+ {
758
+ int offset = calc_pixel_offset(tex, x + cur->xmin, y + cur->ymin);
759
+
760
+ return offset;
761
+ }
762
+
763
+ /* calculate the array offset for a given pixel */
764
+ int
765
+ calc_pixel_offset(texture_info * tex, int x, int y)
766
+ {
767
+ int offset = 4 * (tex->firstpixel + x + tex->yincr * y);
768
+
769
+ return offset;
770
+ }
771
+
772
+ /* NEWEST version that solves segfault on linux, back
773
+ in action due to availability of MAX_TEXTURE_SIZE constant
774
+ in ruby 1.8 */
775
+ unsigned
776
+ max_quad_size(void)
777
+ {
778
+ #if 1
779
+ return 1024;
780
+ #endif
781
+
782
+ static unsigned size = 0;
783
+
784
+ if (size == 0) {
785
+ VALUE gosu = rb_const_get(rb_cObject, rb_intern("Gosu"));
786
+ VALUE rb_size = rb_const_get(gosu, rb_intern("MAX_TEXTURE_SIZE"));
787
+
788
+ size = FIX2INT(rb_size);
789
+ }
790
+
791
+ return size;
792
+ }
793
+
794
+ /* old version for quick update, OUT OF ACTIONN */
795
+ /* unsigned */
796
+ /* max_quad_size(void) */
797
+ /* { */
798
+ /* #ifdef __APPLE__ */
799
+ /* return 1024; */
800
+ /* #else */
801
+ /* static unsigned MIN_SIZE = 256, MAX_SIZE = 1024; */
802
+
803
+ /* static unsigned size = 0; */
804
+ /* if (size == 0) */
805
+ /* { */
806
+ /* GLint width = 1; */
807
+ /* size = MIN_SIZE / 2; */
808
+ /* do { */
809
+ /* size *= 2; */
810
+ /* glTexImage2D(GL_PROXY_TEXTURE_2D, 0, 4, size * 2, size * 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); */
811
+ /* glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); */
812
+ /* } while (width != 0 && size < MAX_SIZE); */
813
+ /* } */
814
+
815
+ /* return size; */
816
+ /* #endif */
817
+ /* } */
818
+
819
+ /* point format utilities */
820
+ bool
821
+ is_a_point(VALUE try_point)
822
+ {
823
+ /* if it responds to 'x' it's near enough (technically must respond to x AND y) */
824
+ /* added the is_a_num() check due to WEIRD bug where FIXNUMS were responding to the 'x' method (wtf?) but returning nil when invoked */
825
+ if(rb_respond_to(try_point, rb_intern("x")) && !is_a_num(try_point))
826
+ return true;
827
+
828
+ return false;
829
+ }
830
+
831
+ VALUE
832
+ point_x(VALUE point)
833
+ {
834
+ return rb_funcall(point, rb_intern("x"), 0);
835
+ }
836
+
837
+ VALUE
838
+ point_y(VALUE point)
839
+ {
840
+ return rb_funcall(point, rb_intern("y"), 0);
841
+ }
842
+
843
+ /* mathematical utils, used mainly by bezier curves */
844
+ double
845
+ power(float base, int exp)
846
+ {
847
+ float ans = 1.0;
848
+ if(base == 0.0) {
849
+ if(exp == 0)
850
+ return 1;
851
+ else
852
+ return 0;
853
+ }
854
+ else if(exp == 0) return 1;
855
+ else {
856
+ for(int k = exp; k >= 1; k--) {
857
+ ans = ans * base;
858
+ }
859
+ return ans;
860
+ }
861
+ }
862
+
863
+ unsigned
864
+ fact(int n)
865
+ {
866
+ if (n == 0 || n == 1) return 1;
867
+ else
868
+ return (n * fact(n - 1));
869
+ }
870
+
871
+ unsigned
872
+ comb(int n, int r)
873
+ {
874
+ /* nCr is symmetrical about n / 2 */
875
+ if(r > (n / 2))
876
+ r = n - r;
877
+
878
+ return perm(n, r) / fact(r);
879
+ }
880
+
881
+ unsigned
882
+ perm(int n, int r)
883
+ {
884
+ int val = 1;
885
+ for(int i = n; i > (n - r); i--)
886
+ val *= i;
887
+
888
+ return val;
889
+ }
890
+
891
+ double
892
+ bernstein(int n, int k, float u)
893
+ {
894
+ double temp = comb(n, k) * pow(u, k) * pow(1 - u, n - k);
895
+ return temp;
896
+ }