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