texplay 0.2.1-x86-mswin32-60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
+