flood_fill() wouldn't fill the right side of a single scan-line fill area.
[imager.git] / regmach.c
CommitLineData
02d1d628 1#include "regmach.h"
aed9d070 2#include <float.h>
02d1d628
AMH
3
4/*#define DEBUG*/
5#ifdef DEBUG
6#define DBG(x) printf x
7#else
8#define DBG(x)
9#endif
10
aed9d070
TC
11static float MAX_EXP_ARG; /* = log(DBL_MAX); */
12
13
02d1d628
AMH
14/* these functions currently assume RGB images - there seems to be some
15 support for other color spaces, but I can't tell how you find what
16 space an image is using.
17
18 HSV conversions from pages 401-403 "Procedural Elements for Computer
19 Graphics", 1985, ISBN 0-07-053534-5. The algorithm presents to produce
20 an HSV color calculates all components at once - I don't, so I've
21 simiplified the algorithm to avoid unnecessary calculation (any errors
22 (of which I had a few ;) are mine).
23*/
24
25/* returns the value (brightness) of color from 0 to 1 */
b33c08f8
TC
26static double hsv_value(i_color color) {
27 return i_max(i_max(color.rgb.r, color.rgb.g), color.rgb.b) / 255.0;
02d1d628
AMH
28}
29
30/* returns the hue (color) of color from 0 to 360 */
b33c08f8 31static double hsv_hue(i_color color) {
02d1d628
AMH
32 int val;
33 int temp;
b33c08f8
TC
34 temp = i_min(i_min(color.rgb.r, color.rgb.g), color.rgb.b);
35 val = i_max(color.rgb.r, i_max(color.rgb.g, color.rgb.b));
02d1d628
AMH
36 if (val == 0 || val==temp) {
37 return 0;
38 }
39 else {
40 double cr = (val - color.rgb.r) / (double)(val - temp);
41 double cg = (val - color.rgb.g) / (double)(val - temp);
42 double cb = (val - color.rgb.b) / (double)(val - temp);
43 double hue;
44 if (color.rgb.r == val) {
45 hue = cb-cg;
46 }
47 else if (color.rgb.g == val) {
48 hue = 2.0 + cr-cb;
49 }
50 else { /* if (blue == val) */
51 hue = 4.0 + cg - cr;
52 }
53 hue *= 60.0; /* to degrees */
54 if (hue < 0)
55 hue += 360;
56
57 return hue;
58 }
59}
60
61/* return the saturation of color from 0 to 1 */
b33c08f8
TC
62static double hsv_sat(i_color color) {
63 int value = i_max(i_max(color.rgb.r, color.rgb.g), color.rgb.b);
02d1d628
AMH
64 if (value == 0) {
65 return 0;
66 }
67 else {
b33c08f8 68 int temp = i_min(i_max(color.rgb.r, color.rgb.g), color.rgb.b);
02d1d628
AMH
69 return (value - temp) / (double)value;
70 }
71}
72
e5744e01 73static i_color make_hsv(double hue, double sat, double val, int alpha) {
02d1d628
AMH
74 int i;
75 i_color c;
76 for( i=0; i< MAXCHANNELS; i++) c.channel[i]=0;
77 DBG(("hsv=%f %f %f\n", hue, sat, val));
78 if (sat <= 0) { /* handle -ve in case someone supplies a bad value */
79 /* should this be * 256? */
80 c.rgb.r = c.rgb.g = c.rgb.b = 255 * val;
81 }
82 else {
83 int i, m, n, k, v;
84 double f;
85
86 if (val < 0) val = 0;
87 if (val > 1) val = 1;
88 if (sat > 1) sat = 1;
89
90 /* I want to handle -360 <= hue < 720 so that the caller can
91 fiddle with colour
92 */
93 if (hue >= 360)
94 hue -= 360;
95 else if (hue < 0)
96 hue += 360;
97 hue /= 60;
98 i = hue; /* floor */
99 f = hue - i;
100 val *= 255;
101 m = val * (1.0 - sat);
102 n = val * (1.0 - sat * f);
103 k = val * (1.0 - sat * (1 - f));
104 v = val;
105 switch (i) {
106 case 0:
107 c.rgb.r = v; c.rgb.g = k; c.rgb.b = m;
108 break;
109 case 1:
110 c.rgb.r = n; c.rgb.g = v; c.rgb.b = m;
111 break;
112 case 2:
113 c.rgb.r = m; c.rgb.g = v; c.rgb.b = k;
114 break;
115 case 3:
116 c.rgb.r = m; c.rgb.g = n; c.rgb.b = v;
117 break;
118 case 4:
119 c.rgb.r = k; c.rgb.g = m; c.rgb.b = v;
120 break;
121 case 5:
122 c.rgb.r = v; c.rgb.g = m; c.rgb.b = n;
123 break;
124 }
125 }
e5744e01 126 c.rgba.a = alpha;
02d1d628
AMH
127
128 return c;
129}
130
e5744e01 131static i_color make_rgb(int r, int g, int b, int a) {
02d1d628
AMH
132 i_color c;
133 if (r < 0)
134 r = 0;
135 if (r > 255)
136 r = 255;
137 c.rgb.r = r;
138 if (g < 0)
139 g = 0;
140 if (g > 255)
141 g = 255;
142 c.rgb.g = g;
143 if (b < 0)
144 b = 0;
145 if (b > 255)
146 b = 255;
147 c.rgb.b = b;
148
e5744e01
TC
149 c.rgba.a = a;
150
02d1d628
AMH
151 return c;
152}
153
154/* greatly simplifies the code */
155#define nout n_regs[codes->rout]
156#define na n_regs[codes->ra]
157#define nb n_regs[codes->rb]
158#define nc n_regs[codes->rc]
159#define nd n_regs[codes->rd]
160#define cout c_regs[codes->rout]
161#define ca c_regs[codes->ra]
162#define cb c_regs[codes->rb]
163#define cc c_regs[codes->rc]
164#define cd c_regs[codes->rd]
165
166/* this is a pretty poor epsilon used for loosening up equality comparisons
167 It isn't currently used for inequalities
168*/
169
170#define n_epsilon(x, y) (abs(x)+abs(y))*0.001
171static i_color bcol = {{ 0 }};
172
b33c08f8 173i_color i_rm_run(struct rm_op codes[], size_t code_count,
02d1d628
AMH
174 double n_regs[], size_t n_regs_count,
175 i_color c_regs[], size_t c_regs_count,
176 i_img *images[], size_t image_count) {
177 double dx, dy;
178 struct rm_op *codes_base = codes;
179 size_t count_base = code_count;
aed9d070 180
02d1d628
AMH
181 DBG(("rm_run(%p, %d)\n", codes, code_count));
182 while (code_count) {
183 DBG((" rm_code %d\n", codes->code));
184 switch (codes->code) {
185 case rbc_add:
186 nout = na + nb;
187 break;
188
189 case rbc_subtract:
190 nout = na - nb;
191 break;
192
193 case rbc_mult:
194 nout = na * nb;
195 break;
196
197 case rbc_div:
198 if (abs(nb) < 1e-10)
199 nout = 1e10;
200 else
201 nout = na / nb;
202 break;
203
204 case rbc_mod:
205 if (abs(nb) > 1e-10) {
206 nout = fmod(na, nb);
207 }
208 else {
209 nout = 0; /* close enough ;) */
210 }
211 break;
212
213 case rbc_pow:
214 nout = pow(na, nb);
215 break;
216
217 case rbc_uminus:
218 nout = -na;
3f29de50 219 break;
02d1d628
AMH
220
221 case rbc_multp:
e5744e01 222 cout = make_rgb(ca.rgb.r * nb, ca.rgb.g * nb, ca.rgb.b * nb, 255);
02d1d628
AMH
223 break;
224
225 case rbc_addp:
226 cout = make_rgb(ca.rgb.r + cb.rgb.r, ca.rgb.g + cb.rgb.g,
e5744e01 227 ca.rgb.b + cb.rgb.b, 255);
02d1d628
AMH
228 break;
229
230 case rbc_subtractp:
231 cout = make_rgb(ca.rgb.r - cb.rgb.r, ca.rgb.g - cb.rgb.g,
e5744e01 232 ca.rgb.b - cb.rgb.b, 255);
02d1d628
AMH
233 break;
234
235 case rbc_sin:
236 nout = sin(na);
237 break;
238
239 case rbc_cos:
240 nout = cos(na);
241 break;
242
243 case rbc_atan2:
244 nout = atan2(na, nb);
245 break;
246
247 case rbc_sqrt:
248 nout = sqrt(na);
249 break;
250
251 case rbc_distance:
252 dx = na-nc;
253 dy = nb-nd;
254 nout = sqrt(dx*dx+dy*dy);
255 break;
256
257 case rbc_getp1:
258 i_gpix(images[0], na, nb, c_regs+codes->rout);
aed9d070 259 if (images[0]->channels < 4) cout.rgba.a = 255;
02d1d628
AMH
260 break;
261
262 case rbc_getp2:
263 i_gpix(images[1], na, nb, c_regs+codes->rout);
aed9d070 264 if (images[1]->channels < 4) cout.rgba.a = 255;
02d1d628
AMH
265 break;
266
267 case rbc_getp3:
268 i_gpix(images[2], na, nb, c_regs+codes->rout);
aed9d070 269 if (images[2]->channels < 4) cout.rgba.a = 255;
02d1d628
AMH
270 break;
271
272 case rbc_value:
273 nout = hsv_value(ca);
274 break;
275
276 case rbc_hue:
277 nout = hsv_hue(ca);
278 break;
279
280 case rbc_sat:
281 nout = hsv_sat(ca);
282 break;
283
284 case rbc_hsv:
e5744e01
TC
285 cout = make_hsv(na, nb, nc, 255);
286 break;
287
288 case rbc_hsva:
289 cout = make_hsv(na, nb, nc, nd);
02d1d628
AMH
290 break;
291
292 case rbc_red:
293 nout = ca.rgb.r;
294 break;
295
296 case rbc_green:
297 nout = ca.rgb.g;
298 break;
299
300 case rbc_blue:
301 nout = ca.rgb.b;
302 break;
303
e5744e01
TC
304 case rbc_alpha:
305 nout = ca.rgba.a;
306 break;
307
02d1d628 308 case rbc_rgb:
e5744e01
TC
309 cout = make_rgb(na, nb, nc, 255);
310 break;
311
312 case rbc_rgba:
313 cout = make_rgb(na, nb, nc, nd);
02d1d628
AMH
314 break;
315
316 case rbc_int:
317 nout = (int)(na);
318 break;
319
320 case rbc_if:
321 nout = na ? nb : nc;
322 break;
323
324 case rbc_ifp:
325 cout = na ? cb : cc;
326 break;
327
328 case rbc_le:
329 nout = na <= nb + n_epsilon(na,nb);
330 break;
331
332 case rbc_lt:
333 nout = na < nb;
334 break;
335
336 case rbc_ge:
337 nout = na >= nb - n_epsilon(na,nb);
338 break;
339
340 case rbc_gt:
341 nout = na > nb;
342 break;
343
344 case rbc_eq:
345 nout = abs(na-nb) <= n_epsilon(na,nb);
346 break;
347
348 case rbc_ne:
349 nout = abs(na-nb) > n_epsilon(na,nb);
350 break;
351
352 case rbc_and:
353 nout = na && nb;
354 break;
355
356 case rbc_or:
357 nout = na || nb;
358 break;
359
360 case rbc_not:
361 nout = !na;
362 break;
363
364 case rbc_abs:
365 nout = abs(na);
366 break;
367
368 case rbc_ret:
369 return ca;
370 break;
371
372 case rbc_jump:
373 /* yes, order is important here */
374 code_count = count_base - codes->ra;
375 codes = codes_base + codes->ra;
376 continue;
377
378 case rbc_jumpz:
379 if (!na) {
380 /* yes, order is important here */
381 code_count = count_base - codes->rb;
382 codes = codes_base + codes->rb;
383 continue;
384 }
385 break;
386
387 case rbc_jumpnz:
388 if (na) {
389 /* yes, order is important here */
390 code_count = count_base - codes->rb;
391 codes = codes_base + codes->rb;
392 continue;
393 }
394 break;
395
396 case rbc_set:
397 nout = na;
398 break;
399
400 case rbc_setp:
401 cout = ca;
402 break;
403
aed9d070
TC
404 case rbc_log:
405 if (na > 0) {
406 nout = log(na);
407 }
408 else {
409 nout = DBL_MAX;
410 }
411 break;
412
413 case rbc_exp:
414 if (!MAX_EXP_ARG) MAX_EXP_ARG = log(DBL_MAX);
415 if (na <= MAX_EXP_ARG) {
416 nout = exp(na);
417 }
418 else {
419 nout = DBL_MAX;
420 }
421 break;
422
02d1d628 423 case rbc_print:
3309187a 424 nout = na;
02d1d628
AMH
425 printf("r%d is %g\n", codes->ra, na);
426 break;
427
3309187a
TC
428 case rbc_det:
429 nout = na*nd-nb*nc;
430 break;
431
02d1d628
AMH
432 default:
433 /*croak("bad opcode"); */
434 printf("bad op %d\n", codes->code);
435 return bcol;
436 }
437 --code_count;
438 ++codes;
439 }
440 return bcol;
441 /* croak("no return opcode"); */
442}