texplay 0.4.3-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/.gemtest +0 -0
  2. data/CHANGELOG +222 -0
  3. data/README.markdown +48 -0
  4. data/Rakefile +16 -0
  5. data/examples/common.rb +18 -0
  6. data/examples/example_alpha_blend.rb +29 -0
  7. data/examples/example_bezier.rb +41 -0
  8. data/examples/example_blank.rb +37 -0
  9. data/examples/example_cache.rb +21 -0
  10. data/examples/example_color_control.rb +69 -0
  11. data/examples/example_color_transform.rb +62 -0
  12. data/examples/example_color_transform_circle.rb +34 -0
  13. data/examples/example_darken.rb +24 -0
  14. data/examples/example_dup.rb +73 -0
  15. data/examples/example_each.rb +39 -0
  16. data/examples/example_effect.rb +34 -0
  17. data/examples/example_fill.rb +43 -0
  18. data/examples/example_fill_old.rb +48 -0
  19. data/examples/example_fluent.rb +29 -0
  20. data/examples/example_font.rb +31 -0
  21. data/examples/example_hash_arguments.rb +46 -0
  22. data/examples/example_ippa.rb +23 -0
  23. data/examples/example_light.rb +75 -0
  24. data/examples/example_light_multiply.rb +18 -0
  25. data/examples/example_lsystem.rb +61 -0
  26. data/examples/example_melt.rb +25 -0
  27. data/examples/example_meyet.rb +62 -0
  28. data/examples/example_polyline.rb +42 -0
  29. data/examples/example_scale.rb +27 -0
  30. data/examples/example_select.rb +36 -0
  31. data/examples/example_select2.rb +25 -0
  32. data/examples/example_simple.rb +46 -0
  33. data/examples/example_splice.rb +26 -0
  34. data/examples/example_sync.rb +59 -0
  35. data/examples/example_tiles.rb +41 -0
  36. data/examples/example_trace.rb +22 -0
  37. data/examples/example_transparent.rb +28 -0
  38. data/examples/example_transparent2.rb +24 -0
  39. data/examples/example_transparent3.rb +20 -0
  40. data/examples/example_turtle.rb +39 -0
  41. data/examples/example_weird.rb +22 -0
  42. data/examples/example_window_render_to_image.rb +41 -0
  43. data/examples/example_window_to_blob.rb +35 -0
  44. data/examples/media/bird.png +0 -0
  45. data/examples/media/body.png +0 -0
  46. data/examples/media/empty2.png +0 -0
  47. data/examples/media/face.png +0 -0
  48. data/examples/media/gob.png +0 -0
  49. data/examples/media/gosu.png +0 -0
  50. data/examples/media/green.png +0 -0
  51. data/examples/media/logo.png +0 -0
  52. data/examples/media/maria.png +0 -0
  53. data/examples/media/object.png +0 -0
  54. data/examples/media/rose.bmp +0 -0
  55. data/examples/media/sand1.png +0 -0
  56. data/examples/media/sunset.png +0 -0
  57. data/examples/media/texplay.png +0 -0
  58. data/ext/texplay/actions.c +1006 -0
  59. data/ext/texplay/actions.h +60 -0
  60. data/ext/texplay/bindings.c +1125 -0
  61. data/ext/texplay/bindings.h +46 -0
  62. data/ext/texplay/cache.c +118 -0
  63. data/ext/texplay/cache.h +24 -0
  64. data/ext/texplay/compat.h +27 -0
  65. data/ext/texplay/extconf.rb +38 -0
  66. data/ext/texplay/graphics_utils.c +1313 -0
  67. data/ext/texplay/graphics_utils.h +22 -0
  68. data/ext/texplay/texplay.c +201 -0
  69. data/ext/texplay/texplay.h +153 -0
  70. data/ext/texplay/utils.c +891 -0
  71. data/ext/texplay/utils.h +153 -0
  72. data/ext/texplay/vendor/freeglut/include/GL/freeglut.h +22 -0
  73. data/ext/texplay/vendor/freeglut/include/GL/freeglut_ext.h +236 -0
  74. data/ext/texplay/vendor/freeglut/include/GL/freeglut_std.h +628 -0
  75. data/ext/texplay/vendor/freeglut/include/GL/glut.h +21 -0
  76. data/lib/texplay-contrib.rb +147 -0
  77. data/lib/texplay.rb +347 -0
  78. data/lib/texplay/1.8/texplay.so +0 -0
  79. data/lib/texplay/1.9/texplay.so +0 -0
  80. data/lib/texplay/alone.rb +20 -0
  81. data/lib/texplay/c_function_docs.rb +178 -0
  82. data/lib/texplay/live.rb +84 -0
  83. data/lib/texplay/version.rb +3 -0
  84. data/live/live.rb +85 -0
  85. data/test/image_spec.rb +45 -0
  86. data/test/texplay_spec.rb +144 -0
  87. metadata +179 -0
