47 |
|
/* Cache of loaded BSDFs */ |
48 |
|
struct SDCache_s *SDcacheList = NULL; |
49 |
|
|
50 |
< |
/* Retain BSDFs in cache list */ |
50 |
> |
/* Retain BSDFs in cache list? */ |
51 |
|
int SDretainSet = SDretainNone; |
52 |
|
|
53 |
+ |
/* Maximum cache size for any given BSDF? */ |
54 |
+ |
unsigned long SDmaxCache = 0; /* 0 == unlimited */ |
55 |
+ |
|
56 |
|
/* Report any error to the indicated stream */ |
57 |
|
SDError |
58 |
|
SDreportError(SDError ec, FILE *fp) |
330 |
|
for (cp = fname; *cp; cp++) |
331 |
|
if (*cp == '.') |
332 |
|
dot = cp; |
333 |
+ |
else if (*cp == '/') |
334 |
+ |
dot = NULL; |
335 |
|
if ((dot == NULL) | (dot < fname+2)) |
336 |
|
dot = cp; |
337 |
|
if (dot - fname >= SDnameLn) |
383 |
|
sd->rLambFront.spec.flags = 0; |
384 |
|
sd->rLambBack.cieY = .0; |
385 |
|
sd->rLambBack.spec.flags = 0; |
386 |
< |
sd->tLamb.cieY = .0; |
387 |
< |
sd->tLamb.spec.flags = 0; |
386 |
> |
sd->tLambFront.cieY = .0; |
387 |
> |
sd->tLambFront.spec.flags = 0; |
388 |
> |
sd->tLambBack.cieY = .0; |
389 |
> |
sd->tLambBack.spec.flags = 0; |
390 |
|
} |
391 |
|
|
392 |
|
/* Find writeable BSDF by name, or allocate new cache entry if absent */ |
429 |
|
if (fname == NULL || !*fname) |
430 |
|
return NULL; |
431 |
|
SDerrorDetail[0] = '\0'; |
432 |
+ |
/* PLACE MUTEX LOCK HERE FOR THREAD-SAFE */ |
433 |
|
if ((sd = SDgetCache(fname)) == NULL) { |
434 |
|
SDreportError(SDEmemory, stderr); |
435 |
|
return NULL; |
437 |
|
if (!SDisLoaded(sd) && (ec = SDloadFile(sd, fname))) { |
438 |
|
SDreportError(ec, stderr); |
439 |
|
SDfreeCache(sd); |
440 |
< |
return NULL; |
440 |
> |
sd = NULL; |
441 |
|
} |
442 |
+ |
/* END MUTEX LOCK */ |
443 |
|
return sd; |
444 |
|
} |
445 |
|
|
503 |
|
sv->cieY = cd->cTotal; |
504 |
|
if (sv->cieY <= 1e-6) { /* nothing to sample? */ |
505 |
|
sv->spec = c_dfcolor; |
506 |
< |
memset(ioVec, 0, 3*sizeof(double)); |
506 |
> |
memset(ioVec, 0, sizeof(FVECT)); |
507 |
|
return SDEnone; |
508 |
|
} |
509 |
|
/* compute sample direction */ |
511 |
|
if (ec) |
512 |
|
return ec; |
513 |
|
/* get BSDF color */ |
514 |
< |
n = (*sdc->func->getBSDFs)(coef, ioVec, inVec, sdc); |
514 |
> |
n = (*sdc->func->getBSDFs)(coef, inVec, ioVec, sdc); |
515 |
|
if (n <= 0) { |
516 |
|
strcpy(SDerrorDetail, "BSDF sample value error"); |
517 |
|
return SDEinternal; |
522 |
|
c_cmix(&sv->spec, d, &sv->spec, coef[n], &sdc->cspec[n]); |
523 |
|
d += coef[n]; |
524 |
|
} |
525 |
< |
/* make sure everything is set */ |
517 |
< |
c_ccvt(&sv->spec, C_CSXY+C_CSSPEC); |
525 |
> |
c_ccvt(&sv->spec, C_CSXY); /* make sure (x,y) is set */ |
526 |
|
return SDEnone; |
527 |
|
} |
528 |
|
|
530 |
|
|
531 |
|
/* Convert 1-dimensional random variable to N-dimensional */ |
532 |
|
void |
533 |
< |
SDmultiSamp(double t[], int n, double randX) |
533 |
> |
SDmultiSamp(RREAL t[], int n, double randX) |
534 |
|
{ |
535 |
|
unsigned nBits; |
536 |
|
double scale; |
560 |
|
|
561 |
|
/* Generate diffuse hemispherical sample */ |
562 |
|
static void |
563 |
< |
SDdiffuseSamp(FVECT outVec, int outFront, double randX) |
563 |
> |
SDdiffuseSamp(FVECT ioVec, int outFront, double randX) |
564 |
|
{ |
565 |
|
/* convert to position on hemisphere */ |
566 |
< |
SDmultiSamp(outVec, 2, randX); |
567 |
< |
SDsquare2disk(outVec, outVec[0], outVec[1]); |
568 |
< |
outVec[2] = 1. - outVec[0]*outVec[0] - outVec[1]*outVec[1]; |
569 |
< |
outVec[2] = sqrt(outVec[2]*(outVec[2]>0)); |
566 |
> |
SDmultiSamp(ioVec, 2, randX); |
567 |
> |
square2disk(ioVec, ioVec[0], ioVec[1]); |
568 |
> |
ioVec[2] = 1. - ioVec[0]*ioVec[0] - ioVec[1]*ioVec[1]; |
569 |
> |
ioVec[2] = sqrt(ioVec[2]*(ioVec[2]>0)); |
570 |
|
if (!outFront) /* going out back? */ |
571 |
< |
outVec[2] = -outVec[2]; |
571 |
> |
ioVec[2] = -ioVec[2]; |
572 |
|
} |
573 |
|
|
574 |
|
/* Query projected solid angle coverage for non-diffuse BSDF direction */ |
603 |
|
rdf = sd->rb; |
604 |
|
tdf = (sd->tb != NULL) ? sd->tb : sd->tf; |
605 |
|
} |
606 |
< |
if (v2 != NULL) /* bidirectional? */ |
606 |
> |
if (v2 != NULL) { /* bidirectional? */ |
607 |
|
if (v1[2] > 0 ^ v2[2] > 0) |
608 |
|
rdf = NULL; |
609 |
|
else |
610 |
|
tdf = NULL; |
611 |
+ |
} |
612 |
|
ec = SDEdata; /* run through components */ |
613 |
|
for (i = (rdf==NULL) ? 0 : rdf->ncomp; i--; ) { |
614 |
|
ec = (*rdf->comp[i].func->queryProjSA)(projSA, v1, v2, |
633 |
|
|
634 |
|
/* Return BSDF for the given incident and scattered ray vectors */ |
635 |
|
SDError |
636 |
< |
SDevalBSDF(SDValue *sv, const FVECT outVec, const FVECT inVec, const SDData *sd) |
636 |
> |
SDevalBSDF(SDValue *sv, const FVECT inVec, const FVECT outVec, const SDData *sd) |
637 |
|
{ |
638 |
|
int inFront, outFront; |
639 |
|
SDSpectralDF *sdf; |
653 |
|
*sv = sd->rLambBack; |
654 |
|
sdf = sd->rb; |
655 |
|
} else if (inFront) { |
656 |
< |
*sv = sd->tLamb; |
656 |
> |
*sv = sd->tLambFront; |
657 |
|
sdf = (sd->tf != NULL) ? sd->tf : sd->tb; |
658 |
< |
} else /* inBack */ { |
659 |
< |
*sv = sd->tLamb; |
658 |
> |
} else /* outFront & !inFront */ { |
659 |
> |
*sv = sd->tLambBack; |
660 |
|
sdf = (sd->tb != NULL) ? sd->tb : sd->tf; |
661 |
|
} |
662 |
|
sv->cieY *= 1./M_PI; |
663 |
|
/* add non-diffuse components */ |
664 |
|
i = (sdf != NULL) ? sdf->ncomp : 0; |
665 |
|
while (i-- > 0) { |
666 |
< |
nch = (*sdf->comp[i].func->getBSDFs)(coef, outVec, inVec, |
666 |
> |
nch = (*sdf->comp[i].func->getBSDFs)(coef, inVec, outVec, |
667 |
|
&sdf->comp[i]); |
668 |
|
while (nch-- > 0) { |
669 |
|
c_cmix(&sv->spec, sv->cieY, &sv->spec, |
671 |
|
sv->cieY += coef[nch]; |
672 |
|
} |
673 |
|
} |
674 |
< |
/* make sure everything is set */ |
666 |
< |
c_ccvt(&sv->spec, C_CSXY+C_CSSPEC); |
674 |
> |
c_ccvt(&sv->spec, C_CSXY); /* make sure (x,y) is set */ |
675 |
|
return SDEnone; |
676 |
|
} |
677 |
|
|
699 |
|
if ((sflags & SDsampDf+SDsampR) != SDsampDf+SDsampR) |
700 |
|
hsum = .0; |
701 |
|
if ((sflags & SDsampDf+SDsampT) == SDsampDf+SDsampT) |
702 |
< |
hsum += sd->tLamb.cieY; |
702 |
> |
hsum += (inVec[2] > 0) ? |
703 |
> |
sd->tLambFront.cieY : sd->tLambBack.cieY; |
704 |
|
/* gather non-diffuse components */ |
705 |
|
i = (((sflags & SDsampSp+SDsampR) == SDsampSp+SDsampR) & |
706 |
|
(rdf != NULL)) ? rdf->ncomp : 0; |
753 |
|
sv->cieY = .0; |
754 |
|
rdiff = sv->cieY; |
755 |
|
if ((sflags & SDsampDf+SDsampT) == SDsampDf+SDsampT) |
756 |
< |
sv->cieY += sd->tLamb.cieY; |
756 |
> |
sv->cieY += inFront ? sd->tLambFront.cieY : sd->tLambBack.cieY; |
757 |
|
/* gather non-diffuse components */ |
758 |
|
i = nr = (((sflags & SDsampSp+SDsampR) == SDsampSp+SDsampR) & |
759 |
|
(rdf != NULL)) ? rdf->ncomp : 0; |
776 |
|
} |
777 |
|
if (sv->cieY <= 1e-6) { /* anything to sample? */ |
778 |
|
sv->cieY = .0; |
779 |
< |
memset(ioVec, 0, 3*sizeof(double)); |
779 |
> |
memset(ioVec, 0, sizeof(FVECT)); |
780 |
|
return SDEnone; |
781 |
|
} |
782 |
|
/* scale random variable */ |
789 |
|
randX -= rdiff; |
790 |
|
/* diffuse transmission? */ |
791 |
|
if ((sflags & SDsampDf+SDsampT) == SDsampDf+SDsampT) { |
792 |
< |
if (randX < sd->tLamb.cieY) { |
793 |
< |
sv->spec = sd->tLamb.spec; |
794 |
< |
SDdiffuseSamp(ioVec, !inFront, randX/sd->tLamb.cieY); |
792 |
> |
const SDValue *sdt = inFront ? &sd->tLambFront : &sd->tLambBack; |
793 |
> |
if (randX < sdt->cieY) { |
794 |
> |
sv->spec = sdt->spec; |
795 |
> |
SDdiffuseSamp(ioVec, !inFront, randX/sdt->cieY); |
796 |
|
goto done; |
797 |
|
} |
798 |
< |
randX -= sd->tLamb.cieY; |
798 |
> |
randX -= sdt->cieY; |
799 |
|
} |
800 |
|
/* else one of cumulative dist. */ |
801 |
< |
for (i = 0; i < n && randX > cdarr[i]->cTotal; i++) |
801 |
> |
for (i = 0; i < n && randX >= cdarr[i]->cTotal; i++) |
802 |
|
randX -= cdarr[i]->cTotal; |
803 |
|
if (i >= n) |
804 |
|
return SDEinternal; |
808 |
|
if (ec) |
809 |
|
return ec; |
810 |
|
/* compute color */ |
811 |
< |
j = (*sdc->func->getBSDFs)(coef, ioVec, inVec, sdc); |
811 |
> |
j = (*sdc->func->getBSDFs)(coef, inVec, ioVec, sdc); |
812 |
|
if (j <= 0) { |
813 |
|
sprintf(SDerrorDetail, "BSDF \"%s\" sampling value error", |
814 |
|
sd->name); |
823 |
|
done: |
824 |
|
if (cdarr != NULL) |
825 |
|
free(cdarr); |
826 |
< |
/* make sure everything is set */ |
817 |
< |
c_ccvt(&sv->spec, C_CSXY+C_CSSPEC); |
826 |
> |
c_ccvt(&sv->spec, C_CSXY); /* make sure (x,y) is set */ |
827 |
|
return SDEnone; |
828 |
|
} |
829 |
|
|