Back to index

radiance  4R0+20100331
context.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: context.c,v 1.28 2003/07/27 22:12:02 schorsch Exp $";
00003 #endif
00004 /*
00005  * Context handlers
00006  */
00007 
00008 #include <stdio.h>
00009 #include <math.h>
00010 #include <stdlib.h>
00011 #include <string.h>
00012 #include "parser.h"
00013 #include "lookup.h"
00014 
00015                             /* default context values */
00016 static C_COLOR              c_dfcolor = C_DEFCOLOR;
00017 static C_MATERIAL    c_dfmaterial = C_DEFMATERIAL;
00018 static C_VERTEX             c_dfvertex = C_DEFVERTEX;
00019 
00020                             /* the unnamed contexts */
00021 static C_COLOR              c_uncolor = C_DEFCOLOR;
00022 static C_MATERIAL    c_unmaterial = C_DEFMATERIAL;
00023 static C_VERTEX             c_unvertex = C_DEFVERTEX;
00024 
00025                             /* the current contexts */
00026 C_COLOR              *c_ccolor = &c_uncolor;
00027 char          *c_ccname = NULL;
00028 C_MATERIAL    *c_cmaterial = &c_unmaterial;
00029 char          *c_cmname = NULL;
00030 C_VERTEX      *c_cvertex = &c_unvertex;
00031 char          *c_cvname = NULL;
00032 
00033 static LUTAB  clr_tab = LU_SINIT(free,free);     /* color lookup table */
00034 static LUTAB  mat_tab = LU_SINIT(free,free);     /* material lookup table */
00035 static LUTAB  vtx_tab = LU_SINIT(free,free);     /* vertex lookup table */
00036 
00037                             /* CIE 1931 Standard Observer curves */
00038 static C_COLOR       cie_xf = { 1, NULL, C_CDSPEC|C_CSSPEC|C_CSXY|C_CSEFF,
00039                      {14,42,143,435,1344,2839,3483,3362,2908,1954,956,
00040                      320,49,93,633,1655,2904,4334,5945,7621,9163,10263,
00041                      10622,10026,8544,6424,4479,2835,1649,874,468,227,
00042                      114,58,29,14,7,3,2,1,0}, 106836L, .467, .368, 362.230
00043                      };
00044 static C_COLOR       cie_yf = { 1, NULL, C_CDSPEC|C_CSSPEC|C_CSXY|C_CSEFF,
00045                      {0,1,4,12,40,116,230,380,600,910,1390,2080,3230,
00046                      5030,7100,8620,9540,9950,9950,9520,8700,7570,6310,
00047                      5030,3810,2650,1750,1070,610,320,170,82,41,21,10,
00048                      5,2,1,1,0,0}, 106856L, .398, .542, 493.525
00049                      };
00050 static C_COLOR       cie_zf = { 1, NULL, C_CDSPEC|C_CSSPEC|C_CSXY|C_CSEFF,
00051                      {65,201,679,2074,6456,13856,17471,17721,16692,
00052                      12876,8130,4652,2720,1582,782,422,203,87,39,21,17,
00053                      11,8,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00054                      106770L, .147, .077, 54.363
00055                      };
00056                             /* Derived CIE 1931 Primaries (imaginary) */
00057 static C_COLOR       cie_xp = { 1, NULL, C_CDSPEC|C_CSSPEC|C_CSXY,
00058                      {-174,-198,-195,-197,-202,-213,-235,-272,-333,
00059                      -444,-688,-1232,-2393,-4497,-6876,-6758,-5256,
00060                      -3100,-815,1320,3200,4782,5998,6861,7408,7754,
00061                      7980,8120,8199,8240,8271,8292,8309,8283,8469,
00062                      8336,8336,8336,8336,8336,8336},
00063                      127424L, 1., .0,
00064                      };
00065 static C_COLOR       cie_yp = { 1, NULL, C_CDSPEC|C_CSSPEC|C_CSXY,
00066                      {-451,-431,-431,-430,-427,-417,-399,-366,-312,
00067                      -204,57,691,2142,4990,8810,9871,9122,7321,5145,
00068                      3023,1123,-473,-1704,-2572,-3127,-3474,-3704,
00069                      -3846,-3927,-3968,-3999,-4021,-4038,-4012,-4201,
00070                      -4066,-4066,-4066,-4066,-4066,-4066},
00071                      -23035L, .0, 1.,
00072                      };
00073 static C_COLOR       cie_zp = { 1, NULL, C_CDSPEC|C_CSSPEC|C_CSXY,
00074                      {4051,4054,4052,4053,4054,4056,4059,4064,4071,
00075                      4074,4056,3967,3677,2933,1492,313,-440,-795,
00076                      -904,-918,-898,-884,-869,-863,-855,-855,-851,
00077                      -848,-847,-846,-846,-846,-845,-846,-843,-845,
00078                      -845,-845,-845,-845,-845},
00079                      36057L, .0, .0,
00080                      };
00081 
00082 static int    setspectrum();
00083 static int    setbbtemp();
00084 static void   mixcolors();
00085 
00086 
00087 int
00088 c_hcolor(ac, av)            /* handle color entity */
00089 int    ac;
00090 register char **av;
00091 {
00092        double w, wsum;
00093        register int  i;
00094        register LUENT       *lp;
00095 
00096        switch (mg_entity(av[0])) {
00097        case MG_E_COLOR:     /* get/set color context */
00098               if (ac > 4)
00099                      return(MG_EARGC);
00100               if (ac == 1) {              /* set unnamed color context */
00101                      c_uncolor = c_dfcolor;
00102                      c_ccolor = &c_uncolor;
00103                      c_ccname = NULL;
00104                      return(MG_OK);
00105               }
00106               if (!isname(av[1]))
00107                      return(MG_EILL);
00108               lp = lu_find(&clr_tab, av[1]);     /* lookup context */
00109               if (lp == NULL)
00110                      return(MG_EMEM);
00111               c_ccname = lp->key;
00112               c_ccolor = (C_COLOR *)lp->data;
00113               if (ac == 2) {              /* reestablish previous context */
00114                      if (c_ccolor == NULL)
00115                             return(MG_EUNDEF);
00116                      return(MG_OK);
00117               }
00118               if (av[2][0] != '=' || av[2][1])
00119                      return(MG_ETYPE);
00120               if (c_ccolor == NULL) {     /* create new color context */
00121                      lp->key = (char *)malloc(strlen(av[1])+1);
00122                      if (lp->key == NULL)
00123                             return(MG_EMEM);
00124                      strcpy(lp->key, av[1]);
00125                      lp->data = (char *)malloc(sizeof(C_COLOR));
00126                      if (lp->data == NULL)
00127                             return(MG_EMEM);
00128                      c_ccname = lp->key;
00129                      c_ccolor = (C_COLOR *)lp->data;
00130                      c_ccolor->clock = 0;
00131                      c_ccolor->client_data = NULL;
00132               }
00133               i = c_ccolor->clock;
00134               if (ac == 3) {              /* use default template */
00135                      *c_ccolor = c_dfcolor;
00136                      c_ccolor->clock = i + 1;
00137                      return(MG_OK);
00138               }
00139               lp = lu_find(&clr_tab, av[3]);     /* lookup template */
00140               if (lp == NULL)
00141                      return(MG_EMEM);
00142               if (lp->data == NULL)
00143                      return(MG_EUNDEF);
00144               *c_ccolor = *(C_COLOR *)lp->data;
00145               c_ccolor->clock = i + 1;
00146               return(MG_OK);
00147        case MG_E_CXY:              /* assign CIE XY value */
00148               if (ac != 3)
00149                      return(MG_EARGC);
00150               if (!isflt(av[1]) | !isflt(av[2]))
00151                      return(MG_ETYPE);
00152               c_ccolor->cx = atof(av[1]);
00153               c_ccolor->cy = atof(av[2]);
00154               c_ccolor->flags = C_CDXY|C_CSXY;
00155               if ((c_ccolor->cx < 0.) | (c_ccolor->cy < 0.) |
00156                             (c_ccolor->cx + c_ccolor->cy > 1.))
00157                      return(MG_EILL);
00158               c_ccolor->clock++;
00159               return(MG_OK);
00160        case MG_E_CSPEC:     /* assign spectral values */
00161               if (ac < 5)
00162                      return(MG_EARGC);
00163               if (!isflt(av[1]) | !isflt(av[2]))
00164                      return(MG_ETYPE);
00165               return(setspectrum(c_ccolor, atof(av[1]), atof(av[2]),
00166                             ac-3, av+3));
00167        case MG_E_CCT:              /* assign black body spectrum */
00168               if (ac != 2)
00169                      return(MG_EARGC);
00170               if (!isflt(av[1]))
00171                      return(MG_ETYPE);
00172               return(setbbtemp(c_ccolor, atof(av[1])));
00173        case MG_E_CMIX:             /* mix colors */
00174               if (ac < 5 || (ac-1)%2)
00175                      return(MG_EARGC);
00176               if (!isflt(av[1]))
00177                      return(MG_ETYPE);
00178               wsum = atof(av[1]);
00179               if ((lp = lu_find(&clr_tab, av[2])) == NULL)
00180                      return(MG_EMEM);
00181               if (lp->data == NULL)
00182                      return(MG_EUNDEF);
00183               *c_ccolor = *(C_COLOR *)lp->data;
00184               for (i = 3; i < ac; i += 2) {
00185                      if (!isflt(av[i]))
00186                             return(MG_ETYPE);
00187                      w = atof(av[i]);
00188                      if ((lp = lu_find(&clr_tab, av[i+1])) == NULL)
00189                             return(MG_EMEM);
00190                      if (lp->data == NULL)
00191                             return(MG_EUNDEF);
00192                      mixcolors(c_ccolor, wsum, c_ccolor,
00193                                    w, (C_COLOR *)lp->data);
00194                      wsum += w;
00195               }
00196               if (wsum <= 0.)
00197                      return(MG_EILL);
00198               c_ccolor->clock++;
00199               return(MG_OK);
00200        }
00201        return(MG_EUNK);
00202 }
00203 
00204 
00205 int
00206 c_hmaterial(ac, av)         /* handle material entity */
00207 int    ac;
00208 register char **av;
00209 {
00210        int    i;
00211        register LUENT       *lp;
00212 
00213        switch (mg_entity(av[0])) {
00214        case MG_E_MATERIAL:  /* get/set material context */
00215               if (ac > 4)
00216                      return(MG_EARGC);
00217               if (ac == 1) {              /* set unnamed material context */
00218                      c_unmaterial = c_dfmaterial;
00219                      c_cmaterial = &c_unmaterial;
00220                      c_cmname = NULL;
00221                      return(MG_OK);
00222               }
00223               if (!isname(av[1]))
00224                      return(MG_EILL);
00225               lp = lu_find(&mat_tab, av[1]);     /* lookup context */
00226               if (lp == NULL)
00227                      return(MG_EMEM);
00228               c_cmname = lp->key;
00229               c_cmaterial = (C_MATERIAL *)lp->data;
00230               if (ac == 2) {              /* reestablish previous context */
00231                      if (c_cmaterial == NULL)
00232                             return(MG_EUNDEF);
00233                      return(MG_OK);
00234               }
00235               if (av[2][0] != '=' || av[2][1])
00236                      return(MG_ETYPE);
00237               if (c_cmaterial == NULL) {  /* create new material */
00238                      lp->key = (char *)malloc(strlen(av[1])+1);
00239                      if (lp->key == NULL)
00240                             return(MG_EMEM);
00241                      strcpy(lp->key, av[1]);
00242                      lp->data = (char *)malloc(sizeof(C_MATERIAL));
00243                      if (lp->data == NULL)
00244                             return(MG_EMEM);
00245                      c_cmname = lp->key;
00246                      c_cmaterial = (C_MATERIAL *)lp->data;
00247                      c_cmaterial->clock = 0;
00248                      c_cmaterial->client_data = NULL;
00249               }
00250               i = c_cmaterial->clock;
00251               if (ac == 3) {              /* use default template */
00252                      *c_cmaterial = c_dfmaterial;
00253                      c_cmaterial->clock = i + 1;
00254                      return(MG_OK);
00255               }
00256               lp = lu_find(&mat_tab, av[3]);     /* lookup template */
00257               if (lp == NULL)
00258                      return(MG_EMEM);
00259               if (lp->data == NULL)
00260                      return(MG_EUNDEF);
00261               *c_cmaterial = *(C_MATERIAL *)lp->data;
00262               c_cmaterial->clock = i + 1;
00263               return(MG_OK);
00264        case MG_E_IR:        /* set index of refraction */
00265               if (ac != 3)
00266                      return(MG_EARGC);
00267               if (!isflt(av[1]) | !isflt(av[2]))
00268                      return(MG_ETYPE);
00269               c_cmaterial->nr = atof(av[1]);
00270               c_cmaterial->ni = atof(av[2]);
00271               if (c_cmaterial->nr <= FTINY)
00272                      return(MG_EILL);
00273               c_cmaterial->clock++;
00274               return(MG_OK);
00275        case MG_E_RD:        /* set diffuse reflectance */
00276               if (ac != 2)
00277                      return(MG_EARGC);
00278               if (!isflt(av[1]))
00279                      return(MG_ETYPE);
00280               c_cmaterial->rd = atof(av[1]);
00281               if ((c_cmaterial->rd < 0.) | (c_cmaterial->rd > 1.))
00282                      return(MG_EILL);
00283               c_cmaterial->rd_c = *c_ccolor;
00284               c_cmaterial->clock++;
00285               return(MG_OK);
00286        case MG_E_ED:        /* set diffuse emittance */
00287               if (ac != 2)
00288                      return(MG_EARGC);
00289               if (!isflt(av[1]))
00290                      return(MG_ETYPE);
00291               c_cmaterial->ed = atof(av[1]);
00292               if (c_cmaterial->ed < 0.)
00293                      return(MG_EILL);
00294               c_cmaterial->ed_c = *c_ccolor;
00295               c_cmaterial->clock++;
00296               return(MG_OK);
00297        case MG_E_TD:        /* set diffuse transmittance */
00298               if (ac != 2)
00299                      return(MG_EARGC);
00300               if (!isflt(av[1]))
00301                      return(MG_ETYPE);
00302               c_cmaterial->td = atof(av[1]);
00303               if ((c_cmaterial->td < 0.) | (c_cmaterial->td > 1.))
00304                      return(MG_EILL);
00305               c_cmaterial->td_c = *c_ccolor;
00306               c_cmaterial->clock++;
00307               return(MG_OK);
00308        case MG_E_RS:        /* set specular reflectance */
00309               if (ac != 3)
00310                      return(MG_EARGC);
00311               if (!isflt(av[1]) | !isflt(av[2]))
00312                      return(MG_ETYPE);
00313               c_cmaterial->rs = atof(av[1]);
00314               c_cmaterial->rs_a = atof(av[2]);
00315               if ((c_cmaterial->rs < 0.) | (c_cmaterial->rs > 1.) |
00316                             (c_cmaterial->rs_a < 0.))
00317                      return(MG_EILL);
00318               c_cmaterial->rs_c = *c_ccolor;
00319               c_cmaterial->clock++;
00320               return(MG_OK);
00321        case MG_E_TS:        /* set specular transmittance */
00322               if (ac != 3)
00323                      return(MG_EARGC);
00324               if (!isflt(av[1]) | !isflt(av[2]))
00325                      return(MG_ETYPE);
00326               c_cmaterial->ts = atof(av[1]);
00327               c_cmaterial->ts_a = atof(av[2]);
00328               if ((c_cmaterial->ts < 0.) | (c_cmaterial->ts > 1.) |
00329                             (c_cmaterial->ts_a < 0.))
00330                      return(MG_EILL);
00331               c_cmaterial->ts_c = *c_ccolor;
00332               c_cmaterial->clock++;
00333               return(MG_OK);
00334        case MG_E_SIDES:     /* set number of sides */
00335               if (ac != 2)
00336                      return(MG_EARGC);
00337               if (!isint(av[1]))
00338                      return(MG_ETYPE);
00339               i = atoi(av[1]);
00340               if (i == 1)
00341                      c_cmaterial->sided = 1;
00342               else if (i == 2)
00343                      c_cmaterial->sided = 0;
00344               else
00345                      return(MG_EILL);
00346               c_cmaterial->clock++;
00347               return(MG_OK);
00348        }
00349        return(MG_EUNK);
00350 }
00351 
00352 
00353 int
00354 c_hvertex(ac, av)           /* handle a vertex entity */
00355 int    ac;
00356 register char **av;
00357 {
00358        int    i;
00359        register LUENT       *lp;
00360 
00361        switch (mg_entity(av[0])) {
00362        case MG_E_VERTEX:    /* get/set vertex context */
00363               if (ac > 4)
00364                      return(MG_EARGC);
00365               if (ac == 1) {              /* set unnamed vertex context */
00366                      c_unvertex = c_dfvertex;
00367                      c_cvertex = &c_unvertex;
00368                      c_cvname = NULL;
00369                      return(MG_OK);
00370               }
00371               if (!isname(av[1]))
00372                      return(MG_EILL);
00373               lp = lu_find(&vtx_tab, av[1]);     /* lookup context */
00374               if (lp == NULL)
00375                      return(MG_EMEM);
00376               c_cvname = lp->key;
00377               c_cvertex = (C_VERTEX *)lp->data;
00378               if (ac == 2) {              /* reestablish previous context */
00379                      if (c_cvertex == NULL)
00380                             return(MG_EUNDEF);
00381                      return(MG_OK);
00382               }
00383               if (av[2][0] != '=' || av[2][1])
00384                      return(MG_ETYPE);
00385               if (c_cvertex == NULL) {    /* create new vertex context */
00386                      lp->key = (char *)malloc(strlen(av[1])+1);
00387                      if (lp->key == NULL)
00388                             return(MG_EMEM);
00389                      strcpy(lp->key, av[1]);
00390                      lp->data = (char *)malloc(sizeof(C_VERTEX));
00391                      if (lp->data == NULL)
00392                             return(MG_EMEM);
00393                      c_cvname = lp->key;
00394                      c_cvertex = (C_VERTEX *)lp->data;
00395                      c_cvertex->clock = 0;
00396                      c_cvertex->client_data = NULL;
00397               }
00398               i = c_cvertex->clock;
00399               if (ac == 3) {              /* use default template */
00400                      *c_cvertex = c_dfvertex;
00401                      c_cvertex->clock = i + 1;
00402                      return(MG_OK);
00403               }
00404               lp = lu_find(&vtx_tab, av[3]);     /* lookup template */
00405               if (lp == NULL)
00406                      return(MG_EMEM);
00407               if (lp->data == NULL)
00408                      return(MG_EUNDEF);
00409               *c_cvertex = *(C_VERTEX *)lp->data;
00410               c_cvertex->clock = i + 1;
00411               return(MG_OK);
00412        case MG_E_POINT:     /* set point */
00413               if (ac != 4)
00414                      return(MG_EARGC);
00415               if (!isflt(av[1]) | !isflt(av[2]) | !isflt(av[3]))
00416                      return(MG_ETYPE);
00417               c_cvertex->p[0] = atof(av[1]);
00418               c_cvertex->p[1] = atof(av[2]);
00419               c_cvertex->p[2] = atof(av[3]);
00420               c_cvertex->clock++;
00421               return(MG_OK);
00422        case MG_E_NORMAL:    /* set normal */
00423               if (ac != 4)
00424                      return(MG_EARGC);
00425               if (!isflt(av[1]) | !isflt(av[2]) | !isflt(av[3]))
00426                      return(MG_ETYPE);
00427               c_cvertex->n[0] = atof(av[1]);
00428               c_cvertex->n[1] = atof(av[2]);
00429               c_cvertex->n[2] = atof(av[3]);
00430               (void)normalize(c_cvertex->n);
00431               c_cvertex->clock++;
00432               return(MG_OK);
00433        }
00434        return(MG_EUNK);
00435 }
00436 
00437 
00438 void
00439 c_clearall()                /* empty context tables */
00440 {
00441        c_uncolor = c_dfcolor;
00442        c_ccolor = &c_uncolor;
00443        c_ccname = NULL;
00444        lu_done(&clr_tab);
00445        c_unmaterial = c_dfmaterial;
00446        c_cmaterial = &c_unmaterial;
00447        c_cmname = NULL;
00448        lu_done(&mat_tab);
00449        c_unvertex = c_dfvertex;
00450        c_cvertex = &c_unvertex;
00451        c_cvname = NULL;
00452        lu_done(&vtx_tab);
00453 }
00454 
00455 
00456 C_MATERIAL *
00457 c_getmaterial(name)         /* get a named material */
00458 char   *name;
00459 {
00460        register LUENT       *lp;
00461 
00462        if ((lp = lu_find(&mat_tab, name)) == NULL)
00463               return(NULL);
00464        return((C_MATERIAL *)lp->data);
00465 }
00466 
00467 
00468 C_VERTEX *
00469 c_getvert(name)                    /* get a named vertex */
00470 char   *name;
00471 {
00472        register LUENT       *lp;
00473 
00474        if ((lp = lu_find(&vtx_tab, name)) == NULL)
00475               return(NULL);
00476        return((C_VERTEX *)lp->data);
00477 }
00478 
00479 
00480 C_COLOR *
00481 c_getcolor(name)            /* get a named color */
00482 char   *name;
00483 {
00484        register LUENT       *lp;
00485 
00486        if ((lp = lu_find(&clr_tab, name)) == NULL)
00487               return(NULL);
00488        return((C_COLOR *)lp->data);
00489 }
00490 
00491 
00492 int
00493 c_isgrey(clr)               /* check if color is grey */
00494 register C_COLOR     *clr;
00495 {
00496        if (!(clr->flags & (C_CSXY|C_CSSPEC)))
00497               return(1);           /* no settings == grey */
00498        c_ccvt(clr, C_CSXY);
00499        return(clr->cx >= .323 && clr->cx <= .343 &&
00500                      clr->cy >= .323 && clr->cy <= .343);
00501 }
00502 
00503 
00504 void
00505 c_ccvt(clr, fl)                    /* convert color representations */
00506 register C_COLOR     *clr;
00507 int    fl;
00508 {
00509        double x, y, z;
00510        register int  i;
00511 
00512        fl &= ~clr->flags;                 /* ignore what's done */
00513        if (!fl)                           /* everything's done! */
00514               return;
00515        if (!(clr->flags & (C_CSXY|C_CSSPEC)))    /* nothing set! */
00516               *clr = c_dfcolor;
00517        if (fl & C_CSXY) {          /* cspec -> cxy */
00518               x = y = z = 0.;
00519               for (i = 0; i < C_CNSS; i++) {
00520                      x += cie_xf.ssamp[i] * clr->ssamp[i];
00521                      y += cie_yf.ssamp[i] * clr->ssamp[i];
00522                      z += cie_zf.ssamp[i] * clr->ssamp[i];
00523               }
00524               x /= (double)cie_xf.ssum;
00525               y /= (double)cie_yf.ssum;
00526               z /= (double)cie_zf.ssum;
00527               z += x + y;
00528               clr->cx = x / z;
00529               clr->cy = y / z;
00530               clr->flags |= C_CSXY;
00531        } else if (fl & C_CSSPEC) { /* cxy -> cspec */
00532               x = clr->cx;
00533               y = clr->cy;
00534               z = 1. - x - y;
00535               clr->ssum = 0;
00536               for (i = 0; i < C_CNSS; i++) {
00537                      clr->ssamp[i] = x*cie_xp.ssamp[i] + y*cie_yp.ssamp[i]
00538                                    + z*cie_zp.ssamp[i] + .5;
00539                      if (clr->ssamp[i] < 0)             /* out of gamut! */
00540                             clr->ssamp[i] = 0;
00541                      else
00542                             clr->ssum += clr->ssamp[i];
00543               }
00544               clr->flags |= C_CSSPEC;
00545        }
00546        if (fl & C_CSEFF) {         /* compute efficacy */
00547               if (clr->flags & C_CSSPEC) {              /* from spectrum */
00548                      y = 0.;
00549                      for (i = 0; i < C_CNSS; i++)
00550                             y += cie_yf.ssamp[i] * clr->ssamp[i];
00551                      clr->eff = C_CLPWM * y / clr->ssum;
00552               } else /* clr->flags & C_CSXY */ { /* from (x,y) */
00553                      clr->eff = clr->cx*cie_xf.eff + clr->cy*cie_yf.eff +
00554                                    (1. - clr->cx - clr->cy)*cie_zf.eff;
00555               }
00556               clr->flags |= C_CSEFF;
00557        }
00558 }
00559 
00560 
00561 static int
00562 setspectrum(clr, wlmin, wlmax, ac, av)    /* convert a spectrum */
00563 register C_COLOR     *clr;
00564 double wlmin, wlmax;
00565 int    ac;
00566 char   **av;
00567 {
00568        double scale;
00569        float  va[C_CNSS];
00570        register int  i, pos;
00571        int    n, imax;
00572        int    wl;
00573        double wl0, wlstep;
00574        double boxpos, boxstep;
00575                                    /* check bounds */
00576        if ((wlmax <= C_CMINWL) | (wlmax <= wlmin) | (wlmin >= C_CMAXWL))
00577               return(MG_EILL);
00578        wlstep = (wlmax - wlmin)/(ac-1);
00579        while (wlmin < C_CMINWL) {
00580               wlmin += wlstep;
00581               ac--; av++;
00582        }
00583        while (wlmax > C_CMAXWL) {
00584               wlmax -= wlstep;
00585               ac--;
00586        }
00587        imax = ac;                  /* box filter if necessary */
00588        boxpos = 0;
00589        boxstep = 1;
00590        if (wlstep < C_CWLI) {
00591               imax = (wlmax - wlmin)/C_CWLI + (1-FTINY);
00592               boxpos = (wlmin - C_CMINWL)/C_CWLI;
00593               boxstep = wlstep/C_CWLI;
00594               wlstep = C_CWLI;
00595        }
00596        scale = 0.;                 /* get values and maximum */
00597        pos = 0;
00598        for (i = 0; i < imax; i++) {
00599               va[i] = 0.; n = 0;
00600               while (boxpos < i+.5 && pos < ac) {
00601                      if (!isflt(av[pos]))
00602                             return(MG_ETYPE);
00603                      va[i] += atof(av[pos++]);
00604                      n++;
00605                      boxpos += boxstep;
00606               }
00607               if (n > 1)
00608                      va[i] /= (double)n;
00609               if (va[i] > scale)
00610                      scale = va[i];
00611               else if (va[i] < -scale)
00612                      scale = -va[i];
00613        }
00614        if (scale <= FTINY)
00615               return(MG_EILL);
00616        scale = C_CMAXV / scale;
00617        clr->ssum = 0;                     /* convert to our spacing */
00618        wl0 = wlmin;
00619        pos = 0;
00620        for (i = 0, wl = C_CMINWL; i < C_CNSS; i++, wl += C_CWLI)
00621               if ((wl < wlmin) | (wl > wlmax))
00622                      clr->ssamp[i] = 0;
00623               else {
00624                      while (wl0 + wlstep < wl+FTINY) {
00625                             wl0 += wlstep;
00626                             pos++;
00627                      }
00628                      if ((wl+FTINY >= wl0) & (wl-FTINY <= wl0))
00629                             clr->ssamp[i] = scale*va[pos] + .5;
00630                      else          /* interpolate if necessary */
00631                             clr->ssamp[i] = .5 + scale / wlstep *
00632                                           ( va[pos]*(wl0+wlstep - wl) +
00633                                                  va[pos+1]*(wl - wl0) );
00634                      clr->ssum += clr->ssamp[i];
00635               }
00636        clr->flags = C_CDSPEC|C_CSSPEC;
00637        clr->clock++;
00638        return(MG_OK);
00639 }
00640 
00641 
00642 static void
00643 mixcolors(cres, w1, c1, w2, c2)    /* mix two colors according to weights given */
00644 register C_COLOR     *cres, *c1, *c2;
00645 double w1, w2;
00646 {
00647        double scale;
00648        float  cmix[C_CNSS];
00649        register int  i;
00650 
00651        if ((c1->flags|c2->flags) & C_CDSPEC) {          /* spectral mixing */
00652               c_ccvt(c1, C_CSSPEC|C_CSEFF);
00653               c_ccvt(c2, C_CSSPEC|C_CSEFF);
00654               w1 /= c1->eff*c1->ssum;
00655               w2 /= c2->eff*c2->ssum;
00656               scale = 0.;
00657               for (i = 0; i < C_CNSS; i++) {
00658                      cmix[i] = w1*c1->ssamp[i] + w2*c2->ssamp[i];
00659                      if (cmix[i] > scale)
00660                             scale = cmix[i];
00661               }
00662               scale = C_CMAXV / scale;
00663               cres->ssum = 0;
00664               for (i = 0; i < C_CNSS; i++)
00665                      cres->ssum += cres->ssamp[i] = scale*cmix[i] + .5;
00666               cres->flags = C_CDSPEC|C_CSSPEC;
00667        } else {                                  /* CIE xy mixing */
00668               c_ccvt(c1, C_CSXY);
00669               c_ccvt(c2, C_CSXY);
00670               scale = w1/c1->cy + w2/c2->cy;
00671               if (scale == 0.)
00672                      return;
00673               scale = 1. / scale;
00674               cres->cx = (c1->cx*w1/c1->cy + c2->cx*w2/c2->cy) * scale;
00675               cres->cy = (w1 + w2) * scale;
00676               cres->flags = C_CDXY|C_CSXY;
00677        }
00678 }
00679 
00680 
00681 #define       C1            3.741832e-16  /* W-m^2 */
00682 #define C2           1.4388e-2     /* m-K */
00683 
00684 #define bbsp(l,t)    (C1/((l)*(l)*(l)*(l)*(l)*(exp(C2/((t)*(l)))-1.)))
00685 #define bblm(t)             (C2/5./(t))
00686 
00687 static int
00688 setbbtemp(clr, tk)          /* set black body spectrum */
00689 register C_COLOR     *clr;
00690 double tk;
00691 {
00692        double sf, wl;
00693        register int  i;
00694 
00695        if (tk < 1000)
00696               return(MG_EILL);
00697        wl = bblm(tk);                     /* scalefactor based on peak */
00698        if (wl < C_CMINWL*1e-9)
00699               wl = C_CMINWL*1e-9;
00700        else if (wl > C_CMAXWL*1e-9)
00701               wl = C_CMAXWL*1e-9;
00702        sf = C_CMAXV/bbsp(wl,tk);
00703        clr->ssum = 0;
00704        for (i = 0; i < C_CNSS; i++) {
00705               wl = (C_CMINWL + i*C_CWLI)*1e-9;
00706               clr->ssum += clr->ssamp[i] = sf*bbsp(wl,tk) + .5;
00707        }
00708        clr->flags = C_CDSPEC|C_CSSPEC;
00709        clr->clock++;
00710        return(MG_OK);
00711 }
00712 
00713 #undef C1
00714 #undef C2
00715 #undef bbsp
00716 #undef bblm