@@ -0,0 +1,22 @@
1
+ #ifndef GUARD_GRAPHICS_UTILS_H
2
+ #define GUARD_GRAPHICS_UTILS_H
3
+
4
+ void update_lazy_bounds(action_struct * cur, texture_info * tex);
5
+ void update_bounds(action_struct * cur, int xmin, int ymin, int xmax, int ymax);
6
+ void set_local_bounds(action_struct * cur, int xmin, int ymin, int xmax, int ymax, texture_info * tex);
7
+
8
+ void draw_prologue(action_struct * cur, texture_info * tex, int xmin, int ymin, int xmax, int ymax, VALUE * hash_arg,
9
+ sync sync_mode, bool primary, action_struct ** payload_ptr);
10
+ void draw_epilogue(action_struct * cur, texture_info * tex, bool primary);
11
+
12
+ void set_pixel_color_with_style(action_struct * payload, texture_info * tex, int x, int y);
13
+ void set_pixel_color(rgba * pixel_color, texture_info * tex, int x, int y);
14
+
15
+ rgba get_pixel_color_from_chunk(float * chunk, int width, int height, int x, int y);
16
+ rgba get_pixel_color(texture_info * tex, int x, int y);
17
+ float* get_pixel_data(texture_info * tex, int x, int y);
18
+
19
+ /* create a blank gosu image of width and height */
20
+ VALUE create_image(VALUE window, int width, int height);
21
+
22
+ #endif
@@ -0,0 +1,201 @@
1
+ /* texplay.c, light-weight alternative to rmagick for ruby */
2
+ /* (C) John Mair 2009
3
+ * This program is distributed under the terms of the MIT License
4
+ * */
5
+
6
+ #include <ruby.h>
7
+ #include <stdio.h>
8
+ #include <time.h>
9
+ #include "texplay.h"
10
+ #include "actions.h"
11
+ #include "utils.h"
12
+ #include "bindings.h"
13
+ #ifdef __APPLE__
14
+ # include <glut.h>
15
+ #else
16
+ # include <GL/glut.h>
17
+ #endif
18
+
19
+
20
+ /* setup ruby bindings */
21
+
22
+ /** constructor for TPPoint class **/
23
+ static VALUE m_init_TPPoint(int argc, VALUE * argv, VALUE self);
24
+ static void monkey_patch_gosu(void);
25
+ static VALUE gosu_window(void);
26
+
27
+ void
28
+ Init_texplay() {
29
+
30
+ VALUE jm_Module = rb_define_module("TexPlay");
31
+ VALUE TPPoint = rb_define_class_under(jm_Module, "TPPoint", rb_cObject);
32
+
33
+ /** define basic point class TPPoint **/
34
+ rb_attr(TPPoint, rb_intern("x"), 1, 1, Qtrue);
35
+ rb_attr(TPPoint, rb_intern("y"), 1, 1, Qtrue);
36
+ rb_define_method(TPPoint, "initialize", m_init_TPPoint, -1);
37
+ /** end of TPPoint definition **/
38
+
39
+ /* TexPlay methods */
40
+ rb_define_method(jm_Module, "paint", m_paint, -1);
41
+ rb_define_method(jm_Module, "get_pixel", m_getpixel, -1);
42
+ rb_define_method(jm_Module, "circle", m_circle, -1);
43
+ rb_define_method(jm_Module, "line", m_line, -1);
44
+ rb_define_method(jm_Module, "rect", m_rect, -1);
45
+ rb_define_method(jm_Module, "pixel", m_pixel, -1);
46
+ rb_define_method(jm_Module, "fill", m_flood_fill, -1);
47
+ rb_define_method(jm_Module, "bezier", m_bezier, -1);
48
+ rb_define_method(jm_Module, "polyline", m_polyline, -1);
49
+ rb_define_method(jm_Module, "ngon", m_ngon, -1);
50
+
51
+ rb_define_method(jm_Module, "splice", m_splice, -1);
52
+
53
+ rb_define_method(jm_Module, "color", m_color, -1);
54
+ rb_define_method(jm_Module, "offset", m_offset, -1);
55
+ rb_define_method(jm_Module, "method_missing", m_missing, -1);
56
+ rb_define_method(jm_Module, "quad_cached?", m_quad_cached, 0);
57
+
58
+ rb_define_method(jm_Module, "each", m_each, -1);
59
+
60
+ /* needs to be updated, not yet done **/
61
+ /* rb_define_method(jm_Module, "bitmask", m_bitmask, -1); */
62
+ /* rb_define_method(jm_Module, "leftshift", m_lshift, -1); */
63
+ /* rb_define_method(jm_Module, "rightshift", m_rshift, -1); */
64
+ /* rb_define_method(jm_Module, "[]=", m_special_pixel, -1); */
65
+
66
+ rb_define_method(jm_Module, "dup", m_dup_image, 0);
67
+ rb_define_method(jm_Module, "clone", m_clone_image, 0);
68
+ rb_define_method(jm_Module, "to_blob", m_to_blob, 0);
69
+ rb_define_method(jm_Module, "force_sync", m_force_sync, 1);
70
+ rb_define_method(jm_Module, "set_options", m_user_set_options, 1);
71
+ rb_define_method(jm_Module, "get_options", m_get_options, 0);
72
+ rb_define_method(jm_Module, "delete_options", m_user_delete_options, 0);
73
+
74
+ rb_define_method(jm_Module, "refresh_cache", m_cache_refresh, 0);
75
+
76
+ /* a constant containing the sidelength of largest allowable quad */
77
+ rb_define_const(jm_Module, "TP_MAX_QUAD_SIZE", INT2FIX(max_quad_size() - 2));
78
+
79
+ /* singleton method for creating & removing macros */
80
+ rb_define_singleton_method(jm_Module, "create_macro", M_create_macro, 1);
81
+ rb_define_singleton_method(jm_Module, "remove_macro", M_remove_macro, 1);
82
+ rb_define_singleton_method(jm_Module, "refresh_cache_all", M_refresh_cache_all, 0);
83
+ /* rb_define_singleton_method(jm_Module, "create_blank_image", M_create_blank, 3); */
84
+
85
+ /** aliases; must be made on singleton class because we're using class methods **/
86
+ rb_define_method(jm_Module, "box", m_rect, -1);
87
+ rb_define_method(jm_Module, "colour", m_color, -1);
88
+ rb_define_method(jm_Module, "composite", m_splice, -1);
89
+ rb_define_method(jm_Module, "set_pixel", m_pixel, -1);
90
+ rb_define_method(jm_Module, "[]", m_getpixel, -1);
91
+ rb_define_method(jm_Module, "cache", m_cache_refresh, 0);
92
+ /** end of aliases **/
93
+
94
+ /** basic setup **/
95
+
96
+ /* seed the random number generator */
97
+ srand(time(NULL));
98
+
99
+ monkey_patch_gosu();
100
+ /** end basic setup **/
101
+ }
102
+
103
+ /** constructor for TPPoint class **/
104
+ static VALUE
105
+ m_init_TPPoint(int argc, VALUE * argv, VALUE self)
106
+ {
107
+ if(argc == 0) {
108
+ rb_iv_set(self, "@x", INT2FIX(0));
109
+ rb_iv_set(self, "@y", INT2FIX(0));
110
+ }
111
+ else if(argc == 2){
112
+ if(is_a_num(argv[0]) && is_a_num(argv[1])) {
113
+ rb_iv_set(self, "@x", argv[0]);
114
+ rb_iv_set(self, "@y", argv[1]);
115
+ }
116
+ else
117
+ rb_raise(rb_eArgError, "must provide two numbers");
118
+ }
119
+ else
120
+ rb_raise(rb_eArgError, "please provide x and y args only");
121
+
122
+ return Qnil;
123
+
124
+ }
125
+ /** end constructor for TPPoint **/
126
+
127
+
128
+ static VALUE
129
+ gosu_window_to_blob(VALUE self, VALUE rb_x, VALUE rb_y, VALUE rb_width, VALUE rb_height)
130
+ {
131
+ int x = FIX2INT(rb_x);
132
+ int y = FIX2INT(rb_y);
133
+ int width = FIX2INT(rb_width);
134
+ int height = FIX2INT(rb_height);
135
+ int window_height = FIX2INT(rb_funcall(self, rb_intern("height"), 0));
136
+
137
+ VALUE blob = rb_str_new(NULL, 4 * width * height);
138
+
139
+ rb_funcall(self, rb_intern("flush"), 0);
140
+ glFinish();
141
+
142
+ glReadPixels(x, y, width, window_height - y, GL_RGBA,
143
+ GL_UNSIGNED_BYTE, RSTRING_PTR(blob));
144
+
145
+ return blob;
146
+ }
147
+
148
+ static VALUE
149
+ gosu_window_to_texture(VALUE self, VALUE rb_tex_name, VALUE rb_xoffset, VALUE rb_yoffset,
150
+ VALUE rb_x, VALUE rb_y, VALUE rb_width, VALUE rb_height)
151
+ {
152
+
153
+ int tex_name = FIX2INT(rb_tex_name);
154
+ int xoffset = FIX2INT(rb_xoffset);
155
+ int yoffset = FIX2INT(rb_yoffset);
156
+ int x = FIX2INT(rb_x);
157
+ int y = FIX2INT(rb_y);
158
+ int width = FIX2INT(rb_width);
159
+ int height = FIX2INT(rb_height);
160
+
161
+ rb_funcall(self, rb_intern("flush"), 0);
162
+ glFinish();
163
+
164
+ glEnable(GL_TEXTURE_2D);
165
+ glBindTexture(GL_TEXTURE_2D, tex_name);
166
+
167
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, x, y, width, height);
168
+ glDisable(GL_TEXTURE_2D);
169
+
170
+ return Qnil;
171
+ }
172
+
173
+
174
+ static void
175
+ monkey_patch_gosu(void)
176
+ {
177
+ rb_define_method(gosu_window(), "to_blob", gosu_window_to_blob, 4);
178
+ rb_define_method(gosu_window(), "to_texture", gosu_window_to_texture, 7);
179
+ }
180
+
181
+ static VALUE
182
+ gosu_window(void)
183
+ {
184
+ static VALUE GosuWindow = 0;
185
+
186
+ if (!GosuWindow) {
187
+ VALUE Gosu = rb_const_get(rb_cObject, rb_intern("Gosu"));
188
+ GosuWindow = rb_const_get(Gosu, rb_intern("Window"));
189
+ }
190
+
191
+ return GosuWindow;
192
+ }
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+
201
+
@@ -0,0 +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
@@ -0,0 +1,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 <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
+ }