| 1 | /* Copyright (c) 1994 Regents of the University of California */ | 
| 2 |  | 
| 3 | #ifndef lint | 
| 4 | static char SCCSid[] = "$SunId$ LBL"; | 
| 5 | #endif | 
| 6 |  | 
| 7 | /* | 
| 8 | * Context handlers | 
| 9 | */ | 
| 10 |  | 
| 11 | #include <stdio.h> | 
| 12 | #include <math.h> | 
| 13 | #include <string.h> | 
| 14 | #include "parser.h" | 
| 15 | #include "lookup.h" | 
| 16 |  | 
| 17 | /* default context values */ | 
| 18 | static C_COLOR          c_dfcolor = C_DEFCOLOR; | 
| 19 | static C_MATERIAL       c_dfmaterial = C_DEFMATERIAL; | 
| 20 | static C_VERTEX         c_dfvertex = C_DEFVERTEX; | 
| 21 |  | 
| 22 | /* the unnamed contexts */ | 
| 23 | static C_COLOR          c_uncolor = C_DEFCOLOR; | 
| 24 | static C_MATERIAL       c_unmaterial = C_DEFMATERIAL; | 
| 25 | static C_VERTEX         c_unvertex = C_DEFVERTEX; | 
| 26 |  | 
| 27 | /* the current contexts */ | 
| 28 | C_COLOR         *c_ccolor = &c_uncolor; | 
| 29 | char            *c_ccname = NULL; | 
| 30 | C_MATERIAL      *c_cmaterial = &c_unmaterial; | 
| 31 | char            *c_cmname = NULL; | 
| 32 | C_VERTEX        *c_cvertex = &c_unvertex; | 
| 33 | char            *c_cvname = NULL; | 
| 34 |  | 
| 35 | static LUTAB    clr_tab = LU_SINIT(free,free);  /* color lookup table */ | 
| 36 | static LUTAB    mat_tab = LU_SINIT(free,free);  /* material lookup table */ | 
| 37 | static LUTAB    vtx_tab = LU_SINIT(free,free);  /* vertex lookup table */ | 
| 38 |  | 
| 39 | /* CIE 1931 Standard Observer curves */ | 
| 40 | static C_COLOR  cie_xf = { 1, C_CDSPEC|C_CSSPEC|C_CSXY|C_CSEFF, | 
| 41 | {14,42,143,435,1344,2839,3483,3362,2908,1954,956, | 
| 42 | 320,49,93,633,1655,2904,4334,5945,7621,9163,10263, | 
| 43 | 10622,10026,8544,6424,4479,2835,1649,874,468,227, | 
| 44 | 114,58,29,14,7,3,2,1,0}, 106836L, .467, .368, 362.230 | 
| 45 | }; | 
| 46 | static C_COLOR  cie_yf = { 1, C_CDSPEC|C_CSSPEC|C_CSXY|C_CSEFF, | 
| 47 | {0,1,4,12,40,116,230,380,600,910,1390,2080,3230, | 
| 48 | 5030,7100,8620,9540,9950,9950,9520,8700,7570,6310, | 
| 49 | 5030,3810,2650,1750,1070,610,320,170,82,41,21,10, | 
| 50 | 5,2,1,1,0,0}, 106856L, .398, .542, 493.525 | 
| 51 | }; | 
| 52 | static C_COLOR  cie_zf = { 1, C_CDSPEC|C_CSSPEC|C_CSXY|C_CSEFF, | 
| 53 | {65,201,679,2074,6456,13856,17471,17721,16692, | 
| 54 | 12876,8130,4652,2720,1582,782,422,203,87,39,21,17, | 
| 55 | 11,8,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, | 
| 56 | 106770L, .147, .077, 54.363 | 
| 57 | }; | 
| 58 | /* Derived CIE 1931 Primaries (imaginary) */ | 
| 59 | static C_COLOR  cie_xp = { 1, C_CDSPEC|C_CSSPEC|C_CSXY, | 
| 60 | {-174,-198,-195,-197,-202,-213,-235,-272,-333, | 
| 61 | -444,-688,-1232,-2393,-4497,-6876,-6758,-5256, | 
| 62 | -3100,-815,1320,3200,4782,5998,6861,7408,7754, | 
| 63 | 7980,8120,8199,8240,8271,8292,8309,8283,8469, | 
| 64 | 8336,8336,8336,8336,8336,8336}, | 
| 65 | 127424L, 1., .0, | 
| 66 | }; | 
| 67 | static C_COLOR  cie_yp = { 1, C_CDSPEC|C_CSSPEC|C_CSXY, | 
| 68 | {-451,-431,-431,-430,-427,-417,-399,-366,-312, | 
| 69 | -204,57,691,2142,4990,8810,9871,9122,7321,5145, | 
| 70 | 3023,1123,-473,-1704,-2572,-3127,-3474,-3704, | 
| 71 | -3846,-3927,-3968,-3999,-4021,-4038,-4012,-4201, | 
| 72 | -4066,-4066,-4066,-4066,-4066,-4066}, | 
| 73 | -23035L, .0, 1., | 
| 74 | }; | 
| 75 | static C_COLOR  cie_zp = { 1, C_CDSPEC|C_CSSPEC|C_CSXY, | 
| 76 | {4051,4054,4052,4053,4054,4056,4059,4064,4071, | 
| 77 | 4074,4056,3967,3677,2933,1492,313,-440,-795, | 
| 78 | -904,-918,-898,-884,-869,-863,-855,-855,-851, | 
| 79 | -848,-847,-846,-846,-846,-845,-846,-843,-845, | 
| 80 | -845,-845,-845,-845,-845}, | 
| 81 | 36057L, .0, .0, | 
| 82 | }; | 
| 83 |  | 
| 84 | static int      setspectrum(); | 
| 85 | static int      setbbtemp(); | 
| 86 | static void     mixcolors(); | 
| 87 |  | 
| 88 |  | 
| 89 | int | 
| 90 | c_hcolor(ac, av)                /* handle color entity */ | 
| 91 | int     ac; | 
| 92 | register char   **av; | 
| 93 | { | 
| 94 | double  w, wsum; | 
| 95 | register int    i; | 
| 96 | register LUENT  *lp; | 
| 97 |  | 
| 98 | switch (mg_entity(av[0])) { | 
| 99 | case MG_E_COLOR:        /* get/set color context */ | 
| 100 | if (ac > 4) | 
| 101 | return(MG_EARGC); | 
| 102 | if (ac == 1) {          /* set unnamed color context */ | 
| 103 | c_uncolor = c_dfcolor; | 
| 104 | c_ccolor = &c_uncolor; | 
| 105 | c_ccname = NULL; | 
| 106 | return(MG_OK); | 
| 107 | } | 
| 108 | lp = lu_find(&clr_tab, av[1]);  /* lookup context */ | 
| 109 | if (lp == NULL) | 
| 110 | return(MG_EMEM); | 
| 111 | c_ccname = lp->key; | 
| 112 | c_ccolor = (C_COLOR *)lp->data; | 
| 113 | if (ac == 2) {          /* reestablish previous context */ | 
| 114 | if (c_ccolor == NULL) | 
| 115 | return(MG_EUNDEF); | 
| 116 | return(MG_OK); | 
| 117 | } | 
| 118 | if (av[2][0] != '=' || av[2][1]) | 
| 119 | return(MG_ETYPE); | 
| 120 | if (c_ccolor == NULL) { /* create new color context */ | 
| 121 | lp->key = (char *)malloc(strlen(av[1])+1); | 
| 122 | if (lp->key == NULL) | 
| 123 | return(MG_EMEM); | 
| 124 | strcpy(lp->key, av[1]); | 
| 125 | lp->data = (char *)malloc(sizeof(C_COLOR)); | 
| 126 | if (lp->data == NULL) | 
| 127 | return(MG_EMEM); | 
| 128 | c_ccname = lp->key; | 
| 129 | c_ccolor = (C_COLOR *)lp->data; | 
| 130 | c_ccolor->clock = 0; | 
| 131 | } | 
| 132 | i = c_ccolor->clock; | 
| 133 | if (ac == 3) {          /* use default template */ | 
| 134 | *c_ccolor = c_dfcolor; | 
| 135 | c_ccolor->clock = i + 1; | 
| 136 | return(MG_OK); | 
| 137 | } | 
| 138 | lp = lu_find(&clr_tab, av[3]);  /* lookup template */ | 
| 139 | if (lp == NULL) | 
| 140 | return(MG_EMEM); | 
| 141 | if (lp->data == NULL) | 
| 142 | return(MG_EUNDEF); | 
| 143 | *c_ccolor = *(C_COLOR *)lp->data; | 
| 144 | c_ccolor->clock = i + 1; | 
| 145 | return(MG_OK); | 
| 146 | case MG_E_CXY:          /* assign CIE XY value */ | 
| 147 | if (ac != 3) | 
| 148 | return(MG_EARGC); | 
| 149 | if (!isflt(av[1]) | !isflt(av[2])) | 
| 150 | return(MG_ETYPE); | 
| 151 | c_ccolor->cx = atof(av[1]); | 
| 152 | c_ccolor->cy = atof(av[2]); | 
| 153 | c_ccolor->flags = C_CDXY|C_CSXY; | 
| 154 | if (c_ccolor->cx < 0. | c_ccolor->cy < 0. | | 
| 155 | c_ccolor->cx + c_ccolor->cy > 1.) | 
| 156 | return(MG_EILL); | 
| 157 | c_ccolor->clock++; | 
| 158 | return(MG_OK); | 
| 159 | case MG_E_CSPEC:        /* assign spectral values */ | 
| 160 | if (ac < 5) | 
| 161 | return(MG_EARGC); | 
| 162 | if (!isflt(av[1]) | !isflt(av[2])) | 
| 163 | return(MG_ETYPE); | 
| 164 | return(setspectrum(c_ccolor, atof(av[1]), atof(av[2]), | 
| 165 | ac-3, av+3)); | 
| 166 | case MG_E_CCT:          /* assign black body spectrum */ | 
| 167 | if (ac != 2) | 
| 168 | return(MG_EARGC); | 
| 169 | if (!isflt(av[1])) | 
| 170 | return(MG_ETYPE); | 
| 171 | return(setbbtemp(c_ccolor, atof(av[1]))); | 
| 172 | case MG_E_CMIX:         /* mix colors */ | 
| 173 | if (ac < 5 || (ac-1)%2) | 
| 174 | return(MG_EARGC); | 
| 175 | if (!isflt(av[1])) | 
| 176 | return(MG_ETYPE); | 
| 177 | wsum = atof(av[1]); | 
| 178 | if (wsum < 0.) | 
| 179 | return(MG_EILL); | 
| 180 | if ((lp = lu_find(&clr_tab, av[2])) == NULL) | 
| 181 | return(MG_EMEM); | 
| 182 | if (lp->data == NULL) | 
| 183 | return(MG_EUNDEF); | 
| 184 | *c_ccolor = *(C_COLOR *)lp->data; | 
| 185 | for (i = 3; i < ac; i += 2) { | 
| 186 | if (!isflt(av[i])) | 
| 187 | return(MG_ETYPE); | 
| 188 | w = atof(av[i]); | 
| 189 | if (w < 0.) | 
| 190 | return(MG_EILL); | 
| 191 | if ((lp = lu_find(&clr_tab, av[i+1])) == NULL) | 
| 192 | return(MG_EMEM); | 
| 193 | if (lp->data == NULL) | 
| 194 | return(MG_EUNDEF); | 
| 195 | mixcolors(c_ccolor, wsum, c_ccolor, | 
| 196 | w, (C_COLOR *)lp->data); | 
| 197 | wsum += w; | 
| 198 | } | 
| 199 | c_ccolor->clock++; | 
| 200 | return(MG_OK); | 
| 201 | } | 
| 202 | return(MG_EUNK); | 
| 203 | } | 
| 204 |  | 
| 205 |  | 
| 206 | int | 
| 207 | c_hmaterial(ac, av)             /* handle material entity */ | 
| 208 | int     ac; | 
| 209 | register char   **av; | 
| 210 | { | 
| 211 | int     i; | 
| 212 | register LUENT  *lp; | 
| 213 |  | 
| 214 | switch (mg_entity(av[0])) { | 
| 215 | case MG_E_MATERIAL:     /* get/set material context */ | 
| 216 | if (ac > 4) | 
| 217 | return(MG_EARGC); | 
| 218 | if (ac == 1) {          /* set unnamed material context */ | 
| 219 | c_unmaterial = c_dfmaterial; | 
| 220 | c_cmaterial = &c_unmaterial; | 
| 221 | c_cmname = NULL; | 
| 222 | return(MG_OK); | 
| 223 | } | 
| 224 | lp = lu_find(&mat_tab, av[1]);  /* lookup context */ | 
| 225 | if (lp == NULL) | 
| 226 | return(MG_EMEM); | 
| 227 | c_cmname = lp->key; | 
| 228 | c_cmaterial = (C_MATERIAL *)lp->data; | 
| 229 | if (ac == 2) {          /* reestablish previous context */ | 
| 230 | if (c_cmaterial == NULL) | 
| 231 | return(MG_EUNDEF); | 
| 232 | return(MG_OK); | 
| 233 | } | 
| 234 | if (av[2][0] != '=' || av[2][1]) | 
| 235 | return(MG_ETYPE); | 
| 236 | if (c_cmaterial == NULL) {      /* create new material */ | 
| 237 | lp->key = (char *)malloc(strlen(av[1])+1); | 
| 238 | if (lp->key == NULL) | 
| 239 | return(MG_EMEM); | 
| 240 | strcpy(lp->key, av[1]); | 
| 241 | lp->data = (char *)malloc(sizeof(C_MATERIAL)); | 
| 242 | if (lp->data == NULL) | 
| 243 | return(MG_EMEM); | 
| 244 | c_cmname = lp->key; | 
| 245 | c_cmaterial = (C_MATERIAL *)lp->data; | 
| 246 | c_cmaterial->clock = 0; | 
| 247 | } | 
| 248 | i = c_cmaterial->clock; | 
| 249 | if (ac == 3) {          /* use default template */ | 
| 250 | *c_cmaterial = c_dfmaterial; | 
| 251 | c_cmaterial->clock = i + 1; | 
| 252 | return(MG_OK); | 
| 253 | } | 
| 254 | lp = lu_find(&mat_tab, av[3]);  /* lookup template */ | 
| 255 | if (lp == NULL) | 
| 256 | return(MG_EMEM); | 
| 257 | if (lp->data == NULL) | 
| 258 | return(MG_EUNDEF); | 
| 259 | *c_cmaterial = *(C_MATERIAL *)lp->data; | 
| 260 | c_cmaterial->clock = i + 1; | 
| 261 | return(MG_OK); | 
| 262 | case MG_E_RD:           /* set diffuse reflectance */ | 
| 263 | if (ac != 2) | 
| 264 | return(MG_EARGC); | 
| 265 | if (!isflt(av[1])) | 
| 266 | return(MG_ETYPE); | 
| 267 | c_cmaterial->rd = atof(av[1]); | 
| 268 | if (c_cmaterial->rd < 0. | c_cmaterial->rd > 1.) | 
| 269 | return(MG_EILL); | 
| 270 | c_cmaterial->rd_c = *c_ccolor; | 
| 271 | c_cmaterial->clock++; | 
| 272 | return(MG_OK); | 
| 273 | case MG_E_ED:           /* set diffuse emittance */ | 
| 274 | if (ac != 2) | 
| 275 | return(MG_EARGC); | 
| 276 | if (!isflt(av[1])) | 
| 277 | return(MG_ETYPE); | 
| 278 | c_cmaterial->ed = atof(av[1]); | 
| 279 | if (c_cmaterial->ed < 0.) | 
| 280 | return(MG_EILL); | 
| 281 | c_cmaterial->ed_c = *c_ccolor; | 
| 282 | c_cmaterial->clock++; | 
| 283 | return(MG_OK); | 
| 284 | case MG_E_TD:           /* set diffuse transmittance */ | 
| 285 | if (ac != 2) | 
| 286 | return(MG_EARGC); | 
| 287 | if (!isflt(av[1])) | 
| 288 | return(MG_ETYPE); | 
| 289 | c_cmaterial->td = atof(av[1]); | 
| 290 | if (c_cmaterial->td < 0. | c_cmaterial->td > 1.) | 
| 291 | return(MG_EILL); | 
| 292 | c_cmaterial->td_c = *c_ccolor; | 
| 293 | c_cmaterial->clock++; | 
| 294 | return(MG_OK); | 
| 295 | case MG_E_RS:           /* set specular reflectance */ | 
| 296 | if (ac != 3) | 
| 297 | return(MG_EARGC); | 
| 298 | if (!isflt(av[1]) | !isflt(av[2])) | 
| 299 | return(MG_ETYPE); | 
| 300 | c_cmaterial->rs = atof(av[1]); | 
| 301 | c_cmaterial->rs_a = atof(av[2]); | 
| 302 | if (c_cmaterial->rs < 0. | c_cmaterial->rs > 1. | | 
| 303 | c_cmaterial->rs_a < 0.) | 
| 304 | return(MG_EILL); | 
| 305 | c_cmaterial->rs_c = *c_ccolor; | 
| 306 | c_cmaterial->clock++; | 
| 307 | return(MG_OK); | 
| 308 | case MG_E_TS:           /* set specular transmittance */ | 
| 309 | if (ac != 3) | 
| 310 | return(MG_EARGC); | 
| 311 | if (!isflt(av[1]) | !isflt(av[2])) | 
| 312 | return(MG_ETYPE); | 
| 313 | c_cmaterial->ts = atof(av[1]); | 
| 314 | c_cmaterial->ts_a = atof(av[2]); | 
| 315 | if (c_cmaterial->ts < 0. | c_cmaterial->ts > 1. | | 
| 316 | c_cmaterial->ts_a < 0.) | 
| 317 | return(MG_EILL); | 
| 318 | c_cmaterial->ts_c = *c_ccolor; | 
| 319 | c_cmaterial->clock++; | 
| 320 | return(MG_OK); | 
| 321 | case MG_E_SIDES:        /* set number of sides */ | 
| 322 | if (ac != 2) | 
| 323 | return(MG_EARGC); | 
| 324 | if (!isint(av[1])) | 
| 325 | return(MG_ETYPE); | 
| 326 | i = atoi(av[1]); | 
| 327 | if (i == 1) | 
| 328 | c_cmaterial->sided = 1; | 
| 329 | else if (i == 2) | 
| 330 | c_cmaterial->sided = 0; | 
| 331 | else | 
| 332 | return(MG_EILL); | 
| 333 | c_cmaterial->clock++; | 
| 334 | return(MG_OK); | 
| 335 | } | 
| 336 | return(MG_EUNK); | 
| 337 | } | 
| 338 |  | 
| 339 |  | 
| 340 | int | 
| 341 | c_hvertex(ac, av)               /* handle a vertex entity */ | 
| 342 | int     ac; | 
| 343 | register char   **av; | 
| 344 | { | 
| 345 | int     i; | 
| 346 | register LUENT  *lp; | 
| 347 |  | 
| 348 | switch (mg_entity(av[0])) { | 
| 349 | case MG_E_VERTEX:       /* get/set vertex context */ | 
| 350 | if (ac > 4) | 
| 351 | return(MG_EARGC); | 
| 352 | if (ac == 1) {          /* set unnamed vertex context */ | 
| 353 | c_unvertex = c_dfvertex; | 
| 354 | c_cvertex = &c_unvertex; | 
| 355 | c_cvname = NULL; | 
| 356 | return(MG_OK); | 
| 357 | } | 
| 358 | lp = lu_find(&vtx_tab, av[1]);  /* lookup context */ | 
| 359 | if (lp == NULL) | 
| 360 | return(MG_EMEM); | 
| 361 | c_cvname = lp->key; | 
| 362 | c_cvertex = (C_VERTEX *)lp->data; | 
| 363 | if (ac == 2) {          /* reestablish previous context */ | 
| 364 | if (c_cvertex == NULL) | 
| 365 | return(MG_EUNDEF); | 
| 366 | return(MG_OK); | 
| 367 | } | 
| 368 | if (av[2][0] != '=' || av[2][1]) | 
| 369 | return(MG_ETYPE); | 
| 370 | if (c_cvertex == NULL) {        /* create new vertex context */ | 
| 371 | lp->key = (char *)malloc(strlen(av[1])+1); | 
| 372 | if (lp->key == NULL) | 
| 373 | return(MG_EMEM); | 
| 374 | strcpy(lp->key, av[1]); | 
| 375 | lp->data = (char *)malloc(sizeof(C_VERTEX)); | 
| 376 | if (lp->data == NULL) | 
| 377 | return(MG_EMEM); | 
| 378 | c_cvname = lp->key; | 
| 379 | c_cvertex = (C_VERTEX *)lp->data; | 
| 380 | } | 
| 381 | i = c_cvertex->clock; | 
| 382 | if (ac == 3) {          /* use default template */ | 
| 383 | *c_cvertex = c_dfvertex; | 
| 384 | c_cvertex->clock = i + 1; | 
| 385 | return(MG_OK); | 
| 386 | } | 
| 387 | lp = lu_find(&vtx_tab, av[3]);  /* lookup template */ | 
| 388 | if (lp == NULL) | 
| 389 | return(MG_EMEM); | 
| 390 | if (lp->data == NULL) | 
| 391 | return(MG_EUNDEF); | 
| 392 | *c_cvertex = *(C_VERTEX *)lp->data; | 
| 393 | c_cvertex->clock = i + 1; | 
| 394 | return(MG_OK); | 
| 395 | case MG_E_POINT:        /* set point */ | 
| 396 | if (ac != 4) | 
| 397 | return(MG_EARGC); | 
| 398 | if (!isflt(av[1]) | !isflt(av[2]) | !isflt(av[3])) | 
| 399 | return(MG_ETYPE); | 
| 400 | c_cvertex->p[0] = atof(av[1]); | 
| 401 | c_cvertex->p[1] = atof(av[2]); | 
| 402 | c_cvertex->p[2] = atof(av[3]); | 
| 403 | c_cvertex->clock++; | 
| 404 | return(MG_OK); | 
| 405 | case MG_E_NORMAL:       /* set normal */ | 
| 406 | if (ac != 4) | 
| 407 | return(MG_EARGC); | 
| 408 | if (!isflt(av[1]) | !isflt(av[2]) | !isflt(av[3])) | 
| 409 | return(MG_ETYPE); | 
| 410 | c_cvertex->n[0] = atof(av[1]); | 
| 411 | c_cvertex->n[1] = atof(av[2]); | 
| 412 | c_cvertex->n[2] = atof(av[3]); | 
| 413 | (void)normalize(c_cvertex->n); | 
| 414 | c_cvertex->clock++; | 
| 415 | return(MG_OK); | 
| 416 | } | 
| 417 | return(MG_EUNK); | 
| 418 | } | 
| 419 |  | 
| 420 |  | 
| 421 | void | 
| 422 | c_clearall()                    /* empty context tables */ | 
| 423 | { | 
| 424 | c_uncolor = c_dfcolor; | 
| 425 | c_ccolor = &c_uncolor; | 
| 426 | c_ccname = NULL; | 
| 427 | lu_done(&clr_tab); | 
| 428 | c_unmaterial = c_dfmaterial; | 
| 429 | c_cmaterial = &c_unmaterial; | 
| 430 | c_cmname = NULL; | 
| 431 | lu_done(&mat_tab); | 
| 432 | c_unvertex = c_dfvertex; | 
| 433 | c_cvertex = &c_unvertex; | 
| 434 | c_cvname = NULL; | 
| 435 | lu_done(&vtx_tab); | 
| 436 | } | 
| 437 |  | 
| 438 |  | 
| 439 | C_MATERIAL * | 
| 440 | c_getmaterial(name)             /* get a named material */ | 
| 441 | char    *name; | 
| 442 | { | 
| 443 | register LUENT  *lp; | 
| 444 |  | 
| 445 | if ((lp = lu_find(&mat_tab, name)) == NULL) | 
| 446 | return(NULL); | 
| 447 | return((C_MATERIAL *)lp->data); | 
| 448 | } | 
| 449 |  | 
| 450 |  | 
| 451 | C_VERTEX * | 
| 452 | c_getvert(name)                 /* get a named vertex */ | 
| 453 | char    *name; | 
| 454 | { | 
| 455 | register LUENT  *lp; | 
| 456 |  | 
| 457 | if ((lp = lu_find(&vtx_tab, name)) == NULL) | 
| 458 | return(NULL); | 
| 459 | return((C_VERTEX *)lp->data); | 
| 460 | } | 
| 461 |  | 
| 462 |  | 
| 463 | C_COLOR * | 
| 464 | c_getcolor(name)                /* get a named color */ | 
| 465 | char    *name; | 
| 466 | { | 
| 467 | register LUENT  *lp; | 
| 468 |  | 
| 469 | if ((lp = lu_find(&clr_tab, name)) == NULL) | 
| 470 | return(NULL); | 
| 471 | return((C_COLOR *)lp->data); | 
| 472 | } | 
| 473 |  | 
| 474 |  | 
| 475 | int | 
| 476 | c_isgrey(clr)                   /* check if color is grey */ | 
| 477 | register C_COLOR        *clr; | 
| 478 | { | 
| 479 | if (!(clr->flags & (C_CSXY|C_CSSPEC))) | 
| 480 | return(1);              /* no settings == grey */ | 
| 481 | c_ccvt(clr, C_CSXY); | 
| 482 | return(clr->cx >= .323 && clr->cx <= .343 && | 
| 483 | clr->cy >= .323 && clr->cy <= .343); | 
| 484 | } | 
| 485 |  | 
| 486 |  | 
| 487 | void | 
| 488 | c_ccvt(clr, fl)                 /* convert color representations */ | 
| 489 | register C_COLOR        *clr; | 
| 490 | int     fl; | 
| 491 | { | 
| 492 | double  x, y, z; | 
| 493 | register int    i; | 
| 494 |  | 
| 495 | fl &= ~clr->flags;                      /* ignore what's done */ | 
| 496 | if (!fl)                                /* everything's done! */ | 
| 497 | return; | 
| 498 | if (!(clr->flags & (C_CSXY|C_CSSPEC)))  /* nothing set! */ | 
| 499 | *clr = c_dfcolor; | 
| 500 | if (fl & C_CSXY) {              /* cspec -> cxy */ | 
| 501 | x = y = z = 0.; | 
| 502 | for (i = 0; i < C_CNSS; i++) { | 
| 503 | x += cie_xf.ssamp[i] * clr->ssamp[i]; | 
| 504 | y += cie_yf.ssamp[i] * clr->ssamp[i]; | 
| 505 | z += cie_zf.ssamp[i] * clr->ssamp[i]; | 
| 506 | } | 
| 507 | x /= (double)cie_xf.ssum; | 
| 508 | y /= (double)cie_yf.ssum; | 
| 509 | z /= (double)cie_zf.ssum; | 
| 510 | z += x + y; | 
| 511 | clr->cx = x / z; | 
| 512 | clr->cy = y / z; | 
| 513 | clr->flags |= C_CSXY; | 
| 514 | } else if (fl & C_CSSPEC) {     /* cxy -> cspec */ | 
| 515 | x = clr->cx; | 
| 516 | y = clr->cy; | 
| 517 | z = 1. - x - y; | 
| 518 | clr->ssum = 0; | 
| 519 | for (i = 0; i < C_CNSS; i++) { | 
| 520 | clr->ssamp[i] = x*cie_xp.ssamp[i] + y*cie_yp.ssamp[i] | 
| 521 | + z*cie_zp.ssamp[i] + .5; | 
| 522 | if (clr->ssamp[i] < 0)          /* out of gamut! */ | 
| 523 | clr->ssamp[i] = 0; | 
| 524 | else | 
| 525 | clr->ssum += clr->ssamp[i]; | 
| 526 | } | 
| 527 | clr->flags |= C_CSSPEC; | 
| 528 | } | 
| 529 | if (fl & C_CSEFF) {             /* compute efficacy */ | 
| 530 | if (clr->flags & C_CSSPEC) {            /* from spectrum */ | 
| 531 | y = 0.; | 
| 532 | for (i = 0; i < C_CNSS; i++) | 
| 533 | y += cie_yf.ssamp[i] * clr->ssamp[i]; | 
| 534 | clr->eff = C_CLPWM * y / clr->ssum; | 
| 535 | } else /* clr->flags & C_CSXY */ {      /* from (x,y) */ | 
| 536 | clr->eff = clr->cx*cie_xf.eff + clr->cy*cie_yf.eff + | 
| 537 | (1. - clr->cx - clr->cy)*cie_zf.eff; | 
| 538 | } | 
| 539 | clr->flags |= C_CSEFF; | 
| 540 | } | 
| 541 | } | 
| 542 |  | 
| 543 |  | 
| 544 | static int | 
| 545 | setspectrum(clr, wlmin, wlmax, ac, av)  /* convert a spectrum */ | 
| 546 | register C_COLOR        *clr; | 
| 547 | double  wlmin, wlmax; | 
| 548 | int     ac; | 
| 549 | char    **av; | 
| 550 | { | 
| 551 | double  scale; | 
| 552 | float   va[C_CNSS]; | 
| 553 | register int    i, pos; | 
| 554 | int     n, imax; | 
| 555 | int     wl; | 
| 556 | double  wl0, wlstep; | 
| 557 | double  boxpos, boxstep; | 
| 558 | /* check bounds */ | 
| 559 | if (wlmax <= C_CMINWL | wlmax <= wlmin | wlmin >= C_CMAXWL) | 
| 560 | return(MG_EILL); | 
| 561 | wlstep = (wlmax - wlmin)/(ac-1); | 
| 562 | while (wlmin < C_CMINWL) { | 
| 563 | wlmin += wlstep; | 
| 564 | ac--; av++; | 
| 565 | } | 
| 566 | while (wlmax > C_CMAXWL) { | 
| 567 | wlmax -= wlstep; | 
| 568 | ac--; | 
| 569 | } | 
| 570 | imax = ac;                      /* box filter if necessary */ | 
| 571 | boxpos = 0; | 
| 572 | boxstep = 1; | 
| 573 | if (wlstep < C_CWLI) { | 
| 574 | imax = (wlmax - wlmin)/C_CWLI + (1-FTINY); | 
| 575 | boxpos = (wlmin - C_CMINWL)/C_CWLI; | 
| 576 | boxstep = wlstep/C_CWLI; | 
| 577 | wlstep = C_CWLI; | 
| 578 | } | 
| 579 | scale = 0.;                     /* get values and maximum */ | 
| 580 | pos = 0; | 
| 581 | for (i = 0; i < imax; i++) { | 
| 582 | va[i] = 0.; n = 0; | 
| 583 | while (boxpos < i+.5 && pos < ac) { | 
| 584 | if (!isflt(av[pos])) | 
| 585 | return(MG_ETYPE); | 
| 586 | va[i] += atof(av[pos++]); | 
| 587 | n++; | 
| 588 | boxpos += boxstep; | 
| 589 | } | 
| 590 | if (n > 1) | 
| 591 | va[i] /= (double)n; | 
| 592 | if (va[i] < 0.) | 
| 593 | return(MG_EILL); | 
| 594 | if (va[i] > scale) | 
| 595 | scale = va[i]; | 
| 596 | } | 
| 597 | if (scale <= FTINY) | 
| 598 | return(MG_EILL); | 
| 599 | scale = C_CMAXV / scale; | 
| 600 | clr->ssum = 0;                  /* convert to our spacing */ | 
| 601 | wl0 = wlmin; | 
| 602 | pos = 0; | 
| 603 | for (i = 0, wl = C_CMINWL; i < C_CNSS; i++, wl += C_CWLI) | 
| 604 | if (wl < wlmin | wl > wlmax) | 
| 605 | clr->ssamp[i] = 0; | 
| 606 | else { | 
| 607 | while (wl0 + wlstep < wl+FTINY) { | 
| 608 | wl0 += wlstep; | 
| 609 | pos++; | 
| 610 | } | 
| 611 | if (wl+FTINY >= wl0 & wl-FTINY <= wl0) | 
| 612 | clr->ssamp[i] = scale*va[pos] + .5; | 
| 613 | else            /* interpolate if necessary */ | 
| 614 | clr->ssamp[i] = .5 + scale / wlstep * | 
| 615 | ( va[pos]*(wl0+wlstep - wl) + | 
| 616 | va[pos+1]*(wl - wl0) ); | 
| 617 | clr->ssum += clr->ssamp[i]; | 
| 618 | } | 
| 619 | clr->flags = C_CDSPEC|C_CSSPEC; | 
| 620 | clr->clock++; | 
| 621 | return(MG_OK); | 
| 622 | } | 
| 623 |  | 
| 624 |  | 
| 625 | static void | 
| 626 | mixcolors(cres, w1, c1, w2, c2) /* mix two colors according to weights given */ | 
| 627 | register C_COLOR        *cres, *c1, *c2; | 
| 628 | double  w1, w2; | 
| 629 | { | 
| 630 | double  scale; | 
| 631 | float   cmix[C_CNSS]; | 
| 632 | register int    i; | 
| 633 |  | 
| 634 | if ((c1->flags|c2->flags) & C_CDSPEC) {         /* spectral mixing */ | 
| 635 | c_ccvt(c1, C_CSSPEC|C_CSEFF); | 
| 636 | c_ccvt(c2, C_CSSPEC|C_CSEFF); | 
| 637 | w1 /= c1->eff*c1->ssum; | 
| 638 | w2 /= c2->eff*c2->ssum; | 
| 639 | scale = 0.; | 
| 640 | for (i = 0; i < C_CNSS; i++) { | 
| 641 | cmix[i] = w1*c1->ssamp[i] + w2*c2->ssamp[i]; | 
| 642 | if (cmix[i] > scale) | 
| 643 | scale = cmix[i]; | 
| 644 | } | 
| 645 | scale = C_CMAXV / scale; | 
| 646 | cres->ssum = 0; | 
| 647 | for (i = 0; i < C_CNSS; i++) | 
| 648 | cres->ssum += cres->ssamp[i] = scale*cmix[i] + .5; | 
| 649 | cres->flags = C_CDSPEC|C_CSSPEC; | 
| 650 | } else {                                        /* CIE xy mixing */ | 
| 651 | c_ccvt(c1, C_CSXY); | 
| 652 | c_ccvt(c2, C_CSXY); | 
| 653 | scale = 1. / (w1/c1->cy + w2/c2->cy); | 
| 654 | cres->cx = (c1->cx*w1/c1->cy + c2->cx*w2/c2->cy) * scale; | 
| 655 | cres->cy = (w1 + w2) * scale; | 
| 656 | cres->flags = C_CDXY|C_CSXY; | 
| 657 | } | 
| 658 | } | 
| 659 |  | 
| 660 |  | 
| 661 | #define C1              3.741832e-16    /* W-m^2 */ | 
| 662 | #define C2              1.4388e-2       /* m-K */ | 
| 663 |  | 
| 664 | #define bbsp(l,t)       (C1/((l)*(l)*(l)*(l)*(l)*(exp(C2/((t)*(l)))-1.))) | 
| 665 | #define bblm(t)         (C2/5./(t)) | 
| 666 |  | 
| 667 | static int | 
| 668 | setbbtemp(clr, tk)              /* set black body spectrum */ | 
| 669 | register C_COLOR        *clr; | 
| 670 | double  tk; | 
| 671 | { | 
| 672 | double  sf, wl; | 
| 673 | register int    i; | 
| 674 |  | 
| 675 | if (tk < 1000) | 
| 676 | return(MG_EILL); | 
| 677 | wl = bblm(tk);                  /* scalefactor based on peak */ | 
| 678 | if (wl < C_CMINWL*1e-9) | 
| 679 | wl = C_CMINWL*1e-9; | 
| 680 | else if (wl > C_CMAXWL*1e-9) | 
| 681 | wl = C_CMAXWL*1e-9; | 
| 682 | sf = C_CMAXV/bbsp(wl,tk); | 
| 683 | clr->ssum = 0; | 
| 684 | for (i = 0; i < C_CNSS; i++) { | 
| 685 | wl = (C_CMINWL + i*C_CWLI)*1e-9; | 
| 686 | clr->ssum += clr->ssamp[i] = sf*bbsp(wl,tk) + .5; | 
| 687 | } | 
| 688 | clr->flags = C_CDSPEC|C_CSSPEC; | 
| 689 | clr->clock++; | 
| 690 | return(MG_OK); | 
| 691 | } | 
| 692 |  | 
| 693 | #undef  C1 | 
| 694 | #undef  C2 | 
| 695 | #undef  bbsp | 
| 696 | #undef  bblm |