texplay 0.2.1-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/CHANGELOG +68 -0
  2. data/README +21 -0
  3. data/README1st +9 -0
  4. data/Rakefile +85 -0
  5. data/examples/basic.rb +48 -0
  6. data/examples/basic2.rb +37 -0
  7. data/examples/benchmark.rb +299 -0
  8. data/examples/common.rb +8 -0
  9. data/examples/example_alpha_blend.rb +31 -0
  10. data/examples/example_bezier.rb +51 -0
  11. data/examples/example_color_control.rb +68 -0
  12. data/examples/example_color_transform.rb +29 -0
  13. data/examples/example_dup.rb +52 -0
  14. data/examples/example_each.rb +42 -0
  15. data/examples/example_effect.rb +35 -0
  16. data/examples/example_fill.rb +49 -0
  17. data/examples/example_fill_old.rb +49 -0
  18. data/examples/example_fluent.rb +31 -0
  19. data/examples/example_gen_eval.rb +34 -0
  20. data/examples/example_hash_arguments.rb +47 -0
  21. data/examples/example_melt.rb +27 -0
  22. data/examples/example_polyline.rb +43 -0
  23. data/examples/example_simple.rb +35 -0
  24. data/examples/example_sync.rb +60 -0
  25. data/examples/example_turtle.rb +40 -0
  26. data/examples/media/empty2.png +0 -0
  27. data/examples/media/gosu.png +0 -0
  28. data/examples/media/maria.png +0 -0
  29. data/examples/media/rose.bmp +0 -0
  30. data/examples/media/sand1.png +0 -0
  31. data/examples/media/sunset.png +0 -0
  32. data/examples/media/texplay.png +0 -0
  33. data/examples/specs.rb +240 -0
  34. data/examples/test.rb +70 -0
  35. data/examples/test2.rb +72 -0
  36. data/lib/ctexplay.18.so +0 -0
  37. data/lib/ctexplay.19.so +0 -0
  38. data/lib/texplay-contrib.rb +77 -0
  39. data/lib/texplay.rb +134 -0
  40. data/src/Makefile +181 -0
  41. data/src/TAGS +286 -0
  42. data/src/actions.c +1306 -0
  43. data/src/actions.h +52 -0
  44. data/src/actions.obj +0 -0
  45. data/src/bindings.c +1081 -0
  46. data/src/bindings.h +45 -0
  47. data/src/bindings.obj +0 -0
  48. data/src/cache.c +132 -0
  49. data/src/cache.h +24 -0
  50. data/src/cache.obj +0 -0
  51. data/src/compat.h +23 -0
  52. data/src/ctexplay-i386-mswin32.def +2 -0
  53. data/src/ctexplay-i386-mswin32.exp +0 -0
  54. data/src/ctexplay-i386-mswin32.lib +0 -0
  55. data/src/ctexplay-i386-mswin32.pdb +0 -0
  56. data/src/ctexplay.so +0 -0
  57. data/src/extconf.rb +18 -0
  58. data/src/gen_eval.c +209 -0
  59. data/src/gen_eval.h +20 -0
  60. data/src/gen_eval.obj +0 -0
  61. data/src/mkmf.log +18 -0
  62. data/src/object2module.c +171 -0
  63. data/src/object2module.h +11 -0
  64. data/src/object2module.obj +0 -0
  65. data/src/texplay.c +136 -0
  66. data/src/texplay.h +107 -0
  67. data/src/texplay.obj +0 -0
  68. data/src/utils.c +959 -0
  69. data/src/utils.h +143 -0
  70. data/src/utils.obj +0 -0
  71. data/src/vc60.pdb +0 -0
  72. metadata +132 -0
