Initial revision
[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 double hsv_value(i_color color) {
23   return max(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 double hsv_hue(i_color color) {
28   int val;
29   int temp;
30   temp = min(min(color.rgb.r, color.rgb.g), color.rgb.b);
31   val = max(color.rgb.r, 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 double hsv_sat(i_color color) {
59   int value = max(max(color.rgb.r, color.rgb.g), color.rgb.b);
60   if (value == 0) {
61     return 0;
62   }
63   else {
64     int temp = min(max(color.rgb.r, color.rgb.g), color.rgb.b);
65     return (value - temp) / (double)value;
66   }
67 }
68
69 i_color make_hsv(double hue, double sat, double val) {
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
123   return c;
124 }
125
126 i_color make_rgb(int r, int g, int b) {
127   i_color c;
128   if (r < 0)
129     r = 0;
130   if (r > 255)
131     r = 255;
132   c.rgb.r = r;
133   if (g < 0)
134     g = 0;
135   if (g > 255)
136     g = 255;
137   c.rgb.g = g;
138   if (b < 0)
139     b = 0;
140   if (b > 255)
141     b = 255;
142   c.rgb.b = b;
143
144   return c;
145 }
146
147 /* greatly simplifies the code */
148 #define nout n_regs[codes->rout]
149 #define na n_regs[codes->ra]
150 #define nb n_regs[codes->rb]
151 #define nc n_regs[codes->rc]
152 #define nd n_regs[codes->rd]
153 #define cout c_regs[codes->rout]
154 #define ca c_regs[codes->ra]
155 #define cb c_regs[codes->rb]
156 #define cc c_regs[codes->rc]
157 #define cd c_regs[codes->rd]
158
159 /* this is a pretty poor epsilon used for loosening up equality comparisons
160    It isn't currently used for inequalities 
161 */
162
163 #define n_epsilon(x, y) (abs(x)+abs(y))*0.001
164 static i_color bcol = {{ 0 }};
165
166 i_color rm_run(struct rm_op codes[], size_t code_count, 
167                double n_regs[],  size_t n_regs_count,
168                i_color c_regs[], size_t c_regs_count,
169                i_img *images[],  size_t image_count) {
170   double dx, dy;
171   struct rm_op *codes_base = codes;
172   size_t count_base = code_count;
173   DBG(("rm_run(%p, %d)\n", codes, code_count));
174   while (code_count) {
175     DBG((" rm_code %d\n", codes->code));
176     switch (codes->code) {
177     case rbc_add:
178       nout = na + nb;
179       break;
180       
181     case rbc_subtract:
182       nout = na - nb;
183       break;
184       
185     case rbc_mult:
186       nout = na * nb;
187       break;
188       
189     case rbc_div:
190       if (abs(nb) < 1e-10)
191         nout = 1e10;
192       else
193         nout = na / nb;
194       break;
195       
196     case rbc_mod:
197       if (abs(nb) > 1e-10) {
198         nout = fmod(na, nb);
199       }
200       else {
201         nout = 0; /* close enough ;) */
202       }
203       break;
204
205     case rbc_pow:
206       nout = pow(na, nb);
207       break;
208
209     case rbc_uminus:
210       nout = -na;
211
212     case rbc_multp:
213       cout = make_rgb(ca.rgb.r * nb, ca.rgb.g * nb, ca.rgb.b * nb);
214       break;
215
216     case rbc_addp:
217       cout = make_rgb(ca.rgb.r + cb.rgb.r, ca.rgb.g + cb.rgb.g, 
218                       ca.rgb.b + cb.rgb.b);
219       break;
220
221     case rbc_subtractp:
222       cout = make_rgb(ca.rgb.r - cb.rgb.r, ca.rgb.g - cb.rgb.g, 
223                       ca.rgb.b - cb.rgb.b);
224       break;
225
226     case rbc_sin:
227       nout = sin(na);
228       break;
229
230     case rbc_cos:
231       nout = cos(na);
232       break;
233
234     case rbc_atan2:
235       nout = atan2(na, nb);
236       break;
237
238     case rbc_sqrt:
239       nout = sqrt(na);
240       break;
241
242     case rbc_distance:
243       dx = na-nc;
244       dy = nb-nd;
245       nout = sqrt(dx*dx+dy*dy);
246       break;
247
248     case rbc_getp1:
249       i_gpix(images[0], na, nb, c_regs+codes->rout);
250       break;
251
252     case rbc_getp2:
253       i_gpix(images[1], na, nb, c_regs+codes->rout);
254       break;
255
256     case rbc_getp3:
257       i_gpix(images[2], na, nb, c_regs+codes->rout);
258       break;
259
260     case rbc_value:
261       nout = hsv_value(ca);
262       break;
263
264     case rbc_hue:
265       nout = hsv_hue(ca);
266       break;
267
268     case rbc_sat:
269       nout = hsv_sat(ca);
270       break;
271       
272     case rbc_hsv:
273       cout = make_hsv(na, nb, nc);
274       break;
275
276     case rbc_red:
277       nout = ca.rgb.r;
278       break;
279
280     case rbc_green:
281       nout = ca.rgb.g;
282       break;
283
284     case rbc_blue:
285       nout = ca.rgb.b;
286       break;
287
288     case rbc_rgb:
289       cout = make_rgb(na, nb, nc);
290       break;
291
292     case rbc_int:
293       nout = (int)(na);
294       break;
295
296     case rbc_if:
297       nout = na ? nb : nc;
298       break;
299
300     case rbc_ifp:
301       cout = na ? cb : cc;
302       break;
303
304     case rbc_le:
305       nout = na <= nb + n_epsilon(na,nb);
306       break;
307
308     case rbc_lt:
309       nout = na < nb;
310       break;
311
312     case rbc_ge:
313       nout = na >= nb - n_epsilon(na,nb);
314       break;
315
316     case rbc_gt:
317       nout = na > nb;
318       break;
319
320     case rbc_eq:
321       nout = abs(na-nb) <= n_epsilon(na,nb);
322       break;
323
324     case rbc_ne:
325       nout = abs(na-nb) > n_epsilon(na,nb);
326       break;
327
328     case rbc_and:
329       nout = na && nb;
330       break;
331  
332     case rbc_or:
333       nout = na || nb;
334       break;
335
336     case rbc_not:
337       nout = !na;
338       break;
339
340     case rbc_abs:
341       nout = abs(na);
342       break;
343
344     case rbc_ret:
345       return ca;
346       break;
347
348     case rbc_jump:
349       /* yes, order is important here */
350       code_count = count_base - codes->ra;
351       codes = codes_base + codes->ra;
352       continue;
353     
354     case rbc_jumpz:
355       if (!na) {        
356         /* yes, order is important here */
357         code_count = count_base - codes->rb;
358         codes = codes_base + codes->rb;
359         continue;
360       }
361       break;
362
363     case rbc_jumpnz:
364       if (na) {
365         /* yes, order is important here */
366         code_count = count_base - codes->rb;
367         codes = codes_base + codes->rb;
368         continue;
369       }
370       break;
371
372     case rbc_set:
373       nout = na;
374       break;
375
376     case rbc_setp:
377       cout = ca;
378       break;
379
380     case rbc_print:
381       printf("r%d is %g\n", codes->ra, na);
382       break;
383
384     default:
385       /*croak("bad opcode"); */
386       printf("bad op %d\n", codes->code);
387       return bcol;
388     }
389     --code_count;
390     ++codes;
391   }
392   return bcol;
393   /* croak("no return opcode"); */
394 }