| 35 |
|
"Unknown error" |
| 36 |
|
}; |
| 37 |
|
|
| 38 |
+ |
/* Pointer to error list in preferred language */ |
| 39 |
+ |
const char **SDerrorList = SDerrorEnglish; |
| 40 |
+ |
|
| 41 |
|
/* Additional information on last error (ASCII English) */ |
| 42 |
|
char SDerrorDetail[256]; |
| 43 |
|
|
| 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 |
< |
/* Report any error to the indicated stream (in English) */ |
| 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 |
< |
SDreportEnglish(SDError ec, FILE *fp) |
| 58 |
> |
SDreportError(SDError ec, FILE *fp) |
| 59 |
|
{ |
| 60 |
|
if (!ec) |
| 61 |
|
return SDEnone; |
| 65 |
|
} |
| 66 |
|
if (fp == NULL) |
| 67 |
|
return ec; |
| 68 |
< |
fputs(SDerrorEnglish[ec], fp); |
| 68 |
> |
fputs(SDerrorList[ec], fp); |
| 69 |
|
if (SDerrorDetail[0]) { |
| 70 |
|
fputs(": ", fp); |
| 71 |
|
fputs(SDerrorDetail, fp); |
| 202 |
|
} |
| 203 |
|
wtl = ezxml_child(ezxml_child(fl, "Optical"), "Layer"); |
| 204 |
|
if (wtl == NULL) { |
| 205 |
< |
sprintf(SDerrorDetail, "BSDF \"%s\": no optical layers'", |
| 205 |
> |
sprintf(SDerrorDetail, "BSDF \"%s\": no optical layers", |
| 206 |
|
sd->name); |
| 207 |
|
ezxml_free(fl); |
| 208 |
|
return SDEformat; |
| 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 |
< |
SDreportEnglish(SDEmemory, stderr); |
| 434 |
> |
SDreportError(SDEmemory, stderr); |
| 435 |
|
return NULL; |
| 436 |
|
} |
| 437 |
|
if (!SDisLoaded(sd) && (ec = SDloadFile(sd, fname))) { |
| 438 |
< |
SDreportEnglish(ec, stderr); |
| 438 |
> |
SDreportError(ec, stderr); |
| 439 |
|
SDfreeCache(sd); |
| 440 |
< |
return NULL; |
| 440 |
> |
sd = NULL; |
| 441 |
|
} |
| 442 |
+ |
/* END MUTEX LOCK */ |
| 443 |
|
return sd; |
| 444 |
|
} |
| 445 |
|
|
| 497 |
|
return SDEargument; |
| 498 |
|
/* get cumulative distribution */ |
| 499 |
|
VCOPY(inVec, ioVec); |
| 500 |
+ |
sv->cieY = 0; |
| 501 |
|
cd = (*sdc->func->getCDist)(inVec, sdc); |
| 502 |
< |
if (cd == NULL) |
| 503 |
< |
return SDEmemory; |
| 504 |
< |
if (cd->cTotal <= 1e-6) { /* anything to sample? */ |
| 502 |
> |
if (cd != NULL) |
| 503 |
> |
sv->cieY = cd->cTotal; |
| 504 |
> |
if (sv->cieY <= 1e-6) { /* nothing to sample? */ |
| 505 |
|
sv->spec = c_dfcolor; |
| 506 |
< |
sv->cieY = .0; |
| 494 |
< |
memset(ioVec, 0, 3*sizeof(double)); |
| 506 |
> |
memset(ioVec, 0, sizeof(FVECT)); |
| 507 |
|
return SDEnone; |
| 508 |
|
} |
| 497 |
– |
sv->cieY = cd->cTotal; |
| 509 |
|
/* compute sample direction */ |
| 510 |
|
ec = (*sdc->func->sampCDist)(ioVec, randX, cd); |
| 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 */ |
| 515 |
< |
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 |
|
|
| 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 |
< |
if (outVec[2] > 0) /* a bit of paranoia */ |
| 560 |
< |
outVec[2] = sqrt(outVec[2]); |
| 566 |
> |
SDmultiSamp(ioVec, 2, randX); |
| 567 |
> |
SDsquare2disk(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, |
| 626 |
|
projSA[0] = M_PI; |
| 627 |
|
if (qflags == SDqueryMin+SDqueryMax) |
| 628 |
|
projSA[1] = M_PI; |
| 629 |
< |
} |
| 629 |
> |
} else if (qflags == SDqueryMin+SDqueryMax && projSA[0] > projSA[1]) |
| 630 |
> |
projSA[0] = projSA[1]; |
| 631 |
|
return SDEnone; |
| 632 |
|
} |
| 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 */ |
| 664 |
< |
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; |
| 764 |
|
return SDEmemory; |
| 765 |
|
while (j-- > 0) { /* non-diffuse transmission */ |
| 766 |
|
cdarr[i+j] = (*tdf->comp[j].func->getCDist)(inVec, &tdf->comp[j]); |
| 767 |
< |
if (cdarr[i+j] == NULL) { |
| 768 |
< |
free(cdarr); |
| 758 |
< |
return SDEmemory; |
| 759 |
< |
} |
| 767 |
> |
if (cdarr[i+j] == NULL) |
| 768 |
> |
cdarr[i+j] = &SDemptyCD; |
| 769 |
|
sv->cieY += cdarr[i+j]->cTotal; |
| 770 |
|
} |
| 771 |
|
while (i-- > 0) { /* non-diffuse reflection */ |
| 772 |
|
cdarr[i] = (*rdf->comp[i].func->getCDist)(inVec, &rdf->comp[i]); |
| 773 |
< |
if (cdarr[i] == NULL) { |
| 774 |
< |
free(cdarr); |
| 766 |
< |
return SDEmemory; |
| 767 |
< |
} |
| 773 |
> |
if (cdarr[i] == NULL) |
| 774 |
> |
cdarr[i] = &SDemptyCD; |
| 775 |
|
sv->cieY += cdarr[i]->cTotal; |
| 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 */ |
| 819 |
< |
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 |
|
|