avoid an unneeded check in the FT1 has_chars() method implementation
[imager.git] / regmach.c
1 #include "regmach.h"
2 #include <float.h>
3 #include "imageri.h"
4
5 /*#define DEBUG*/
6 #ifdef DEBUG
7 #define DBG(x) printf x
8 #else
9 #define DBG(x) 
10 #endif
11
12 static float MAX_EXP_ARG; /* = log(DBL_MAX); */
13
14
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 */
27 static double hsv_value(i_color color) {
28   return i_max(i_max(color.rgb.r, color.rgb.g), color.rgb.b) / 255.0;
29 }
30
31 /* returns the hue (color) of color from 0 to 360 */
32 static double hsv_hue(i_color color) {
33   int val;
34   int temp;
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));
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 */
63 static double hsv_sat(i_color color) {
64   int value = i_max(i_max(color.rgb.r, color.rgb.g), color.rgb.b);
65   if (value == 0) {
66     return 0;
67   }
68   else {
69     int temp = i_min(i_min(color.rgb.r, color.rgb.g), color.rgb.b);
70     return (value - temp) / (double)value;
71   }
72 }
73
74 static i_color make_hsv(double hue, double sat, double val, int alpha) {
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   }
127   c.rgba.a = alpha;
128
129   return c;
130 }
131
132 static i_color make_rgb(int r, int g, int b, int a) {
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
150   c.rgba.a = a;
151
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
171 #define n_epsilon(x, y) (fabs(x)+fabs(y))*0.001
172 static i_color bcol = {{ 0 }};
173
174 i_color i_rm_run(struct rm_op codes[], size_t code_count, 
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;
181
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:
199       if (fabs(nb) < 1e-10)
200         nout = 1e10;
201       else
202         nout = na / nb;
203       break;
204       
205     case rbc_mod:
206       if (fabs(nb) > 1e-10) {
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;
220       break;
221
222     case rbc_multp:
223       cout = make_rgb(ca.rgb.r * nb, ca.rgb.g * nb, ca.rgb.b * nb, 255);
224       break;
225
226     case rbc_addp:
227       cout = make_rgb(ca.rgb.r + cb.rgb.r, ca.rgb.g + cb.rgb.g, 
228                       ca.rgb.b + cb.rgb.b, 255);
229       break;
230
231     case rbc_subtractp:
232       cout = make_rgb(ca.rgb.r - cb.rgb.r, ca.rgb.g - cb.rgb.g, 
233                       ca.rgb.b - cb.rgb.b, 255);
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);
260       if (images[0]->channels < 4) cout.rgba.a = 255;
261       break;
262
263     case rbc_getp2:
264       i_gpix(images[1], na, nb, c_regs+codes->rout);
265       if (images[1]->channels < 4) cout.rgba.a = 255;
266       break;
267
268     case rbc_getp3:
269       i_gpix(images[2], na, nb, c_regs+codes->rout);
270       if (images[2]->channels < 4) cout.rgba.a = 255;
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:
286       cout = make_hsv(na, nb, nc, 255);
287       break;
288
289     case rbc_hsva:
290       cout = make_hsv(na, nb, nc, nd);
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
305     case rbc_alpha:
306       nout = ca.rgba.a;
307       break;
308
309     case rbc_rgb:
310       cout = make_rgb(na, nb, nc, 255);
311       break;
312
313     case rbc_rgba:
314       cout = make_rgb(na, nb, nc, nd);
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:
346       nout = fabs(na-nb) <= n_epsilon(na,nb);
347       break;
348
349     case rbc_ne:
350       nout = fabs(na-nb) > n_epsilon(na,nb);
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:
366       nout = fabs(na);
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
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
424     case rbc_print:
425       nout = na;
426       printf("r%d is %g\n", codes->ra, na);
427       break;
428
429     case rbc_det:
430       nout = na*nd-nb*nc;
431       break;
432
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 }