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