45 |
|
SDError |
46 |
|
SDreportEnglish(SDError ec, FILE *fp) |
47 |
|
{ |
48 |
– |
if (fp == NULL) |
49 |
– |
return ec; |
48 |
|
if (!ec) |
49 |
|
return SDEnone; |
50 |
+ |
if ((ec < SDEnone) | (ec > SDEunknown)) { |
51 |
+ |
SDerrorDetail[0] = '\0'; |
52 |
+ |
ec = SDEunknown; |
53 |
+ |
} |
54 |
+ |
if (fp == NULL) |
55 |
+ |
return ec; |
56 |
|
fputs(SDerrorEnglish[ec], fp); |
57 |
|
if (SDerrorDetail[0]) { |
58 |
|
fputs(": ", fp); |
81 |
|
|
82 |
|
/* Load geometric dimensions and description (if any) */ |
83 |
|
static SDError |
84 |
< |
SDloadGeometry(SDData *dp, ezxml_t wdb) |
84 |
> |
SDloadGeometry(SDData *sd, ezxml_t wdb) |
85 |
|
{ |
86 |
|
ezxml_t geom; |
87 |
|
double cfact; |
88 |
|
const char *fmt, *mgfstr; |
89 |
|
|
90 |
< |
sprintf(SDerrorDetail, "Negative size in \"%s\"", dp->name); |
91 |
< |
dp->dim[0] = dp->dim[1] = dp->dim[2] = .0; |
90 |
> |
if (wdb == NULL) /* no geometry section? */ |
91 |
> |
return SDEnone; |
92 |
> |
sd->dim[0] = sd->dim[1] = sd->dim[2] = .0; |
93 |
|
if ((geom = ezxml_child(wdb, "Width")) != NULL) |
94 |
< |
dp->dim[0] = atof(ezxml_txt(geom)) * |
94 |
> |
sd->dim[0] = atof(ezxml_txt(geom)) * |
95 |
|
to_meters(ezxml_attr(geom, "unit")); |
96 |
|
if ((geom = ezxml_child(wdb, "Height")) != NULL) |
97 |
< |
dp->dim[1] = atof(ezxml_txt(geom)) * |
97 |
> |
sd->dim[1] = atof(ezxml_txt(geom)) * |
98 |
|
to_meters(ezxml_attr(geom, "unit")); |
99 |
|
if ((geom = ezxml_child(wdb, "Thickness")) != NULL) |
100 |
< |
dp->dim[2] = atof(ezxml_txt(geom)) * |
100 |
> |
sd->dim[2] = atof(ezxml_txt(geom)) * |
101 |
|
to_meters(ezxml_attr(geom, "unit")); |
102 |
< |
if ((dp->dim[0] < .0) | (dp->dim[1] < .0) | (dp->dim[2] < .0)) |
102 |
> |
if ((sd->dim[0] < .0) | (sd->dim[1] < .0) | (sd->dim[2] < .0)) { |
103 |
> |
sprintf(SDerrorDetail, "Negative size in \"%s\"", sd->name); |
104 |
|
return SDEdata; |
105 |
+ |
} |
106 |
|
if ((geom = ezxml_child(wdb, "Geometry")) == NULL || |
107 |
|
(mgfstr = ezxml_txt(geom)) == NULL) |
108 |
|
return SDEnone; |
110 |
|
strcasecmp(fmt, "MGF")) { |
111 |
|
sprintf(SDerrorDetail, |
112 |
|
"Unrecognized geometry format '%s' in \"%s\"", |
113 |
< |
fmt, dp->name); |
113 |
> |
fmt, sd->name); |
114 |
|
return SDEsupport; |
115 |
|
} |
116 |
|
cfact = to_meters(ezxml_attr(geom, "unit")); |
117 |
< |
dp->mgf = (char *)malloc(strlen(mgfstr)+32); |
118 |
< |
if (dp->mgf == NULL) { |
117 |
> |
sd->mgf = (char *)malloc(strlen(mgfstr)+32); |
118 |
> |
if (sd->mgf == NULL) { |
119 |
|
strcpy(SDerrorDetail, "Out of memory in SDloadGeometry"); |
120 |
|
return SDEmemory; |
121 |
|
} |
122 |
|
if (cfact < 0.99 || cfact > 1.01) |
123 |
< |
sprintf(dp->mgf, "xf -s %.5f\n%s\nxf\n", cfact, mgfstr); |
123 |
> |
sprintf(sd->mgf, "xf -s %.5f\n%s\nxf\n", cfact, mgfstr); |
124 |
|
else |
125 |
< |
strcpy(dp->mgf, mgfstr); |
125 |
> |
strcpy(sd->mgf, mgfstr); |
126 |
|
return SDEnone; |
127 |
|
} |
128 |
|
|
122 |
– |
|
129 |
|
/* Load a BSDF struct from the given file (free first and keep name) */ |
130 |
|
SDError |
131 |
|
SDloadFile(SDData *sd, const char *fname) |
132 |
|
{ |
133 |
|
SDError lastErr; |
134 |
< |
ezxml_t fl; |
134 |
> |
ezxml_t fl, wtl; |
135 |
|
|
136 |
|
if ((sd == NULL) | (fname == NULL || !*fname)) |
137 |
|
return SDEargument; |
148 |
|
ezxml_free(fl); |
149 |
|
return SDEformat; |
150 |
|
} |
151 |
+ |
if (strcmp(ezxml_name(fl), "WindowElement")) { |
152 |
+ |
sprintf(SDerrorDetail, |
153 |
+ |
"BSDF \"%s\": top level node not 'WindowElement'", |
154 |
+ |
sd->name); |
155 |
+ |
ezxml_free(fl); |
156 |
+ |
return SDEformat; |
157 |
+ |
} |
158 |
+ |
wtl = ezxml_child(ezxml_child(fl, "Optical"), "Layer"); |
159 |
+ |
if (wtl == NULL) { |
160 |
+ |
sprintf(SDerrorDetail, "BSDF \"%s\": no optical layer'", |
161 |
+ |
sd->name); |
162 |
+ |
ezxml_free(fl); |
163 |
+ |
return SDEformat; |
164 |
+ |
} |
165 |
|
/* load geometry if present */ |
166 |
< |
if ((lastErr = SDloadGeometry(sd, fl))) |
166 |
> |
lastErr = SDloadGeometry(sd, ezxml_child(wtl, "Material")); |
167 |
> |
if (lastErr) |
168 |
|
return lastErr; |
169 |
|
/* try loading variable resolution data */ |
170 |
< |
lastErr = SDloadTre(sd, fl); |
170 |
> |
lastErr = SDloadTre(sd, wtl); |
171 |
|
/* check our result */ |
172 |
|
switch (lastErr) { |
173 |
|
case SDEformat: |
174 |
|
case SDEdata: |
175 |
|
case SDEsupport: /* possibly we just tried the wrong format */ |
176 |
< |
lastErr = SDloadMtx(sd, fl); |
176 |
> |
lastErr = SDloadMtx(sd, wtl); |
177 |
|
break; |
178 |
|
default: /* variable res. OK else serious error */ |
179 |
|
break; |
180 |
|
} |
181 |
|
/* done with XML file */ |
182 |
|
ezxml_free(fl); |
183 |
< |
/* return success or failure */ |
184 |
< |
return lastErr; |
183 |
> |
|
184 |
> |
if (lastErr) { /* was there a load error? */ |
185 |
> |
SDfreeBSDF(sd); |
186 |
> |
return lastErr; |
187 |
> |
} |
188 |
> |
/* remove any insignificant components */ |
189 |
> |
if (sd->rf != NULL && sd->rf->maxHemi <= .001) { |
190 |
> |
SDfreeSpectralDF(sd->rf); sd->rf = NULL; |
191 |
> |
} |
192 |
> |
if (sd->rb != NULL && sd->rb->maxHemi <= .001) { |
193 |
> |
SDfreeSpectralDF(sd->rb); sd->rb = NULL; |
194 |
> |
} |
195 |
> |
if (sd->tf != NULL && sd->tf->maxHemi <= .001) { |
196 |
> |
SDfreeSpectralDF(sd->tf); sd->tf = NULL; |
197 |
> |
} |
198 |
> |
/* return success */ |
199 |
> |
return SDEnone; |
200 |
|
} |
201 |
|
|
202 |
|
/* Allocate new spectral distribution function */ |
255 |
|
|
256 |
|
/* Shorten file path to useable BSDF name, removing suffix */ |
257 |
|
void |
258 |
< |
SDclipName(char res[SDnameLn], const char *fname) |
258 |
> |
SDclipName(char *res, const char *fname) |
259 |
|
{ |
260 |
|
const char *cp, *dot = NULL; |
261 |
|
|
273 |
|
|
274 |
|
/* Initialize an unused BSDF struct (simply clears to zeroes) */ |
275 |
|
void |
276 |
< |
SDclearBSDF(SDData *sd) |
276 |
> |
SDclearBSDF(SDData *sd, const char *fname) |
277 |
|
{ |
278 |
< |
if (sd != NULL) |
279 |
< |
memset(sd, 0, sizeof(SDData)); |
278 |
> |
if (sd == NULL) |
279 |
> |
return; |
280 |
> |
memset(sd, 0, sizeof(SDData)); |
281 |
> |
if (fname == NULL) |
282 |
> |
return; |
283 |
> |
SDclipName(sd->name, fname); |
284 |
|
} |
285 |
|
|
286 |
|
/* Free data associated with BSDF struct */ |
306 |
|
sd->tf = NULL; |
307 |
|
} |
308 |
|
sd->rLambFront.cieY = .0; |
309 |
< |
sd->rLambFront.spec.clock = 0; |
309 |
> |
sd->rLambFront.spec.flags = 0; |
310 |
|
sd->rLambBack.cieY = .0; |
311 |
< |
sd->rLambBack.spec.clock = 0; |
311 |
> |
sd->rLambBack.spec.flags = 0; |
312 |
|
sd->tLamb.cieY = .0; |
313 |
< |
sd->tLamb.spec.clock = 0; |
313 |
> |
sd->tLamb.spec.flags = 0; |
314 |
|
} |
315 |
|
|
316 |
|
/* Find writeable BSDF by name, or allocate new cache entry if absent */ |
338 |
|
sdl->next = SDcacheList; |
339 |
|
SDcacheList = sdl; |
340 |
|
|
341 |
< |
sdl->refcnt++; |
341 |
> |
sdl->refcnt = 1; |
342 |
|
return &sdl->bsdf; |
343 |
|
} |
344 |
|
|
382 |
|
for (sdl = SDcacheList; sdl != NULL; sdl = (sdLast=sdl)->next) |
383 |
|
if (&sdl->bsdf == sd) |
384 |
|
break; |
385 |
< |
if (sdl == NULL || --sdl->refcnt) |
385 |
> |
if (sdl == NULL || (sdl->refcnt -= (sdl->refcnt > 0))) |
386 |
|
return; /* missing or still in use */ |
387 |
|
/* keep unreferenced data? */ |
388 |
|
if (SDisLoaded(sd) && SDretainSet) { |
459 |
|
bitmask_t ndx, coord[MS_MAXDIM]; |
460 |
|
|
461 |
|
while (n > MS_MAXDIM) /* punt for higher dimensions */ |
462 |
< |
t[--n] = drand48(); |
462 |
> |
t[--n] = rand()*(1./(RAND_MAX+.5)); |
463 |
|
nBits = (8*sizeof(bitmask_t) - 1) / n; |
464 |
|
ndx = randX * (double)((bitmask_t)1 << (nBits*n)); |
465 |
|
/* get coordinate on Hilbert curve */ |
467 |
|
/* convert back to [0,1) range */ |
468 |
|
scale = 1. / (double)((bitmask_t)1 << nBits); |
469 |
|
while (n--) |
470 |
< |
t[n] = scale * ((double)coord[n] + drand48()); |
470 |
> |
t[n] = scale * ((double)coord[n] + rand()*(1./(RAND_MAX+.5))); |
471 |
|
} |
472 |
|
|
473 |
|
#undef MS_MAXDIM |
488 |
|
|
489 |
|
/* Query projected solid angle coverage for non-diffuse BSDF direction */ |
490 |
|
SDError |
491 |
< |
SDsizeBSDF(double *projSA, const FVECT vec, int qflags, const SDData *sd) |
491 |
> |
SDsizeBSDF(double *projSA, const FVECT v1, const RREAL *v2, |
492 |
> |
int qflags, const SDData *sd) |
493 |
|
{ |
494 |
|
SDSpectralDF *rdf; |
495 |
|
SDError ec; |
496 |
|
int i; |
497 |
|
/* check arguments */ |
498 |
< |
if ((projSA == NULL) | (vec == NULL) | (sd == NULL)) |
498 |
> |
if ((projSA == NULL) | (v1 == NULL)) |
499 |
|
return SDEargument; |
500 |
|
/* initialize extrema */ |
501 |
< |
switch (qflags & SDqueryMin+SDqueryMax) { |
501 |
> |
switch (qflags) { |
502 |
|
case SDqueryMax: |
503 |
|
projSA[0] = .0; |
504 |
|
break; |
511 |
|
case 0: |
512 |
|
return SDEargument; |
513 |
|
} |
514 |
< |
if (vec[2] > .0) /* front surface query? */ |
514 |
> |
if (v1[2] > .0) /* front surface query? */ |
515 |
|
rdf = sd->rf; |
516 |
|
else |
517 |
|
rdf = sd->rb; |
518 |
|
ec = SDEdata; /* run through components */ |
519 |
|
for (i = (rdf==NULL) ? 0 : rdf->ncomp; i--; ) { |
520 |
< |
ec = (*rdf->comp[i].func->queryProjSA)(projSA, vec, qflags, |
521 |
< |
rdf->comp[i].dist); |
520 |
> |
ec = (*rdf->comp[i].func->queryProjSA)(projSA, v1, v2, |
521 |
> |
qflags, rdf->comp[i].dist); |
522 |
|
if (ec) |
523 |
|
return ec; |
524 |
|
} |
525 |
|
for (i = (sd->tf==NULL) ? 0 : sd->tf->ncomp; i--; ) { |
526 |
< |
ec = (*sd->tf->comp[i].func->queryProjSA)(projSA, vec, qflags, |
527 |
< |
sd->tf->comp[i].dist); |
526 |
> |
ec = (*sd->tf->comp[i].func->queryProjSA)(projSA, v1, v2, |
527 |
> |
qflags, sd->tf->comp[i].dist); |
528 |
|
if (ec) |
529 |
|
return ec; |
530 |
|
} |
531 |
< |
return ec; |
531 |
> |
if (ec) { /* all diffuse? */ |
532 |
> |
projSA[0] = M_PI; |
533 |
> |
if (qflags == SDqueryMin+SDqueryMax) |
534 |
> |
projSA[1] = M_PI; |
535 |
> |
} |
536 |
> |
return SDEnone; |
537 |
|
} |
538 |
|
|
539 |
|
/* Return BSDF for the given incident and scattered ray vectors */ |
1123 |
|
break; |
1124 |
|
} |
1125 |
|
if (i < 0) { |
1126 |
< |
sprintf(errmsg, "undefined RowAngleBasis '%s'", cbasis); |
1126 |
> |
sprintf(errmsg, "undefined RowAngleBasis '%s'", rbasis); |
1127 |
|
error(WARNING, errmsg); |
1128 |
|
return; |
1129 |
|
} |