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.
- data/CHANGELOG +68 -0
- data/README +21 -0
- data/README1st +9 -0
- data/Rakefile +85 -0
- data/examples/basic.rb +48 -0
- data/examples/basic2.rb +37 -0
- data/examples/benchmark.rb +299 -0
- data/examples/common.rb +8 -0
- data/examples/example_alpha_blend.rb +31 -0
- data/examples/example_bezier.rb +51 -0
- data/examples/example_color_control.rb +68 -0
- data/examples/example_color_transform.rb +29 -0
- data/examples/example_dup.rb +52 -0
- data/examples/example_each.rb +42 -0
- data/examples/example_effect.rb +35 -0
- data/examples/example_fill.rb +49 -0
- data/examples/example_fill_old.rb +49 -0
- data/examples/example_fluent.rb +31 -0
- data/examples/example_gen_eval.rb +34 -0
- data/examples/example_hash_arguments.rb +47 -0
- data/examples/example_melt.rb +27 -0
- data/examples/example_polyline.rb +43 -0
- data/examples/example_simple.rb +35 -0
- data/examples/example_sync.rb +60 -0
- data/examples/example_turtle.rb +40 -0
- data/examples/media/empty2.png +0 -0
- data/examples/media/gosu.png +0 -0
- data/examples/media/maria.png +0 -0
- data/examples/media/rose.bmp +0 -0
- data/examples/media/sand1.png +0 -0
- data/examples/media/sunset.png +0 -0
- data/examples/media/texplay.png +0 -0
- data/examples/specs.rb +240 -0
- data/examples/test.rb +70 -0
- data/examples/test2.rb +72 -0
- data/lib/ctexplay.18.so +0 -0
- data/lib/ctexplay.19.so +0 -0
- data/lib/texplay-contrib.rb +77 -0
- data/lib/texplay.rb +134 -0
- data/src/Makefile +181 -0
- data/src/TAGS +286 -0
- data/src/actions.c +1306 -0
- data/src/actions.h +52 -0
- data/src/actions.obj +0 -0
- data/src/bindings.c +1081 -0
- data/src/bindings.h +45 -0
- data/src/bindings.obj +0 -0
- data/src/cache.c +132 -0
- data/src/cache.h +24 -0
- data/src/cache.obj +0 -0
- data/src/compat.h +23 -0
- data/src/ctexplay-i386-mswin32.def +2 -0
- data/src/ctexplay-i386-mswin32.exp +0 -0
- data/src/ctexplay-i386-mswin32.lib +0 -0
- data/src/ctexplay-i386-mswin32.pdb +0 -0
- data/src/ctexplay.so +0 -0
- data/src/extconf.rb +18 -0
- data/src/gen_eval.c +209 -0
- data/src/gen_eval.h +20 -0
- data/src/gen_eval.obj +0 -0
- data/src/mkmf.log +18 -0
- data/src/object2module.c +171 -0
- data/src/object2module.h +11 -0
- data/src/object2module.obj +0 -0
- data/src/texplay.c +136 -0
- data/src/texplay.h +107 -0
- data/src/texplay.obj +0 -0
- data/src/utils.c +959 -0
- data/src/utils.h +143 -0
- data/src/utils.obj +0 -0
- data/src/vc60.pdb +0 -0
- 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(¤t_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(¤t_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
|
+
|