ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/bsdf2ttree.c
Revision: 2.64
Committed: Sat Jun 7 05:09:45 2025 UTC (15 hours, 53 minutes ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.63: +1 -3 lines
Error occurred while calculating annotation data.
Log Message:
refactor: Put some declarations into "paths.h" and included in "platform.h"

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: bsdf2ttree.c,v 2.63 2025/06/03 21:31:51 greg Exp $";
3 #endif
4 /*
5 * Load measured BSDF interpolant and write out as XML file with tensor tree.
6 *
7 * G. Ward
8 */
9
10 #define _USE_MATH_DEFINES
11 #include <stdlib.h>
12 #include <math.h>
13 #include <ctype.h>
14 #include "random.h"
15 #include "rtio.h"
16 #include "calcomp.h"
17 #include "bsdfrep.h"
18 /* reciprocity averaging option */
19 static const char *recip = "";
20 /* percentage to cull (<0 to turn off) */
21 static double pctcull = 90.;
22 /* sampling order */
23 static int samp_order = 6;
24 /* super-sampling threshold */
25 static double ssamp_thresh = 0.35;
26 /* number of super-samples */
27 static int nssamp = 64;
28 /* limit on number of RBF lobes */
29 static int lobe_lim = 15000;
30 /* progress bar length */
31 static int do_prog = 79;
32
33 #define MAXCARG 512 /* wrapBSDF command */
34 static char *wrapBSDF[MAXCARG] = {"wrapBSDF", "-U"};
35 static int wbsdfac = 2;
36
37 /* Add argument to wrapBSDF, allocating space if !isstatic */
38 static void
39 add_wbsdf(const char *arg, int isstatic)
40 {
41 if (arg == NULL)
42 return;
43 if (wbsdfac >= MAXCARG-1) {
44 fputs(progname, stderr);
45 fputs(": too many command arguments to wrapBSDF\n", stderr);
46 exit(1);
47 }
48 if (!*arg)
49 arg = "";
50 else if (!isstatic)
51 arg = savqstr((char *)arg);
52
53 wrapBSDF[wbsdfac++] = (char *)arg;
54 }
55
56 /* Create Yuv component file and add appropriate arguments */
57 static char *
58 create_component_file(int c)
59 {
60 static const char sname[3][6] = {"CIE-Y", "CIE-u", "CIE-v"};
61 static const char cname[4][4] = {"-rf", "-tf", "-tb", "-rb"};
62 char *tfname = mktemp(savqstr(TEMPLATE));
63
64 add_wbsdf("-s", 1); add_wbsdf(sname[c], 1);
65 add_wbsdf(cname[(input_orient>0)<<1 | (output_orient>0)], 1);
66 add_wbsdf(tfname, 1);
67 return(tfname);
68 }
69
70 /* Start new progress bar */
71 #define prog_start(s) if (do_prog) fprintf(stderr, "%s: %s...\n", progname, s); else
72
73 /* Draw progress bar of the appropriate length */
74 static void
75 prog_show(double frac)
76 {
77 static unsigned call_cnt = 0;
78 static char lastc[] = "-\\|/";
79 char pbar[256];
80 int nchars;
81
82 if (do_prog <= 1) return;
83 if (do_prog > sizeof(pbar)-2)
84 do_prog = sizeof(pbar)-2;
85 if (frac < 0) frac = 0;
86 else if (frac >= 1) frac = .9999;
87 nchars = do_prog*frac;
88 pbar[0] = '\r';
89 memset(pbar+1, '*', nchars);
90 pbar[nchars+1] = lastc[call_cnt++ & 3];
91 memset(pbar+2+nchars, '-', do_prog-nchars-1);
92 pbar[do_prog+1] = '\0';
93 fputs(pbar, stderr);
94 }
95
96 /* Finish progress bar */
97 static void
98 prog_done(void)
99 {
100 int n = do_prog;
101
102 if (n <= 1) return;
103 fputc('\r', stderr);
104 while (n--)
105 fputc(' ', stderr);
106 fputc('\r', stderr);
107 }
108
109 /* Compute absolute relative difference */
110 static double
111 abs_diff(double v1, double v0)
112 {
113 if ((v0 < 0) | (v1 < 0))
114 return(.0);
115 v1 = (v1-v0)*2./(v0+v1+.0001);
116 if (v1 < 0)
117 return(-v1);
118 return(v1);
119 }
120
121 /* Interpolate and output isotropic BSDF data */
122 static void
123 eval_isotropic(char *funame)
124 {
125 const int sqres = 1<<samp_order;
126 const double sqfact = 1./(double)sqres;
127 float *val_last = NULL;
128 float *val_next = NULL;
129 SDValue *sdv_next = NULL;
130 FILE *ofp, *uvfp[2];
131 int assignD = 0;
132 char cmd[128];
133 int ix, ox, oy;
134 RREAL iovec[6];
135 float bsdf, uv[2];
136
137 if (pctcull >= 0) {
138 sprintf(cmd, "rttree_reduce%s -h -ff -r 3 -t %f -g %d > %s",
139 recip, pctcull, samp_order, create_component_file(0));
140 ofp = popen(cmd, "w");
141 if (ofp == NULL) {
142 fprintf(stderr, "%s: cannot create pipe to rttree_reduce\n",
143 progname);
144 exit(1);
145 }
146 SET_FILE_BINARY(ofp);
147 #ifdef getc_unlocked /* avoid lock/unlock overhead */
148 flockfile(ofp);
149 #endif
150 if (rbf_colorimetry == RBCtristimulus) {
151 double uvcull = 100. - (100.-pctcull)*.25;
152 sprintf(cmd, "rttree_reduce%s -h -ff -r 3 -t %f -g %d > %s",
153 recip, uvcull, samp_order, create_component_file(1));
154 uvfp[0] = popen(cmd, "w");
155 sprintf(cmd, "rttree_reduce%s -h -ff -r 3 -t %f -g %d > %s",
156 recip, uvcull, samp_order, create_component_file(2));
157 uvfp[1] = popen(cmd, "w");
158 if ((uvfp[0] == NULL) | (uvfp[1] == NULL)) {
159 fprintf(stderr, "%s: cannot open pipes to uv output\n",
160 progname);
161 exit(1);
162 }
163 SET_FILE_BINARY(uvfp[0]); SET_FILE_BINARY(uvfp[1]);
164 #ifdef getc_unlocked
165 flockfile(uvfp[0]); flockfile(uvfp[1]);
166 #endif
167 }
168 } else {
169 ofp = fopen(create_component_file(0), "w");
170 if (ofp == NULL) {
171 fprintf(stderr, "%s: cannot create Y output file\n",
172 progname);
173 exit(1);
174 }
175 fputs("{\n", ofp);
176 if (rbf_colorimetry == RBCtristimulus) {
177 uvfp[0] = fopen(create_component_file(1), "w");
178 uvfp[1] = fopen(create_component_file(2), "w");
179 if ((uvfp[0] == NULL) | (uvfp[1] == NULL)) {
180 fprintf(stderr, "%s: cannot create uv output file(s)\n",
181 progname);
182 exit(1);
183 }
184 fputs("{\n", uvfp[0]);
185 fputs("{\n", uvfp[1]);
186 }
187 }
188 if (funame != NULL) /* need to assign Dx, Dy, Dz? */
189 assignD = (fundefined(funame) < 6);
190 val_last = (float *)calloc(sqres, sizeof(float));
191 if (funame == NULL)
192 sdv_next = (SDValue *)malloc(sizeof(SDValue)*sqres);
193 else
194 val_next = (float *)malloc(sizeof(float)*sqres);
195 /* run through directions */
196 for (ix = 0; ix < sqres/2; ix++) {
197 const int zipsgn = (ix & 1)*2 - 1;
198 RBFNODE *rbf = NULL;
199 iovec[0] = 2.*sqfact*(ix+.5) - 1.;
200 iovec[1] = zipsgn*sqfact*.5;
201 iovec[2] = input_orient * sqrt(1. - iovec[0]*iovec[0]
202 - iovec[1]*iovec[1]);
203 if (funame == NULL)
204 rbf = advect_rbf(iovec, lobe_lim);
205 /* presample first row */
206 for (oy = 0; oy < sqres; oy++) {
207 square2disk(iovec+3, .5*sqfact, (oy+.5)*sqfact);
208 iovec[5] = output_orient *
209 sqrt(1. - iovec[3]*iovec[3] - iovec[4]*iovec[4]);
210 if (funame == NULL) {
211 eval_rbfcol(&sdv_next[oy], rbf, iovec+3);
212 } else {
213 if (assignD) {
214 varset("Dx", '=', -iovec[3]);
215 varset("Dy", '=', -iovec[4]);
216 varset("Dz", '=', -iovec[5]);
217 ++eclock;
218 }
219 val_next[oy] = funvalue(funame, 6, iovec);
220 }
221 }
222 for (ox = 0; ox < sqres; ox++) {
223 /*
224 * Super-sample when we detect a difference from before
225 * or after in this row, above or below.
226 */
227 for (oy = 0; oy < sqres; oy++) {
228 if (ox < sqres-1) { /* keeping one row ahead... */
229 square2disk(iovec+3, (ox+1.5)*sqfact, (oy+.5)*sqfact);
230 iovec[5] = output_orient *
231 sqrt(1. - iovec[3]*iovec[3] - iovec[4]*iovec[4]);
232 }
233 if (funame == NULL) {
234 SDValue sdv = sdv_next[oy];
235 bsdf = sdv.cieY;
236 if (ox < sqres-1)
237 eval_rbfcol(&sdv_next[oy], rbf, iovec+3);
238 if (abs_diff(bsdf, sdv_next[oy].cieY) > ssamp_thresh ||
239 (ox && abs_diff(bsdf, val_last[oy]) > ssamp_thresh) ||
240 (oy && abs_diff(bsdf, val_last[oy-1]) > ssamp_thresh) ||
241 (oy < sqres-1 &&
242 abs_diff(bsdf, sdv_next[oy+1].cieY) > ssamp_thresh)) {
243 int ssi;
244 double ssa[2], sum = 0, usum = 0, vsum = 0;
245 /* super-sample voxel */
246 for (ssi = nssamp; ssi--; ) {
247 SDmultiSamp(ssa, 2, (ssi+frandom()) /
248 (double)nssamp);
249 square2disk(iovec+3, (ox+ssa[0])*sqfact,
250 (oy+ssa[1])*sqfact);
251 iovec[5] = output_orient *
252 sqrt(1. - iovec[3]*iovec[3] - iovec[4]*iovec[4]);
253 eval_rbfcol(&sdv, rbf, iovec+3);
254 sum += sdv.cieY;
255 if (rbf_colorimetry == RBCtristimulus) {
256 sdv.cieY /=
257 -2.*sdv.spec.cx + 12.*sdv.spec.cy + 3.;
258 usum += 4.*sdv.spec.cx * sdv.cieY;
259 vsum += 9.*sdv.spec.cy * sdv.cieY;
260 }
261 }
262 bsdf = sum / (double)nssamp;
263 if (rbf_colorimetry == RBCtristimulus) {
264 uv[0] = usum / (sum+FTINY);
265 uv[1] = vsum / (sum+FTINY);
266 }
267 } else if (rbf_colorimetry == RBCtristimulus) {
268 uv[0] = uv[1] = 1. /
269 (-2.*sdv.spec.cx + 12.*sdv.spec.cy + 3.);
270 uv[0] *= 4.*sdv.spec.cx;
271 uv[1] *= 9.*sdv.spec.cy;
272 }
273 } else {
274 bsdf = val_next[oy];
275 if (ox < sqres-1) {
276 if (assignD) {
277 varset("Dx", '=', -iovec[3]);
278 varset("Dy", '=', -iovec[4]);
279 varset("Dz", '=', -iovec[5]);
280 ++eclock;
281 }
282 val_next[oy] = funvalue(funame, 6, iovec);
283 }
284 if (abs_diff(bsdf, val_next[oy]) > ssamp_thresh ||
285 (ox && abs_diff(bsdf, val_last[oy]) > ssamp_thresh) ||
286 (oy && abs_diff(bsdf, val_last[oy-1]) > ssamp_thresh) ||
287 (oy < sqres-1 &&
288 abs_diff(bsdf, val_next[oy+1]) > ssamp_thresh)) {
289 int ssi;
290 double ssa[4], ssvec[6], sum = 0;
291 /* super-sample voxel */
292 for (ssi = nssamp; ssi--; ) {
293 SDmultiSamp(ssa, 4, (ssi+frandom()) /
294 (double)nssamp);
295 ssvec[0] = 2.*sqfact*(ix+ssa[0]) - 1.;
296 ssvec[1] = zipsgn*sqfact*ssa[1];
297 ssvec[2] = 1. - ssvec[0]*ssvec[0]
298 - ssvec[1]*ssvec[1];
299 if (ssvec[2] < .0) {
300 ssvec[1] = 0;
301 ssvec[2] = 1. - ssvec[0]*ssvec[0];
302 }
303 ssvec[2] = input_orient * sqrt(ssvec[2]);
304 square2disk(ssvec+3, (ox+ssa[2])*sqfact,
305 (oy+ssa[3])*sqfact);
306 ssvec[5] = output_orient *
307 sqrt(1. - ssvec[3]*ssvec[3] -
308 ssvec[4]*ssvec[4]);
309 if (assignD) {
310 varset("Dx", '=', -ssvec[3]);
311 varset("Dy", '=', -ssvec[4]);
312 varset("Dz", '=', -ssvec[5]);
313 ++eclock;
314 }
315 sum += funvalue(funame, 6, ssvec);
316 }
317 bsdf = sum / (double)nssamp;
318 }
319 }
320 if (pctcull >= 0)
321 putbinary(&bsdf, sizeof(bsdf), 1, ofp);
322 else
323 fprintf(ofp, "\t%.3e\n", bsdf);
324
325 if (rbf_colorimetry == RBCtristimulus) {
326 if (pctcull >= 0) {
327 putbinary(&uv[0], sizeof(*uv), 1, uvfp[0]);
328 putbinary(&uv[1], sizeof(*uv), 1, uvfp[1]);
329 } else {
330 fprintf(uvfp[0], "\t%.3e\n", uv[0]);
331 fprintf(uvfp[1], "\t%.3e\n", uv[1]);
332 }
333 }
334 if (val_last != NULL)
335 val_last[oy] = bsdf;
336 }
337 }
338 if (rbf != NULL)
339 free(rbf);
340 prog_show((ix+1.)*(2.*sqfact));
341 }
342 prog_done();
343 if (val_last != NULL) {
344 free(val_last);
345 if (val_next != NULL) free(val_next);
346 if (sdv_next != NULL) free(sdv_next);
347 }
348 if (pctcull >= 0) { /* finish output */
349 if (pclose(ofp)) {
350 fprintf(stderr, "%s: error running rttree_reduce on Y\n",
351 progname);
352 exit(1);
353 }
354 if (rbf_colorimetry == RBCtristimulus &&
355 (pclose(uvfp[0]) || pclose(uvfp[1]))) {
356 fprintf(stderr, "%s: error running rttree_reduce on uv\n",
357 progname);
358 exit(1);
359 }
360 } else {
361 for (ix = sqres*sqres*sqres/2; ix--; )
362 fputs("\t0\n", ofp);
363 fputs("}\n", ofp);
364 if (fclose(ofp)) {
365 fprintf(stderr, "%s: error writing Y file\n",
366 progname);
367 exit(1);
368 }
369 if (rbf_colorimetry == RBCtristimulus) {
370 for (ix = sqres*sqres*sqres/2; ix--; ) {
371 fputs("\t0\n", uvfp[0]);
372 fputs("\t0\n", uvfp[1]);
373 }
374 fputs("}\n", uvfp[0]);
375 fputs("}\n", uvfp[1]);
376 if (fclose(uvfp[0]) || fclose(uvfp[1])) {
377 fprintf(stderr, "%s: error writing uv file(s)\n",
378 progname);
379 exit(1);
380 }
381 }
382 }
383 }
384
385 /* Interpolate and output anisotropic BSDF data */
386 static void
387 eval_anisotropic(char *funame)
388 {
389 const int sqres = 1<<samp_order;
390 const double sqfact = 1./(double)sqres;
391 float *val_last = NULL;
392 float *val_next = NULL;
393 SDValue *sdv_next = NULL;
394 FILE *ofp, *uvfp[2];
395 int assignD = 0;
396 char cmd[128];
397 int ix, iy, ox, oy;
398 RREAL iovec[6];
399 float bsdf, uv[2];
400
401 if (pctcull >= 0) {
402 const char *avgopt = (input_orient>0 ^ output_orient>0)
403 ? "" : recip;
404 sprintf(cmd, "rttree_reduce%s -h -ff -r 4 -t %f -g %d > %s",
405 avgopt, pctcull, samp_order,
406 create_component_file(0));
407 ofp = popen(cmd, "w");
408 if (ofp == NULL) {
409 fprintf(stderr, "%s: cannot create pipe to rttree_reduce\n",
410 progname);
411 exit(1);
412 }
413 SET_FILE_BINARY(ofp);
414 #ifdef getc_unlocked /* avoid lock/unlock overhead */
415 flockfile(ofp);
416 #endif
417 if (rbf_colorimetry == RBCtristimulus) {
418 double uvcull = 100. - (100.-pctcull)*.25;
419 sprintf(cmd, "rttree_reduce%s -h -ff -r 4 -t %f -g %d > %s",
420 avgopt, uvcull, samp_order,
421 create_component_file(1));
422 uvfp[0] = popen(cmd, "w");
423 sprintf(cmd, "rttree_reduce%s -h -ff -r 4 -t %f -g %d > %s",
424 avgopt, uvcull, samp_order,
425 create_component_file(2));
426 uvfp[1] = popen(cmd, "w");
427 if ((uvfp[0] == NULL) | (uvfp[1] == NULL)) {
428 fprintf(stderr, "%s: cannot open pipes to uv output\n",
429 progname);
430 exit(1);
431 }
432 SET_FILE_BINARY(uvfp[0]); SET_FILE_BINARY(uvfp[1]);
433 #ifdef getc_unlocked
434 flockfile(uvfp[0]); flockfile(uvfp[1]);
435 #endif
436 }
437 } else {
438 ofp = fopen(create_component_file(0), "w");
439 if (ofp == NULL) {
440 fprintf(stderr, "%s: cannot create Y output file\n",
441 progname);
442 exit(1);
443 }
444 fputs("{\n", ofp);
445 if (rbf_colorimetry == RBCtristimulus) {
446 uvfp[0] = fopen(create_component_file(1), "w");
447 uvfp[1] = fopen(create_component_file(2), "w");
448 if ((uvfp[0] == NULL) | (uvfp[1] == NULL)) {
449 fprintf(stderr, "%s: cannot create uv output file(s)\n",
450 progname);
451 exit(1);
452 }
453 fputs("{\n", uvfp[0]);
454 fputs("{\n", uvfp[1]);
455 }
456 }
457 if (funame != NULL) /* need to assign Dx, Dy, Dz? */
458 assignD = (fundefined(funame) < 6);
459 val_last = (float *)calloc(sqres, sizeof(float));
460 if (funame == NULL)
461 sdv_next = (SDValue *)malloc(sizeof(SDValue)*sqres);
462 else
463 val_next = (float *)malloc(sizeof(float)*sqres);
464 /* run through directions */
465 for (ix = 0; ix < sqres; ix++)
466 for (iy = 0; iy < sqres; iy++) {
467 RBFNODE *rbf = NULL; /* Klems reversal */
468 square2disk(iovec, 1.-(ix+.5)*sqfact, 1.-(iy+.5)*sqfact);
469 iovec[2] = input_orient *
470 sqrt(1. - iovec[0]*iovec[0] - iovec[1]*iovec[1]);
471 if (funame == NULL)
472 rbf = advect_rbf(iovec, lobe_lim);
473 /* presample first row */
474 for (oy = 0; oy < sqres; oy++) {
475 square2disk(iovec+3, .5*sqfact, (oy+.5)*sqfact);
476 iovec[5] = output_orient *
477 sqrt(1. - iovec[3]*iovec[3] - iovec[4]*iovec[4]);
478 if (funame == NULL) {
479 eval_rbfcol(&sdv_next[oy], rbf, iovec+3);
480 } else {
481 if (assignD) {
482 varset("Dx", '=', -iovec[3]);
483 varset("Dy", '=', -iovec[4]);
484 varset("Dz", '=', -iovec[5]);
485 ++eclock;
486 }
487 val_next[oy] = funvalue(funame, 6, iovec);
488 }
489 }
490 for (ox = 0; ox < sqres; ox++) {
491 /*
492 * Super-sample when we detect a difference from before
493 * or after in this row, above or below.
494 */
495 for (oy = 0; oy < sqres; oy++) {
496 if (ox < sqres-1) { /* keeping one row ahead... */
497 square2disk(iovec+3, (ox+1.5)*sqfact, (oy+.5)*sqfact);
498 iovec[5] = output_orient *
499 sqrt(1. - iovec[3]*iovec[3] - iovec[4]*iovec[4]);
500 }
501 if (funame == NULL) {
502 SDValue sdv = sdv_next[oy];
503 bsdf = sdv.cieY;
504 if (ox < sqres-1)
505 eval_rbfcol(&sdv_next[oy], rbf, iovec+3);
506 if (abs_diff(bsdf, sdv_next[oy].cieY) > ssamp_thresh ||
507 (ox && abs_diff(bsdf, val_last[oy]) > ssamp_thresh) ||
508 (oy && abs_diff(bsdf, val_last[oy-1]) > ssamp_thresh) ||
509 (oy < sqres-1 &&
510 abs_diff(bsdf, sdv_next[oy+1].cieY) > ssamp_thresh)) {
511 int ssi;
512 double ssa[2], sum = 0, usum = 0, vsum = 0;
513 /* super-sample voxel */
514 for (ssi = nssamp; ssi--; ) {
515 SDmultiSamp(ssa, 2, (ssi+frandom()) /
516 (double)nssamp);
517 square2disk(iovec+3, (ox+ssa[0])*sqfact,
518 (oy+ssa[1])*sqfact);
519 iovec[5] = output_orient *
520 sqrt(1. - iovec[3]*iovec[3] - iovec[4]*iovec[4]);
521 eval_rbfcol(&sdv, rbf, iovec+3);
522 sum += sdv.cieY;
523 if (rbf_colorimetry == RBCtristimulus) {
524 sdv.cieY /=
525 -2.*sdv.spec.cx + 12.*sdv.spec.cy + 3.;
526 usum += 4.*sdv.spec.cx * sdv.cieY;
527 vsum += 9.*sdv.spec.cy * sdv.cieY;
528 }
529 }
530 bsdf = sum / (double)nssamp;
531 if (rbf_colorimetry == RBCtristimulus) {
532 uv[0] = usum / (sum+FTINY);
533 uv[1] = vsum / (sum+FTINY);
534 }
535 } else if (rbf_colorimetry == RBCtristimulus) {
536 uv[0] = uv[1] = 1. /
537 (-2.*sdv.spec.cx + 12.*sdv.spec.cy + 3.);
538 uv[0] *= 4.*sdv.spec.cx;
539 uv[1] *= 9.*sdv.spec.cy;
540 }
541 } else {
542 bsdf = val_next[oy];
543 if (ox < sqres-1) {
544 if (assignD) {
545 varset("Dx", '=', -iovec[3]);
546 varset("Dy", '=', -iovec[4]);
547 varset("Dz", '=', -iovec[5]);
548 ++eclock;
549 }
550 val_next[oy] = funvalue(funame, 6, iovec);
551 }
552 if (abs_diff(bsdf, val_next[oy]) > ssamp_thresh ||
553 (ox && abs_diff(bsdf, val_last[oy]) > ssamp_thresh) ||
554 (oy && abs_diff(bsdf, val_last[oy-1]) > ssamp_thresh) ||
555 (oy < sqres-1 &&
556 abs_diff(bsdf, val_next[oy+1]) > ssamp_thresh)) {
557 int ssi;
558 double ssa[4], ssvec[6], sum = 0;
559 /* super-sample voxel */
560 for (ssi = nssamp; ssi--; ) {
561 SDmultiSamp(ssa, 4, (ssi+frandom()) /
562 (double)nssamp);
563 square2disk(ssvec, 1.-(ix+ssa[0])*sqfact,
564 1.-(iy+ssa[1])*sqfact);
565 ssvec[2] = input_orient *
566 sqrt(1. - ssvec[0]*ssvec[0] -
567 ssvec[1]*ssvec[1]);
568 square2disk(ssvec+3, (ox+ssa[2])*sqfact,
569 (oy+ssa[3])*sqfact);
570 ssvec[5] = output_orient *
571 sqrt(1. - ssvec[3]*ssvec[3] -
572 ssvec[4]*ssvec[4]);
573 if (assignD) {
574 varset("Dx", '=', -ssvec[3]);
575 varset("Dy", '=', -ssvec[4]);
576 varset("Dz", '=', -ssvec[5]);
577 ++eclock;
578 }
579 sum += funvalue(funame, 6, ssvec);
580 }
581 bsdf = sum / (double)nssamp;
582 }
583 }
584 if (pctcull >= 0)
585 putbinary(&bsdf, sizeof(bsdf), 1, ofp);
586 else
587 fprintf(ofp, "\t%.3e\n", bsdf);
588
589 if (rbf_colorimetry == RBCtristimulus) {
590 if (pctcull >= 0) {
591 putbinary(&uv[0], sizeof(*uv), 1, uvfp[0]);
592 putbinary(&uv[1], sizeof(*uv), 1, uvfp[1]);
593 } else {
594 fprintf(uvfp[0], "\t%.3e\n", uv[0]);
595 fprintf(uvfp[1], "\t%.3e\n", uv[1]);
596 }
597 }
598 if (val_last != NULL)
599 val_last[oy] = bsdf;
600 }
601 }
602 if (rbf != NULL)
603 free(rbf);
604 prog_show((ix*sqres+iy+1.)/(sqres*sqres));
605 }
606 prog_done();
607 if (val_last != NULL) {
608 free(val_last);
609 if (val_next != NULL) free(val_next);
610 if (sdv_next != NULL) free(sdv_next);
611 }
612 if (pctcull >= 0) { /* finish output */
613 if (pclose(ofp)) {
614 fprintf(stderr, "%s: error running rttree_reduce on Y\n",
615 progname);
616 exit(1);
617 }
618 if (rbf_colorimetry == RBCtristimulus &&
619 (pclose(uvfp[0]) || pclose(uvfp[1]))) {
620 fprintf(stderr, "%s: error running rttree_reduce on uv\n",
621 progname);
622 exit(1);
623 }
624 } else {
625 fputs("}\n", ofp);
626 if (fclose(ofp)) {
627 fprintf(stderr, "%s: error writing Y file\n",
628 progname);
629 exit(1);
630 }
631 if (rbf_colorimetry == RBCtristimulus) {
632 fputs("}\n", uvfp[0]);
633 fputs("}\n", uvfp[1]);
634 if (fclose(uvfp[0]) || fclose(uvfp[1])) {
635 fprintf(stderr, "%s: error writing uv file(s)\n",
636 progname);
637 exit(1);
638 }
639 }
640 }
641 }
642
643 #if defined(_WIN32) || defined(_WIN64)
644 /* Execute wrapBSDF command (may never return) */
645 static int
646 wrap_up(void)
647 {
648 char cmd[32700];
649
650 if (bsdf_manuf[0]) {
651 add_wbsdf("-f", 1);
652 strcpy(cmd, "m=");
653 strcpy(cmd+2, bsdf_manuf);
654 add_wbsdf(cmd, 0);
655 }
656 if (bsdf_name[0]) {
657 add_wbsdf("-f", 1);
658 strcpy(cmd, "n=");
659 strcpy(cmd+2, bsdf_name);
660 add_wbsdf(cmd, 0);
661 }
662 if (!convert_commandline(cmd, sizeof(cmd), wrapBSDF)) {
663 fputs(progname, stderr);
664 fputs(": command line too long in wrap_up()\n", stderr);
665 return(1);
666 }
667 return(system(cmd));
668 }
669 #else
670 /* Execute wrapBSDF command (may never return) */
671 static int
672 wrap_up(void)
673 {
674 char buf[256];
675 char *compath = getpath((char *)wrapBSDF[0], getenv("PATH"), X_OK);
676
677 if (compath == NULL) {
678 fprintf(stderr, "%s: cannot locate %s\n", progname, wrapBSDF[0]);
679 return(1);
680 }
681 if (bsdf_manuf[0]) {
682 add_wbsdf("-f", 1);
683 strcpy(buf, "m=");
684 strcpy(buf+2, bsdf_manuf);
685 add_wbsdf(buf, 0);
686 }
687 if (bsdf_name[0]) {
688 add_wbsdf("-f", 1);
689 strcpy(buf, "n=");
690 strcpy(buf+2, bsdf_name);
691 add_wbsdf(buf, 0);
692 }
693 execv(compath, wrapBSDF); /* successful call never returns */
694 perror(compath);
695 return(1);
696 }
697 #endif
698
699 #define HEAD_BUFLEN 10240
700 static char head_buf[HEAD_BUFLEN];
701 static int cur_headlen = 0;
702
703 /* Record header line as comment associated with this SIR input */
704 static int
705 record2header(char *s)
706 {
707 int len = strlen(s);
708
709 if (cur_headlen+len >= HEAD_BUFLEN-6)
710 return(0);
711 /* includes EOL */
712 strcpy(head_buf+cur_headlen, s);
713 cur_headlen += len;
714
715 #if defined(_WIN32) || defined(_WIN64)
716 if (head_buf[cur_headlen-1] == '\n')
717 head_buf[cur_headlen-1] = '\t';
718 #endif
719 return(1);
720 }
721
722 /* Finish off header for this file */
723 static void
724 done_header(void)
725 {
726 while (cur_headlen > 0 && isspace(head_buf[cur_headlen-1]))
727 --cur_headlen;
728 head_buf[cur_headlen] = '\0';
729 if (!cur_headlen)
730 return;
731 add_wbsdf("-C", 1);
732 add_wbsdf(head_buf, 0);
733 head_buf[cur_headlen=0] = '\0';
734 }
735
736 /* Read in BSDF and interpolate as tensor tree representation */
737 int
738 main(int argc, char *argv[])
739 {
740 static const char tfmt[2][4] = {"t4", "t3"};
741 int dofwd = 0, dobwd = 1;
742 int nsirs = 0;
743 char buf[1024];
744 int i;
745 /* set global progname */
746 fixargv0(argv[0]);
747 esupport |= E_VARIABLE|E_FUNCTION|E_RCONST;
748 esupport &= ~(E_INCHAN|E_OUTCHAN);
749 scompile("PI:3.14159265358979323846", NULL, 0);
750 biggerlib();
751 strcpy(buf, "File produced by: ");
752 if (convert_commandline(buf+18, sizeof(buf)-18, argv) != NULL) {
753 add_wbsdf("-C", 1); add_wbsdf(buf, 0);
754 }
755 for (i = 1; i < argc; i++)
756 if ((argv[i][0] == '-') | (argv[i][0] == '+')) {
757 switch (argv[i][1]) { /* get option */
758 case 'e':
759 scompile(argv[++i], NULL, 0);
760 if (single_plane_incident < 0)
761 single_plane_incident = 0;
762 break;
763 case 'f':
764 if ((argv[i][0] == '-') & !argv[i][2]) {
765 if (strchr(argv[++i], '=') != NULL) {
766 add_wbsdf("-f", 1);
767 add_wbsdf(argv[i], 1);
768 } else {
769 char *fpath = getpath(argv[i],
770 getrlibpath(), 0);
771 if (fpath == NULL) {
772 fprintf(stderr,
773 "%s: cannot find file '%s'\n",
774 argv[0], argv[i]);
775 return(1);
776 }
777 fcompile(fpath);
778 if (single_plane_incident < 0)
779 single_plane_incident = 0;
780 }
781 } else
782 dofwd = (argv[i][0] == '+');
783 break;
784 case 'a':
785 recip = (argv[i][0] == '+') ? " -a" : "";
786 break;
787 case 'b':
788 dobwd = (argv[i][0] == '+');
789 break;
790 case 'n':
791 nssamp = atoi(argv[++i]);
792 if (nssamp <= 0)
793 goto userr;
794 break;
795 case 's':
796 ssamp_thresh = atof(argv[++i]);
797 if (ssamp_thresh <= FTINY)
798 goto userr;
799 break;
800 case 't':
801 switch (argv[i][2]) {
802 case '3':
803 single_plane_incident = 1;
804 break;
805 case '4':
806 single_plane_incident = 0;
807 break;
808 case '\0':
809 pctcull = atof(argv[++i]);
810 break;
811 default:
812 goto userr;
813 }
814 break;
815 case 'g':
816 samp_order = atoi(argv[++i]);
817 break;
818 case 'l':
819 lobe_lim = atoi(argv[++i]);
820 break;
821 case 'p':
822 do_prog = atoi(argv[i]+2);
823 break;
824 case 'W':
825 add_wbsdf(argv[i], 1);
826 break;
827 case 'u':
828 case 'C':
829 add_wbsdf(argv[i], 1);
830 add_wbsdf(argv[++i], 1);
831 break;
832 default:
833 goto userr;
834 }
835 } else { /* input SIR or function */
836 FILE *fpin;
837 if (!nsirs & (single_plane_incident >= 0))
838 break; /* must be a function */
839 if (nsirs >= 4) {
840 fprintf(stderr, "At most 4 SIR inputs supported\n");
841 goto userr;
842 }
843 fpin = fopen(argv[i], "rb"); /* open SIR file */
844 if (fpin == NULL) {
845 fprintf(stderr, "%s: cannot open BSDF interpolant '%s'\n",
846 progname, argv[i]);
847 return(1);
848 }
849 sprintf(buf, "%s:\n", argv[i]);
850 record2header(buf);
851 sir_headshare = &record2header;
852 if (!load_bsdf_rep(fpin))
853 return(1);
854 fclose(fpin);
855 done_header();
856 sprintf(buf, "Interpolating component '%s'", argv[i]);
857 prog_start(buf);
858 if (!nsirs++) {
859 add_wbsdf("-a", 1);
860 add_wbsdf(tfmt[single_plane_incident], 1);
861 }
862 if (single_plane_incident)
863 eval_isotropic(NULL);
864 else
865 eval_anisotropic(NULL);
866 }
867 if (i < argc) { /* function-based BSDF? */
868 void (*evf)(char *s) = single_plane_incident ?
869 eval_isotropic : eval_anisotropic;
870 if (i != argc-1 || fundefined(argv[i]) < 3) {
871 fprintf(stderr,
872 "%s: need single function with 6 arguments: bsdf(ix,iy,iz,ox,oy,oz)\n",
873 progname);
874 fprintf(stderr, "\tor 3 arguments using Dx,Dy,Dz: bsdf(ix,iy,iz)\n");
875 goto userr;
876 }
877 doptimize(1); /* optimize definitions */
878 ++eclock;
879 add_wbsdf("-a", 1);
880 add_wbsdf(tfmt[single_plane_incident], 1);
881 if (dofwd) {
882 input_orient = -1;
883 output_orient = -1;
884 prog_start("Evaluating outside reflectance");
885 (*evf)(argv[i]);
886 output_orient = 1;
887 prog_start("Evaluating outside->inside transmission");
888 (*evf)(argv[i]);
889 }
890 if (dobwd) {
891 input_orient = 1;
892 output_orient = 1;
893 prog_start("Evaluating inside reflectance");
894 (*evf)(argv[i]);
895 output_orient = -1;
896 prog_start("Evaluating inside->outside transmission");
897 (*evf)(argv[i]);
898 }
899 } else if (!nsirs) { /* else load SIR from stdin? */
900 record2header("<stdin>:\n");
901 sir_headshare = &record2header;
902 if (!load_bsdf_rep(stdin))
903 return(1);
904 done_header();
905 prog_start("Interpolating from standard input");
906 add_wbsdf("-a", 1);
907 add_wbsdf(tfmt[single_plane_incident], 1);
908 if (single_plane_incident) /* resample dist. */
909 eval_isotropic(NULL);
910 else
911 eval_anisotropic(NULL);
912 }
913 return(wrap_up()); /* call wrapBSDF */
914 userr:
915 fprintf(stderr,
916 "Usage: %s [{+|-}a][-g Nlog2][-t pctcull][-n nss][-s thresh][-l maxlobes][bsdf.sir ..] > bsdf.xml\n",
917 progname);
918 fprintf(stderr,
919 " or: %s -t{3|4} [{+|-}a][-g Nlog2][-t pctcull][-n nss][-s thresh][{+|-}for[ward]][{+|-}b[ackward]][-e expr][-f file] bsdf_func > bsdf.xml\n",
920 progname);
921 return(1);
922 }