]> git.imager.perl.org - imager.git/blob - regmach.c
merge circle outline branch
[imager.git] / regmach.c
1 #include "regmach.h"
2 #include <float.h>
3
4 /*#define DEBUG*/
5 #ifdef DEBUG
6 #define DBG(x) printf x
7 #else
8 #define DBG(x) 
9 #endif
10
11 static float MAX_EXP_ARG; /* = log(DBL_MAX); */
12
13
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 */
26 static double hsv_value(i_color color) {
27   return i_max(i_max(color.rgb.r, color.rgb.g), color.rgb.b) / 255.0;
28 }
29
30 /* returns the hue (color) of color from 0 to 360 */
31 static double hsv_hue(i_color color) {
32   int val;
33   int temp;
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));
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 */
62 static double hsv_sat(i_color color) {
63   int value = i_max(i_max(color.rgb.r, color.rgb.g), color.rgb.b);
64   if (value == 0) {
65     return 0;
66   }
67   else {
68     int temp = i_min(i_max(color.rgb.r, color.rgb.g), color.rgb.b);
69     return (value - temp) / (double)value;
70   }
71 }
72
73 static i_color make_hsv(double hue, double sat, double val, int alpha) {
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   }
126   c.rgba.a = alpha;
127
128   return c;
129 }
130
131 static i_color make_rgb(int r, int g, int b, int a) {
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
149   c.rgba.a = a;
150
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
171 static i_color bcol = {{ 0 }};
172
173 i_color i_rm_run(struct rm_op codes[], size_t code_count, 
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;
180
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;
219       break;
220
221     case rbc_multp:
222       cout = make_rgb(ca.rgb.r * nb, ca.rgb.g * nb, ca.rgb.b * nb, 255);
223       break;
224
225     case rbc_addp:
226       cout = make_rgb(ca.rgb.r + cb.rgb.r, ca.rgb.g + cb.rgb.g, 
227                       ca.rgb.b + cb.rgb.b, 255);
228       break;
229
230     case rbc_subtractp:
231       cout = make_rgb(ca.rgb.r - cb.rgb.r, ca.rgb.g - cb.rgb.g, 
232                       ca.rgb.b - cb.rgb.b, 255);
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);
259       if (images[0]->channels < 4) cout.rgba.a = 255;
260       break;
261
262     case rbc_getp2:
263       i_gpix(images[1], na, nb, c_regs+codes->rout);
264       if (images[1]->channels < 4) cout.rgba.a = 255;
265       break;
266
267     case rbc_getp3:
268       i_gpix(images[2], na, nb, c_regs+codes->rout);
269       if (images[2]->channels < 4) cout.rgba.a = 255;
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:
285       cout = make_hsv(na, nb, nc, 255);
286       break;
287
288     case rbc_hsva:
289       cout = make_hsv(na, nb, nc, nd);
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
304     case rbc_alpha:
305       nout = ca.rgba.a;
306       break;
307
308     case rbc_rgb:
309       cout = make_rgb(na, nb, nc, 255);
310       break;
311
312     case rbc_rgba:
313       cout = make_rgb(na, nb, nc, nd);
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
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
423     case rbc_print:
424       nout = na;
425       printf("r%d is %g\n", codes->ra, na);
426       break;
427
428     case rbc_det:
429       nout = na*nd-nb*nc;
430       break;
431
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 }