ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/context.c
Revision: 1.29
Committed: Mon Jan 3 20:30:21 2011 UTC (13 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.28: +1 -116 lines
Log Message:
Separated color manipulation routines

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: context.c,v 1.28 2003/07/27 22:12:02 schorsch Exp $";
3 #endif
4 /*
5 * Context handlers
6 */
7
8 #include <stdio.h>
9 #include <math.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "parser.h"
13 #include "lookup.h"
14
15 /* default context values */
16 static C_MATERIAL c_dfmaterial = C_DEFMATERIAL;
17 static C_VERTEX c_dfvertex = C_DEFVERTEX;
18
19 /* the unnamed contexts */
20 static C_COLOR c_uncolor = C_DEFCOLOR;
21 static C_MATERIAL c_unmaterial = C_DEFMATERIAL;
22 static C_VERTEX c_unvertex = C_DEFVERTEX;
23
24 /* the current contexts */
25 C_COLOR *c_ccolor = &c_uncolor;
26 char *c_ccname = NULL;
27 C_MATERIAL *c_cmaterial = &c_unmaterial;
28 char *c_cmname = NULL;
29 C_VERTEX *c_cvertex = &c_unvertex;
30 char *c_cvname = NULL;
31
32 static LUTAB clr_tab = LU_SINIT(free,free); /* color lookup table */
33 static LUTAB mat_tab = LU_SINIT(free,free); /* material lookup table */
34 static LUTAB vtx_tab = LU_SINIT(free,free); /* vertex lookup table */
35
36 static int setspectrum();
37 static int setbbtemp();
38 static void mixcolors();
39
40
41 int
42 c_hcolor(ac, av) /* handle color entity */
43 int ac;
44 register char **av;
45 {
46 double w, wsum;
47 register int i;
48 register LUENT *lp;
49
50 switch (mg_entity(av[0])) {
51 case MG_E_COLOR: /* get/set color context */
52 if (ac > 4)
53 return(MG_EARGC);
54 if (ac == 1) { /* set unnamed color context */
55 c_uncolor = c_dfcolor;
56 c_ccolor = &c_uncolor;
57 c_ccname = NULL;
58 return(MG_OK);
59 }
60 if (!isname(av[1]))
61 return(MG_EILL);
62 lp = lu_find(&clr_tab, av[1]); /* lookup context */
63 if (lp == NULL)
64 return(MG_EMEM);
65 c_ccname = lp->key;
66 c_ccolor = (C_COLOR *)lp->data;
67 if (ac == 2) { /* reestablish previous context */
68 if (c_ccolor == NULL)
69 return(MG_EUNDEF);
70 return(MG_OK);
71 }
72 if (av[2][0] != '=' || av[2][1])
73 return(MG_ETYPE);
74 if (c_ccolor == NULL) { /* create new color context */
75 lp->key = (char *)malloc(strlen(av[1])+1);
76 if (lp->key == NULL)
77 return(MG_EMEM);
78 strcpy(lp->key, av[1]);
79 lp->data = (char *)malloc(sizeof(C_COLOR));
80 if (lp->data == NULL)
81 return(MG_EMEM);
82 c_ccname = lp->key;
83 c_ccolor = (C_COLOR *)lp->data;
84 c_ccolor->clock = 0;
85 c_ccolor->client_data = NULL;
86 }
87 i = c_ccolor->clock;
88 if (ac == 3) { /* use default template */
89 *c_ccolor = c_dfcolor;
90 c_ccolor->clock = i + 1;
91 return(MG_OK);
92 }
93 lp = lu_find(&clr_tab, av[3]); /* lookup template */
94 if (lp == NULL)
95 return(MG_EMEM);
96 if (lp->data == NULL)
97 return(MG_EUNDEF);
98 *c_ccolor = *(C_COLOR *)lp->data;
99 c_ccolor->clock = i + 1;
100 return(MG_OK);
101 case MG_E_CXY: /* assign CIE XY value */
102 if (ac != 3)
103 return(MG_EARGC);
104 if (!isflt(av[1]) | !isflt(av[2]))
105 return(MG_ETYPE);
106 c_ccolor->cx = atof(av[1]);
107 c_ccolor->cy = atof(av[2]);
108 c_ccolor->flags = C_CDXY|C_CSXY;
109 if ((c_ccolor->cx < 0.) | (c_ccolor->cy < 0.) |
110 (c_ccolor->cx + c_ccolor->cy > 1.))
111 return(MG_EILL);
112 c_ccolor->clock++;
113 return(MG_OK);
114 case MG_E_CSPEC: /* assign spectral values */
115 if (ac < 5)
116 return(MG_EARGC);
117 if (!isflt(av[1]) | !isflt(av[2]))
118 return(MG_ETYPE);
119 return(setspectrum(c_ccolor, atof(av[1]), atof(av[2]),
120 ac-3, av+3));
121 case MG_E_CCT: /* assign black body spectrum */
122 if (ac != 2)
123 return(MG_EARGC);
124 if (!isflt(av[1]))
125 return(MG_ETYPE);
126 return(setbbtemp(c_ccolor, atof(av[1])));
127 case MG_E_CMIX: /* mix colors */
128 if (ac < 5 || (ac-1)%2)
129 return(MG_EARGC);
130 if (!isflt(av[1]))
131 return(MG_ETYPE);
132 wsum = atof(av[1]);
133 if ((lp = lu_find(&clr_tab, av[2])) == NULL)
134 return(MG_EMEM);
135 if (lp->data == NULL)
136 return(MG_EUNDEF);
137 *c_ccolor = *(C_COLOR *)lp->data;
138 for (i = 3; i < ac; i += 2) {
139 if (!isflt(av[i]))
140 return(MG_ETYPE);
141 w = atof(av[i]);
142 if ((lp = lu_find(&clr_tab, av[i+1])) == NULL)
143 return(MG_EMEM);
144 if (lp->data == NULL)
145 return(MG_EUNDEF);
146 mixcolors(c_ccolor, wsum, c_ccolor,
147 w, (C_COLOR *)lp->data);
148 wsum += w;
149 }
150 if (wsum <= 0.)
151 return(MG_EILL);
152 c_ccolor->clock++;
153 return(MG_OK);
154 }
155 return(MG_EUNK);
156 }
157
158
159 int
160 c_hmaterial(ac, av) /* handle material entity */
161 int ac;
162 register char **av;
163 {
164 int i;
165 register LUENT *lp;
166
167 switch (mg_entity(av[0])) {
168 case MG_E_MATERIAL: /* get/set material context */
169 if (ac > 4)
170 return(MG_EARGC);
171 if (ac == 1) { /* set unnamed material context */
172 c_unmaterial = c_dfmaterial;
173 c_cmaterial = &c_unmaterial;
174 c_cmname = NULL;
175 return(MG_OK);
176 }
177 if (!isname(av[1]))
178 return(MG_EILL);
179 lp = lu_find(&mat_tab, av[1]); /* lookup context */
180 if (lp == NULL)
181 return(MG_EMEM);
182 c_cmname = lp->key;
183 c_cmaterial = (C_MATERIAL *)lp->data;
184 if (ac == 2) { /* reestablish previous context */
185 if (c_cmaterial == NULL)
186 return(MG_EUNDEF);
187 return(MG_OK);
188 }
189 if (av[2][0] != '=' || av[2][1])
190 return(MG_ETYPE);
191 if (c_cmaterial == NULL) { /* create new material */
192 lp->key = (char *)malloc(strlen(av[1])+1);
193 if (lp->key == NULL)
194 return(MG_EMEM);
195 strcpy(lp->key, av[1]);
196 lp->data = (char *)malloc(sizeof(C_MATERIAL));
197 if (lp->data == NULL)
198 return(MG_EMEM);
199 c_cmname = lp->key;
200 c_cmaterial = (C_MATERIAL *)lp->data;
201 c_cmaterial->clock = 0;
202 c_cmaterial->client_data = NULL;
203 }
204 i = c_cmaterial->clock;
205 if (ac == 3) { /* use default template */
206 *c_cmaterial = c_dfmaterial;
207 c_cmaterial->clock = i + 1;
208 return(MG_OK);
209 }
210 lp = lu_find(&mat_tab, av[3]); /* lookup template */
211 if (lp == NULL)
212 return(MG_EMEM);
213 if (lp->data == NULL)
214 return(MG_EUNDEF);
215 *c_cmaterial = *(C_MATERIAL *)lp->data;
216 c_cmaterial->clock = i + 1;
217 return(MG_OK);
218 case MG_E_IR: /* set index of refraction */
219 if (ac != 3)
220 return(MG_EARGC);
221 if (!isflt(av[1]) | !isflt(av[2]))
222 return(MG_ETYPE);
223 c_cmaterial->nr = atof(av[1]);
224 c_cmaterial->ni = atof(av[2]);
225 if (c_cmaterial->nr <= FTINY)
226 return(MG_EILL);
227 c_cmaterial->clock++;
228 return(MG_OK);
229 case MG_E_RD: /* set diffuse reflectance */
230 if (ac != 2)
231 return(MG_EARGC);
232 if (!isflt(av[1]))
233 return(MG_ETYPE);
234 c_cmaterial->rd = atof(av[1]);
235 if ((c_cmaterial->rd < 0.) | (c_cmaterial->rd > 1.))
236 return(MG_EILL);
237 c_cmaterial->rd_c = *c_ccolor;
238 c_cmaterial->clock++;
239 return(MG_OK);
240 case MG_E_ED: /* set diffuse emittance */
241 if (ac != 2)
242 return(MG_EARGC);
243 if (!isflt(av[1]))
244 return(MG_ETYPE);
245 c_cmaterial->ed = atof(av[1]);
246 if (c_cmaterial->ed < 0.)
247 return(MG_EILL);
248 c_cmaterial->ed_c = *c_ccolor;
249 c_cmaterial->clock++;
250 return(MG_OK);
251 case MG_E_TD: /* set diffuse transmittance */
252 if (ac != 2)
253 return(MG_EARGC);
254 if (!isflt(av[1]))
255 return(MG_ETYPE);
256 c_cmaterial->td = atof(av[1]);
257 if ((c_cmaterial->td < 0.) | (c_cmaterial->td > 1.))
258 return(MG_EILL);
259 c_cmaterial->td_c = *c_ccolor;
260 c_cmaterial->clock++;
261 return(MG_OK);
262 case MG_E_RS: /* set specular reflectance */
263 if (ac != 3)
264 return(MG_EARGC);
265 if (!isflt(av[1]) | !isflt(av[2]))
266 return(MG_ETYPE);
267 c_cmaterial->rs = atof(av[1]);
268 c_cmaterial->rs_a = atof(av[2]);
269 if ((c_cmaterial->rs < 0.) | (c_cmaterial->rs > 1.) |
270 (c_cmaterial->rs_a < 0.))
271 return(MG_EILL);
272 c_cmaterial->rs_c = *c_ccolor;
273 c_cmaterial->clock++;
274 return(MG_OK);
275 case MG_E_TS: /* set specular transmittance */
276 if (ac != 3)
277 return(MG_EARGC);
278 if (!isflt(av[1]) | !isflt(av[2]))
279 return(MG_ETYPE);
280 c_cmaterial->ts = atof(av[1]);
281 c_cmaterial->ts_a = atof(av[2]);
282 if ((c_cmaterial->ts < 0.) | (c_cmaterial->ts > 1.) |
283 (c_cmaterial->ts_a < 0.))
284 return(MG_EILL);
285 c_cmaterial->ts_c = *c_ccolor;
286 c_cmaterial->clock++;
287 return(MG_OK);
288 case MG_E_SIDES: /* set number of sides */
289 if (ac != 2)
290 return(MG_EARGC);
291 if (!isint(av[1]))
292 return(MG_ETYPE);
293 i = atoi(av[1]);
294 if (i == 1)
295 c_cmaterial->sided = 1;
296 else if (i == 2)
297 c_cmaterial->sided = 0;
298 else
299 return(MG_EILL);
300 c_cmaterial->clock++;
301 return(MG_OK);
302 }
303 return(MG_EUNK);
304 }
305
306
307 int
308 c_hvertex(ac, av) /* handle a vertex entity */
309 int ac;
310 register char **av;
311 {
312 int i;
313 register LUENT *lp;
314
315 switch (mg_entity(av[0])) {
316 case MG_E_VERTEX: /* get/set vertex context */
317 if (ac > 4)
318 return(MG_EARGC);
319 if (ac == 1) { /* set unnamed vertex context */
320 c_unvertex = c_dfvertex;
321 c_cvertex = &c_unvertex;
322 c_cvname = NULL;
323 return(MG_OK);
324 }
325 if (!isname(av[1]))
326 return(MG_EILL);
327 lp = lu_find(&vtx_tab, av[1]); /* lookup context */
328 if (lp == NULL)
329 return(MG_EMEM);
330 c_cvname = lp->key;
331 c_cvertex = (C_VERTEX *)lp->data;
332 if (ac == 2) { /* reestablish previous context */
333 if (c_cvertex == NULL)
334 return(MG_EUNDEF);
335 return(MG_OK);
336 }
337 if (av[2][0] != '=' || av[2][1])
338 return(MG_ETYPE);
339 if (c_cvertex == NULL) { /* create new vertex context */
340 lp->key = (char *)malloc(strlen(av[1])+1);
341 if (lp->key == NULL)
342 return(MG_EMEM);
343 strcpy(lp->key, av[1]);
344 lp->data = (char *)malloc(sizeof(C_VERTEX));
345 if (lp->data == NULL)
346 return(MG_EMEM);
347 c_cvname = lp->key;
348 c_cvertex = (C_VERTEX *)lp->data;
349 c_cvertex->clock = 0;
350 c_cvertex->client_data = NULL;
351 }
352 i = c_cvertex->clock;
353 if (ac == 3) { /* use default template */
354 *c_cvertex = c_dfvertex;
355 c_cvertex->clock = i + 1;
356 return(MG_OK);
357 }
358 lp = lu_find(&vtx_tab, av[3]); /* lookup template */
359 if (lp == NULL)
360 return(MG_EMEM);
361 if (lp->data == NULL)
362 return(MG_EUNDEF);
363 *c_cvertex = *(C_VERTEX *)lp->data;
364 c_cvertex->clock = i + 1;
365 return(MG_OK);
366 case MG_E_POINT: /* set point */
367 if (ac != 4)
368 return(MG_EARGC);
369 if (!isflt(av[1]) | !isflt(av[2]) | !isflt(av[3]))
370 return(MG_ETYPE);
371 c_cvertex->p[0] = atof(av[1]);
372 c_cvertex->p[1] = atof(av[2]);
373 c_cvertex->p[2] = atof(av[3]);
374 c_cvertex->clock++;
375 return(MG_OK);
376 case MG_E_NORMAL: /* set normal */
377 if (ac != 4)
378 return(MG_EARGC);
379 if (!isflt(av[1]) | !isflt(av[2]) | !isflt(av[3]))
380 return(MG_ETYPE);
381 c_cvertex->n[0] = atof(av[1]);
382 c_cvertex->n[1] = atof(av[2]);
383 c_cvertex->n[2] = atof(av[3]);
384 (void)normalize(c_cvertex->n);
385 c_cvertex->clock++;
386 return(MG_OK);
387 }
388 return(MG_EUNK);
389 }
390
391
392 void
393 c_clearall() /* empty context tables */
394 {
395 c_uncolor = c_dfcolor;
396 c_ccolor = &c_uncolor;
397 c_ccname = NULL;
398 lu_done(&clr_tab);
399 c_unmaterial = c_dfmaterial;
400 c_cmaterial = &c_unmaterial;
401 c_cmname = NULL;
402 lu_done(&mat_tab);
403 c_unvertex = c_dfvertex;
404 c_cvertex = &c_unvertex;
405 c_cvname = NULL;
406 lu_done(&vtx_tab);
407 }
408
409
410 C_MATERIAL *
411 c_getmaterial(name) /* get a named material */
412 char *name;
413 {
414 register LUENT *lp;
415
416 if ((lp = lu_find(&mat_tab, name)) == NULL)
417 return(NULL);
418 return((C_MATERIAL *)lp->data);
419 }
420
421
422 C_VERTEX *
423 c_getvert(name) /* get a named vertex */
424 char *name;
425 {
426 register LUENT *lp;
427
428 if ((lp = lu_find(&vtx_tab, name)) == NULL)
429 return(NULL);
430 return((C_VERTEX *)lp->data);
431 }
432
433
434 C_COLOR *
435 c_getcolor(name) /* get a named color */
436 char *name;
437 {
438 register LUENT *lp;
439
440 if ((lp = lu_find(&clr_tab, name)) == NULL)
441 return(NULL);
442 return((C_COLOR *)lp->data);
443 }
444
445
446 static int
447 setspectrum(clr, wlmin, wlmax, ac, av) /* convert a spectrum */
448 register C_COLOR *clr;
449 double wlmin, wlmax;
450 int ac;
451 char **av;
452 {
453 double scale;
454 float va[C_CNSS];
455 register int i, pos;
456 int n, imax;
457 int wl;
458 double wl0, wlstep;
459 double boxpos, boxstep;
460 /* check bounds */
461 if ((wlmax <= C_CMINWL) | (wlmax <= wlmin) | (wlmin >= C_CMAXWL))
462 return(MG_EILL);
463 wlstep = (wlmax - wlmin)/(ac-1);
464 while (wlmin < C_CMINWL) {
465 wlmin += wlstep;
466 ac--; av++;
467 }
468 while (wlmax > C_CMAXWL) {
469 wlmax -= wlstep;
470 ac--;
471 }
472 imax = ac; /* box filter if necessary */
473 boxpos = 0;
474 boxstep = 1;
475 if (wlstep < C_CWLI) {
476 imax = (wlmax - wlmin)/C_CWLI + (1-FTINY);
477 boxpos = (wlmin - C_CMINWL)/C_CWLI;
478 boxstep = wlstep/C_CWLI;
479 wlstep = C_CWLI;
480 }
481 scale = 0.; /* get values and maximum */
482 pos = 0;
483 for (i = 0; i < imax; i++) {
484 va[i] = 0.; n = 0;
485 while (boxpos < i+.5 && pos < ac) {
486 if (!isflt(av[pos]))
487 return(MG_ETYPE);
488 va[i] += atof(av[pos++]);
489 n++;
490 boxpos += boxstep;
491 }
492 if (n > 1)
493 va[i] /= (double)n;
494 if (va[i] > scale)
495 scale = va[i];
496 else if (va[i] < -scale)
497 scale = -va[i];
498 }
499 if (scale <= FTINY)
500 return(MG_EILL);
501 scale = C_CMAXV / scale;
502 clr->ssum = 0; /* convert to our spacing */
503 wl0 = wlmin;
504 pos = 0;
505 for (i = 0, wl = C_CMINWL; i < C_CNSS; i++, wl += C_CWLI)
506 if ((wl < wlmin) | (wl > wlmax))
507 clr->ssamp[i] = 0;
508 else {
509 while (wl0 + wlstep < wl+FTINY) {
510 wl0 += wlstep;
511 pos++;
512 }
513 if ((wl+FTINY >= wl0) & (wl-FTINY <= wl0))
514 clr->ssamp[i] = scale*va[pos] + .5;
515 else /* interpolate if necessary */
516 clr->ssamp[i] = .5 + scale / wlstep *
517 ( va[pos]*(wl0+wlstep - wl) +
518 va[pos+1]*(wl - wl0) );
519 clr->ssum += clr->ssamp[i];
520 }
521 clr->flags = C_CDSPEC|C_CSSPEC;
522 clr->clock++;
523 return(MG_OK);
524 }
525
526
527 static void
528 mixcolors(cres, w1, c1, w2, c2) /* mix two colors according to weights given */
529 register C_COLOR *cres, *c1, *c2;
530 double w1, w2;
531 {
532 double scale;
533 float cmix[C_CNSS];
534 register int i;
535
536 if ((c1->flags|c2->flags) & C_CDSPEC) { /* spectral mixing */
537 c_ccvt(c1, C_CSSPEC|C_CSEFF);
538 c_ccvt(c2, C_CSSPEC|C_CSEFF);
539 w1 /= c1->eff*c1->ssum;
540 w2 /= c2->eff*c2->ssum;
541 scale = 0.;
542 for (i = 0; i < C_CNSS; i++) {
543 cmix[i] = w1*c1->ssamp[i] + w2*c2->ssamp[i];
544 if (cmix[i] > scale)
545 scale = cmix[i];
546 }
547 scale = C_CMAXV / scale;
548 cres->ssum = 0;
549 for (i = 0; i < C_CNSS; i++)
550 cres->ssum += cres->ssamp[i] = scale*cmix[i] + .5;
551 cres->flags = C_CDSPEC|C_CSSPEC;
552 } else { /* CIE xy mixing */
553 c_ccvt(c1, C_CSXY);
554 c_ccvt(c2, C_CSXY);
555 scale = w1/c1->cy + w2/c2->cy;
556 if (scale == 0.)
557 return;
558 scale = 1. / scale;
559 cres->cx = (c1->cx*w1/c1->cy + c2->cx*w2/c2->cy) * scale;
560 cres->cy = (w1 + w2) * scale;
561 cres->flags = C_CDXY|C_CSXY;
562 }
563 }
564
565
566 #define C1 3.741832e-16 /* W-m^2 */
567 #define C2 1.4388e-2 /* m-K */
568
569 #define bbsp(l,t) (C1/((l)*(l)*(l)*(l)*(l)*(exp(C2/((t)*(l)))-1.)))
570 #define bblm(t) (C2/5./(t))
571
572 static int
573 setbbtemp(clr, tk) /* set black body spectrum */
574 register C_COLOR *clr;
575 double tk;
576 {
577 double sf, wl;
578 register int i;
579
580 if (tk < 1000)
581 return(MG_EILL);
582 wl = bblm(tk); /* scalefactor based on peak */
583 if (wl < C_CMINWL*1e-9)
584 wl = C_CMINWL*1e-9;
585 else if (wl > C_CMAXWL*1e-9)
586 wl = C_CMAXWL*1e-9;
587 sf = C_CMAXV/bbsp(wl,tk);
588 clr->ssum = 0;
589 for (i = 0; i < C_CNSS; i++) {
590 wl = (C_CMINWL + i*C_CWLI)*1e-9;
591 clr->ssum += clr->ssamp[i] = sf*bbsp(wl,tk) + .5;
592 }
593 clr->flags = C_CDSPEC|C_CSSPEC;
594 clr->clock++;
595 return(MG_OK);
596 }
597
598 #undef C1
599 #undef C2
600 #undef bbsp
601 #undef bblm