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 |
|
*coef = yval; |
590 |
|
return 1; /* no color */ |
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; |
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)); |
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 <= .01/M_PI) |
1232 |
> |
if ((vmin >= vmaxmin) | (vmin <= .01/M_PI)) |
1233 |
|
return .0; /* not worth bothering about */ |
1234 |
|
|
1235 |
|
SDsubtractTreVal(st, vmin); |
1351 |
|
SDtraverseTre(stc[tt_Y], NULL, 0, get_min_RGB, &my_min); |
1352 |
|
/* convert to C_COLOR */ |
1353 |
|
ymin = c_fromSharpRGB(my_min.rgb, cs); |
1354 |
< |
if (ymin <= .01/M_PI) /* not worth bothering about? */ |
1355 |
< |
return .0; |
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); |
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, |