ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/bsdf_m.c
(Generate patch)

Comparing ray/src/common/bsdf_m.c (file contents):
Revision 3.19 by greg, Thu Jul 7 15:48:00 2011 UTC vs.
Revision 3.32 by greg, Wed Apr 8 02:41:02 2015 UTC

# Line 13 | Line 13 | static const char RCSid[] = "$Id$";
13  
14   #define _USE_MATH_DEFINES
15   #include "rtio.h"
16 #include <stdlib.h>
16   #include <math.h>
17   #include <ctype.h>
18   #include "ezxml.h"
# Line 29 | Line 28 | static const char RCSid[] = "$Id$";
28   #define RC_INTERR       (-4)
29   #define RC_MEMERR       (-5)
30  
31 < #define MAXLATS         46              /* maximum number of latitudes */
33 <
34 < /* BSDF angle specification */
35 < typedef struct {
36 <        char    name[64];               /* basis name */
37 <        int     nangles;                /* total number of directions */
38 <        struct {
39 <                float   tmin;                   /* starting theta */
40 <                int     nphis;                  /* number of phis (0 term) */
41 <        } lat[MAXLATS+1];               /* latitudes */
42 < } ANGLE_BASIS;
43 <
44 < #define MAXABASES       7               /* limit on defined bases */
45 <
46 < static ANGLE_BASIS      abase_list[MAXABASES] = {
31 > ANGLE_BASIS     abase_list[MAXABASES] = {
32          {
33                  "LBNL/Klems Full", 145,
34 <                { {-5., 1},
34 >                { {0., 1},
35                  {5., 8},
36                  {15., 16},
37                  {25., 20},
# Line 58 | Line 43 | static ANGLE_BASIS     abase_list[MAXABASES] = {
43                  {90., 0} }
44          }, {
45                  "LBNL/Klems Half", 73,
46 <                { {-6.5, 1},
46 >                { {0., 1},
47                  {6.5, 8},
48                  {19.5, 12},
49                  {32.5, 16},
# Line 68 | Line 53 | static ANGLE_BASIS     abase_list[MAXABASES] = {
53                  {90., 0} }
54          }, {
55                  "LBNL/Klems Quarter", 41,
56 <                { {-9., 1},
56 >                { {0., 1},
57                  {9., 8},
58                  {27., 12},
59                  {46., 12},
# Line 77 | Line 62 | static ANGLE_BASIS     abase_list[MAXABASES] = {
62          }
63   };
64  
65 < static int      nabases = 3;    /* current number of defined bases */
65 > int             nabases = 3;            /* current number of defined bases */
66  
67 + C_COLOR         mtx_RGB_prim[3];        /* our RGB primaries  */
68 + float           mtx_RGB_coef[3];        /* corresponding Y coefficients */
69 +
70 + enum {mtx_Y, mtx_X, mtx_Z};             /* matrix components (mtx_Y==0) */
71 +
72 + /* check if two real values are near enough to equal */
73   static int
74   fequal(double a, double b)
75   {
# Line 87 | Line 78 | fequal(double a, double b)
78          return (a <= 1e-6) & (a >= -1e-6);
79   }
80  
81 < /* Returns the given tag's character content or empty string if none */
91 < #ifdef ezxml_txt
92 < #undef ezxml_txt
93 < static char *
94 < ezxml_txt(ezxml_t xml)
95 < {
96 <        if (xml == NULL)
97 <                return "";
98 <        return xml->txt;
99 < }
100 < #endif
101 <
102 < /* Convert error to standard BSDF code */
81 > /* convert error to standard BSDF code */
82   static SDError
83   convert_errcode(int ec)
84   {
# Line 120 | Line 99 | convert_errcode(int ec)
99          return SDEunknown;
100   }
101  
102 < /* Allocate a BSDF matrix of the given size */
102 > /* allocate a BSDF matrix of the given size */
103   static SDMat *
104   SDnewMatrix(int ni, int no)
105   {
# Line 144 | Line 123 | SDnewMatrix(int ni, int no)
123   }
124  
125   /* Free a BSDF matrix */
126 < #define SDfreeMatrix            free
126 > void
127 > SDfreeMatrix(void *ptr)
128 > {
129 >        SDMat   *mp = (SDMat *)ptr;
130  
131 < /* get vector for this angle basis index (front exiting) */
132 < static int
131 >        if (mp->chroma != NULL) free(mp->chroma);
132 >        free(ptr);
133 > }
134 >
135 > /* compute square of real value */
136 > static double sq(double x) { return x*x; }
137 >
138 > /* Get vector for this angle basis index (front exiting) */
139 > int
140   fo_getvec(FVECT v, double ndxr, void *p)
141   {
142          ANGLE_BASIS     *ab = (ANGLE_BASIS *)p;
# Line 155 | Line 144 | fo_getvec(FVECT v, double ndxr, void *p)
144          double          randX = ndxr - ndx;
145          double          rx[2];
146          int             li;
147 <        double          pol, azi, d;
147 >        double          azi, d;
148          
149          if ((ndxr < 0) | (ndx >= ab->nangles))
150                  return RC_FAIL;
151          for (li = 0; ndx >= ab->lat[li].nphis; li++)
152                  ndx -= ab->lat[li].nphis;
153          SDmultiSamp(rx, 2, randX);
154 <        pol = M_PI/180.*( (1.-rx[0])*ab->lat[li].tmin +
155 <                                rx[0]*ab->lat[li+1].tmin );
154 >        d = (1. - randX)*sq(cos(M_PI/180.*ab->lat[li].tmin)) +
155 >                randX*sq(cos(M_PI/180.*ab->lat[li+1].tmin));
156 >        v[2] = d = sqrt(d);     /* cos(pol) */
157          azi = 2.*M_PI*(ndx + rx[1] - .5)/ab->lat[li].nphis;
168        v[2] = d = cos(pol);
158          d = sqrt(1. - d*d);     /* sin(pol) */
159          v[0] = cos(azi)*d;
160          v[1] = sin(azi)*d;
161          return RC_GOOD;
162   }
163  
164 < /* get index corresponding to the given vector (front exiting) */
165 < static int
164 > /* Get index corresponding to the given vector (front exiting) */
165 > int
166   fo_getndx(const FVECT v, void *p)
167   {
168          ANGLE_BASIS     *ab = (ANGLE_BASIS *)p;
# Line 184 | Line 173 | fo_getndx(const FVECT v, void *p)
173                  return -1;
174          if ((v[2] < 0) | (v[2] > 1.))
175                  return -1;
176 <        pol = 180.0/M_PI*acos(v[2]);
176 >        pol = 180.0/M_PI*Acos(v[2]);
177          azi = 180.0/M_PI*atan2(v[1], v[0]);
178          if (azi < 0.0) azi += 360.0;
179          for (li = 1; ab->lat[li].tmin <= pol; li++)
# Line 198 | Line 187 | fo_getndx(const FVECT v, void *p)
187          return ndx;
188   }
189  
190 < /* compute square of real value */
191 < static double sq(double x) { return x*x; }
203 <
204 < /* get projected solid angle for this angle basis index (universal) */
205 < static double
190 > /* Get projected solid angle for this angle basis index (universal) */
191 > double
192   io_getohm(int ndx, void *p)
193   {
194          static int      last_li = -1;
# Line 218 | Line 204 | io_getohm(int ndx, void *p)
204          if (li == last_li)                      /* cached latitude? */
205                  return last_ohm;
206          last_li = li;
221        theta1 = M_PI/180. * ab->lat[li+1].tmin;
222        if (ab->lat[li].nphis == 1)             /* special case */
223                return last_ohm = M_PI*(1. - sq(cos(theta1)));
207          theta = M_PI/180. * ab->lat[li].tmin;
208 +        theta1 = M_PI/180. * ab->lat[li+1].tmin;
209          return last_ohm = M_PI*(sq(cos(theta)) - sq(cos(theta1))) /
210                                  (double)ab->lat[li].nphis;
211   }
212  
213 < /* get vector for this angle basis index (back incident) */
214 < static int
213 > /* Get vector for this angle basis index (back incident) */
214 > int
215   bi_getvec(FVECT v, double ndxr, void *p)
216   {
217          if (!fo_getvec(v, ndxr, p))
# Line 240 | Line 224 | bi_getvec(FVECT v, double ndxr, void *p)
224          return RC_GOOD;
225   }
226  
227 < /* get index corresponding to the vector (back incident) */
228 < static int
227 > /* Get index corresponding to the vector (back incident) */
228 > int
229   bi_getndx(const FVECT v, void *p)
230   {
231          FVECT  v2;
# Line 253 | Line 237 | bi_getndx(const FVECT v, void *p)
237          return fo_getndx(v2, p);
238   }
239  
240 < /* get vector for this angle basis index (back exiting) */
241 < static int
240 > /* Get vector for this angle basis index (back exiting) */
241 > int
242   bo_getvec(FVECT v, double ndxr, void *p)
243   {
244          if (!fo_getvec(v, ndxr, p))
# Line 265 | Line 249 | bo_getvec(FVECT v, double ndxr, void *p)
249          return RC_GOOD;
250   }
251  
252 < /* get index corresponding to the vector (back exiting) */
253 < static int
252 > /* Get index corresponding to the vector (back exiting) */
253 > int
254   bo_getndx(const FVECT v, void *p)
255   {
256          FVECT  v2;
# Line 278 | Line 262 | bo_getndx(const FVECT v, void *p)
262          return fo_getndx(v2, p);
263   }
264  
265 < /* get vector for this angle basis index (front incident) */
266 < static int
265 > /* Get vector for this angle basis index (front incident) */
266 > int
267   fi_getvec(FVECT v, double ndxr, void *p)
268   {
269          if (!fo_getvec(v, ndxr, p))
# Line 291 | Line 275 | fi_getvec(FVECT v, double ndxr, void *p)
275          return RC_GOOD;
276   }
277  
278 < /* get index corresponding to the vector (front incident) */
279 < static int
278 > /* Get index corresponding to the vector (front incident) */
279 > int
280   fi_getndx(const FVECT v, void *p)
281   {
282          FVECT  v2;
# Line 304 | Line 288 | fi_getndx(const FVECT v, void *p)
288          return fo_getndx(v2, p);
289   }
290  
291 + /* Get color or grayscale value for BSDF for the given direction pair */
292 + int
293 + mBSDF_color(float coef[], const SDMat *dp, int i, int o)
294 + {
295 +        C_COLOR cxy;
296 +
297 +        coef[0] = mBSDF_value(dp, i, o);
298 +        if (dp->chroma == NULL)
299 +                return 1;       /* grayscale */
300 +
301 +        c_decodeChroma(&cxy, dp->chroma[o*dp->ninc + i]);
302 +        c_toSharpRGB(&cxy, coef[0], coef);
303 +        coef[0] *= mtx_RGB_coef[0];
304 +        coef[1] *= mtx_RGB_coef[1];
305 +        coef[2] *= mtx_RGB_coef[2];
306 +        return 3;               /* RGB color */
307 + }
308 +
309   /* load custom BSDF angle basis */
310   static int
311   load_angle_basis(ezxml_t wab)
# Line 335 | Line 337 | load_angle_basis(ezxml_t wab)
337                                  ezxml_child(ezxml_child(wbb,
338                                          "ThetaBounds"), "UpperTheta")));
339                  if (!i)
340 <                        abase_list[nabases].lat[i].tmin =
339 <                                        -abase_list[nabases].lat[i+1].tmin;
340 >                        abase_list[nabases].lat[0].tmin = 0;
341                  else if (!fequal(atof(ezxml_txt(ezxml_child(ezxml_child(wbb,
342                                          "ThetaBounds"), "LowerTheta"))),
343                                  abase_list[nabases].lat[i].tmin)) {
# Line 397 | Line 398 | get_extrema(SDSpectralDF *df)
398  
399   /* load BSDF distribution for this wavelength */
400   static int
401 < load_bsdf_data(SDData *sd, ezxml_t wdb, int rowinc)
401 > load_bsdf_data(SDData *sd, ezxml_t wdb, int ct, int rowinc)
402   {
403          SDSpectralDF    *df;
404          SDMat           *dp;
405          char            *sdata;
405        int             tfront;
406          int             inbi, outbi;
407          int             i;
408                                          /* allocate BSDF component */
# Line 411 | Line 411 | load_bsdf_data(SDData *sd, ezxml_t wdb, int rowinc)
411                  return RC_FAIL;
412          /*
413           * Remember that front and back are reversed from WINDOW 6 orientations
414         * Favor their "Front" (incoming light) since that's more often valid
414           */
415 <        tfront = !strcasecmp(sdata, "Transmission Back");
416 <        if (!strcasecmp(sdata, "Transmission Front") ||
418 <                        tfront & (sd->tf == NULL)) {
419 <                if (sd->tf != NULL)
420 <                        SDfreeSpectralDF(sd->tf);
421 <                if ((sd->tf = SDnewSpectralDF(1)) == NULL)
415 >        if (!strcasecmp(sdata, "Transmission Front")) {
416 >                if (sd->tb == NULL && (sd->tb = SDnewSpectralDF(3)) == NULL)
417                          return RC_MEMERR;
418 +                df = sd->tb;
419 +        } else if (!strcasecmp(sdata, "Transmission Back")) {
420 +                if (sd->tf == NULL && (sd->tf = SDnewSpectralDF(3)) == NULL)
421 +                        return RC_MEMERR;
422                  df = sd->tf;
423          } else if (!strcasecmp(sdata, "Reflection Front")) {
424 <                if (sd->rb != NULL)     /* note back-front reversal */
426 <                        SDfreeSpectralDF(sd->rb);
427 <                if ((sd->rb = SDnewSpectralDF(1)) == NULL)
424 >                if (sd->rb == NULL && (sd->rb = SDnewSpectralDF(3)) == NULL)
425                          return RC_MEMERR;
426                  df = sd->rb;
427          } else if (!strcasecmp(sdata, "Reflection Back")) {
428 <                if (sd->rf != NULL)     /* note front-back reversal */
432 <                        SDfreeSpectralDF(sd->rf);
433 <                if ((sd->rf = SDnewSpectralDF(1)) == NULL)
428 >                if (sd->rf == NULL && (sd->rf = SDnewSpectralDF(3)) == NULL)
429                          return RC_MEMERR;
430                  df = sd->rf;
431          } else
432                  return RC_FAIL;
433 <        /* XXX should also check "ScatteringDataType" for consistency? */
433 >                                        /* free previous matrix if any */
434 >        if (df->comp[ct].dist != NULL) {
435 >                SDfreeMatrix(df->comp[ct].dist);
436 >                df->comp[ct].dist = NULL;
437 >        }
438                                          /* get angle bases */
439          sdata = ezxml_txt(ezxml_child(wdb,"ColumnAngleBasis"));
440          if (!sdata || !*sdata) {
# Line 470 | Line 469 | load_bsdf_data(SDData *sd, ezxml_t wdb, int rowinc)
469          dp->ib_priv = &abase_list[inbi];
470          dp->ob_priv = &abase_list[outbi];
471          if (df == sd->tf) {
472 <                if (tfront) {
473 <                        dp->ib_vec = &fi_getvec;
474 <                        dp->ib_ndx = &fi_getndx;
475 <                        dp->ob_vec = &bo_getvec;
476 <                        dp->ob_ndx = &bo_getndx;
477 <                } else {
478 <                        dp->ib_vec = &bi_getvec;
479 <                        dp->ib_ndx = &bi_getndx;
480 <                        dp->ob_vec = &fo_getvec;
482 <                        dp->ob_ndx = &fo_getndx;
483 <                }
472 >                dp->ib_vec = &fi_getvec;
473 >                dp->ib_ndx = &fi_getndx;
474 >                dp->ob_vec = &bo_getvec;
475 >                dp->ob_ndx = &bo_getndx;
476 >        } else if (df == sd->tb) {
477 >                dp->ib_vec = &bi_getvec;
478 >                dp->ib_ndx = &bi_getndx;
479 >                dp->ob_vec = &fo_getvec;
480 >                dp->ob_ndx = &fo_getndx;
481          } else if (df == sd->rf) {
482                  dp->ib_vec = &fi_getvec;
483                  dp->ib_ndx = &fi_getndx;
# Line 494 | Line 491 | load_bsdf_data(SDData *sd, ezxml_t wdb, int rowinc)
491          }
492          dp->ib_ohm = &io_getohm;
493          dp->ob_ohm = &io_getohm;
494 <        df->comp[0].cspec[0] = c_dfcolor; /* XXX monochrome for now */
495 <        df->comp[0].dist = dp;
499 <        df->comp[0].func = &SDhandleMtx;
494 >        df->comp[ct].dist = dp;
495 >        df->comp[ct].func = &SDhandleMtx;
496                                          /* read BSDF data */
497          sdata = ezxml_txt(ezxml_child(wdb, "ScatteringData"));
498          if (!sdata || !*sdata) {
# Line 505 | Line 501 | load_bsdf_data(SDData *sd, ezxml_t wdb, int rowinc)
501                  return RC_FORMERR;
502          }
503          for (i = 0; i < dp->ninc*dp->nout; i++) {
504 <                char  *sdnext = fskip(sdata);
504 >                char    *sdnext = fskip(sdata);
505 >                double  val;
506                  if (sdnext == NULL) {
507                          sprintf(SDerrorDetail,
508                                  "Bad/missing BSDF ScatteringData in '%s'",
# Line 515 | Line 512 | load_bsdf_data(SDData *sd, ezxml_t wdb, int rowinc)
512                  while (isspace(*sdnext))
513                          sdnext++;
514                  if (*sdnext == ',') sdnext++;
515 +                if ((val = atof(sdata)) < 0)
516 +                        val = 0;        /* don't allow negative values */
517                  if (rowinc) {
518                          int     r = i/dp->nout;
519                          int     c = i - r*dp->nout;
520 <                        mBSDF_value(dp,r,c) = atof(sdata);
520 >                        mBSDF_value(dp,r,c) = val;
521                  } else
522 <                        dp->bsdf[i] = atof(sdata);
522 >                        dp->bsdf[i] = val;
523                  sdata = sdnext;
524          }
525 <        return get_extrema(df);
525 >        return (ct == mtx_Y) ? get_extrema(df) : RC_GOOD;
526   }
527  
528 < /* Subtract minimum (diffuse) scattering amount from BSDF */
528 > /* copy our RGB (x,y) primary chromaticities */
529 > static void
530 > copy_RGB_prims(C_COLOR cspec[])
531 > {
532 >        if (mtx_RGB_coef[1] < .001) {   /* need to initialize */
533 >                int     i = 3;
534 >                while (i--) {
535 >                        float   rgb[3];
536 >                        rgb[0] = rgb[1] = rgb[2] = .0f;
537 >                        rgb[i] = 1.f;
538 >                        mtx_RGB_coef[i] = c_fromSharpRGB(rgb, &mtx_RGB_prim[i]);
539 >                }
540 >        }
541 >        memcpy(cspec, mtx_RGB_prim, sizeof(mtx_RGB_prim));
542 > }
543 >
544 > /* encode chromaticity if XYZ -- reduce to one channel in any case */
545 > static SDSpectralDF *
546 > encode_chroma(SDSpectralDF *df)
547 > {
548 >        SDMat   *mpx, *mpy, *mpz;
549 >        int     n;
550 >
551 >        if (df == NULL || df->ncomp != 3)
552 >                return df;
553 >
554 >        mpy = (SDMat *)df->comp[mtx_Y].dist;
555 >        if (mpy == NULL) {
556 >                free(df);
557 >                return NULL;
558 >        }
559 >        mpx = (SDMat *)df->comp[mtx_X].dist;
560 >        mpz = (SDMat *)df->comp[mtx_Z].dist;
561 >        if (mpx == NULL || (mpx->ninc != mpy->ninc) | (mpx->nout != mpy->nout))
562 >                goto done;
563 >        if (mpz == NULL || (mpz->ninc != mpy->ninc) | (mpz->nout != mpy->nout))
564 >                goto done;
565 >        mpy->chroma = (C_CHROMA *)malloc(sizeof(C_CHROMA)*mpy->ninc*mpy->nout);
566 >        if (mpy->chroma == NULL)
567 >                goto done;              /* XXX punt */
568 >                                        /* encode chroma values */
569 >        for (n = mpy->ninc*mpy->nout; n--; ) {
570 >                const double    sum = mpx->bsdf[n] + mpy->bsdf[n] + mpz->bsdf[n];
571 >                C_COLOR         cxy;
572 >                if (sum > .0)
573 >                        c_cset(&cxy, mpx->bsdf[n]/sum, mpy->bsdf[n]/sum);
574 >                else
575 >                        c_cset(&cxy, 1./3., 1./3.);
576 >                mpy->chroma[n] = c_encodeChroma(&cxy);
577 >        }
578 > done:                                   /* free X & Z channels */
579 >        if (mpx != NULL) SDfreeMatrix(mpx);
580 >        if (mpz != NULL) SDfreeMatrix(mpz);
581 >        if (mpy->chroma == NULL)        /* grayscale after all? */
582 >                df->comp[0].cspec[0] = c_dfcolor;
583 >        else                            /* else copy RGB primaries */
584 >                copy_RGB_prims(df->comp[0].cspec);
585 >        df->ncomp = 1;                  /* return resized struct */
586 >        return (SDSpectralDF *)realloc(df, sizeof(SDSpectralDF));
587 > }
588 >
589 > /* subtract minimum (diffuse) scattering amount from BSDF */
590   static double
591 < subtract_min(SDMat *sm)
591 > subtract_min(C_COLOR *cs, SDMat *sm)
592   {
593 <        float   minv = sm->bsdf[0];
594 <        int     n = sm->ninc*sm->nout;
595 <        int     i;
593 >        const int       ncomp = 1 + 2*(sm->chroma != NULL);
594 >        float           min_coef[3], ymin, coef[3];
595 >        int             i, o, c;
596          
597 <        for (i = n; --i; )
598 <                if (sm->bsdf[i] < minv)
599 <                        minv = sm->bsdf[i];
600 <        
601 <        if (minv <= FTINY)
597 >        min_coef[0] = min_coef[1] = min_coef[2] = FHUGE;
598 >        for (i = 0; i < sm->ninc; i++)
599 >                for (o = 0; o < sm->nout; o++) {
600 >                        c = mBSDF_color(coef, sm, i, o);
601 >                        while (c--)
602 >                                if (coef[c] < min_coef[c])
603 >                                        min_coef[c] = coef[c];
604 >                }
605 >        ymin = 0;
606 >        for (c = ncomp; c--; )
607 >                ymin += min_coef[c];
608 >        if (ymin <= .01/M_PI)           /* not worth bothering about? */
609                  return .0;
610 +        if (ncomp == 1) {               /* subtract grayscale minimum */
611 +                for (i = sm->ninc*sm->nout; i--; )
612 +                        sm->bsdf[i] -= ymin;
613 +                *cs = c_dfcolor;
614 +                return M_PI*ymin;
615 +        }
616 +                                        /* else subtract colored minimum */
617 +        for (i = 0; i < sm->ninc; i++)
618 +                for (o = 0; o < sm->nout; o++) {
619 +                        C_COLOR cxy;
620 +                        c = mBSDF_color(coef, sm, i, o);
621 +                        while (c--)
622 +                                coef[c] = (coef[c] - min_coef[c]) /
623 +                                                mtx_RGB_coef[c];
624 +                        if (c_fromSharpRGB(coef, &cxy) > 1e-5)
625 +                                sm->chroma[o*sm->ninc + i] = c_encodeChroma(&cxy);
626 +                        mBSDF_value(sm,i,o) -= ymin;
627 +                }
628 +                                        /* return colored minimum */
629 +        for (i = 3; i--; )
630 +                coef[i] = min_coef[i]/mtx_RGB_coef[i];
631 +        c_fromSharpRGB(coef, cs);
632  
633 <        for (i = n; i--; )
545 <                sm->bsdf[i] -= minv;
546 <
547 <        return minv*M_PI;               /* be sure to include multiplier */
633 >        return M_PI*ymin;
634   }
635  
636 < /* Extract and separate diffuse portion of BSDF */
637 < static void
636 > /* Extract and separate diffuse portion of BSDF & convert color */
637 > static SDSpectralDF *
638   extract_diffuse(SDValue *dv, SDSpectralDF *df)
639   {
554        int     n;
640  
641 +        df = encode_chroma(df);         /* reduce XYZ to Y + chroma */
642          if (df == NULL || df->ncomp <= 0) {
643                  dv->spec = c_dfcolor;
644                  dv->cieY = .0;
645 <                return;
645 >                return df;
646          }
647 <        dv->spec = df->comp[0].cspec[0];
648 <        dv->cieY = subtract_min((SDMat *)df->comp[0].dist);
563 <                                        /* in case of multiple components */
564 <        for (n = df->ncomp; --n; ) {
565 <                double  ymin = subtract_min((SDMat *)df->comp[n].dist);
566 <                c_cmix(&dv->spec, dv->cieY, &dv->spec, ymin, &df->comp[n].cspec[0]);
567 <                dv->cieY += ymin;
568 <        }
647 >                                        /* subtract minimum value */
648 >        dv->cieY = subtract_min(&dv->spec, (SDMat *)df->comp[0].dist);
649          df->maxHemi -= dv->cieY;        /* adjust maximum hemispherical */
650                                          /* make sure everything is set */
651          c_ccvt(&dv->spec, C_CSXY+C_CSSPEC);
652 +        return df;
653   }
654  
655   /* Load a BSDF matrix from an open XML file */
# Line 608 | Line 689 | SDloadMtx(SDData *sd, ezxml_t wtl)
689                                          /* load BSDF components */
690          for (wld = ezxml_child(wtl, "WavelengthData");
691                                  wld != NULL; wld = wld->next) {
692 <                if (strcasecmp(ezxml_txt(ezxml_child(wld,"Wavelength")),
693 <                                "Visible"))
694 <                        continue;       /* just visible for now */
692 >                const char      *cnm = ezxml_txt(ezxml_child(wld,"Wavelength"));
693 >                int             ct = -1;
694 >                if (!strcasecmp(cnm, "Visible"))
695 >                        ct = mtx_Y;
696 >                else if (!strcasecmp(cnm, "CIE-X"))
697 >                        ct = mtx_X;
698 >                else if (!strcasecmp(cnm, "CIE-Z"))
699 >                        ct = mtx_Z;
700 >                else
701 >                        continue;
702                  for (wdb = ezxml_child(wld, "WavelengthDataBlock");
703                                          wdb != NULL; wdb = wdb->next)
704 <                        if ((rval = load_bsdf_data(sd, wdb, rowIn)) < 0)
704 >                        if ((rval = load_bsdf_data(sd, wdb, ct, rowIn)) < 0)
705                                  return convert_errcode(rval);
706          }
707                                          /* separate diffuse components */
708 <        extract_diffuse(&sd->rLambFront, sd->rf);
709 <        extract_diffuse(&sd->rLambBack, sd->rb);
710 <        extract_diffuse(&sd->tLamb, sd->tf);
708 >        sd->rf = extract_diffuse(&sd->rLambFront, sd->rf);
709 >        sd->rb = extract_diffuse(&sd->rLambBack, sd->rb);
710 >        if (sd->tf != NULL)
711 >                sd->tf = extract_diffuse(&sd->tLamb, sd->tf);
712 >        if (sd->tb != NULL)
713 >                sd->tb = extract_diffuse(&sd->tLamb, sd->tb);
714                                          /* return success */
715          return SDEnone;
716   }
# Line 645 | Line 736 | SDgetMtxBSDF(float coef[SDmaxCh], const FVECT outVec,
736          }
737          if ((i_ndx < 0) | (o_ndx < 0))
738                  return 0;               /* nothing from this component */
739 <        coef[0] = mBSDF_value(dp, i_ndx, o_ndx);
740 <        return 1;                       /* XXX monochrome for now */
739 >
740 >        return mBSDF_color(coef, dp, i_ndx, o_ndx);
741   }
742  
743   /* Query solid angle for vector(s) */
# Line 759 | Line 850 | SDgetMtxCDist(const FVECT inVec, SDComponent *sdc)
850          }
851          cdlast = NULL;                  /* check for it in cache list */
852          for (cd = (SDMatCDst *)sdc->cdList; cd != NULL;
853 <                                cdlast = cd, cd = (SDMatCDst *)cd->next)
853 >                                        cdlast = cd, cd = cd->next)
854                  if (cd->indx == myCD.indx && (cd->calen == myCD.calen) &
855                                          (cd->ob_priv == myCD.ob_priv) &
856                                          (cd->ob_vec == myCD.ob_vec))
# Line 778 | Line 869 | SDgetMtxCDist(const FVECT inVec, SDComponent *sdc)
869          }
870          if (cdlast != NULL) {           /* move entry to head of cache list */
871                  cdlast->next = cd->next;
872 <                cd->next = sdc->cdList;
872 >                cd->next = (SDMatCDst *)sdc->cdList;
873                  sdc->cdList = (SDCDst *)cd;
874          }
875          return (SDCDst *)cd;            /* ready to go */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines