]> git.imager.perl.org - imager.git/blame - regmach.c
All the little fixup changes for the 0.42 release.
[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 */
b33c08f8
TC
22static double hsv_value(i_color color) {
23 return i_max(i_max(color.rgb.r, color.rgb.g), color.rgb.b) / 255.0;
02d1d628
AMH
24}
25
26/* returns the hue (color) of color from 0 to 360 */
b33c08f8 27static double hsv_hue(i_color color) {
02d1d628
AMH
28 int val;
29 int temp;
b33c08f8
TC
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));
02d1d628
AMH
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 */
b33c08f8
TC
58static double hsv_sat(i_color color) {
59 int value = i_max(i_max(color.rgb.r, color.rgb.g), color.rgb.b);
02d1d628
AMH
60 if (value == 0) {
61 return 0;
62 }
63 else {
b33c08f8 64 int temp = i_min(i_max(color.rgb.r, color.rgb.g), color.rgb.b);
02d1d628
AMH
65 return (value - temp) / (double)value;
66 }
67}
68
e5744e01 69static i_color make_hsv(double hue, double sat, double val, int alpha) {
02d1d628
AMH
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 }
e5744e01 122 c.rgba.a = alpha;
02d1d628
AMH
123
124 return c;
125}
126
e5744e01 127static i_color make_rgb(int r, int g, int b, int a) {
02d1d628
AMH
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
e5744e01
TC
145 c.rgba.a = a;
146
02d1d628
AMH
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
167static i_color bcol = {{ 0 }};
168
b33c08f8 169i_color i_rm_run(struct rm_op codes[], size_t code_count,
02d1d628
AMH
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:
e5744e01 216 cout = make_rgb(ca.rgb.r * nb, ca.rgb.g * nb, ca.rgb.b * nb, 255);
02d1d628
AMH
217 break;
218
219 case rbc_addp:
220 cout = make_rgb(ca.rgb.r + cb.rgb.r, ca.rgb.g + cb.rgb.g,
e5744e01 221 ca.rgb.b + cb.rgb.b, 255);
02d1d628
AMH
222 break;
223
224 case rbc_subtractp:
225 cout = make_rgb(ca.rgb.r - cb.rgb.r, ca.rgb.g - cb.rgb.g,
e5744e01 226 ca.rgb.b - cb.rgb.b, 255);
02d1d628
AMH
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:
e5744e01
TC
276 cout = make_hsv(na, nb, nc, 255);
277 break;
278
279 case rbc_hsva:
280 cout = make_hsv(na, nb, nc, nd);
02d1d628
AMH
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
e5744e01
TC
295 case rbc_alpha:
296 nout = ca.rgba.a;
297 break;
298
02d1d628 299 case rbc_rgb:
e5744e01
TC
300 cout = make_rgb(na, nb, nc, 255);
301 break;
302
303 case rbc_rgba:
304 cout = make_rgb(na, nb, nc, nd);
02d1d628
AMH
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}