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 */ | |
22 | double 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 */ | |
27 | double 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 */ | |
58 | double 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 | ||
69 | i_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 | ||
126 | i_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 | |
164 | static i_color bcol = {{ 0 }}; | |
165 | ||
166 | i_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 | } |