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