texplay 0.4.3 → 0.4.4.pre

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