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

Comparing ray/src/common/bsdf.c (file contents):
Revision 2.15 by greg, Fri Feb 18 00:40:25 2011 UTC vs.
Revision 2.30 by greg, Thu Jun 9 17:09:39 2011 UTC

# Line 10 | Line 10 | static const char RCSid[] = "$Id$";
10   *
11   */
12  
13 + #define _USE_MATH_DEFINES
14   #include <stdio.h>
15   #include <stdlib.h>
16   #include <math.h>
# Line 45 | Line 46 | int                    SDretainSet = SDretainNone;
46   SDError
47   SDreportEnglish(SDError ec, FILE *fp)
48   {
48        if (fp == NULL)
49                return ec;
49          if (!ec)
50                  return SDEnone;
51 +        if ((ec < SDEnone) | (ec > SDEunknown)) {
52 +                SDerrorDetail[0] = '\0';
53 +                ec = SDEunknown;
54 +        }
55 +        if (fp == NULL)
56 +                return ec;
57          fputs(SDerrorEnglish[ec], fp);
58          if (SDerrorDetail[0]) {
59                  fputs(": ", fp);
# Line 77 | Line 82 | to_meters(             /* return factor to convert given unit to
82  
83   /* Load geometric dimensions and description (if any) */
84   static SDError
85 < SDloadGeometry(SDData *dp, ezxml_t wdb)
85 > SDloadGeometry(SDData *sd, ezxml_t wdb)
86   {
87          ezxml_t         geom;
88          double          cfact;
89          const char      *fmt, *mgfstr;
90  
91 <        sprintf(SDerrorDetail, "Negative size in \"%s\"", dp->name);
92 <        dp->dim[0] = dp->dim[1] = dp->dim[2] = .0;
91 >        if (wdb == NULL)                /* no geometry section? */
92 >                return SDEnone;
93 >        sd->dim[0] = sd->dim[1] = sd->dim[2] = .0;
94          if ((geom = ezxml_child(wdb, "Width")) != NULL)
95 <                dp->dim[0] = atof(ezxml_txt(geom)) *
95 >                sd->dim[0] = atof(ezxml_txt(geom)) *
96                                  to_meters(ezxml_attr(geom, "unit"));
97          if ((geom = ezxml_child(wdb, "Height")) != NULL)
98 <                dp->dim[1] = atof(ezxml_txt(geom)) *
98 >                sd->dim[1] = atof(ezxml_txt(geom)) *
99                                  to_meters(ezxml_attr(geom, "unit"));
100          if ((geom = ezxml_child(wdb, "Thickness")) != NULL)
101 <                dp->dim[2] = atof(ezxml_txt(geom)) *
101 >                sd->dim[2] = atof(ezxml_txt(geom)) *
102                                  to_meters(ezxml_attr(geom, "unit"));
103 <        if ((dp->dim[0] < .0) | (dp->dim[1] < .0) | (dp->dim[2] < .0))
103 >        if ((sd->dim[0] < 0) | (sd->dim[1] < 0) | (sd->dim[2] < 0)) {
104 >                sprintf(SDerrorDetail, "Negative size in \"%s\"", sd->name);
105                  return SDEdata;
106 +        }
107          if ((geom = ezxml_child(wdb, "Geometry")) == NULL ||
108                          (mgfstr = ezxml_txt(geom)) == NULL)
109                  return SDEnone;
# Line 103 | Line 111 | SDloadGeometry(SDData *dp, ezxml_t wdb)
111                          strcasecmp(fmt, "MGF")) {
112                  sprintf(SDerrorDetail,
113                          "Unrecognized geometry format '%s' in \"%s\"",
114 <                                        fmt, dp->name);
114 >                                        fmt, sd->name);
115                  return SDEsupport;
116          }
117          cfact = to_meters(ezxml_attr(geom, "unit"));
118 <        dp->mgf = (char *)malloc(strlen(mgfstr)+32);
119 <        if (dp->mgf == NULL) {
118 >        sd->mgf = (char *)malloc(strlen(mgfstr)+32);
119 >        if (sd->mgf == NULL) {
120                  strcpy(SDerrorDetail, "Out of memory in SDloadGeometry");
121                  return SDEmemory;
122          }
123          if (cfact < 0.99 || cfact > 1.01)
124 <                sprintf(dp->mgf, "xf -s %.5f\n%s\nxf\n", cfact, mgfstr);
124 >                sprintf(sd->mgf, "xf -s %.5f\n%s\nxf\n", cfact, mgfstr);
125          else
126 <                strcpy(dp->mgf, mgfstr);
126 >                strcpy(sd->mgf, mgfstr);
127          return SDEnone;
128   }
129  
122
130   /* Load a BSDF struct from the given file (free first and keep name) */
131   SDError
132   SDloadFile(SDData *sd, const char *fname)
133   {
134          SDError         lastErr;
135 <        ezxml_t         fl;
135 >        ezxml_t         fl, wtl;
136  
137          if ((sd == NULL) | (fname == NULL || !*fname))
138                  return SDEargument;
# Line 142 | Line 149 | SDloadFile(SDData *sd, const char *fname)
149                  ezxml_free(fl);
150                  return SDEformat;
151          }
152 +        if (strcmp(ezxml_name(fl), "WindowElement")) {
153 +                sprintf(SDerrorDetail,
154 +                        "BSDF \"%s\": top level node not 'WindowElement'",
155 +                                sd->name);
156 +                ezxml_free(fl);
157 +                return SDEformat;
158 +        }
159 +        wtl = ezxml_child(ezxml_child(fl, "Optical"), "Layer");
160 +        if (wtl == NULL) {
161 +                sprintf(SDerrorDetail, "BSDF \"%s\": no optical layer'",
162 +                                sd->name);
163 +                ezxml_free(fl);
164 +                return SDEformat;
165 +        }
166                                  /* load geometry if present */
167 <        if ((lastErr = SDloadGeometry(sd, fl)))
167 >        lastErr = SDloadGeometry(sd, ezxml_child(wtl, "Material"));
168 >        if (lastErr)
169                  return lastErr;
170                                  /* try loading variable resolution data */
171 <        lastErr = SDloadTre(sd, fl);
171 >        lastErr = SDloadTre(sd, wtl);
172                                  /* check our result */
173 <        switch (lastErr) {
174 <        case SDEformat:
175 <        case SDEdata:
154 <        case SDEsupport:        /* possibly we just tried the wrong format */
155 <                lastErr = SDloadMtx(sd, fl);
156 <                break;
157 <        default:                /* variable res. OK else serious error */
158 <                break;
159 <        }
173 >        if (lastErr == SDEsupport)      /* try matrix BSDF if not tree data */
174 >                lastErr = SDloadMtx(sd, wtl);
175 >                
176                                  /* done with XML file */
177          ezxml_free(fl);
178 <                                /* return success or failure */
179 <        return lastErr;
178 >        
179 >        if (lastErr) {          /* was there a load error? */
180 >                SDfreeBSDF(sd);
181 >                return lastErr;
182 >        }
183 >                                /* remove any insignificant components */
184 >        if (sd->rf != NULL && sd->rf->maxHemi <= .001) {
185 >                SDfreeSpectralDF(sd->rf); sd->rf = NULL;
186 >        }
187 >        if (sd->rb != NULL && sd->rb->maxHemi <= .001) {
188 >                SDfreeSpectralDF(sd->rb); sd->rb = NULL;
189 >        }
190 >        if (sd->tf != NULL && sd->tf->maxHemi <= .001) {
191 >                SDfreeSpectralDF(sd->tf); sd->tf = NULL;
192 >        }
193 >                                /* return success */
194 >        return SDEnone;
195   }
196  
197   /* Allocate new spectral distribution function */
# Line 219 | Line 250 | SDfreeSpectralDF(SDSpectralDF *df)
250  
251   /* Shorten file path to useable BSDF name, removing suffix */
252   void
253 < SDclipName(char res[SDnameLn], const char *fname)
253 > SDclipName(char *res, const char *fname)
254   {
255          const char      *cp, *dot = NULL;
256          
# Line 237 | Line 268 | SDclipName(char res[SDnameLn], const char *fname)
268  
269   /* Initialize an unused BSDF struct (simply clears to zeroes) */
270   void
271 < SDclearBSDF(SDData *sd)
271 > SDclearBSDF(SDData *sd, const char *fname)
272   {
273 <        if (sd != NULL)
274 <                memset(sd, 0, sizeof(SDData));
273 >        if (sd == NULL)
274 >                return;
275 >        memset(sd, 0, sizeof(SDData));
276 >        if (fname == NULL)
277 >                return;
278 >        SDclipName(sd->name, fname);
279   }
280  
281   /* Free data associated with BSDF struct */
# Line 266 | Line 301 | SDfreeBSDF(SDData *sd)
301                  sd->tf = NULL;
302          }
303          sd->rLambFront.cieY = .0;
304 <        sd->rLambFront.spec.clock = 0;
304 >        sd->rLambFront.spec.flags = 0;
305          sd->rLambBack.cieY = .0;
306 <        sd->rLambBack.spec.clock = 0;
306 >        sd->rLambBack.spec.flags = 0;
307          sd->tLamb.cieY = .0;
308 <        sd->tLamb.spec.clock = 0;
308 >        sd->tLamb.spec.flags = 0;
309   }
310  
311   /* Find writeable BSDF by name, or allocate new cache entry if absent */
# Line 298 | Line 333 | SDgetCache(const char *bname)
333          sdl->next = SDcacheList;
334          SDcacheList = sdl;
335  
336 <        sdl->refcnt++;
336 >        sdl->refcnt = 1;
337          return &sdl->bsdf;
338   }
339  
# Line 342 | Line 377 | SDfreeCache(const SDData *sd)
377          for (sdl = SDcacheList; sdl != NULL; sdl = (sdLast=sdl)->next)
378                  if (&sdl->bsdf == sd)
379                          break;
380 <        if (sdl == NULL || --sdl->refcnt)
380 >        if (sdl == NULL || (sdl->refcnt -= (sdl->refcnt > 0)))
381                  return;                 /* missing or still in use */
382                                          /* keep unreferenced data? */
383          if (SDisLoaded(sd) && SDretainSet) {
# Line 365 | Line 400 | SDfreeCache(const SDData *sd)
400  
401   /* Sample an individual BSDF component */
402   SDError
403 < SDsampComponent(SDValue *sv, FVECT outVec, const FVECT inVec,
369 <                        double randX, SDComponent *sdc)
403 > SDsampComponent(SDValue *sv, FVECT ioVec, double randX, SDComponent *sdc)
404   {
405          float           coef[SDmaxCh];
406          SDError         ec;
407 +        FVECT           inVec;
408          const SDCDst    *cd;
409          double          d;
410          int             n;
411                                          /* check arguments */
412 <        if ((sv == NULL) | (outVec == NULL) | (inVec == NULL) | (sdc == NULL))
412 >        if ((sv == NULL) | (ioVec == NULL) | (sdc == NULL))
413                  return SDEargument;
414                                          /* get cumulative distribution */
415 +        VCOPY(inVec, ioVec);
416          cd = (*sdc->func->getCDist)(inVec, sdc);
417          if (cd == NULL)
418                  return SDEmemory;
419          if (cd->cTotal <= 1e-7) {       /* anything to sample? */
420                  sv->spec = c_dfcolor;
421                  sv->cieY = .0;
422 <                memset(outVec, 0, 3*sizeof(double));
422 >                memset(ioVec, 0, 3*sizeof(double));
423                  return SDEnone;
424          }
425          sv->cieY = cd->cTotal;
426                                          /* compute sample direction */
427 <        ec = (*sdc->func->sampCDist)(outVec, randX, cd);
427 >        ec = (*sdc->func->sampCDist)(ioVec, randX, cd);
428          if (ec)
429                  return ec;
430                                          /* get BSDF color */
431 <        n = (*sdc->func->getBSDFs)(coef, outVec, inVec, sdc->dist);
431 >        n = (*sdc->func->getBSDFs)(coef, ioVec, inVec, sdc);
432          if (n <= 0) {
433                  strcpy(SDerrorDetail, "BSDF sample value error");
434                  return SDEinternal;
# Line 419 | Line 455 | SDmultiSamp(double t[], int n, double randX)
455          bitmask_t       ndx, coord[MS_MAXDIM];
456          
457          while (n > MS_MAXDIM)           /* punt for higher dimensions */
458 <                t[--n] = drand48();
458 >                t[--n] = rand()*(1./(RAND_MAX+.5));
459          nBits = (8*sizeof(bitmask_t) - 1) / n;
460          ndx = randX * (double)((bitmask_t)1 << (nBits*n));
461                                          /* get coordinate on Hilbert curve */
# Line 427 | Line 463 | SDmultiSamp(double t[], int n, double randX)
463                                          /* convert back to [0,1) range */
464          scale = 1. / (double)((bitmask_t)1 << nBits);
465          while (n--)
466 <                t[n] = scale * ((double)coord[n] + drand48());
466 >                t[n] = scale * ((double)coord[n] + rand()*(1./(RAND_MAX+.5)));
467   }
468  
469   #undef MS_MAXDIM
# Line 440 | Line 476 | SDdiffuseSamp(FVECT outVec, int outFront, double randX
476          SDmultiSamp(outVec, 2, randX);
477          SDsquare2disk(outVec, outVec[0], outVec[1]);
478          outVec[2] = 1. - outVec[0]*outVec[0] - outVec[1]*outVec[1];
479 <        if (outVec[2] > .0)             /* a bit of paranoia */
479 >        if (outVec[2] > 0)              /* a bit of paranoia */
480                  outVec[2] = sqrt(outVec[2]);
481          if (!outFront)                  /* going out back? */
482                  outVec[2] = -outVec[2];
# Line 448 | Line 484 | SDdiffuseSamp(FVECT outVec, int outFront, double randX
484  
485   /* Query projected solid angle coverage for non-diffuse BSDF direction */
486   SDError
487 < SDsizeBSDF(double *projSA, const FVECT vec, int qflags, const SDData *sd)
487 > SDsizeBSDF(double *projSA, const FVECT v1, const RREAL *v2,
488 >                                int qflags, const SDData *sd)
489   {
490 <        SDSpectralDF    *rdf;
490 >        SDSpectralDF    *rdf, *tdf;
491          SDError         ec;
492          int             i;
493                                          /* check arguments */
494 <        if ((projSA == NULL) | (vec == NULL) | (sd == NULL))
494 >        if ((projSA == NULL) | (v1 == NULL) | (sd == NULL))
495                  return SDEargument;
496                                          /* initialize extrema */
497 <        switch (qflags & SDqueryMin+SDqueryMax) {
497 >        switch (qflags) {
498          case SDqueryMax:
499                  projSA[0] = .0;
500                  break;
# Line 470 | Line 507 | SDsizeBSDF(double *projSA, const FVECT vec, int qflags
507          case 0:
508                  return SDEargument;
509          }
510 <        if (vec[2] > .0)                /* front surface query? */
510 >        if (v1[2] > 0)                  /* front surface query? */
511                  rdf = sd->rf;
512          else
513                  rdf = sd->rb;
514 +        tdf = sd->tf;
515 +        if (v2 != NULL)                 /* bidirectional? */
516 +                if (v1[2] > 0 ^ v2[2] > 0)
517 +                        rdf = NULL;
518 +                else
519 +                        tdf = NULL;
520          ec = SDEdata;                   /* run through components */
521          for (i = (rdf==NULL) ? 0 : rdf->ncomp; i--; ) {
522 <                ec = (*rdf->comp[i].func->queryProjSA)(projSA, vec, qflags,
523 <                                                        rdf->comp[i].dist);
522 >                ec = (*rdf->comp[i].func->queryProjSA)(projSA, v1, v2,
523 >                                                qflags, &rdf->comp[i]);
524                  if (ec)
525                          return ec;
526          }
527 <        for (i = (sd->tf==NULL) ? 0 : sd->tf->ncomp; i--; ) {
528 <                ec = (*sd->tf->comp[i].func->queryProjSA)(projSA, vec, qflags,
529 <                                                        sd->tf->comp[i].dist);
527 >        for (i = (tdf==NULL) ? 0 : tdf->ncomp; i--; ) {
528 >                ec = (*tdf->comp[i].func->queryProjSA)(projSA, v1, v2,
529 >                                                qflags, &tdf->comp[i]);
530                  if (ec)
531                          return ec;
532          }
533 <        return ec;
533 >        if (ec) {                       /* all diffuse? */
534 >                projSA[0] = M_PI;
535 >                if (qflags == SDqueryMin+SDqueryMax)
536 >                        projSA[1] = M_PI;
537 >        }
538 >        return SDEnone;
539   }
540  
541   /* Return BSDF for the given incident and scattered ray vectors */
# Line 502 | Line 550 | SDevalBSDF(SDValue *sv, const FVECT outVec, const FVEC
550          if ((sv == NULL) | (outVec == NULL) | (inVec == NULL) | (sd == NULL))
551                  return SDEargument;
552                                          /* whose side are we on? */
553 <        inFront = (inVec[2] > .0);
554 <        outFront = (outVec[2] > .0);
553 >        inFront = (inVec[2] > 0);
554 >        outFront = (outVec[2] > 0);
555                                          /* start with diffuse portion */
556          if (inFront & outFront) {
557                  *sv = sd->rLambFront;
# Line 520 | Line 568 | SDevalBSDF(SDValue *sv, const FVECT outVec, const FVEC
568          i = (sdf != NULL) ? sdf->ncomp : 0;
569          while (i-- > 0) {
570                  nch = (*sdf->comp[i].func->getBSDFs)(coef, outVec, inVec,
571 <                                                        sdf->comp[i].dist);
571 >                                                        &sdf->comp[i]);
572                  while (nch-- > 0) {
573                          c_cmix(&sv->spec, sv->cieY, &sv->spec,
574                                          coef[nch], &sdf->comp[i].cspec[nch]);
# Line 544 | Line 592 | SDdirectHemi(const FVECT inVec, int sflags, const SDDa
592          if ((inVec == NULL) | (sd == NULL))
593                  return .0;
594                                          /* gather diffuse components */
595 <        if (inVec[2] > .0) {
595 >        if (inVec[2] > 0) {
596                  hsum = sd->rLambFront.cieY;
597                  rdf = sd->rf;
598          } else /* !inFront */ {
# Line 575 | Line 623 | SDdirectHemi(const FVECT inVec, int sflags, const SDDa
623  
624   /* Sample BSDF direction based on the given random variable */
625   SDError
626 < SDsampBSDF(SDValue *sv, FVECT outVec, const FVECT inVec,
579 <                        double randX, int sflags, const SDData *sd)
626 > SDsampBSDF(SDValue *sv, FVECT ioVec, double randX, int sflags, const SDData *sd)
627   {
628          SDError         ec;
629 +        FVECT           inVec;
630          int             inFront;
631          SDSpectralDF    *rdf;
632          double          rdiff;
# Line 587 | Line 635 | SDsampBSDF(SDValue *sv, FVECT outVec, const FVECT inVe
635          SDComponent     *sdc;
636          const SDCDst    **cdarr = NULL;
637                                          /* check arguments */
638 <        if ((sv == NULL) | (outVec == NULL) | (inVec == NULL) | (sd == NULL) |
639 <                        (randX < .0) | (randX >= 1.))
638 >        if ((sv == NULL) | (ioVec == NULL) | (sd == NULL) |
639 >                        (randX < 0) | (randX >= 1.))
640                  return SDEargument;
641                                          /* whose side are we on? */
642 <        inFront = (inVec[2] > .0);
642 >        VCOPY(inVec, ioVec);
643 >        inFront = (inVec[2] > 0);
644                                          /* remember diffuse portions */
645          if (inFront) {
646                  *sv = sd->rLambFront;
# Line 631 | Line 680 | SDsampBSDF(SDValue *sv, FVECT outVec, const FVECT inVe
680          }
681          if (sv->cieY <= 1e-7) {         /* anything to sample? */
682                  sv->cieY = .0;
683 <                memset(outVec, 0, 3*sizeof(double));
683 >                memset(ioVec, 0, 3*sizeof(double));
684                  return SDEnone;
685          }
686                                          /* scale random variable */
687          randX *= sv->cieY;
688                                          /* diffuse reflection? */
689          if (randX < rdiff) {
690 <                SDdiffuseSamp(outVec, inFront, randX/rdiff);
690 >                SDdiffuseSamp(ioVec, inFront, randX/rdiff);
691                  goto done;
692          }
693          randX -= rdiff;
# Line 646 | Line 695 | SDsampBSDF(SDValue *sv, FVECT outVec, const FVECT inVe
695          if ((sflags & SDsampDf+SDsampT) == SDsampDf+SDsampT) {
696                  if (randX < sd->tLamb.cieY) {
697                          sv->spec = sd->tLamb.spec;
698 <                        SDdiffuseSamp(outVec, !inFront, randX/sd->tLamb.cieY);
698 >                        SDdiffuseSamp(ioVec, !inFront, randX/sd->tLamb.cieY);
699                          goto done;
700                  }
701                  randX -= sd->tLamb.cieY;
# Line 658 | Line 707 | SDsampBSDF(SDValue *sv, FVECT outVec, const FVECT inVe
707                  return SDEinternal;
708                                          /* compute sample direction */
709          sdc = (i < nr) ? &rdf->comp[i] : &sd->tf->comp[i-nr];
710 <        ec = (*sdc->func->sampCDist)(outVec, randX/cdarr[i]->cTotal, cdarr[i]);
710 >        ec = (*sdc->func->sampCDist)(ioVec, randX/cdarr[i]->cTotal, cdarr[i]);
711          if (ec)
712                  return ec;
713                                          /* compute color */
714 <        j = (*sdc->func->getBSDFs)(coef, outVec, inVec, sdc->dist);
714 >        j = (*sdc->func->getBSDFs)(coef, ioVec, inVec, sdc);
715          if (j <= 0) {
716                  sprintf(SDerrorDetail, "BSDF \"%s\" sampling value error",
717                                  sd->name);
# Line 689 | Line 738 | SDcompXform(RREAL vMtx[3][3], const FVECT sNrm, const
738          if ((vMtx == NULL) | (sNrm == NULL) | (uVec == NULL))
739                  return SDEargument;
740          VCOPY(vMtx[2], sNrm);
741 <        if (normalize(vMtx[2]) == .0)
741 >        if (normalize(vMtx[2]) == 0)
742                  return SDEargument;
743          fcross(vMtx[0], uVec, vMtx[2]);
744 <        if (normalize(vMtx[0]) == .0)
744 >        if (normalize(vMtx[0]) == 0)
745                  return SDEargument;
746          fcross(vMtx[1], vMtx[2], vMtx[0]);
747          return SDEnone;
# Line 712 | Line 761 | SDinvXform(RREAL iMtx[3][3], RREAL vMtx[3][3])
761          mTmp[0][1] = vMtx[2][1]*vMtx[0][2] - vMtx[2][2]*vMtx[0][1];
762          mTmp[0][2] = vMtx[1][2]*vMtx[0][1] - vMtx[1][1]*vMtx[0][2];
763          d = vMtx[0][0]*mTmp[0][0] + vMtx[1][0]*mTmp[0][1] + vMtx[2][0]*mTmp[0][2];
764 <        if (d == .0) {
764 >        if (d == 0) {
765                  strcpy(SDerrorDetail, "Zero determinant in matrix inversion");
766                  return SDEargument;
767          }
# Line 739 | Line 788 | SDmapDir(FVECT resVec, RREAL vMtx[3][3], const FVECT i
788          if (vMtx == NULL) {             /* assume they just want to normalize */
789                  if (resVec != inpVec)
790                          VCOPY(resVec, inpVec);
791 <                return (normalize(resVec) > .0) ? SDEnone : SDEargument;
791 >                return (normalize(resVec) > 0) ? SDEnone : SDEargument;
792          }
793          vTmp[0] = DOT(vMtx[0], inpVec);
794          vTmp[1] = DOT(vMtx[1], inpVec);
795          vTmp[2] = DOT(vMtx[2], inpVec);
796 <        if (normalize(vTmp) == .0)
796 >        if (normalize(vTmp) == 0)
797                  return SDEargument;
798          VCOPY(resVec, vTmp);
799          return SDEnone;
# Line 816 | Line 865 | static int     nabases = 3;    /* current number of defined b
865   static int
866   fequal(double a, double b)
867   {
868 <        if (b != .0)
868 >        if (b != 0)
869                  a = a/b - 1.;
870          return((a <= 1e-6) & (a >= -1e-6));
871   }
# Line 1077 | Line 1126 | load_bsdf_data(                /* load BSDF distribution for this wa
1126                          break;
1127                  }
1128          if (i < 0) {
1129 <                sprintf(errmsg, "undefined RowAngleBasis '%s'", cbasis);
1129 >                sprintf(errmsg, "undefined RowAngleBasis '%s'", rbasis);
1130                  error(WARNING, errmsg);
1131                  return;
1132          }
# Line 1134 | Line 1183 | check_bsdf_data(       /* check that BSDF data is sane */
1183          hemi_total = .0;
1184          for (i = dp->ninc; i--; ) {
1185                  dom = getBSDF_incohm(dp,i);
1186 <                if (dom <= .0) {
1186 >                if (dom <= 0) {
1187                          error(WARNING, "zero/negative incoming solid angle");
1188                          continue;
1189                  }
# Line 1157 | Line 1206 | check_bsdf_data(       /* check that BSDF data is sane */
1206          hemi_total = .0;
1207          for (o = dp->nout; o--; ) {
1208                  dom = getBSDF_outohm(dp,o);
1209 <                if (dom <= .0) {
1209 >                if (dom <= 0) {
1210                          error(WARNING, "zero/negative outgoing solid angle");
1211                          continue;
1212                  }
# Line 1181 | Line 1230 | check_bsdf_data(       /* check that BSDF data is sane */
1230                  hemi_total = .0;
1231                  for (o = dp->nout; o--; ) {
1232                          double  f = BSDF_value(dp,i,o);
1233 <                        if (f >= .0)
1233 >                        if (f >= 0)
1234                                  hemi_total += f*omega_oarr[o];
1235                          else {
1236                                  nneg += (f < -FTINY);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines