515 |
|
c_toSharpRGB(&cxy, yval, rgb); |
516 |
|
} |
517 |
|
|
518 |
+ |
static double |
519 |
+ |
pfrac(double x) |
520 |
+ |
{ |
521 |
+ |
return( x - (int)x ); |
522 |
+ |
} |
523 |
+ |
|
524 |
|
/* Query BSDF value and sample hypercube for the given vectors */ |
525 |
|
static int |
526 |
|
SDqueryTre(const SDTre *sdt, float *coef, |
527 |
< |
const FVECT outVec, const FVECT inVec, double *hc) |
527 |
> |
const FVECT inVec, const FVECT outVec, double *hc) |
528 |
|
{ |
529 |
|
const RREAL *vtmp; |
530 |
+ |
double hcube[SD_MAXDIM+1]; |
531 |
|
float yval; |
532 |
|
FVECT rOutVec; |
533 |
< |
double gridPos[4]; |
533 |
> |
RREAL gridPos[4]; |
534 |
> |
double d; |
535 |
> |
int i; |
536 |
|
|
537 |
|
if (sdt->stc[tt_Y] == NULL) /* paranoia, I hope */ |
538 |
|
return 0; |
570 |
|
spinvector(rOutVec, outVec, zvec, -atan2(-inVec[1],-inVec[0])); |
571 |
|
gridPos[0] = (.5-FTINY) - |
572 |
|
.5*sqrt(inVec[0]*inVec[0] + inVec[1]*inVec[1]); |
573 |
< |
SDdisk2square(gridPos+1, rOutVec[0], rOutVec[1]); |
573 |
> |
disk2square(gridPos+1, rOutVec[0], rOutVec[1]); |
574 |
|
} else if (sdt->stc[tt_Y]->ndim == 4) { |
575 |
< |
SDdisk2square(gridPos, -inVec[0], -inVec[1]); |
576 |
< |
SDdisk2square(gridPos+2, outVec[0], outVec[1]); |
575 |
> |
disk2square(gridPos, -inVec[0], -inVec[1]); |
576 |
> |
disk2square(gridPos+2, outVec[0], outVec[1]); |
577 |
|
} else |
578 |
|
return 0; /* should be internal error */ |
579 |
< |
/* get BSDF value */ |
579 |
> |
|
580 |
> |
if (hc == NULL) hc = hcube; /* get BSDF value */ |
581 |
|
yval = SDlookupTre(sdt->stc[tt_Y], gridPos, hc); |
582 |
+ |
if (coef == NULL) /* just getting hypercube? */ |
583 |
+ |
return 1; |
584 |
+ |
d = 0; /* position-specific perturbation */ |
585 |
+ |
for (i = sdt->stc[tt_Y]->ndim; i--; ) |
586 |
+ |
d += pfrac((2<<i)/(hc[i]+.01687)) - .5; |
587 |
+ |
yval *= 1. + 1e-4*d; /* assumes tolerance is > 0.04% */ |
588 |
|
if (sdt->stc[tt_u] == NULL || sdt->stc[tt_v] == NULL) { |
589 |
< |
if (coef != NULL) *coef = yval; |
589 |
> |
*coef = yval; |
590 |
|
return 1; /* no color */ |
591 |
|
} |
576 |
– |
if (coef == NULL) /* just getting hypercube? */ |
577 |
– |
return 1; |
592 |
|
/* else decode color */ |
593 |
|
SDyuv2rgb(yval, SDlookupTre(sdt->stc[tt_u], gridPos, NULL), |
594 |
|
SDlookupTre(sdt->stc[tt_v], gridPos, NULL), coef); |
758 |
|
const SDCDst * |
759 |
|
SDgetTreCDist(const FVECT inVec, SDComponent *sdc) |
760 |
|
{ |
761 |
+ |
unsigned long cacheLeft = SDmaxCache; |
762 |
|
const SDTre *sdt; |
763 |
< |
double inCoord[2]; |
763 |
> |
RREAL inCoord[2]; |
764 |
|
int i; |
765 |
|
int mode; |
766 |
< |
SDTreCDst *cd, *cdlast; |
766 |
> |
SDTreCDst *cd, *cdlast, *cdlimit; |
767 |
|
/* check arguments */ |
768 |
|
if ((inVec == NULL) | (sdc == NULL) || |
769 |
|
(sdt = (SDTre *)sdc->dist) == NULL) |
795 |
|
.5*sqrt(inVec[0]*inVec[0] + inVec[1]*inVec[1]); |
796 |
|
} else if (sdt->stc[tt_Y]->ndim == 4) { |
797 |
|
if (mode != sdt->sidef) /* use reciprocity? */ |
798 |
< |
SDdisk2square(inCoord, inVec[0], inVec[1]); |
798 |
> |
disk2square(inCoord, inVec[0], inVec[1]); |
799 |
|
else |
800 |
< |
SDdisk2square(inCoord, -inVec[0], -inVec[1]); |
800 |
> |
disk2square(inCoord, -inVec[0], -inVec[1]); |
801 |
|
} else |
802 |
|
return NULL; /* should be internal error */ |
803 |
|
/* quantize to avoid f.p. errors */ |
804 |
|
for (i = sdt->stc[tt_Y]->ndim - 2; i--; ) |
805 |
|
inCoord[i] = floor(inCoord[i]/quantum)*quantum + .5*quantum; |
806 |
< |
cdlast = NULL; /* check for direction in cache list */ |
806 |
> |
cdlast = cdlimit = NULL; /* check for direction in cache list */ |
807 |
> |
/* PLACE MUTEX LOCK HERE FOR THREAD-SAFE */ |
808 |
|
for (cd = (SDTreCDst *)sdc->cdList; cd != NULL; |
809 |
|
cdlast = cd, cd = cd->next) { |
810 |
+ |
if (cacheLeft) { /* check cache size limit */ |
811 |
+ |
long csiz = sizeof(SDTreCDst) + |
812 |
+ |
sizeof(cd->carr[0])*cd->calen; |
813 |
+ |
if (cacheLeft > csiz) |
814 |
+ |
cacheLeft -= csiz; |
815 |
+ |
else { |
816 |
+ |
cdlimit = cdlast; |
817 |
+ |
cacheLeft = 0; |
818 |
+ |
} |
819 |
+ |
} |
820 |
|
if (cd->sidef != mode) |
821 |
|
continue; |
822 |
|
for (i = sdt->stc[tt_Y]->ndim - 2; i--; ) |
826 |
|
if (i < 0) |
827 |
|
break; /* means we have a match */ |
828 |
|
} |
829 |
< |
if (cd == NULL) /* need to create new entry? */ |
829 |
> |
if (cd == NULL) { /* need to create new entry? */ |
830 |
> |
if (cdlimit != NULL) /* exceeded cache size limit? */ |
831 |
> |
while ((cd = cdlimit->next) != NULL) { |
832 |
> |
cdlimit->next = cd->next; |
833 |
> |
free(cd); |
834 |
> |
} |
835 |
|
cdlast = cd = make_cdist(sdt, inCoord, mode != sdt->sidef); |
836 |
+ |
} |
837 |
|
if (cdlast != NULL) { /* move entry to head of cache list */ |
838 |
|
cdlast->next = cd->next; |
839 |
|
cd->next = (SDTreCDst *)sdc->cdList; |
840 |
|
sdc->cdList = (SDCDst *)cd; |
841 |
|
} |
842 |
+ |
/* END MUTEX LOCK */ |
843 |
|
return (SDCDst *)cd; /* ready to go */ |
844 |
|
} |
845 |
|
|
902 |
|
const SDTreCDst *cd = (const SDTreCDst *)cdp; |
903 |
|
const unsigned target = randX*cumlmax; |
904 |
|
bitmask_t hndx, hcoord[2]; |
905 |
< |
double gpos[3], rotangle; |
905 |
> |
FVECT gpos; |
906 |
> |
double rotangle; |
907 |
|
int i, iupper, ilower; |
908 |
|
/* check arguments */ |
909 |
|
if ((ioVec == NULL) | (cd == NULL)) |
933 |
|
for (i = 2; i--; ) |
934 |
|
gpos[i] = ((double)hcoord[i] + rand()*(1./(RAND_MAX+.5))) / |
935 |
|
(double)((bitmask_t)1 << nBitsC); |
936 |
< |
SDsquare2disk(gpos, gpos[0], gpos[1]); |
936 |
> |
square2disk(gpos, gpos[0], gpos[1]); |
937 |
|
/* compute Z-coordinate */ |
938 |
|
gpos[2] = 1. - gpos[0]*gpos[0] - gpos[1]*gpos[1]; |
939 |
|
gpos[2] = sqrt(gpos[2]*(gpos[2]>0)); |
958 |
|
} |
959 |
|
|
960 |
|
/* Advance pointer past matching token (or any token if c==0) */ |
961 |
< |
#define eat_token(spp,c) (next_token(spp)==(c) ^ !(c) ? *(*(spp))++ : 0) |
961 |
> |
#define eat_token(spp,c) ((next_token(spp)==(c)) ^ !(c) ? *(*(spp))++ : 0) |
962 |
|
|
963 |
|
/* Count words from this point in string to '}' */ |
964 |
|
static int |
1208 |
|
static double |
1209 |
|
subtract_min_Y(SDNode *st) |
1210 |
|
{ |
1211 |
< |
float vmin; |
1211 |
> |
const float vmaxmin = 1.5/M_PI; |
1212 |
> |
float vmin; |
1213 |
|
/* be sure to skip unused portion */ |
1214 |
|
if (st->ndim == 3) { |
1215 |
|
int n; |
1216 |
< |
vmin = 1./M_PI; |
1216 |
> |
vmin = vmaxmin; |
1217 |
|
if (st->log2GR < 0) { |
1218 |
|
for (n = 0; n < 8; n += 2) { |
1219 |
|
float v = SDgetTreMin(st->u.t[n]); |
1229 |
|
} else /* anisotropic covers entire tree */ |
1230 |
|
vmin = SDgetTreMin(st); |
1231 |
|
|
1232 |
< |
if (vmin <= FTINY) |
1233 |
< |
return .0; |
1232 |
> |
if ((vmin >= vmaxmin) | (vmin <= .01/M_PI)) |
1233 |
> |
return .0; /* not worth bothering about */ |
1234 |
|
|
1235 |
|
SDsubtractTreVal(st, vmin); |
1236 |
|
|
1276 |
|
{ |
1277 |
|
SDextRGBs *mp = (SDextRGBs *)cptr; |
1278 |
|
double cmax[SD_MAXDIM]; |
1279 |
+ |
double yval; |
1280 |
|
float rgb[3]; |
1281 |
< |
int ok; |
1281 |
> |
C_COLOR clr; |
1282 |
|
|
1283 |
|
if (mp->stc[tt_Y]->ndim == 3) { |
1284 |
|
if (cmin[0] + .5*csiz >= .5) |
1289 |
|
cmax[1] = cmin[1] + csiz; |
1290 |
|
cmax[2] = cmin[2] + csiz; |
1291 |
|
/* average RGB color over voxel */ |
1292 |
< |
SDyuv2rgb(SDavgTreBox(mp->stc[tt_Y], cmin, cmax), uprime, |
1292 |
> |
SDyuv2rgb(yval=SDavgTreBox(mp->stc[tt_Y], cmin, cmax), uprime, |
1293 |
|
SDavgTreBox(mp->stc[tt_v], cmin, cmax), rgb); |
1294 |
< |
/* subtract minimum */ |
1295 |
< |
ok = (rgb[0] -= mp->rgb[0]) > 1e-5; |
1296 |
< |
ok &= (rgb[1] -= mp->rgb[1]) > 1e-5; |
1297 |
< |
ok &= (rgb[2] -= mp->rgb[2]) > 1e-5; |
1298 |
< |
if (ok) { /* compute new u' for adj. RGB */ |
1299 |
< |
C_COLOR clr; |
1264 |
< |
c_fromSharpRGB(rgb, &clr); |
1265 |
< |
uprime = 4.*clr.cx/(-2.*clr.cx + 12.*clr.cy + 3.); |
1266 |
< |
} else |
1267 |
< |
uprime = 4./3./(-2./3. + 12./3. + 3.); |
1294 |
> |
/* subtract minimum (& clamp) */ |
1295 |
> |
if ((rgb[0] -= mp->rgb[0]) < 1e-5*yval) rgb[0] = 1e-5*yval; |
1296 |
> |
if ((rgb[1] -= mp->rgb[1]) < 1e-5*yval) rgb[1] = 1e-5*yval; |
1297 |
> |
if ((rgb[2] -= mp->rgb[2]) < 1e-5*yval) rgb[2] = 1e-5*yval; |
1298 |
> |
c_fromSharpRGB(rgb, &clr); /* compute new u' for adj. RGB */ |
1299 |
> |
uprime = 4.*clr.cx/(-2.*clr.cx + 12.*clr.cy + 3.); |
1300 |
|
/* assign in new u' tree */ |
1301 |
|
mp->new_stu = SDsetVoxel(mp->new_stu, mp->stc[tt_Y]->ndim, |
1302 |
|
cmin, csiz, uprime); |
1309 |
|
{ |
1310 |
|
SDextRGBs *mp = (SDextRGBs *)cptr; |
1311 |
|
double cmax[SD_MAXDIM]; |
1312 |
+ |
double yval; |
1313 |
|
float rgb[3]; |
1314 |
< |
int ok; |
1314 |
> |
C_COLOR clr; |
1315 |
|
|
1316 |
|
if (mp->stc[tt_Y]->ndim == 3) { |
1317 |
|
if (cmin[0] + .5*csiz >= .5) |
1322 |
|
cmax[1] = cmin[1] + csiz; |
1323 |
|
cmax[2] = cmin[2] + csiz; |
1324 |
|
/* average RGB color over voxel */ |
1325 |
< |
SDyuv2rgb(SDavgTreBox(mp->stc[tt_Y], cmin, cmax), |
1325 |
> |
SDyuv2rgb(yval=SDavgTreBox(mp->stc[tt_Y], cmin, cmax), |
1326 |
|
SDavgTreBox(mp->stc[tt_u], cmin, cmax), |
1327 |
|
vprime, rgb); |
1328 |
< |
/* subtract minimum */ |
1329 |
< |
ok = (rgb[0] -= mp->rgb[0]) > 1e-5; |
1330 |
< |
ok &= (rgb[1] -= mp->rgb[1]) > 1e-5; |
1331 |
< |
ok &= (rgb[2] -= mp->rgb[2]) > 1e-5; |
1332 |
< |
if (ok) { /* compute new v' for adj. RGB */ |
1333 |
< |
C_COLOR clr; |
1301 |
< |
c_fromSharpRGB(rgb, &clr); |
1302 |
< |
vprime = 9.*clr.cy/(-2.*clr.cx + 12.*clr.cy + 3.); |
1303 |
< |
} else |
1304 |
< |
vprime = 9./3./(-2./3. + 12./3. + 3.); |
1328 |
> |
/* subtract minimum (& clamp) */ |
1329 |
> |
if ((rgb[0] -= mp->rgb[0]) < 1e-5*yval) rgb[0] = 1e-5*yval; |
1330 |
> |
if ((rgb[1] -= mp->rgb[1]) < 1e-5*yval) rgb[1] = 1e-5*yval; |
1331 |
> |
if ((rgb[2] -= mp->rgb[2]) < 1e-5*yval) rgb[2] = 1e-5*yval; |
1332 |
> |
c_fromSharpRGB(rgb, &clr); /* compute new v' for adj. RGB */ |
1333 |
> |
vprime = 9.*clr.cy/(-2.*clr.cx + 12.*clr.cy + 3.); |
1334 |
|
/* assign in new v' tree */ |
1335 |
|
mp->new_stv = SDsetVoxel(mp->new_stv, mp->stc[tt_Y]->ndim, |
1336 |
|
cmin, csiz, vprime); |
1349 |
|
my_min.new_stu = my_min.new_stv = NULL; |
1350 |
|
/* get minimum RGB value */ |
1351 |
|
SDtraverseTre(stc[tt_Y], NULL, 0, get_min_RGB, &my_min); |
1352 |
< |
ymin = tt_RGB_coef[0]*my_min.rgb[0] + |
1353 |
< |
tt_RGB_coef[1]*my_min.rgb[1] + |
1354 |
< |
tt_RGB_coef[2]*my_min.rgb[2]; |
1355 |
< |
if (ymin <= 1e-5) { |
1356 |
< |
*cs = c_dfcolor; |
1328 |
< |
return .0; /* not worth bothering about */ |
1329 |
< |
} |
1330 |
< |
/* adjust u' & v' values */ |
1352 |
> |
/* convert to C_COLOR */ |
1353 |
> |
ymin = c_fromSharpRGB(my_min.rgb, cs); |
1354 |
> |
if ((ymin >= .5*FHUGE) | (ymin <= .01/M_PI)) |
1355 |
> |
return .0; /* close to zero or no tree */ |
1356 |
> |
/* adjust u' & v' trees */ |
1357 |
|
SDtraverseTre(stc[tt_u], NULL, 0, adjust_utree, &my_min); |
1358 |
|
SDtraverseTre(stc[tt_v], NULL, 0, adjust_vtree, &my_min); |
1359 |
|
SDfreeTre(stc[tt_u]); SDfreeTre(stc[tt_v]); |
1360 |
|
stc[tt_u] = SDsimplifyTre(my_min.new_stu); |
1361 |
|
stc[tt_v] = SDsimplifyTre(my_min.new_stv); |
1362 |
< |
/* finally, subtract Y value */ |
1362 |
> |
/* subtract Y & return hemispherical */ |
1363 |
|
SDsubtractTreVal(stc[tt_Y], ymin); |
1364 |
< |
/* return color and Y */ |
1365 |
< |
c_fromSharpRGB(my_min.rgb, cs); |
1340 |
< |
return M_PI*ymin; |
1364 |
> |
|
1365 |
> |
return M_PI * ymin; |
1366 |
|
} |
1367 |
|
|
1368 |
|
/* Extract and separate diffuse portion of BSDF */ |
1389 |
|
memcpy(df->comp[0].cspec, tt_RGB_prim, sizeof(tt_RGB_prim)); |
1390 |
|
dv->cieY = subtract_min_RGB(&dv->spec, sdt->stc); |
1391 |
|
} else { |
1392 |
< |
df->comp[0].cspec[0] = c_dfcolor; |
1392 |
> |
df->comp[0].cspec[0] = dv->spec = c_dfcolor; |
1393 |
|
dv->cieY = subtract_min_Y(sdt->stc[tt_Y]); |
1394 |
|
} |
1395 |
|
df->maxHemi -= dv->cieY; /* adjust maximum hemispherical */ |
1396 |
< |
/* make sure everything is set */ |
1397 |
< |
c_ccvt(&dv->spec, C_CSXY+C_CSSPEC); |
1396 |
> |
|
1397 |
> |
c_ccvt(&dv->spec, C_CSXY); /* make sure (x,y) is set */ |
1398 |
|
} |
1399 |
|
|
1400 |
|
/* Load a variable-resolution BSDF tree from an open XML file */ |
1445 |
|
/* separate diffuse components */ |
1446 |
|
extract_diffuse(&sd->rLambFront, sd->rf); |
1447 |
|
extract_diffuse(&sd->rLambBack, sd->rb); |
1448 |
< |
if (sd->tf != NULL) |
1449 |
< |
extract_diffuse(&sd->tLamb, sd->tf); |
1450 |
< |
if (sd->tb != NULL) |
1451 |
< |
extract_diffuse(&sd->tLamb, sd->tb); |
1448 |
> |
extract_diffuse(&sd->tLambFront, sd->tf); |
1449 |
> |
if (sd->tb != NULL) { |
1450 |
> |
extract_diffuse(&sd->tLambBack, sd->tb); |
1451 |
> |
if (sd->tf == NULL) |
1452 |
> |
sd->tLambFront = sd->tLambBack; |
1453 |
> |
} else if (sd->tf != NULL) |
1454 |
> |
sd->tLambBack = sd->tLambFront; |
1455 |
|
/* return success */ |
1456 |
|
return SDEnone; |
1457 |
|
} |
1458 |
|
|
1459 |
|
/* Variable resolution BSDF methods */ |
1460 |
< |
SDFunc SDhandleTre = { |
1460 |
> |
const SDFunc SDhandleTre = { |
1461 |
|
&SDgetTreBSDF, |
1462 |
|
&SDqueryTreProjSA, |
1463 |
|
&SDgetTreCDist, |