data/src/TAGS ADDED
@@ -0,0 +1,286 @@
1
+
2
+ actions.c,3564
3
+ do_sync(action_struct * cur, texture_info * tex) do_sync34,1286
4
+ line_do_action(int x1, int y1, int x2, int y2, texture_info * tex, VALUE hash_arg,line_do_action44,1509
5
+ #define SIMPLE_FORMAT SIMPLE_FORMAT126,3531
6
+ #define POINT_FORMAT POINT_FORMAT127,3555
7
+ polyline_point(VALUE points, int k, int * x, int * y, int format, int draw_offset_x,polyline_point131,3622
8
+ polyline_do_action(VALUE points, texture_info * tex, VALUE hash_arg,polyline_do_action154,4324
9
+ ngon_do_action(int x, int y, int r, int num_sides, texture_info * tex, VALUE hash_arg,ngon_do_action231,6780
10
+ rect_do_action(int x1, int y1, int x2, int y2, texture_info * tex, VALUE hash_arg,rect_do_action275,8056
11
+ circle_do_action(int x1, int y1, int r, texture_info * tex, VALUE hash_arg,circle_do_action329,9856
12
+ pixel_do_action(int x1, int y1, texture_info * tex, VALUE hash_arg,pixel_do_action403,12271
13
+ typedef struct { int x1, x2, y, dy; } LINESEGMENT;x1417,12704
14
+ typedef struct { int x1, x2, y, dy; } LINESEGMENT;x2417,12704
15
+ typedef struct { int x1, x2, y, dy; } LINESEGMENT;y417,12704
16
+ typedef struct { int x1, x2, y, dy; } LINESEGMENT;dy417,12704
17
+ typedef struct { int x1, x2, y, dy; } LINESEGMENT;LINESEGMENT417,12704
18
+ #define MAXDEPTH MAXDEPTH419,12756
19
+ #define PUSH(PUSH421,12780
20
+ #define POP(POP425,12997
21
+ flood_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg,flood_fill_do_action429,13142
22
+ glow_floodFill( int x, int y, rgba * seed_color, action_struct * cur, texture_info * tex, texture_info * tex2 )glow_floodFill498,15194
23
+ glow_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg,glow_fill_do_action552,17088
24
+ #define stackSize stackSize586,18167
25
+ int stack[stackSize];stack587,18194
26
+ int stackPointer;stackPointer588,18216
27
+ pop(int * x, int * y, int h) pop591,18247
28
+ push(int x, int y, int h) push608,18559
29
+ emptyStack() emptyStack623,18834
30
+ scan_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg,scan_fill_do_action630,18902
31
+ bezier_point(VALUE points, float u, float * x, float * y, int n, int format,bezier_point700,21601
32
+ bezier_do_action(VALUE points, texture_info * tex, VALUE hash_arg, sync sync_mode,bezier_do_action731,22561
33
+ set_color_array(VALUE ary, rgba * color)set_color_array831,25683
34
+ each_pixel_do_action(int x1, int y1, int x2, int y2, VALUE proc, texture_info * tex, VALUE hash_arg,each_pixel_do_action840,25963
35
+ splice_do_action(int x0, int y0, int cx1, int cy1, int cx2, int cy2, texture_info * splice_tex,splice_do_action869,26797
36
+ process_common_hash_args(action_struct * cur, VALUE * hash_arg, sync sync_mode, bool primary)process_common_hash_args940,29218
37
+ update_lazy_bounds(action_struct * cur, texture_info * tex)update_lazy_bounds1021,32185
38
+ update_bounds(action_struct * cur, int xmin, int ymin, int xmax, int ymax)update_bounds1044,33016
39
+ set_local_bounds(action_struct * cur, int xmin, int ymin, int xmax, int ymax, texture_info * tex)set_local_bounds1056,33341
40
+ draw_prologue(action_struct * cur, texture_info * tex, int xmin, int ymin, int xmax, int ymax,draw_prologue1072,33773
41
+ draw_epilogue(action_struct * cur, texture_info * tex, bool primary)draw_epilogue1089,34284
42
+ prepare_color_control(action_struct * cur)prepare_color_control1119,34991
43
+ exec_color_control_proc(action_struct * cur, texture_info * tex, int x, int y)exec_color_control_proc1135,35475
44
+ prepare_fill_texture(action_struct * payload)prepare_fill_texture1179,37313
45
+ set_pixel_color_with_style(action_struct * payload, texture_info * tex, int x, int y)set_pixel_color_with_style1195,37707
46
+
47
+ actions.h,45
48
+ #define GUARD_ACTIONS_HGUARD_ACTIONS_H2,24
49
+
50
+ bindings.c,2070
51
+ sync sync_mode = eager_sync;sync_mode31,585
52
+ process_x_y_pairs(VALUE image, int num_pairs, VALUE * argv, ...)process_x_y_pairs34,627
53
+ M_create_macro(VALUE self, VALUE method_name) M_create_macro78,1755
54
+ M_remove_macro(VALUE self, VALUE method_name) M_remove_macro96,2138
55
+ M_refresh_cache_all(VALUE self) M_refresh_cache_all107,2385
56
+ M_create_blank(VALUE self, VALUE window, VALUE width, VALUE height)M_create_blank116,2500
57
+ rb_lazy_bounds_to_image_bounds(VALUE image, image_bounds * bounds)rb_lazy_bounds_to_image_bounds128,2767
58
+ parse_sync_mode(VALUE user_sync_mode)parse_sync_mode143,3223
59
+ m_paint(int argc, VALUE * argv, VALUE self) m_paint166,3853
60
+ m_force_sync(VALUE self, VALUE ary)m_force_sync239,5754
61
+ m_dup_image(VALUE self)m_dup_image261,6219
62
+ m_clone_image(VALUE self)m_clone_image290,7033
63
+ m_user_set_options(VALUE self, VALUE options)m_user_set_options305,7329
64
+ m_user_delete_options(VALUE self)m_user_delete_options318,7587
65
+ m_get_options(VALUE self)m_get_options329,7723
66
+ m_getpixel(int argc, VALUE * argv, VALUE self) m_getpixel338,7882
67
+ m_circle(int argc, VALUE * argv, VALUE self) m_circle363,8384
68
+ m_ngon(int argc, VALUE * argv, VALUE self)m_ngon392,8958
69
+ m_flood_fill(int argc, VALUE * argv, VALUE self)m_flood_fill420,9519
70
+ m_line(int argc, VALUE * argv, VALUE self) m_line463,10488
71
+ m_rect(int argc, VALUE * argv, VALUE self) m_rect487,10973
72
+ m_pixel(int argc, VALUE * argv, VALUE self) m_pixel513,11463
73
+ m_bezier(int argc, VALUE * argv, VALUE self)m_bezier537,11925
74
+ m_polyline(int argc, VALUE * argv, VALUE self)m_polyline563,12455
75
+ m_splice(int argc, VALUE * argv, VALUE self) m_splice591,12982
76
+ m_clear(int argc, VALUE * argv, VALUE self) m_clear638,14314
77
+ m_offset(int argc, VALUE * argv, VALUE self) m_offset654,14599
78
+ m_color(int argc, VALUE * argv, VALUE self) m_color688,15349
79
+ m_missing(int argc, VALUE * argv, VALUE self) m_missing718,16182
80
+ m_cache_refresh(VALUE self) m_cache_refresh736,16672
81
+ m_quad_cached(VALUE self) m_quad_cached751,16895
82
+ m_each(int argc, VALUE * argv, VALUE self)m_each777,17450
83
+
84
+ bindings.h,47
85
+ #define GUARD_BINDINGS_HGUARD_BINDINGS_H2,25
86
+
87
+ cache.c,338
88
+ static cache_t cache = {0}; cache16,219
89
+ cache_create_entry(int tname) {cache_create_entry20,293
90
+ find_in_cache(int tname) {find_in_cache59,1556
91
+ find_or_create_cache_entry(int tname) {find_or_create_cache_entry73,1908
92
+ cache_refresh_all(void) {cache_refresh_all84,2130
93
+ cache_refresh_entry(int tname) {cache_refresh_entry109,2794
94
+
95
+ cache.h,350
96
+ #define GUARD_CACHE_HGUARD_CACHE_H5,71
97
+ #define CACHE_SIZE CACHE_SIZE8,108
98
+ int tname;tname12,167
99
+ int sidelength;sidelength13,182
100
+ float * tdata;tdata14,202
101
+ } cache_entry;cache_entry15,221
102
+ int len;len18,254
103
+ cache_entry entry[CACHE_SIZE]; entry19,267
104
+ } cache_t;cache_t20,344
105
+
106
+ compat.h,241
107
+ #define GUARD_COMPAT_HGUARD_COMPAT_H4,102
108
+ # define RUBY_19RUBY_1910,218
109
+ # define RCLASS_M_TBL(RCLASS_M_TBL15,309
110
+ # define RCLASS_SUPER(RCLASS_SUPER16,353
111
+ # define RCLASS_IV_TBL(RCLASS_IV_TBL17,397
112
+ #define KLASS_OF(KLASS_OF21,534
113
+
114
+ gen_eval.c,444
115
+ retrieve_hidden_self(VALUE duped_context)retrieve_hidden_self11,247
116
+ set_hidden_self(VALUE duped_context, VALUE hidden_self)set_hidden_self25,652
117
+ rb_capture(VALUE self) {rb_capture38,1103
118
+ redirect_iv_for_object(VALUE obj, VALUE dest)redirect_iv_for_object59,1553
119
+ release_iv_for_object(VALUE obj)release_iv_for_object79,2305
120
+ rb_gen_eval(int argc, VALUE * argv, VALUE self) {rb_gen_eval93,2658
121
+ Init_gen_eval() {Init_gen_eval185,5307
122
+
123
+ gen_eval.h,87
124
+ #define GUARD_GEN_EVAL_HGUARD_GEN_EVAL_H4,43
125
+ #define ADJUST_SELF(ADJUST_SELF14,345
126
+
127
+ object2module.c,410
128
+ class_alloc(VALUE flags, VALUE klass)class_alloc18,359
129
+ j_class_new(VALUE module, VALUE sup)j_class_new34,752
130
+ rb_to_module(VALUE self)rb_to_module81,1735
131
+ rb_reset_tbls(VALUE self)rb_reset_tbls115,2493
132
+ rb_gen_extend(int argc, VALUE * argv, VALUE self)rb_gen_extend124,2738
133
+ rb_gen_include(int argc, VALUE * argv, VALUE self)rb_gen_include145,3259
134
+ void Init_object2module()Init_object2module163,3696
135
+
136
+ object2module.h,57
137
+ #define GUARD_OBJECT2MODULE_HGUARD_OBJECT2MODULE_H4,53
138
+
139
+ texplay.c,410
140
+ Init_ctexplay() {Init_ctexplay29,843
141
+ m_init_TPPoint(int argc, VALUE * argv, VALUE self)m_init_TPPoint133,5456
142
+ m_init_EmptyImageStub(int argc, VALUE * argv, VALUE self)m_init_EmptyImageStub157,6066
143
+ m_EmptyImageStub_columns(VALUE self)m_EmptyImageStub_columns176,6583
144
+ m_EmptyImageStub_rows(VALUE self)m_EmptyImageStub_rows182,6672
145
+ m_EmptyImageStub_to_blob(VALUE self)m_EmptyImageStub_to_blob188,6758
146
+
147
+ texplay.h,2622
148
+ #define GUARD_TEXPLAY_HGUARD_TEXPLAY_H8,201
149
+ #define OOB_VAL OOB_VAL13,260
150
+ #define XMAX_OOB XMAX_OOB14,281
151
+ #define YMAX_OOB YMAX_OOB15,306
152
+ #define XMIN_OOB XMIN_OOB16,331
153
+ #define YMIN_OOB YMIN_OOB17,357
154
+ #define PI PI19,384
155
+ #define SWAP(SWAP22,426
156
+ #define ROUND(ROUND23,485
157
+ #define ARY_SIZE(ARY_SIZE24,519
158
+ #define SGN(SGN25,562
159
+ #define MAX(MAX26,597
160
+ #define MIN(MIN27,638
161
+ #define ABS(ABS28,680
162
+ typedef enum e_bool {e_bool31,732
163
+ false, truefalse32,754
164
+ false, truetrue32,754
165
+ } bool;bool33,770
166
+ typedef enum e_color {e_color35,779
167
+ red, green, blue, alphared36,802
168
+ red, green, blue, alphagreen36,802
169
+ red, green, blue, alphablue36,802
170
+ red, green, blue, alphaalpha36,802
171
+ } color_t;color_t37,830
172
+ typedef enum e_sync_mode {e_sync_mode39,842
173
+ lazy_sync, eager_sync, no_synclazy_sync40,869
174
+ lazy_sync, eager_sync, no_synceager_sync40,869
175
+ lazy_sync, eager_sync, no_syncno_sync40,869
176
+ } sync;sync41,904
177
+ typedef struct s_rgba {s_rgba44,927
178
+ float red, green, blue, alpha;red45,951
179
+ float red, green, blue, alpha;green45,951
180
+ float red, green, blue, alpha;blue45,951
181
+ float red, green, blue, alpha;alpha45,951
182
+ } rgba;rgba46,986
183
+ int width, height; width50,1036
184
+ int width, height; height50,1036
185
+ float top, left; top51,1063
186
+ float top, left; left51,1063
187
+ int tname;tname52,1088
188
+ float * td_array;td_array53,1103
189
+ int yincr, firstpixel;yincr54,1125
190
+ int yincr, firstpixel;firstpixel54,1125
191
+ int x_offset, y_offset;x_offset55,1152
192
+ int x_offset, y_offset;y_offset55,1152
193
+ VALUE image;image56,1180
194
+ } texture_info;texture_info57,1197
195
+ #define IMAGE_BOUNDS(IMAGE_BOUNDS61,1239
196
+ int xmin;xmin63,1303
197
+ int ymin;ymin64,1317
198
+ int xmax;xmax65,1331
199
+ int ymax;ymax66,1345
200
+ } image_bounds;image_bounds67,1359
201
+ typedef struct action_struct {action_struct69,1376
202
+ int xmin, ymin, xmax, ymax;xmin70,1407
203
+ int xmin, ymin, xmax, ymax;ymin70,1407
204
+ int xmin, ymin, xmax, ymax;xmax70,1407
205
+ int xmin, ymin, xmax, ymax;ymax70,1407
206
+ rgba color;color71,1439
207
+ sync sync_mode;sync_mode72,1455
208
+ VALUE color_control_proc;color_control_proc75,1504
209
+ bool has_color_control_proc;has_color_control_proc76,1534
210
+ int color_control_arity;color_control_arity77,1567
211
+ texture_info source_tex;source_tex80,1620
212
+ bool has_source_texture;has_source_texture81,1649
213
+ bool alpha_blend;alpha_blend84,1701
214
+ texture_info * tex;tex89,1880
215
+ VALUE hash_arg;hash_arg91,1909
216
+ } action_struct;action_struct92,1929
217
+
218
+ utils.c,4100
219
+ static const rgba not_a_color_v = { -1.0, -1.0, -1.0, -1.0 };not_a_color_v36,974
220
+ lowercase(char * string) lowercase40,1067
221
+ sym2string(VALUE sym) sym2string53,1228
222
+ string2sym(char * string) string2sym59,1298
223
+ is_a_hash(VALUE try_hash)is_a_hash65,1373
224
+ is_an_array(VALUE try_array)is_an_array71,1446
225
+ bool is_a_num(VALUE try_num)is_a_num76,1519
226
+ get_from_hash(VALUE hash, char * sym) get_from_hash82,1625
227
+ set_hash_value(VALUE hash, char * sym, VALUE val)set_hash_value91,1808
228
+ delete_from_hash(VALUE hash, char * sym)delete_from_hash101,2016
229
+ hash_value_is(VALUE hash, char * sym, VALUE val)hash_value_is111,2295
230
+ has_optional_hash_arg(VALUE hash, char * sym) has_optional_hash_arg122,2482
231
+ set_array_value(VALUE array, int index, VALUE val)set_array_value134,2710
232
+ get_from_array(VALUE array, int index) get_from_array144,2913
233
+ init_image_local(VALUE image)init_image_local154,3092
234
+ set_image_local(VALUE image, int name, VALUE val)set_image_local173,3553
235
+ get_image_local(VALUE image, int name)get_image_local183,3731
236
+ convert_image_local_color_to_rgba(VALUE image)convert_image_local_color_to_rgba252,5880
237
+ save_rgba_to_image_local_color(VALUE image, rgba color)save_rgba_to_image_local_color266,6319
238
+ create_image(VALUE window, int width, int height)create_image283,6877
239
+ not_a_color(rgba color1) not_a_color303,7451
240
+ is_a_color(rgba color1)is_a_color309,7516
241
+ cmp_color(rgba color1, rgba color2) cmp_color315,7583
242
+ color_copy(float * source, float * dest) color_copy323,7778
243
+ zero_color(float * tex) zero_color330,7908
244
+ get_pixel_color_from_chunk(float * chunk, int width, int height, int x, int y)get_pixel_color_from_chunk336,7982
245
+ get_pixel_color(texture_info * tex, int x, int y) get_pixel_color357,8429
246
+ get_pixel_data(texture_info * tex, int x, int y) get_pixel_data379,9024
247
+ set_pixel_color(rgba * pixel_color, texture_info * tex, int x, int y) set_pixel_color388,9204
248
+ find_color_from_string(char * try_color) find_color_from_string410,9769
249
+ convert_rgba_to_rb_color(rgba * pix)convert_rgba_to_rb_color471,12271
250
+ convert_rb_color_to_rgba(VALUE cval)convert_rb_color_to_rgba487,12747
251
+ check_mask(VALUE mask) check_mask530,13964
252
+ check_image(VALUE image) check_image548,14470
253
+ is_gosu_image(VALUE try_image)is_gosu_image555,14634
254
+ #define outcode outcode565,14808
255
+ const int RIGHT = 8; //1000RIGHT566,14828
256
+ const int TOP = 4; //0100TOP567,14857
257
+ const int LEFT = 2; //0010LEFT568,14886
258
+ const int BOTTOM = 1; //0001BOTTOM569,14915
259
+ ComputeOutCode (int x, int y, int xmin, int ymin, int xmax, int ymax)ComputeOutCode574,15083
260
+ cohen_sutherland_clip (int * x0, int * y0,int * x1, int * y1, int xmin, int ymin,cohen_sutherland_clip592,15643
261
+ constrain_boundaries(int * x0, int * y0, int * x1, int * y1, int width, int height) constrain_boundaries669,18664
262
+ bound_by_rect_and_inner(int x, int y, int x0, int y0, int x1, int y1, int inner) bound_by_rect_and_inner692,19249
263
+ bound_by_rect(int x, int y, int x0, int y0, int x1, int y1) bound_by_rect701,19577
264
+ calc_pixel_offset_for_action(action_struct * cur, texture_info * tex, int x, int y) calc_pixel_offset_for_action708,19783
265
+ calc_pixel_offset(texture_info * tex, int x, int y) calc_pixel_offset717,20019
266
+ max_quad_size(void)max_quad_size726,20217
267
+ check_for_texture_info(VALUE image) check_for_texture_info751,20843
268
+ allocate_texture(int width, int height)allocate_texture772,21587
269
+ sync_to_gl(int tex_name, int x_offset, int y_offset, int width, int height, void * sub)sync_to_gl787,21894
270
+ create_subtexture_and_sync_to_gl(image_bounds * img_bounds, texture_info * tex)create_subtexture_and_sync_to_gl799,22251
271
+ get_image_chunk(texture_info * tex, int xmin, int ymin, int xmax, int ymax)get_image_chunk823,23096
272
+ get_texture_info(VALUE image, texture_info * tex) get_texture_info852,23802
273
+ is_a_point(VALUE try_point)is_a_point897,25165
274
+ point_x(VALUE point)point_x907,25380
275
+ point_y(VALUE point)point_y913,25461
276
+ power(float base, int exp)power920,25598
277
+ fact(int n)fact940,25926
278
+ comb(int n, int k)comb948,26031
279
+ bernstein(int n, int k, float u)bernstein955,26132
280
+
281
+ utils.h,201
282
+ #define GUARD_UTILS_HGUARD_UTILS_H2,22
283
+ #define DRAW_OFFSET DRAW_OFFSET6,102
284
+ #define LAZY_BOUNDS LAZY_BOUNDS7,124
285
+ #define IMAGE_COLOR IMAGE_COLOR8,146
286
+ #define USER_DEFAULTS USER_DEFAULTS9,168
data/src/actions.c ADDED
@@ -0,0 +1,1306 @@
1
+ #include "texplay.h"
2
+ #include "utils.h"
3
+ #include "actions.h"
4
+ #include <assert.h>
5
+ #include <math.h>
6
+ #ifdef __APPLE__
7
+ # include <glut.h>
8
+ #else
9
+ # include <GL/glut.h>
10
+ #endif
11
+
12
+
13
+ /* small helper functions */
14
+ static void process_common_hash_args(action_struct * cur, VALUE * hash_arg, sync sync_mode, bool primary);
15
+ static void update_bounds(action_struct * cur, int xmin, int ymin, int xmax, int ymax);
16
+ static void update_lazy_bounds(action_struct * cur, texture_info * tex);
17
+ static void set_local_bounds(action_struct * cur, int xmin, int ymin, int xmax, int ymax, texture_info * tex);
18
+
19
+ static void draw_prologue(action_struct * cur, texture_info * tex,
20
+ int xmin, int ymin, int xmax, int ymax, VALUE * hash_arg, sync sync_mode,
21
+ bool primary, action_struct ** payload_ptr);
22
+ static void draw_epilogue(action_struct * cur, texture_info * tex, bool primary);
23
+
24
+ static void prepare_fill_texture(action_struct * cur);
25
+ static void prepare_color_control(action_struct * cur);
26
+ static rgba exec_color_control_proc(action_struct * cur, texture_info * tex, int x, int y);
27
+ static void set_pixel_color_with_style(action_struct * payload, texture_info * tex,
28
+ int x, int y);
29
+ /* end helpers */
30
+
31
+
32
+ /** line_do_action, bresenham's algorithm **/
33
+ void
34
+ line_do_action(int x1, int y1, int x2, int y2, texture_info * tex, VALUE hash_arg,
35
+ sync sync_mode, bool primary, action_struct * payload)
36
+ {
37
+ int x, y, W, H, F;
38
+ int xinc, yinc;
39
+ action_struct cur;
40
+ int thickness = 1;
41
+
42
+ draw_prologue(&cur, tex, x1, y1,
43
+ x2, y2, &hash_arg, sync_mode, primary, &payload);
44
+
45
+ if(has_optional_hash_arg(hash_arg, "thickness"))
46
+ thickness = NUM2INT(get_from_hash(hash_arg, "thickness"));
47
+
48
+ /* clip the line */
49
+ cohen_sutherland_clip(&x1, &y1, &x2, &y2, 0, 0, tex->width - 1, tex->height - 1);
50
+
51
+ W = ABS(x2 - x1);
52
+ H = ABS(y2 - y1);
53
+
54
+ if(x1 < x2)
55
+ xinc = 1;
56
+ else
57
+ xinc = -1;
58
+
59
+ if(y1 < y2)
60
+ yinc = 1;
61
+ else
62
+ yinc = -1;
63
+
64
+ x = x1;
65
+ y = y1;
66
+
67
+ if(W >= H) {
68
+ F = 2 * H - W;
69
+ while(x != x2) {
70
+ if(F < 0)
71
+ F += 2 * H;
72
+ else {
73
+ F += 2 * (H - W);
74
+ y += yinc;
75
+ }
76
+ x += xinc;
77
+
78
+ if(thickness <= 1) {
79
+ set_pixel_color_with_style(payload, tex, x, y);
80
+ }
81
+ else {
82
+ set_hash_value(hash_arg, "fill", Qtrue);
83
+ circle_do_action(x, y, thickness / 2, tex, hash_arg, no_sync, false, payload);
84
+ }
85
+ }
86
+ }
87
+ else {
88
+ F = 2 * W - H;
89
+ while(y != y2 ) {
90
+ if(F < 0)
91
+ F += 2 * W;
92
+ else {
93
+ F += 2 * (W - H);
94
+ x += xinc;
95
+ }
96
+ y += yinc;
97
+
98
+ if(thickness <= 1) {
99
+ set_pixel_color_with_style(payload, tex, x, y);
100
+ }
101
+ else {
102
+ set_hash_value(hash_arg, "fill", Qtrue);
103
+ circle_do_action(x, y, thickness / 2, tex, hash_arg, no_sync, false, payload);
104
+ }
105
+
106
+ }
107
+ }
108
+
109
+ draw_epilogue(&cur, tex, primary);
110
+ }
111
+ /** end line **/
112
+
113
+ /** polyline algorithm **/
114
+
115
+ /* used by both polyline and bezier */
116
+ #define SIMPLE_FORMAT 0
117
+ #define POINT_FORMAT 1
118
+
119
+ /* calculate a single point */
120
+ static void
121
+ polyline_point(VALUE points, int k, int * x, int * y, int format, int draw_offset_x,
122
+ int draw_offset_y)
123
+ {
124
+ int xy_index;
125
+
126
+ switch(format) {
127
+ case POINT_FORMAT:
128
+ *x = NUM2INT(point_x(get_from_array(points, k))) + draw_offset_x;
129
+ *y = NUM2INT(point_y(get_from_array(points, k))) + draw_offset_y;
130
+ break;
131
+
132
+ case SIMPLE_FORMAT:
133
+ xy_index = k * 2;
134
+ *x = NUM2INT(get_from_array(points, xy_index)) + draw_offset_x;
135
+ *y = NUM2INT(get_from_array(points, xy_index + 1)) + draw_offset_y;
136
+
137
+ break;
138
+ default:
139
+ rb_raise(rb_eArgError, "pixel format must be either POINT_FORMAT or SIMPLE_FORMAT");
140
+ }
141
+ }
142
+
143
+ void
144
+ polyline_do_action(VALUE points, texture_info * tex, VALUE hash_arg,
145
+ sync sync_mode, bool primary, action_struct * payload)
146
+ {
147
+ action_struct cur;
148
+ int x1, y1, x2, y2;
149
+ int format;
150
+ int num_point_pairs;
151
+ int k;
152
+ VALUE offset_val;
153
+ int draw_offset_x;
154
+ int draw_offset_y;
155
+ bool closed = false;
156
+
157
+ draw_prologue(&cur, tex, XMAX_OOB, YMAX_OOB, XMIN_OOB, YMIN_OOB, &hash_arg, sync_mode, primary, &payload);
158
+
159
+ /* calculate offset */
160
+ offset_val = get_image_local(tex->image, DRAW_OFFSET);
161
+
162
+ draw_offset_x = NUM2INT(get_from_array(offset_val, 0));
163
+ draw_offset_y = NUM2INT(get_from_array(offset_val, 1));
164
+
165
+ /* if the polyline is 'closed' make the last point the first */
166
+ if(is_a_hash(hash_arg))
167
+ if(RTEST(get_from_hash(hash_arg, "closed")) || RTEST(get_from_hash(hash_arg, "close"))) {
168
+
169
+ /* so that our additional point is not persistent */
170
+ points = rb_obj_dup(points);
171
+ closed = true;
172
+ }
173
+ /* determine format of points */
174
+ if(is_a_point(get_from_array(points, 0))) {
175
+ format = POINT_FORMAT;
176
+
177
+ /* if the polyline is closed to form a polygon then make the last point and first point identical */
178
+ if(closed)
179
+ rb_ary_push(points, get_from_array(points, 0));
180
+
181
+ num_point_pairs = RARRAY_LEN(points);
182
+ }
183
+ else {
184
+ format = SIMPLE_FORMAT;
185
+
186
+ /* ensure there is an 'x' for every 'y' */
187
+ if(RARRAY_LEN(points) % 2)
188
+ rb_raise(rb_eArgError, "polyline needs an even number of points. got %d\n",
189
+ (int)RARRAY_LEN(points));
190
+
191
+ if(closed) {
192
+ rb_ary_push(points, get_from_array(points, 0));
193
+ rb_ary_push(points, get_from_array(points, 1));
194
+ }
195
+
196
+ num_point_pairs = RARRAY_LEN(points) / 2;
197
+ }
198
+
199
+ /* calculate first point */
200
+ polyline_point(points, 0, &x1, &y1, format, draw_offset_x, draw_offset_y);
201
+
202
+ /* calc the points and draw the polyline */
203
+ for(k = 1; k < num_point_pairs; k++) {
204
+
205
+ polyline_point(points, k, &x2, &y2, format, draw_offset_x, draw_offset_y);
206
+
207
+ line_do_action(x1, y1, x2, y2, tex, hash_arg, no_sync, false, payload);
208
+
209
+ /* update drawing rectangle */
210
+ update_bounds(payload, x1, y1, x2, y2);
211
+
212
+ x1 = x2; y1 = y2;
213
+ }
214
+
215
+ draw_epilogue(&cur, tex, primary);
216
+ }
217
+ /** end polyline **/
218
+
219
+ /* regular polygon algorithm */
220
+ void
221
+ ngon_do_action(int x, int y, int r, int num_sides, texture_info * tex, VALUE hash_arg,
222
+ sync sync_mode, bool primary, action_struct * payload)
223
+ {
224
+ action_struct cur;
225
+ int x1, y1, x2, y2, x0, y0;
226
+ int n;
227
+ int thickness;
228
+
229
+ draw_prologue(&cur, tex, x - r, y - r,
230
+ x + r, y + r, &hash_arg, sync_mode, primary, &payload);
231
+
232
+
233
+ if(is_a_hash(hash_arg))
234
+ if(RTEST(get_from_hash(hash_arg, "thickness"))) {
235
+ thickness = NUM2INT(get_from_hash(hash_arg, "thickness"));
236
+
237
+ /* TO DO: find a better way of doing this */
238
+ cur.xmin = x - r - thickness / 2;
239
+ cur.ymin = y - r - thickness / 2;
240
+ cur.xmax = x + r + thickness / 2;
241
+ cur.ymax = y + r + thickness / 2;
242
+ }
243
+
244
+ /* calculate first point */
245
+ x0 = x1 = x + r;
246
+ y0 = y1 = y;
247
+
248
+ for(n = 0; n < num_sides; n++) {
249
+ x2 = x + r * cos((2 * PI / num_sides) * n);
250
+ y2 = y + r * sin((2 * PI / num_sides) * n);
251
+
252
+ line_do_action(x1, y1, x2, y2, tex, hash_arg, no_sync, false, payload);
253
+
254
+ x1 = x2; y1 = y2;
255
+ }
256
+
257
+ line_do_action(x0, y0, x1, y1, tex, hash_arg, no_sync, false, payload);
258
+
259
+ draw_epilogue(&cur, tex, primary);
260
+ }
261
+ /** end of ngon */
262
+
263
+ /** rectangle algorithm **/
264
+ void
265
+ rect_do_action(int x1, int y1, int x2, int y2, texture_info * tex, VALUE hash_arg,
266
+ sync sync_mode, bool primary, action_struct * payload)
267
+ {
268
+ action_struct cur;
269
+ bool fill = false;
270
+ int thickness = 1;
271
+
272
+ draw_prologue(&cur, tex, x1, y1,
273
+ x2, y2, &hash_arg, sync_mode, primary, &payload);
274
+
275
+
276
+ if(is_a_hash(hash_arg)) {
277
+
278
+ /* make our private copy of the hash so we can mess with it */
279
+ hash_arg = rb_obj_dup(hash_arg);
280
+
281
+ if(RTEST(get_from_hash(hash_arg, "fill")) || RTEST(get_from_hash(hash_arg, "filled"))) {
282
+ fill = true;
283
+
284
+ /* since we're filling the rect, line thickness is irrelevant */
285
+ delete_from_hash(hash_arg, "thickness");
286
+ }
287
+ else if(RTEST(get_from_hash(hash_arg, "thickness"))) {
288
+ thickness = NUM2INT(get_from_hash(hash_arg, "thickness"));
289
+ /* TO DO: find a better way of doing this */
290
+
291
+ if(thickness > 1) {
292
+ cur.xmin = x1 - thickness / 2;
293
+ cur.ymin = y1 - thickness / 2;
294
+ cur.xmax = x2 + thickness / 2 + 1;
295
+ cur.ymax = y2 + thickness / 2 + 1;
296
+ }
297
+ }
298
+ }
299
+ if(!fill) {
300
+ line_do_action(x1, y1, x2, y1, tex, hash_arg, no_sync, false, payload);
301
+ line_do_action(x1, y1, x1, y2, tex, hash_arg, no_sync, false, payload);
302
+ line_do_action(x1, y2, x2, y2, tex, hash_arg, no_sync, false, payload);
303
+ line_do_action(x2, y1, x2, y2, tex, hash_arg, no_sync, false, payload);
304
+ }
305
+ else {
306
+ int y;
307
+ if(y1 > y2) SWAP(y1, y2);
308
+
309
+ for(y = y1; y < y2; y++)
310
+ line_do_action(x1, y, x2, y, tex, hash_arg, no_sync, false, payload);
311
+ }
312
+
313
+ draw_epilogue(&cur, tex, primary);
314
+ }
315
+
316
+
317
+ /** midpoint circle algorithm **/
318
+ void
319
+ circle_do_action(int x1, int y1, int r, texture_info * tex, VALUE hash_arg,
320
+ sync sync_mode, bool primary, action_struct * payload)
321
+ {
322
+
323
+ int x, y;
324
+ float p;
325
+ action_struct cur;
326
+ bool fill = false;
327
+
328
+ draw_prologue(&cur, tex, x1 - r, y1 - r, x1 + r, y1 + r, &hash_arg,
329
+ sync_mode, primary, &payload);
330
+
331
+
332
+ if(is_a_hash(hash_arg)) {
333
+
334
+ /* make our private copy of the hash so we can mess with it */
335
+ hash_arg = rb_obj_dup(hash_arg);
336
+
337
+ if(RTEST(get_from_hash(hash_arg, "fill")) || RTEST(get_from_hash(hash_arg, "filled"))) {
338
+ fill = true;
339
+
340
+ /* to prevent infinite recursion set line thickness to 1 :D
341
+ NB: a filled circle uses lines and a thick line uses filled circles :D */
342
+ delete_from_hash(hash_arg, "thickness");
343
+ }
344
+ }
345
+
346
+ x = 0 ; y = r;
347
+ p = 5 / 4 - r;
348
+ if(!fill) {
349
+ while (x <= y) {
350
+ set_pixel_color_with_style(payload, tex, x1 + x, y1 + y);
351
+ set_pixel_color_with_style(payload, tex, x1 + x, y1 - y);
352
+ set_pixel_color_with_style(payload, tex, x1 - x, y1 + y);
353
+ set_pixel_color_with_style(payload, tex, x1 - x, y1 - y);
354
+ set_pixel_color_with_style(payload, tex, x1 + y, y1 + x);
355
+ set_pixel_color_with_style(payload, tex, x1 + y, y1 - x);
356
+ set_pixel_color_with_style(payload, tex, x1 - y, y1 + x);
357
+ set_pixel_color_with_style(payload, tex, x1 - y, y1 - x);
358
+
359
+ if (p < 0) {
360
+ p += 2 * x + 3;
361
+ }
362
+ else {
363
+ y--;
364
+ p += 2 * (x - y) + 5;
365
+ }
366
+ x++;
367
+ }
368
+ }
369
+ else {
370
+ while (x <= y) {
371
+ line_do_action(x1 - x, y1 + y, x1 + x, y1 + y, tex, hash_arg, no_sync, false, payload);
372
+ line_do_action(x1 - x, y1 - y, x1 + x, y1 - y, tex, hash_arg, no_sync, false, payload);
373
+ line_do_action(x1 - y, y1 + x, x1 + y, y1 + x, tex, hash_arg, no_sync, false, payload);
374
+ line_do_action(x1 - y, y1 - x, x1 + y, y1 - x, tex, hash_arg, no_sync, false, payload);
375
+
376
+ if (p < 0) {
377
+ p += 2 * x + 3;
378
+ }
379
+ else {
380
+ y--;
381
+ p += 2 * (x - y) + 5;
382
+ }
383
+ x++;
384
+ }
385
+ }
386
+
387
+ draw_epilogue(&cur, tex, primary);
388
+ }
389
+ /** end circle **/
390
+
391
+ /** set pixel algorithm **/
392
+ void
393
+ pixel_do_action(int x1, int y1, texture_info * tex, VALUE hash_arg,
394
+ sync sync_mode, bool primary, action_struct * payload)
395
+ {
396
+ action_struct cur;
397
+
398
+ draw_prologue(&cur, tex, x1, y1, x1, y1, &hash_arg, sync_mode, primary, &payload);
399
+
400
+ set_pixel_color_with_style(payload, tex, x1, y1);
401
+
402
+ draw_epilogue(&cur, tex, primary);
403
+ }
404
+ /** end set pixel **/
405
+
406
+ /*** non recursive FLOOD FILL, inspired by John R. Shaw ***/
407
+ typedef struct { int x1, x2, y, dy; } LINESEGMENT;
408
+
409
+ #define MAXDEPTH 10000
410
+
411
+ #define PUSH(XL, XR, Y, DY) \
412
+ if( sp < stack+MAXDEPTH && Y+(DY) >= nMinX && Y+(DY) <= nMaxY ) \
413
+ { sp->x1 = XL; sp->x2 = XR; sp->y = Y; sp->dy = DY; ++sp; }
414
+
415
+ #define POP(XL, XR, Y, DY) \
416
+ { --sp; XL = sp->x1; XR = sp->x2; Y = sp->y+(DY = sp->dy); }
417
+
418
+ void
419
+ flood_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg,
420
+ sync sync_mode, bool primary, action_struct * payload)
421
+ {
422
+ int left, x1, x2, dy;
423
+ rgba old_color;
424
+ LINESEGMENT stack[MAXDEPTH], *sp = stack;
425
+
426
+ action_struct cur;
427
+
428
+ int nMinX, nMinY, nMaxX, nMaxY;
429
+
430
+ /* NOTE: 1024 is just a place-holder to indicate maximum possible width/height.
431
+ Values will be constrained to realistic dimensions by constrain_boundaries() function */
432
+ draw_prologue(&cur, tex, 0, 0, 1024, 1024, &hash_arg, sync_mode, primary, &payload);
433
+
434
+ /* fill hates alpha_blend so let's turn it off */
435
+ payload->pen.alpha_blend = false;
436
+
437
+ nMinX = cur.xmin; nMinY = cur.ymin;
438
+ nMaxX = cur.xmax; nMaxY = cur.ymax;
439
+
440
+ old_color = get_pixel_color(tex, x, y);
441
+ if( cmp_color(old_color, cur.color) )
442
+ return;
443
+
444
+ if( x < nMinX || x > nMaxX || y < nMinX || y > nMaxY )
445
+ return;
446
+
447
+ PUSH(x, x, y, 1); /* needed in some cases */
448
+ PUSH(x, x, y + 1, -1); /* seed segment (popped 1st) */
449
+
450
+ while( sp > stack ) {
451
+ POP(x1, x2, y, dy);
452
+
453
+ for( x = x1; x >= nMinX && cmp_color(get_pixel_color(tex, x, y), old_color); --x ) {
454
+ set_pixel_color_with_style(payload, tex, x, y);
455
+ }
456
+
457
+ if( x >= x1 )
458
+ goto SKIP;
459
+
460
+ left = x + 1;
461
+ if( left < x1 )
462
+ PUSH(y, left, x1 - 1, -dy); /* leak on left? */
463
+
464
+ x = x1 + 1;
465
+
466
+ do {
467
+ for( ; x <= nMaxX && cmp_color(get_pixel_color(tex, x, y), old_color); ++x ){
468
+ set_pixel_color_with_style(payload, tex, x, y);
469
+ }
470
+
471
+ PUSH(left, x - 1, y, dy);
472
+
473
+ if( x > x2 + 1 )
474
+ PUSH(x2 + 1, x - 1, y, -dy); /* leak on right? */
475
+
476
+ SKIP: for( ++x; x <= x2 && !cmp_color(get_pixel_color(tex, x, y), old_color); ++x ) {;}
477
+
478
+ left = x;
479
+ } while( x <= x2 );
480
+ }
481
+
482
+ draw_epilogue(&cur, tex, primary);
483
+ }
484
+ /*** END FLOOD FILL ***/
485
+
486
+ /** glow fill algorithm, from the gosu forums **/
487
+ static void
488
+ glow_floodFill( int x, int y, rgba * seed_color, action_struct * cur, texture_info * tex, texture_info * tex2 )
489
+ {
490
+ /* used to flood in both horizontal directions from the given point to form a line. */
491
+ int fillL, fillR;
492
+ int i;
493
+
494
+ /* initialize the flood directions */
495
+ fillL = fillR = x;
496
+
497
+ /* flood left until a new color is hit - or the edge of the image */
498
+ do {
499
+ /* for texture filling */
500
+ if(tex2)
501
+ cur->color = get_pixel_color(tex2, fillL % tex2->width, y % tex2->height);
502
+
503
+ /* TWO VERSIONS of below */
504
+
505
+ /* SLOW BUT MODERN VERSION */
506
+ /* set_pixel_color_with_style(cur, tex, fillL, y); */
507
+
508
+ /* FAST but old version */
509
+ set_pixel_color(&cur->color, tex, fillL, y);
510
+
511
+ fillL--;
512
+ } while( (fillL >= 0 ) && (cmp_color(get_pixel_color(tex, fillL, y), *seed_color)) );
513
+
514
+ /* flood right until a new color is hit - or the edge of the image */
515
+ do {
516
+ // for texture filling
517
+ if(tex2)
518
+ cur->color = get_pixel_color(tex2, fillR % tex2->width, y % tex2->height);
519
+
520
+ /* set_pixel_color_with_style(cur, tex, fillR, y); */
521
+
522
+ set_pixel_color(&cur->color, tex, fillR, y);
523
+
524
+ fillR++;
525
+ } while( (fillR < cur->xmax - 1) && (cmp_color(get_pixel_color(tex, fillR, y), *seed_color)) );
526
+
527
+ /* recurse to the line above and the line below at each point */
528
+ for( i = fillL + 1; i < fillR; i++ ) {
529
+ /* Flood above */
530
+ if( ( y > 0 ) && ( cmp_color(get_pixel_color(tex, i, y - 1), *seed_color) ) ) {
531
+
532
+ glow_floodFill( i, y-1, seed_color, cur, tex, tex2 );
533
+ }
534
+ /* flood below */
535
+ if( (y < cur->ymax - 1) && (cmp_color(get_pixel_color(tex, i, y + 1), *seed_color) )) {
536
+ glow_floodFill( i, y+1, seed_color, cur, tex, tex2 );
537
+ }
538
+ }
539
+ }
540
+
541
+ void
542
+ glow_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg,
543
+ sync sync_mode, bool primary, action_struct * payload)
544
+ {
545
+ action_struct cur;
546
+ rgba seed_color;
547
+ texture_info fill_image;
548
+ texture_info * fill_image_ptr = NULL;
549
+
550
+ if(!bound_by_rect(x, y, 0, 0, tex->width, tex->height)) return;
551
+
552
+ draw_prologue(&cur, tex, 0, 0, 1024, 1024, &hash_arg, sync_mode, primary, &payload);
553
+
554
+ /* fill hates alpha_blend so let's turn it off */
555
+ payload->pen.alpha_blend = false;
556
+
557
+ if(is_a_hash(hash_arg)) {
558
+ VALUE try_image = get_from_hash(hash_arg, "texture");
559
+ if(is_gosu_image(try_image)) {
560
+ get_texture_info(try_image, &fill_image);
561
+ fill_image_ptr = &fill_image;
562
+ }
563
+ }
564
+
565
+ seed_color = get_pixel_color(tex, x, y);
566
+
567
+ /* last argument is pointer to texture fill data (if it exists) or NULL (if it doesn't) */
568
+ glow_floodFill( x, y, &seed_color, &cur, tex, fill_image_ptr );
569
+
570
+ draw_epilogue(&cur, tex, primary);
571
+ }
572
+ /** end of glow fill **/
573
+
574
+ /** scanfill algorithm **/
575
+ /* the stack */
576
+ #define stackSize 16777218
577
+ int stack[stackSize];
578
+ int stackPointer;
579
+
580
+ static bool
581
+ pop(int * x, int * y, int h)
582
+ {
583
+ if(stackPointer > 0)
584
+ {
585
+ int p = stack[stackPointer];
586
+ *x = p / h;
587
+ *y = p % h;
588
+ stackPointer--;
589
+ return true;
590
+ }
591
+ else
592
+ {
593
+ return false;
594
+ }
595
+ }
596
+
597
+ static bool
598
+ push(int x, int y, int h)
599
+ {
600
+ if(stackPointer < stackSize - 1)
601
+ {
602
+ stackPointer++;
603
+ stack[stackPointer] = h * x + y;
604
+ return true;
605
+ }
606
+ else
607
+ {
608
+ return false;
609
+ }
610
+ }
611
+
612
+ static void
613
+ emptyStack()
614
+ {
615
+ int x, y;
616
+ while(pop(&x, &y, 0));
617
+ }
618
+
619
+ void
620
+ scan_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg,
621
+ sync sync_mode, bool primary, action_struct * payload)
622
+ {
623
+ action_struct cur;
624
+ rgba old_color;
625
+ int y1;
626
+ bool spanLeft, spanRight;
627
+
628
+ if(!bound_by_rect(x, y, 0, 0, tex->width - 1, tex->height - 1)) return;
629
+
630
+ /* NB: using XMAX_OOB etc since we dont know the drawing area yet; drawing area will be set by
631
+ update_bounds() function in main loop */
632
+ draw_prologue(&cur, tex, XMAX_OOB, YMAX_OOB, XMIN_OOB, YMIN_OOB, &hash_arg, sync_mode, primary, &payload);
633
+
634
+ /* fill hates alpha_blend so let's turn it off */
635
+ payload->pen.alpha_blend = false;
636
+
637
+ old_color = get_pixel_color(tex, x, y);
638
+
639
+ if(cmp_color(old_color, cur.color)) return;
640
+
641
+ emptyStack();
642
+
643
+ if(!push(x, y, tex->width - 1)) return;
644
+
645
+ while(pop(&x, &y, tex->width - 1))
646
+ {
647
+ y1 = y;
648
+ while(y1 >= 0 && cmp_color(old_color, get_pixel_color(tex, x, y1))) y1--;
649
+ y1++;
650
+ spanLeft = spanRight = false;
651
+ while(y1 < tex->height && cmp_color(old_color, get_pixel_color(tex, x, y1)) )
652
+ {
653
+ set_pixel_color_with_style(payload, tex, x, y1);
654
+
655
+ /* update the drawing rectangle */
656
+ update_bounds(payload, x, y1, x, y1);
657
+
658
+ if(!spanLeft && x > 1 && cmp_color(old_color, get_pixel_color(tex, x - 1, y1)))
659
+ {
660
+ if(!push(x - 1, y1, tex->width - 1)) return;
661
+ spanLeft = true;
662
+ }
663
+
664
+ else if(spanLeft && !cmp_color(old_color, get_pixel_color(tex, x - 1, y1)))
665
+ {
666
+ spanLeft = false;
667
+ }
668
+
669
+ if(!spanRight && x < tex->width - 1 && cmp_color(old_color,
670
+ get_pixel_color(tex, x + 1, y1)))
671
+ {
672
+ if(!push(x + 1, y1, tex->width - 1)) return;
673
+ spanRight = true;
674
+ }
675
+
676
+ else if(spanRight && x < tex->width - 1 && !cmp_color(old_color,get_pixel_color(tex, x + 1, y1)))
677
+ {
678
+ spanRight = false;
679
+ }
680
+ y1++;
681
+ }
682
+ }
683
+ draw_epilogue(&cur, tex, primary);
684
+ }
685
+ /** end of scanfill **/
686
+
687
+ /** bezier curve algorithm **/
688
+ static void
689
+ bezier_point(VALUE points, float u, float * x, float * y, int n, int format,
690
+ int draw_offset_x, int draw_offset_y)
691
+ {
692
+ int k;
693
+ int xy_index;
694
+ double sumx = 0, sumy = 0;
695
+
696
+
697
+ for(k = 0; k < n; k++) {
698
+ switch(format) {
699
+ case POINT_FORMAT:
700
+
701
+ sumx += NUM2DBL(point_x(get_from_array(points, k))) * bernstein(n - 1, k, u);
702
+ sumy += NUM2DBL(point_y(get_from_array(points, k))) * bernstein(n - 1, k, u);
703
+ break;
704
+ case SIMPLE_FORMAT:
705
+
706
+ xy_index = k * 2;
707
+ sumx += NUM2DBL(get_from_array(points, xy_index)) * bernstein(n - 1, k, u);
708
+ sumy += NUM2DBL(get_from_array(points, xy_index + 1)) * bernstein(n - 1, k, u);
709
+ break;
710
+ default:
711
+ rb_raise(rb_eArgError, "pixel format must be either POINT_FORMAT or SIMPLE_FORMAT");
712
+ }
713
+ }
714
+
715
+ *x = sumx + draw_offset_x;
716
+ *y = sumy + draw_offset_y;
717
+ }
718
+
719
+ void
720
+ bezier_do_action(VALUE points, texture_info * tex, VALUE hash_arg, sync sync_mode,
721
+ bool primary, action_struct * payload)
722
+ {
723
+ float u = 0.0;
724
+ action_struct cur;
725
+ float x1, y1, x2, y2;
726
+ int first_x, first_y;
727
+ int format;
728
+ int num_point_pairs;
729
+ bool closed = false;
730
+ VALUE offset_val;
731
+ int draw_offset_x, draw_offset_y;
732
+
733
+ /* defaults to 200 (1 / 0.005) samples per curve */
734
+ float step_size = 0.005;
735
+
736
+ draw_prologue(&cur, tex, XMAX_OOB, YMAX_OOB, XMIN_OOB, YMIN_OOB, &hash_arg, sync_mode, primary, &payload);
737
+
738
+ /* calculate offset */
739
+ offset_val = get_image_local(tex->image, DRAW_OFFSET);
740
+
741
+ draw_offset_x = NUM2INT(get_from_array(offset_val, 0));
742
+ draw_offset_y = NUM2INT(get_from_array(offset_val, 1));
743
+
744
+ if(is_a_hash(hash_arg)) {
745
+
746
+ /* if the polyline is 'closed' make the last point the first */
747
+ if(RTEST(get_from_hash(hash_arg, "closed")) || RTEST(get_from_hash(hash_arg, "close"))) {
748
+
749
+ /* so that our additional point is not persistent */
750
+ points = rb_obj_dup(points);
751
+ closed = true;
752
+ }
753
+
754
+ /* number of points to sample */
755
+ if(RTEST(get_from_hash(hash_arg, "sample_size"))) {
756
+ VALUE c = get_from_hash(hash_arg, "sample_size");
757
+ Check_Type(c, T_FIXNUM);
758
+ step_size = 1.0 / (float)FIX2INT(c);
759
+ }
760
+ }
761
+
762
+ if(is_a_point(get_from_array(points, 0))) {
763
+ format = POINT_FORMAT;
764
+
765
+ if(closed)
766
+ rb_ary_push(points, get_from_array(points, 0));
767
+
768
+ num_point_pairs = RARRAY_LEN(points);
769
+ }
770
+ else {
771
+ format = SIMPLE_FORMAT;
772
+
773
+ /* ensure points are given in pairs */
774
+ if(RARRAY_LEN(points) % 2)
775
+ rb_raise(rb_eArgError, "bezier needs an even number of points. got %d\n", (int)RARRAY_LEN(points));
776
+
777
+ if(closed) {
778
+ rb_ary_push(points, get_from_array(points, 0));
779
+ rb_ary_push(points, get_from_array(points, 1));
780
+ }
781
+
782
+ num_point_pairs = RARRAY_LEN(points) / 2;
783
+ }
784
+
785
+ if(num_point_pairs > 13)
786
+ rb_raise(rb_eArgError, "too many points for bezier curve. 13 points is current maximum. got %d\n",
787
+ num_point_pairs);
788
+
789
+ /* get the first point */
790
+ bezier_point(points, 0, &x1, &y1, num_point_pairs, format, draw_offset_x, draw_offset_y);
791
+
792
+ /* save it so we can link up with last point properly if the curve is 'closed' */
793
+ first_x = x1;
794
+ first_y = y1;
795
+
796
+ while(u <= 1) {
797
+ bezier_point(points, u, &x2, &y2, num_point_pairs, format, draw_offset_x, draw_offset_y);
798
+
799
+ line_do_action(x1, y1, x2, y2, tex, hash_arg, no_sync, false, payload);
800
+
801
+ /* update drawing rectangle */
802
+ update_bounds(payload, x1, y1, x2, y2);
803
+
804
+ x1 = x2;
805
+ y1 = y2;
806
+
807
+ u += step_size;
808
+ }
809
+
810
+ /* sometimes beziers dont close properly, so we'll ensure it's closed */
811
+ if(closed)
812
+ line_do_action(x2, y2, first_x, first_y, tex, hash_arg, no_sync, false, payload);
813
+
814
+ draw_epilogue(&cur, tex, primary);
815
+ }
816
+ /** end of bezier **/
817
+
818
+ /** each_pixel **/
819
+ static void
820
+ set_color_array(VALUE ary, rgba * color)
821
+ {
822
+ set_array_value(ary, 0, rb_float_new(color->red));
823
+ set_array_value(ary, 1, rb_float_new(color->green));
824
+ set_array_value(ary, 2, rb_float_new(color->blue));
825
+ set_array_value(ary, 3, rb_float_new(color->alpha));
826
+ }
827
+
828
+ void
829
+ each_pixel_do_action(int x1, int y1, int x2, int y2, VALUE proc, texture_info * tex, VALUE hash_arg,
830
+ sync sync_mode, bool primary, action_struct * payload)
831
+ {
832
+ action_struct cur;
833
+ int x, y, arity;
834
+ VALUE rb_pix = rb_ary_new2(4);
835
+
836
+ draw_prologue(&cur, tex, x1, y1, x2, y2, &hash_arg, sync_mode, primary, &payload);
837
+
838
+ arity = FIX2INT(rb_funcall(proc, rb_intern("arity"), 0));
839
+
840
+ for(y = y1; y < y2 + 1; y++)
841
+ for(x = x1; x < x2 + 1; x++) {
842
+ rgba pix = get_pixel_color(tex, x, y);
843
+
844
+ set_color_array(rb_pix, &pix);
845
+
846
+ /* invoke the block */
847
+ switch(arity) {
848
+ case 1:
849
+ rb_funcall(proc, rb_intern("call"), 1, rb_pix);
850
+ break;
851
+ case 3:
852
+ rb_funcall(proc, rb_intern("call"), 3, rb_pix, INT2FIX(x), INT2FIX(y));
853
+ break;
854
+ default:
855
+ rb_raise(rb_eArgError, "permissible arities for each are 1 & 3. Got %d\n",
856
+ arity);
857
+
858
+ }
859
+
860
+ pix = convert_rb_color_to_rgba(rb_pix);
861
+
862
+ set_pixel_color(&pix, tex, x, y);
863
+ }
864
+
865
+ draw_epilogue(&cur, tex, primary);
866
+ }
867
+ /** end each_pixel iterator **/
868
+
869
+ /** splice algorithm **/
870
+ void
871
+ splice_do_action(int x0, int y0, int cx1, int cy1, int cx2, int cy2, texture_info * splice_tex,
872
+ texture_info * tex, VALUE hash_arg, sync sync_mode,
873
+ bool primary, action_struct * payload)
874
+ {
875
+ action_struct cur;
876
+ int xbound;
877
+ int ybound;
878
+ rgba chromakey;
879
+ int x, y;
880
+ float * image_buf = NULL;
881
+ bool inverse_chroma = false;
882
+ bool has_chroma = false;
883
+ bool same_image = false;
884
+
885
+ constrain_boundaries(&cx1, &cy1, &cx2, &cy2, splice_tex->width, splice_tex->height);
886
+ xbound = cx2 - cx1 + 1;
887
+ ybound = cy2 - cy1 + 1;
888
+
889
+ draw_prologue(&cur, tex, x0, y0,
890
+ x0 + xbound, y0 + ybound, &hash_arg, sync_mode, primary, &payload);
891
+
892
+
893
+ if(has_optional_hash_arg(hash_arg, "chroma_key")) {
894
+ VALUE c = get_from_hash(hash_arg, "chroma_key");
895
+ chromakey = convert_rb_color_to_rgba(c);
896
+ has_chroma = true;
897
+ }
898
+ else if(has_optional_hash_arg(hash_arg, "chroma_key_not")) {
899
+ chromakey = convert_rb_color_to_rgba(get_from_hash(hash_arg, "chroma_key_not"));
900
+ inverse_chroma = true;
901
+ has_chroma = true;
902
+ }
903
+
904
+ if(splice_tex->image == tex->image)
905
+ same_image = true;
906
+
907
+ /* NB: we do not use this in the general case since it's almost 1.5 times as slow.
908
+ It is necessary for splicing from/to the same region of pixels though.
909
+ */
910
+ if(same_image)
911
+ image_buf = get_image_chunk(splice_tex, cx1, cy1, cx2, cy2);
912
+
913
+ for(y = 0; y < ybound; y++)
914
+ for(x = 0; x < xbound; x++) {
915
+
916
+ if(!same_image)
917
+ payload->color = get_pixel_color(splice_tex, cx1 + x, cy1 + y);
918
+ else
919
+ payload->color = get_pixel_color_from_chunk(image_buf, xbound, ybound, x, y);
920
+
921
+ if(has_chroma) {
922
+ bool cmp = cmp_color(payload->color, chromakey);
923
+ if(!cmp && !inverse_chroma)
924
+ set_pixel_color_with_style(payload, tex, x0 + x, y0 + y);
925
+ else if(cmp && inverse_chroma)
926
+ set_pixel_color_with_style(payload, tex, x0 + x, y0 + y);
927
+ }
928
+ else
929
+ set_pixel_color_with_style(payload, tex, x0 + x, y0 + y);
930
+ }
931
+
932
+ if(same_image)
933
+ free(image_buf);
934
+
935
+ draw_epilogue(&cur, tex, primary);
936
+ }
937
+ /** end splice **/
938
+
939
+ static void
940
+ initialize_action_struct(action_struct * cur, VALUE hash_arg, sync sync_mode)
941
+ {
942
+ /* initialize action-struct to default values */
943
+ cur->sync_mode = sync_mode;
944
+ cur->hash_arg = hash_arg;
945
+
946
+ cur->color = convert_image_local_color_to_rgba(cur->tex->image);
947
+ cur->pen.has_color_control_proc = false;
948
+ cur->pen.has_color_control_transform = false;
949
+ cur->pen.has_source_texture = false;
950
+ cur->pen.alpha_blend = false;
951
+
952
+ /* set static color control transformations to defaults */
953
+ cur->pen.color_mult.red = 1.0;
954
+ cur->pen.color_mult.green = 1.0;
955
+ cur->pen.color_mult.blue = 1.0;
956
+ cur->pen.color_mult.alpha = 1.0;
957
+
958
+ cur->pen.color_add.red = 0.0;
959
+ cur->pen.color_add.green = 0.0;
960
+ cur->pen.color_add.blue = 0.0;
961
+ cur->pen.color_add.alpha = 0.0;
962
+ }
963
+
964
+ /* TODO: fix this function below, it's too ugly and bulky and weird **/
965
+ static void
966
+ process_common_hash_args(action_struct * cur, VALUE * hash_arg, sync sync_mode, bool primary)
967
+ {
968
+
969
+ VALUE user_defaults;
970
+ VALUE hash_blend;
971
+
972
+
973
+ /* if a hash doesn't exist then create one */
974
+ if(!is_a_hash(*hash_arg))
975
+ *hash_arg = rb_hash_new();
976
+
977
+ /* init the action to default values */
978
+ initialize_action_struct(cur, *hash_arg, sync_mode);
979
+
980
+ /* get the user default options & merge with given options */
981
+ user_defaults = get_image_local(cur->tex->image, USER_DEFAULTS);
982
+ hash_blend = rb_funcall(user_defaults, rb_intern("merge"), 1, *hash_arg);
983
+ rb_funcall(*hash_arg, rb_intern("merge!"), 1, hash_blend);
984
+
985
+ if(has_optional_hash_arg(*hash_arg, "color")) {
986
+ VALUE c = get_from_hash(*hash_arg, "color");
987
+ cur->color = convert_rb_color_to_rgba(c);
988
+ if(c == string2sym("random")) {
989
+ set_hash_value(*hash_arg, "color", convert_rgba_to_rb_color(&cur->color));
990
+ }
991
+ }
992
+
993
+ /* shadows */
994
+ if(RTEST(get_from_hash(*hash_arg, "shadow"))) {
995
+ cur->pen.color_mult.red = 0.66;
996
+ cur->pen.color_mult.green = 0.66;
997
+ cur->pen.color_mult.blue = 0.66;
998
+ cur->pen.color_mult.alpha = 1;
999
+
1000
+ cur->pen.has_color_control_transform = true;
1001
+ }
1002
+
1003
+ /* sync mode */
1004
+ if(has_optional_hash_arg(*hash_arg, "sync_mode")) {
1005
+ VALUE user_sync_mode = get_from_hash(*hash_arg, "sync_mode");
1006
+
1007
+ Check_Type(user_sync_mode, T_SYMBOL);
1008
+
1009
+ if(user_sync_mode == string2sym("lazy_sync"))
1010
+ cur->sync_mode = lazy_sync;
1011
+ else if(user_sync_mode == string2sym("eager_sync"))
1012
+ cur->sync_mode = eager_sync;
1013
+ else if(user_sync_mode == string2sym("no_sync"))
1014
+ cur->sync_mode = no_sync;
1015
+ else
1016
+ rb_raise(rb_eArgError, "unrecognized sync mode: %s\n. Allowable modes are "
1017
+ ":lazy_sync, :eager_sync, :no_sync.",
1018
+ sym2string(user_sync_mode));
1019
+
1020
+ delete_from_hash(*hash_arg, "sync_mode");
1021
+
1022
+ }
1023
+
1024
+ /* process the color_control block or transform (if there is one) */
1025
+ prepare_color_control(cur);
1026
+
1027
+ /* process the filling texture (if there is one) */
1028
+ prepare_fill_texture(cur);
1029
+
1030
+ /* does the user want to blend alpha values ? */
1031
+ if(get_from_hash(*hash_arg, "alpha_blend") == Qtrue)
1032
+ cur->pen.alpha_blend = true;
1033
+
1034
+ }
1035
+
1036
+ static void
1037
+ update_lazy_bounds(action_struct * cur, texture_info * tex)
1038
+ {
1039
+
1040
+ /* only update global bounds if we're doing a lazy_sync */
1041
+ if(cur->sync_mode == lazy_sync) {
1042
+ int xmin, ymin, xmax, ymax;
1043
+ VALUE lazy_bounds;
1044
+
1045
+ lazy_bounds = get_image_local(tex->image, LAZY_BOUNDS);
1046
+
1047
+ xmin = INT2FIX(MIN(cur->xmin, FIX2INT(get_from_array(lazy_bounds, 0))));
1048
+ ymin = INT2FIX(MIN(cur->ymin, FIX2INT(get_from_array(lazy_bounds, 1))));
1049
+ xmax = INT2FIX(MAX(cur->xmax, FIX2INT(get_from_array(lazy_bounds, 2))));
1050
+ ymax = INT2FIX(MAX(cur->ymax, FIX2INT(get_from_array(lazy_bounds, 3))));
1051
+
1052
+ set_array_value(lazy_bounds, 0, xmin);
1053
+ set_array_value(lazy_bounds, 1, ymin);
1054
+ set_array_value(lazy_bounds, 2, xmax);
1055
+ set_array_value(lazy_bounds, 3, ymax);
1056
+ }
1057
+ }
1058
+
1059
+ static void
1060
+ update_bounds(action_struct * cur, int xmin, int ymin, int xmax, int ymax)
1061
+ {
1062
+ if(xmin > xmax) SWAP(xmin, xmax);
1063
+ if(ymin > ymax) SWAP(ymin, ymax);
1064
+
1065
+ cur->xmin = MIN(cur->xmin, xmin);
1066
+ cur->ymin = MIN(cur->ymin, ymin);
1067
+ cur->xmax = MAX(cur->xmax, xmax);
1068
+ cur->ymax = MAX(cur->ymax, ymax);
1069
+ }
1070
+
1071
+ static void
1072
+ set_local_bounds(action_struct * cur, int xmin, int ymin, int xmax, int ymax, texture_info * tex)
1073
+ {
1074
+ if(cur->sync_mode == no_sync)
1075
+ return;
1076
+
1077
+ /* local bounds used by both eager_sync and lazy_sync: */
1078
+
1079
+ /* eager sync: to demarcate precise area to sync to opengl */
1080
+ /* lazy sync: to update global bounds */
1081
+ cur->xmin = xmin;
1082
+ cur->ymin = ymin;
1083
+ cur->xmax = xmax;
1084
+ cur->ymax = ymax;
1085
+ }
1086
+
1087
+ static void
1088
+ draw_prologue(action_struct * cur, texture_info * tex, int xmin, int ymin, int xmax, int ymax,
1089
+ VALUE * hash_arg, sync sync_mode, bool primary, action_struct ** payload_ptr)
1090
+ {
1091
+ if(!primary) return;
1092
+
1093
+ /* set the payload pointer */
1094
+ *payload_ptr = cur;
1095
+
1096
+ /* not too happy about having this here, look at texplay.h for why */
1097
+ cur->tex = tex;
1098
+
1099
+ process_common_hash_args(cur, hash_arg, sync_mode, primary);
1100
+
1101
+ set_local_bounds(cur, xmin, ymin, xmax, ymax, tex);
1102
+ }
1103
+
1104
+ void
1105
+ draw_epilogue(action_struct * cur, texture_info * tex, bool primary)
1106
+ {
1107
+ /* only primary actions get sync'd */
1108
+ if(!primary) return;
1109
+
1110
+ switch(cur->sync_mode) {
1111
+
1112
+ /* do not sync */
1113
+ case no_sync:
1114
+ return;
1115
+ break;
1116
+
1117
+ /* sync immediately */
1118
+ case eager_sync:
1119
+ create_subtexture_and_sync_to_gl(IMAGE_BOUNDS(cur), tex);
1120
+ break;
1121
+
1122
+ /* sync later (at end of paint block?) */
1123
+ case lazy_sync:
1124
+ update_lazy_bounds(cur, tex);
1125
+ break;
1126
+
1127
+ default:
1128
+ rb_raise(rb_eRuntimeError,
1129
+ "sync_mode may only be: lazy_sync, eager_sync, no_sync. got %d\n", cur->sync_mode);
1130
+ }
1131
+ }
1132
+
1133
+ /* set action color to return value of color_control proc */
1134
+ static void
1135
+ prepare_color_control(action_struct * cur)
1136
+ {
1137
+
1138
+ if(is_a_hash(cur->hash_arg)) {
1139
+ VALUE try_val = get_from_hash(cur->hash_arg, "color_control");
1140
+
1141
+ if(rb_respond_to(try_val, rb_intern("call"))) {
1142
+ cur->pen.color_control_proc = try_val;
1143
+ cur->pen.color_control_arity = FIX2INT(rb_funcall(try_val, rb_intern("arity"), 0));
1144
+ cur->pen.has_color_control_proc = true;
1145
+ }
1146
+ else if(is_a_hash(try_val)) {
1147
+ VALUE try_add = get_from_hash(try_val, "add");
1148
+ VALUE try_mult = get_from_hash(try_val, "mult");
1149
+
1150
+ if(is_an_array(try_add)) {
1151
+ if(RARRAY_LEN(try_add) < 4)
1152
+ rb_raise(rb_eArgError, ":color_control transform :add needs 4 parameters");
1153
+
1154
+ cur->pen.color_add.red = NUM2DBL(get_from_array(try_add, 0));
1155
+ cur->pen.color_add.green = NUM2DBL(get_from_array(try_add, 1));
1156
+ cur->pen.color_add.blue = NUM2DBL(get_from_array(try_add, 2));
1157
+ cur->pen.color_add.alpha = NUM2DBL(get_from_array(try_add, 3));
1158
+
1159
+ cur->pen.has_color_control_transform = true;
1160
+ }
1161
+ if(is_an_array(try_mult)) {
1162
+ if(RARRAY_LEN(try_mult) < 4)
1163
+ rb_raise(rb_eArgError, ":color_control transform :mult needs 4 parameters");
1164
+
1165
+ cur->pen.color_mult.red = NUM2DBL(get_from_array(try_mult, 0));
1166
+ cur->pen.color_mult.green = NUM2DBL(get_from_array(try_mult, 1));
1167
+ cur->pen.color_mult.blue = NUM2DBL(get_from_array(try_mult, 2));
1168
+ cur->pen.color_mult.alpha = NUM2DBL(get_from_array(try_mult, 3));
1169
+
1170
+ cur->pen.has_color_control_transform = true;
1171
+ }
1172
+
1173
+ }
1174
+ }
1175
+ }
1176
+
1177
+ static rgba
1178
+ exec_color_control_proc(action_struct * cur, texture_info * tex, int x, int y)
1179
+ {
1180
+ int arity = cur->pen.color_control_arity;
1181
+ VALUE proc = cur->pen.color_control_proc;
1182
+ rgba old_color = get_pixel_color(tex, x, y);
1183
+ rgba current_color = cur->color;
1184
+ rgba new_color;
1185
+
1186
+ if(!cur->pen.has_color_control_proc)
1187
+ rb_raise(rb_eRuntimeError, "needs a proc");
1188
+
1189
+ switch(arity) {
1190
+ case 1:
1191
+ new_color = convert_rb_color_to_rgba(rb_funcall(proc, rb_intern("call"), arity,
1192
+ convert_rgba_to_rb_color(&old_color)));
1193
+ break;
1194
+
1195
+ case 2:
1196
+ new_color = convert_rb_color_to_rgba(rb_funcall(proc, rb_intern("call"), arity,
1197
+ convert_rgba_to_rb_color(&old_color),
1198
+ convert_rgba_to_rb_color(&current_color)));
1199
+ break;
1200
+
1201
+ case 3:
1202
+ new_color = convert_rb_color_to_rgba(rb_funcall(proc, rb_intern("call"), arity,
1203
+ convert_rgba_to_rb_color(&old_color),
1204
+ INT2FIX(x), INT2FIX(y)));
1205
+ break;
1206
+ case 4:
1207
+ new_color = convert_rb_color_to_rgba(rb_funcall(proc, rb_intern("call"), arity,
1208
+ convert_rgba_to_rb_color(&old_color),
1209
+ convert_rgba_to_rb_color(&current_color),
1210
+ INT2FIX(x), INT2FIX(y)));
1211
+ break;
1212
+ default:
1213
+ rb_raise(rb_eArgError, "permissible arities for color_control proc are 1, 2, 3 and 4. Got %d\n",
1214
+ arity);
1215
+ }
1216
+
1217
+ /* update the action color */
1218
+ return new_color;
1219
+ }
1220
+
1221
+ static void
1222
+ prepare_fill_texture(action_struct * payload)
1223
+ {
1224
+ if(is_a_hash(payload->hash_arg)) {
1225
+ VALUE try_image = get_from_hash(payload->hash_arg, "texture");
1226
+ if(is_gosu_image(try_image)) {
1227
+
1228
+ get_texture_info(try_image, &payload->pen.source_tex);
1229
+ payload->pen.has_source_texture = true;
1230
+ }
1231
+ }
1232
+ }
1233
+
1234
+ static void
1235
+ apply_color_control_transform(action_struct * payload, texture_info * tex, int x, int y)
1236
+ {
1237
+ payload->color = get_pixel_color(tex, x, y);
1238
+
1239
+ payload->color.red += payload->pen.color_add.red;
1240
+ payload->color.green += payload->pen.color_add.green;
1241
+ payload->color.blue += payload->pen.color_add.blue;
1242
+ payload->color.alpha += payload->pen.color_add.alpha;
1243
+
1244
+ payload->color.red *= payload->pen.color_mult.red;
1245
+ payload->color.green *= payload->pen.color_mult.green;
1246
+ payload->color.blue *= payload->pen.color_mult.blue;
1247
+ payload->color.alpha *= payload->pen.color_mult.alpha;
1248
+ }
1249
+
1250
+ static void
1251
+ set_pixel_color_with_style(action_struct * payload, texture_info * tex, int x, int y)
1252
+ {
1253
+
1254
+ rgba blended_pixel;
1255
+
1256
+ /* for color_control transform */
1257
+ if(payload->pen.has_color_control_transform)
1258
+ apply_color_control_transform(payload, tex, x, y);
1259
+
1260
+ /* for texture fill */
1261
+ if(payload->pen.has_source_texture)
1262
+ payload->color = get_pixel_color(&payload->pen.source_tex,
1263
+ x % payload->pen.source_tex.width,
1264
+ y % payload->pen.source_tex.height);
1265
+
1266
+ /* for color_control block */
1267
+ if(payload->pen.has_color_control_proc)
1268
+ payload->color = exec_color_control_proc(payload, tex, x, y);
1269
+
1270
+
1271
+ /* TO DO: do bitwise pixel combinations here */
1272
+
1273
+ /* if i do not use blended_pixel and instead use payload->color in the
1274
+ code below i get an interesting blurring effect in images (with alpha_blend => true)
1275
+ */
1276
+ blended_pixel = payload->color;
1277
+
1278
+
1279
+ /* alpha blending
1280
+ TO DO: refactor into its own helper function
1281
+ & rewrite using sse2 */
1282
+ if(payload->pen.alpha_blend) {
1283
+ rgba dest_pixel = get_pixel_color(tex, x, y);
1284
+
1285
+ /* alpha blending is nothing more than a weighted average of src and dest pixels
1286
+ based on source alpha value */
1287
+ /* NB: destination alpha value is ignored */
1288
+ if(is_a_color(payload->color) && is_a_color(dest_pixel)) {
1289
+
1290
+ /** TO DO: rewrite this using sse2 instructions **/
1291
+ blended_pixel.red = payload->color.alpha * payload->color.red + (1 - payload->color.alpha)
1292
+ * dest_pixel.red;
1293
+
1294
+ blended_pixel.green = payload->color.alpha * payload->color.green + (1 - payload->color.alpha)
1295
+ * dest_pixel.green;
1296
+
1297
+ blended_pixel.blue = payload->color.alpha * payload->color.blue + (1 - payload->color.alpha)
1298
+ * dest_pixel.blue;
1299
+
1300
+ blended_pixel.alpha = payload->color.alpha;
1301
+ }
1302
+ }
1303
+
1304
+ set_pixel_color(&blended_pixel, tex, x, y);
1305
+ }
1306
+