518 |
|
/* Query BSDF value and sample hypercube for the given vectors */ |
519 |
|
static int |
520 |
|
SDqueryTre(const SDTre *sdt, float *coef, |
521 |
< |
const FVECT outVec, const FVECT inVec, double *hc) |
521 |
> |
const FVECT inVec, const FVECT outVec, double *hc) |
522 |
|
{ |
523 |
|
const RREAL *vtmp; |
524 |
|
float yval; |
525 |
|
FVECT rOutVec; |
526 |
< |
double gridPos[4]; |
526 |
> |
RREAL gridPos[4]; |
527 |
|
|
528 |
|
if (sdt->stc[tt_Y] == NULL) /* paranoia, I hope */ |
529 |
|
return 0; |
561 |
|
spinvector(rOutVec, outVec, zvec, -atan2(-inVec[1],-inVec[0])); |
562 |
|
gridPos[0] = (.5-FTINY) - |
563 |
|
.5*sqrt(inVec[0]*inVec[0] + inVec[1]*inVec[1]); |
564 |
< |
SDdisk2square(gridPos+1, rOutVec[0], rOutVec[1]); |
564 |
> |
disk2square(gridPos+1, rOutVec[0], rOutVec[1]); |
565 |
|
} else if (sdt->stc[tt_Y]->ndim == 4) { |
566 |
< |
SDdisk2square(gridPos, -inVec[0], -inVec[1]); |
567 |
< |
SDdisk2square(gridPos+2, outVec[0], outVec[1]); |
566 |
> |
disk2square(gridPos, -inVec[0], -inVec[1]); |
567 |
> |
disk2square(gridPos+2, outVec[0], outVec[1]); |
568 |
|
} else |
569 |
|
return 0; /* should be internal error */ |
570 |
|
/* get BSDF value */ |
571 |
|
yval = SDlookupTre(sdt->stc[tt_Y], gridPos, hc); |
572 |
+ |
if (coef == NULL) /* just getting hypercube? */ |
573 |
+ |
return 1; |
574 |
|
if (sdt->stc[tt_u] == NULL || sdt->stc[tt_v] == NULL) { |
575 |
< |
if (coef != NULL) *coef = yval; |
575 |
> |
*coef = yval; |
576 |
|
return 1; /* no color */ |
577 |
|
} |
576 |
– |
if (coef == NULL) /* just getting hypercube? */ |
577 |
– |
return 1; |
578 |
|
/* else decode color */ |
579 |
|
SDyuv2rgb(yval, SDlookupTre(sdt->stc[tt_u], gridPos, NULL), |
580 |
|
SDlookupTre(sdt->stc[tt_v], gridPos, NULL), coef); |
744 |
|
const SDCDst * |
745 |
|
SDgetTreCDist(const FVECT inVec, SDComponent *sdc) |
746 |
|
{ |
747 |
+ |
unsigned long cacheLeft = SDmaxCache; |
748 |
|
const SDTre *sdt; |
749 |
< |
double inCoord[2]; |
749 |
> |
RREAL inCoord[2]; |
750 |
|
int i; |
751 |
|
int mode; |
752 |
< |
SDTreCDst *cd, *cdlast; |
752 |
> |
SDTreCDst *cd, *cdlast, *cdlimit; |
753 |
|
/* check arguments */ |
754 |
|
if ((inVec == NULL) | (sdc == NULL) || |
755 |
|
(sdt = (SDTre *)sdc->dist) == NULL) |
781 |
|
.5*sqrt(inVec[0]*inVec[0] + inVec[1]*inVec[1]); |
782 |
|
} else if (sdt->stc[tt_Y]->ndim == 4) { |
783 |
|
if (mode != sdt->sidef) /* use reciprocity? */ |
784 |
< |
SDdisk2square(inCoord, inVec[0], inVec[1]); |
784 |
> |
disk2square(inCoord, inVec[0], inVec[1]); |
785 |
|
else |
786 |
< |
SDdisk2square(inCoord, -inVec[0], -inVec[1]); |
786 |
> |
disk2square(inCoord, -inVec[0], -inVec[1]); |
787 |
|
} else |
788 |
|
return NULL; /* should be internal error */ |
789 |
|
/* quantize to avoid f.p. errors */ |
790 |
|
for (i = sdt->stc[tt_Y]->ndim - 2; i--; ) |
791 |
|
inCoord[i] = floor(inCoord[i]/quantum)*quantum + .5*quantum; |
792 |
< |
cdlast = NULL; /* check for direction in cache list */ |
792 |
> |
cdlast = cdlimit = NULL; /* check for direction in cache list */ |
793 |
> |
/* PLACE MUTEX LOCK HERE FOR THREAD-SAFE */ |
794 |
|
for (cd = (SDTreCDst *)sdc->cdList; cd != NULL; |
795 |
|
cdlast = cd, cd = cd->next) { |
796 |
+ |
if (cacheLeft) { /* check cache size limit */ |
797 |
+ |
long csiz = sizeof(SDTreCDst) + |
798 |
+ |
sizeof(cd->carr[0])*cd->calen; |
799 |
+ |
if (cacheLeft > csiz) |
800 |
+ |
cacheLeft -= csiz; |
801 |
+ |
else { |
802 |
+ |
cdlimit = cdlast; |
803 |
+ |
cacheLeft = 0; |
804 |
+ |
} |
805 |
+ |
} |
806 |
|
if (cd->sidef != mode) |
807 |
|
continue; |
808 |
|
for (i = sdt->stc[tt_Y]->ndim - 2; i--; ) |
812 |
|
if (i < 0) |
813 |
|
break; /* means we have a match */ |
814 |
|
} |
815 |
< |
if (cd == NULL) /* need to create new entry? */ |
815 |
> |
if (cd == NULL) { /* need to create new entry? */ |
816 |
> |
if (cdlimit != NULL) /* exceeded cache size limit? */ |
817 |
> |
while ((cd = cdlimit->next) != NULL) { |
818 |
> |
cdlimit->next = cd->next; |
819 |
> |
free(cd); |
820 |
> |
} |
821 |
|
cdlast = cd = make_cdist(sdt, inCoord, mode != sdt->sidef); |
822 |
+ |
} |
823 |
|
if (cdlast != NULL) { /* move entry to head of cache list */ |
824 |
|
cdlast->next = cd->next; |
825 |
|
cd->next = (SDTreCDst *)sdc->cdList; |
826 |
|
sdc->cdList = (SDCDst *)cd; |
827 |
|
} |
828 |
+ |
/* END MUTEX LOCK */ |
829 |
|
return (SDCDst *)cd; /* ready to go */ |
830 |
|
} |
831 |
|
|
888 |
|
const SDTreCDst *cd = (const SDTreCDst *)cdp; |
889 |
|
const unsigned target = randX*cumlmax; |
890 |
|
bitmask_t hndx, hcoord[2]; |
891 |
< |
double gpos[3], rotangle; |
891 |
> |
FVECT gpos; |
892 |
> |
double rotangle; |
893 |
|
int i, iupper, ilower; |
894 |
|
/* check arguments */ |
895 |
|
if ((ioVec == NULL) | (cd == NULL)) |
919 |
|
for (i = 2; i--; ) |
920 |
|
gpos[i] = ((double)hcoord[i] + rand()*(1./(RAND_MAX+.5))) / |
921 |
|
(double)((bitmask_t)1 << nBitsC); |
922 |
< |
SDsquare2disk(gpos, gpos[0], gpos[1]); |
922 |
> |
square2disk(gpos, gpos[0], gpos[1]); |
923 |
|
/* compute Z-coordinate */ |
924 |
|
gpos[2] = 1. - gpos[0]*gpos[0] - gpos[1]*gpos[1]; |
925 |
|
gpos[2] = sqrt(gpos[2]*(gpos[2]>0)); |
944 |
|
} |
945 |
|
|
946 |
|
/* Advance pointer past matching token (or any token if c==0) */ |
947 |
< |
#define eat_token(spp,c) (next_token(spp)==(c) ^ !(c) ? *(*(spp))++ : 0) |
947 |
> |
#define eat_token(spp,c) ((next_token(spp)==(c)) ^ !(c) ? *(*(spp))++ : 0) |
948 |
|
|
949 |
|
/* Count words from this point in string to '}' */ |
950 |
|
static int |
1194 |
|
static double |
1195 |
|
subtract_min_Y(SDNode *st) |
1196 |
|
{ |
1197 |
< |
float vmin; |
1197 |
> |
const float vmaxmin = 1.5/M_PI; |
1198 |
> |
float vmin; |
1199 |
|
/* be sure to skip unused portion */ |
1200 |
|
if (st->ndim == 3) { |
1201 |
|
int n; |
1202 |
< |
vmin = 1./M_PI; |
1202 |
> |
vmin = vmaxmin; |
1203 |
|
if (st->log2GR < 0) { |
1204 |
|
for (n = 0; n < 8; n += 2) { |
1205 |
|
float v = SDgetTreMin(st->u.t[n]); |
1215 |
|
} else /* anisotropic covers entire tree */ |
1216 |
|
vmin = SDgetTreMin(st); |
1217 |
|
|
1218 |
< |
if (vmin <= FTINY) |
1219 |
< |
return .0; |
1218 |
> |
if ((vmin >= vmaxmin) | (vmin <= .01/M_PI)) |
1219 |
> |
return .0; /* not worth bothering about */ |
1220 |
|
|
1221 |
|
SDsubtractTreVal(st, vmin); |
1222 |
|
|
1335 |
|
my_min.new_stu = my_min.new_stv = NULL; |
1336 |
|
/* get minimum RGB value */ |
1337 |
|
SDtraverseTre(stc[tt_Y], NULL, 0, get_min_RGB, &my_min); |
1338 |
< |
ymin = tt_RGB_coef[0]*my_min.rgb[0] + |
1339 |
< |
tt_RGB_coef[1]*my_min.rgb[1] + |
1340 |
< |
tt_RGB_coef[2]*my_min.rgb[2]; |
1341 |
< |
if (ymin <= 1e-5) { |
1342 |
< |
*cs = c_dfcolor; |
1322 |
< |
return .0; /* not worth bothering about */ |
1323 |
< |
} |
1324 |
< |
/* adjust u' & v' values */ |
1338 |
> |
/* convert to C_COLOR */ |
1339 |
> |
ymin = c_fromSharpRGB(my_min.rgb, cs); |
1340 |
> |
if ((ymin >= .5*FHUGE) | (ymin <= .01/M_PI)) |
1341 |
> |
return .0; /* close to zero or no tree */ |
1342 |
> |
/* adjust u' & v' trees */ |
1343 |
|
SDtraverseTre(stc[tt_u], NULL, 0, adjust_utree, &my_min); |
1344 |
|
SDtraverseTre(stc[tt_v], NULL, 0, adjust_vtree, &my_min); |
1345 |
|
SDfreeTre(stc[tt_u]); SDfreeTre(stc[tt_v]); |
1346 |
|
stc[tt_u] = SDsimplifyTre(my_min.new_stu); |
1347 |
|
stc[tt_v] = SDsimplifyTre(my_min.new_stv); |
1348 |
< |
/* finally, subtract Y value */ |
1348 |
> |
/* subtract Y & return hemispherical */ |
1349 |
|
SDsubtractTreVal(stc[tt_Y], ymin); |
1350 |
< |
/* return color and Y */ |
1351 |
< |
c_fromSharpRGB(my_min.rgb, cs); |
1334 |
< |
return M_PI*ymin; |
1350 |
> |
|
1351 |
> |
return M_PI * ymin; |
1352 |
|
} |
1353 |
|
|
1354 |
|
/* Extract and separate diffuse portion of BSDF */ |
1375 |
|
memcpy(df->comp[0].cspec, tt_RGB_prim, sizeof(tt_RGB_prim)); |
1376 |
|
dv->cieY = subtract_min_RGB(&dv->spec, sdt->stc); |
1377 |
|
} else { |
1378 |
< |
df->comp[0].cspec[0] = c_dfcolor; |
1378 |
> |
df->comp[0].cspec[0] = dv->spec = c_dfcolor; |
1379 |
|
dv->cieY = subtract_min_Y(sdt->stc[tt_Y]); |
1380 |
|
} |
1381 |
|
df->maxHemi -= dv->cieY; /* adjust maximum hemispherical */ |
1382 |
< |
/* make sure everything is set */ |
1383 |
< |
c_ccvt(&dv->spec, C_CSXY+C_CSSPEC); |
1382 |
> |
|
1383 |
> |
c_ccvt(&dv->spec, C_CSXY); /* make sure (x,y) is set */ |
1384 |
|
} |
1385 |
|
|
1386 |
|
/* Load a variable-resolution BSDF tree from an open XML file */ |
1431 |
|
/* separate diffuse components */ |
1432 |
|
extract_diffuse(&sd->rLambFront, sd->rf); |
1433 |
|
extract_diffuse(&sd->rLambBack, sd->rb); |
1434 |
< |
if (sd->tf != NULL) |
1435 |
< |
extract_diffuse(&sd->tLamb, sd->tf); |
1436 |
< |
if (sd->tb != NULL) |
1437 |
< |
extract_diffuse(&sd->tLamb, sd->tb); |
1434 |
> |
extract_diffuse(&sd->tLambFront, sd->tf); |
1435 |
> |
if (sd->tb != NULL) { |
1436 |
> |
extract_diffuse(&sd->tLambBack, sd->tb); |
1437 |
> |
if (sd->tf == NULL) |
1438 |
> |
sd->tLambFront = sd->tLambBack; |
1439 |
> |
} else if (sd->tf != NULL) |
1440 |
> |
sd->tLambBack = sd->tLambFront; |
1441 |
|
/* return success */ |
1442 |
|
return SDEnone; |
1443 |
|
} |
1444 |
|
|
1445 |
|
/* Variable resolution BSDF methods */ |
1446 |
< |
SDFunc SDhandleTre = { |
1446 |
> |
const SDFunc SDhandleTre = { |
1447 |
|
&SDgetTreBSDF, |
1448 |
|
&SDqueryTreProjSA, |
1449 |
|
&SDgetTreCDist, |