]>
Commit | Line | Data |
---|---|---|
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 |
22 | static 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 | 27 | static 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 |
58 | static 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 | 69 | static 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 | 127 | static 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 | |
167 | static i_color bcol = {{ 0 }}; | |
168 | ||
b33c08f8 | 169 | i_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 | } |