Initial revision
[imager.git] / regmach.c
CommitLineData
02d1d628
AMH
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 */
22double 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 */
27double 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 */
58double 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
69i_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
126i_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
164static i_color bcol = {{ 0 }};
165
166i_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}