ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/bsdf2klems.c
Revision: 2.37
Committed: Tue Jun 3 21:31:51 2025 UTC (3 days, 7 hours ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.36: +3 -5 lines
Log Message:
refactor: More consistent use of global char * progname and fixargv0()

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: bsdf2klems.c,v 2.36 2024/02/23 03:47:57 greg Exp $";
3 #endif
4 /*
5 * Load measured BSDF interpolant and write out as XML file with Klems matrix.
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 "platform.h"
16 #include "paths.h"
17 #include "rtio.h"
18 #include "calcomp.h"
19 #include "bsdfrep.h"
20 #include "bsdf_m.h"
21 /* tristimulus components */
22 enum {CIE_X, CIE_Y, CIE_Z};
23 /* assumed maximum # Klems patches */
24 #define MAXPATCHES 145
25 /* selected basis function name */
26 static const char klems_full[] = "LBNL/Klems Full";
27 static const char klems_half[] = "LBNL/Klems Half";
28 static const char klems_quarter[] = "LBNL/Klems Quarter";
29 static const char *kbasis = klems_full;
30 /* number of BSDF samples per patch */
31 static int npsamps = 1024;
32 /* limit on number of RBF lobes */
33 static int lobe_lim = 15000;
34 /* progress bar length */
35 static int do_prog = 79;
36
37 #define MAXCARG 512 /* wrapBSDF command */
38 static char *wrapBSDF[MAXCARG] = {"wrapBSDF", "-W", "-UU"};
39 static int wbsdfac = 3;
40
41 /* Add argument to wrapBSDF, allocating space if !isstatic */
42 static void
43 add_wbsdf(const char *arg, int isstatic)
44 {
45 if (arg == NULL)
46 return;
47 if (wbsdfac >= MAXCARG-1) {
48 fputs(progname, stderr);
49 fputs(": too many command arguments to wrapBSDF\n", stderr);
50 exit(1);
51 }
52 if (!*arg)
53 arg = "";
54 else if (!isstatic)
55 arg = savqstr((char *)arg);
56
57 wrapBSDF[wbsdfac++] = (char *)arg;
58 }
59
60 /* Start new progress bar */
61 #define prog_start(s) if (do_prog) fprintf(stderr, "%s: %s...\n", progname, s); else
62
63 /* Draw progress bar of the appropriate length */
64 static void
65 prog_show(double frac)
66 {
67 static unsigned call_cnt = 0;
68 static char lastc[] = "-\\|/";
69 char pbar[256];
70 int nchars;
71
72 if (do_prog <= 1) return;
73 if (do_prog > sizeof(pbar)-2)
74 do_prog = sizeof(pbar)-2;
75 if (frac < 0) frac = 0;
76 else if (frac >= 1) frac = .9999;
77 nchars = do_prog*frac;
78 pbar[0] = '\r';
79 memset(pbar+1, '*', nchars);
80 pbar[nchars+1] = lastc[call_cnt++ & 3];
81 memset(pbar+2+nchars, '-', do_prog-nchars-1);
82 pbar[do_prog+1] = '\0';
83 fputs(pbar, stderr);
84 }
85
86 /* Finish progress bar */
87 static void
88 prog_done(void)
89 {
90 int n = do_prog;
91
92 if (n <= 1) return;
93 fputc('\r', stderr);
94 while (n--)
95 fputc(' ', stderr);
96 fputc('\r', stderr);
97 }
98
99 /* Return angle basis corresponding to the given name */
100 static ANGLE_BASIS *
101 get_basis(const char *bn)
102 {
103 int n = nabases;
104
105 while (n-- > 0)
106 if (!strcasecmp(bn, abase_list[n].name))
107 return &abase_list[n];
108 return NULL;
109 }
110
111 /* Copy geometry string to file for wrapBSDF */
112 static char *
113 save_geom(const char *mgf)
114 {
115 char *tfname = mktemp(savqstr(TEMPLATE));
116 int fd = open(tfname, O_CREAT|O_WRONLY, 0600);
117
118 if (fd < 0)
119 return(NULL);
120 write(fd, mgf, strlen(mgf));
121 close(fd);
122 add_wbsdf("-g", 1);
123 add_wbsdf(tfname, 1);
124 return(tfname);
125 }
126
127 /* Open XYZ component file for output and add appropriate arguments */
128 static FILE *
129 open_component_file(int c)
130 {
131 static const char sname[3][6] = {"CIE-X", "CIE-Y", "CIE-Z"};
132 static const char cname[4][4] = {"-rf", "-tf", "-tb", "-rb"};
133 char *tfname = mktemp(savqstr(TEMPLATE));
134 FILE *fp = fopen(tfname, "w");
135
136 if (fp == NULL) {
137 fprintf(stderr, "%s: cannot open '%s' for writing\n",
138 progname, tfname);
139 exit(1);
140 }
141 add_wbsdf("-s", 1); add_wbsdf(sname[c], 1);
142 add_wbsdf(cname[(input_orient>0)<<1 | (output_orient>0)], 1);
143 add_wbsdf(tfname, 1);
144 return(fp);
145 }
146
147 /* Load and resample XML BSDF description using Klems basis */
148 static void
149 eval_bsdf(const char *fname)
150 {
151 ANGLE_BASIS *abp = get_basis(kbasis);
152 FILE *cfp[3];
153 SDData bsd;
154 SDError ec;
155 FVECT vin, vout;
156 SDValue sdv;
157 double sum, xsum, ysum;
158 int i, j, n;
159
160 initurand(npsamps);
161 SDclearBSDF(&bsd, fname); /* load BSDF file */
162 if ((ec = SDloadFile(&bsd, fname)) != SDEnone)
163 goto err;
164 if (bsd.mgf != NULL) /* save geometry */
165 save_geom(bsd.mgf);
166 if (bsd.matn[0]) /* save identifier(s) */
167 strcpy(bsdf_name, bsd.matn);
168 if (bsd.makr[0])
169 strcpy(bsdf_manuf, bsd.makr);
170 if (bsd.dim[2] > 0) { /* save dimension(s) */
171 char buf[64];
172 if ((bsd.dim[0] > 0) & (bsd.dim[1] > 0))
173 sprintf(buf, "w=%g;h=%g;t=%g",
174 bsd.dim[0], bsd.dim[1], bsd.dim[2]);
175 else
176 sprintf(buf, "t=%g", bsd.dim[2]);
177 add_wbsdf("-f", 1);
178 add_wbsdf(buf, 0);
179 }
180 /* front reflection */
181 if (bsd.rf != NULL || bsd.rLambFront.cieY > .002) {
182 input_orient = 1; output_orient = 1;
183 cfp[CIE_Y] = open_component_file(CIE_Y);
184 if (bsd.rf != NULL && bsd.rf->comp[0].cspec[2].flags) {
185 rbf_colorimetry = RBCtristimulus;
186 cfp[CIE_X] = open_component_file(CIE_X);
187 cfp[CIE_Z] = open_component_file(CIE_Z);
188 } else
189 rbf_colorimetry = RBCphotopic;
190 for (j = 0; j < abp->nangles; j++) {
191 for (i = 0; i < abp->nangles; i++) {
192 sum = 0; /* average over patches */
193 xsum = ysum = 0;
194 for (n = npsamps; n-- > 0; ) {
195 fo_getvec(vout, j+(n+frandom())/npsamps, abp);
196 fi_getvec(vin, i+urand(n), abp);
197 ec = SDevalBSDF(&sdv, vin, vout, &bsd);
198 if (ec != SDEnone)
199 goto err;
200 sum += sdv.cieY;
201 if (rbf_colorimetry == RBCtristimulus) {
202 xsum += sdv.cieY * sdv.spec.cx;
203 ysum += sdv.cieY * sdv.spec.cy;
204 }
205 }
206 fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps);
207 if (rbf_colorimetry == RBCtristimulus) {
208 fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum));
209 fprintf(cfp[CIE_Z], "\t%.3e\n",
210 (sum - xsum - ysum)*sum/(npsamps*ysum));
211 }
212 }
213 fputc('\n', cfp[CIE_Y]); /* extra space between rows */
214 if (rbf_colorimetry == RBCtristimulus) {
215 fputc('\n', cfp[CIE_X]);
216 fputc('\n', cfp[CIE_Z]);
217 }
218 }
219 if (fclose(cfp[CIE_Y])) {
220 fprintf(stderr, "%s: error writing Y output\n", progname);
221 exit(1);
222 }
223 if (rbf_colorimetry == RBCtristimulus &&
224 (fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z]))) {
225 fprintf(stderr, "%s: error writing X/Z output\n", progname);
226 exit(1);
227 }
228 }
229 /* back reflection */
230 if (bsd.rb != NULL || bsd.rLambBack.cieY > .002) {
231 input_orient = -1; output_orient = -1;
232 cfp[CIE_Y] = open_component_file(CIE_Y);
233 if (bsd.rb != NULL && bsd.rb->comp[0].cspec[2].flags) {
234 rbf_colorimetry = RBCtristimulus;
235 cfp[CIE_X] = open_component_file(CIE_X);
236 cfp[CIE_Z] = open_component_file(CIE_Z);
237 } else
238 rbf_colorimetry = RBCphotopic;
239 for (j = 0; j < abp->nangles; j++) {
240 for (i = 0; i < abp->nangles; i++) {
241 sum = 0; /* average over patches */
242 xsum = ysum = 0;
243 for (n = npsamps; n-- > 0; ) {
244 bo_getvec(vout, j+(n+frandom())/npsamps, abp);
245 bi_getvec(vin, i+urand(n), abp);
246 ec = SDevalBSDF(&sdv, vin, vout, &bsd);
247 if (ec != SDEnone)
248 goto err;
249 sum += sdv.cieY;
250 if (rbf_colorimetry == RBCtristimulus) {
251 xsum += sdv.cieY * sdv.spec.cx;
252 ysum += sdv.cieY * sdv.spec.cy;
253 }
254 }
255 fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps);
256 if (rbf_colorimetry == RBCtristimulus) {
257 fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum));
258 fprintf(cfp[CIE_Z], "\t%.3e\n",
259 (sum - xsum - ysum)*sum/(npsamps*ysum));
260 }
261 }
262 if (rbf_colorimetry == RBCtristimulus) {
263 fputc('\n', cfp[CIE_X]);
264 fputc('\n', cfp[CIE_Z]);
265 }
266 }
267 if (fclose(cfp[CIE_Y])) {
268 fprintf(stderr, "%s: error writing Y output\n", progname);
269 exit(1);
270 }
271 if (rbf_colorimetry == RBCtristimulus &&
272 (fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z]))) {
273 fprintf(stderr, "%s: error writing X/Z output\n", progname);
274 exit(1);
275 }
276 }
277 /* front transmission */
278 if (bsd.tf != NULL || bsd.tLambFront.cieY > .002) {
279 input_orient = 1; output_orient = -1;
280 cfp[CIE_Y] = open_component_file(CIE_Y);
281 if (bsd.tf != NULL && bsd.tf->comp[0].cspec[2].flags) {
282 rbf_colorimetry = RBCtristimulus;
283 cfp[CIE_X] = open_component_file(CIE_X);
284 cfp[CIE_Z] = open_component_file(CIE_Z);
285 } else
286 rbf_colorimetry = RBCphotopic;
287 for (j = 0; j < abp->nangles; j++) {
288 for (i = 0; i < abp->nangles; i++) {
289 sum = 0; /* average over patches */
290 xsum = ysum = 0;
291 for (n = npsamps; n-- > 0; ) {
292 bo_getvec(vout, j+(n+frandom())/npsamps, abp);
293 fi_getvec(vin, i+urand(n), abp);
294 ec = SDevalBSDF(&sdv, vin, vout, &bsd);
295 if (ec != SDEnone)
296 goto err;
297 sum += sdv.cieY;
298 if (rbf_colorimetry == RBCtristimulus) {
299 xsum += sdv.cieY * sdv.spec.cx;
300 ysum += sdv.cieY * sdv.spec.cy;
301 }
302 }
303 fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps);
304 if (rbf_colorimetry == RBCtristimulus) {
305 fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum));
306 fprintf(cfp[CIE_Z], "\t%.3e\n",
307 (sum - xsum - ysum)*sum/(npsamps*ysum));
308 }
309 }
310 if (rbf_colorimetry == RBCtristimulus) {
311 fputc('\n', cfp[CIE_X]);
312 fputc('\n', cfp[CIE_Z]);
313 }
314 }
315 if (fclose(cfp[CIE_Y])) {
316 fprintf(stderr, "%s: error writing Y output\n", progname);
317 exit(1);
318 }
319 if (rbf_colorimetry == RBCtristimulus &&
320 (fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z]))) {
321 fprintf(stderr, "%s: error writing X/Z output\n", progname);
322 exit(1);
323 }
324 }
325 /* back transmission */
326 if ((bsd.tb != NULL) | (bsd.tf != NULL)) {
327 input_orient = -1; output_orient = 1;
328 cfp[CIE_Y] = open_component_file(CIE_Y);
329 if (bsd.tb != NULL)
330 rbf_colorimetry = bsd.tb->comp[0].cspec[2].flags
331 ? RBCtristimulus : RBCphotopic ;
332 if (rbf_colorimetry == RBCtristimulus) {
333 cfp[CIE_X] = open_component_file(CIE_X);
334 cfp[CIE_Z] = open_component_file(CIE_Z);
335 }
336 for (j = 0; j < abp->nangles; j++) {
337 for (i = 0; i < abp->nangles; i++) {
338 sum = 0; /* average over patches */
339 xsum = ysum = 0;
340 for (n = npsamps; n-- > 0; ) {
341 fo_getvec(vout, j+(n+frandom())/npsamps, abp);
342 bi_getvec(vin, i+urand(n), abp);
343 ec = SDevalBSDF(&sdv, vin, vout, &bsd);
344 if (ec != SDEnone)
345 goto err;
346 sum += sdv.cieY;
347 if (rbf_colorimetry == RBCtristimulus) {
348 xsum += sdv.cieY * sdv.spec.cx;
349 ysum += sdv.cieY * sdv.spec.cy;
350 }
351 }
352 fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps);
353 if (rbf_colorimetry == RBCtristimulus) {
354 fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum));
355 fprintf(cfp[CIE_Z], "\t%.3e\n",
356 (sum - xsum - ysum)*sum/(npsamps*ysum));
357 }
358 }
359 if (rbf_colorimetry == RBCtristimulus) {
360 fputc('\n', cfp[CIE_X]);
361 fputc('\n', cfp[CIE_Z]);
362 }
363 }
364 if (fclose(cfp[CIE_Y])) {
365 fprintf(stderr, "%s: error writing Y output\n", progname);
366 exit(1);
367 }
368 if (rbf_colorimetry == RBCtristimulus &&
369 (fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z]))) {
370 fprintf(stderr, "%s: error writing X/Z output\n", progname);
371 exit(1);
372 }
373 }
374 SDfreeBSDF(&bsd); /* all done */
375 return;
376 err:
377 SDreportError(ec, stderr);
378 exit(1);
379 }
380
381 /* Interpolate and output a BSDF function using Klems basis */
382 static void
383 eval_function(char *funame)
384 {
385 ANGLE_BASIS *abp = get_basis(kbasis);
386 int assignD = (fundefined(funame) < 6);
387 FILE *ofp = open_component_file(CIE_Y);
388 double iovec[6];
389 double sum;
390 int i, j, n;
391
392 initurand(npsamps);
393 for (j = 0; j < abp->nangles; j++) { /* run through directions */
394 for (i = 0; i < abp->nangles; i++) {
395 sum = 0;
396 for (n = npsamps; n--; ) { /* average over patches */
397 if (output_orient > 0)
398 fo_getvec(iovec+3, j+(n+frandom())/npsamps, abp);
399 else
400 bo_getvec(iovec+3, j+(n+frandom())/npsamps, abp);
401
402 if (input_orient > 0)
403 fi_getvec(iovec, i+urand(n), abp);
404 else
405 bi_getvec(iovec, i+urand(n), abp);
406
407 if (assignD) {
408 varset("Dx", '=', -iovec[3]);
409 varset("Dy", '=', -iovec[4]);
410 varset("Dz", '=', -iovec[5]);
411 ++eclock;
412 }
413 sum += funvalue(funame, 6, iovec);
414 }
415 fprintf(ofp, "\t%.3e\n", sum/npsamps);
416 }
417 fputc('\n', ofp);
418 prog_show((j+1.)/abp->nangles);
419 }
420 prog_done();
421 if (fclose(ofp)) {
422 fprintf(stderr, "%s: error writing Y output\n", progname);
423 exit(1);
424 }
425 }
426
427 /* Interpolate and output a radial basis function BSDF representation */
428 static void
429 eval_rbf(void)
430 {
431 ANGLE_BASIS *abp = get_basis(kbasis);
432 float (*XZarr)[2] = NULL;
433 float bsdfarr[MAXPATCHES*MAXPATCHES];
434 FILE *cfp[3];
435 FVECT vin, vout;
436 double sum, xsum, ysum, normf;
437 int i, j, ni, no, nisamps, nosamps;
438 /* sanity check */
439 if (abp->nangles > MAXPATCHES) {
440 fprintf(stderr, "%s: too many patches!\n", progname);
441 exit(1);
442 }
443 memset(bsdfarr, 0, sizeof(bsdfarr));
444 if (rbf_colorimetry == RBCtristimulus)
445 XZarr = (float (*)[2])calloc(abp->nangles*abp->nangles, 2*sizeof(float));
446 nosamps = (int)(pow((double)npsamps, 0.67) + .5);
447 nisamps = (npsamps + (nosamps>>1)) / nosamps;
448 normf = 1./(double)(nisamps*nosamps);
449 for (i = 0; i < abp->nangles; i++) {
450 for (ni = nisamps; ni--; ) { /* sample over incident patch */
451 RBFNODE *rbf;
452 if (input_orient > 0) /* vary incident patch loc. */
453 fi_getvec(vin, i+urand(ni), abp);
454 else
455 bi_getvec(vin, i+urand(ni), abp);
456
457 rbf = advect_rbf(vin, lobe_lim); /* compute radial basis func */
458
459 for (j = 0; j < abp->nangles; j++) {
460 sum = 0; /* sample over exiting patch */
461 xsum = ysum = 0;
462 for (no = nosamps; no--; ) {
463 SDValue sdv;
464 if (output_orient > 0)
465 fo_getvec(vout, j+(no+frandom())/nosamps, abp);
466 else
467 bo_getvec(vout, j+(no+frandom())/nosamps, abp);
468
469 eval_rbfcol(&sdv, rbf, vout);
470 sum += sdv.cieY;
471 if (rbf_colorimetry == RBCtristimulus) {
472 xsum += sdv.cieY * sdv.spec.cx;
473 ysum += sdv.cieY * sdv.spec.cy;
474 }
475 }
476 no = j*abp->nangles + i;
477 bsdfarr[no] += sum * normf;
478 if (rbf_colorimetry == RBCtristimulus) {
479 XZarr[no][0] += xsum*sum*normf/ysum;
480 XZarr[no][1] += (sum - xsum - ysum)*sum*normf/ysum;
481 }
482 }
483 if (rbf != NULL)
484 free(rbf);
485 }
486 prog_show((i+1.)/abp->nangles);
487 }
488 /* write out our matrix */
489 cfp[CIE_Y] = open_component_file(CIE_Y);
490 no = 0;
491 for (j = 0; j < abp->nangles; j++) {
492 for (i = 0; i < abp->nangles; i++, no++)
493 fprintf(cfp[CIE_Y], "\t%.3e\n", bsdfarr[no]);
494 fputc('\n', cfp[CIE_Y]);
495 }
496 prog_done();
497 if (fclose(cfp[CIE_Y])) {
498 fprintf(stderr, "%s: error writing Y output\n", progname);
499 exit(1);
500 }
501 if (XZarr == NULL) /* no color? */
502 return;
503 cfp[CIE_X] = open_component_file(CIE_X);
504 cfp[CIE_Z] = open_component_file(CIE_Z);
505 no = 0;
506 for (j = 0; j < abp->nangles; j++) {
507 for (i = 0; i < abp->nangles; i++, no++) {
508 fprintf(cfp[CIE_X], "\t%.3e\n", XZarr[no][0]);
509 fprintf(cfp[CIE_Z], "\t%.3e\n", XZarr[no][1]);
510 }
511 fputc('\n', cfp[CIE_X]);
512 fputc('\n', cfp[CIE_Z]);
513 }
514 free(XZarr);
515 if (fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z])) {
516 fprintf(stderr, "%s: error writing X/Z output\n", progname);
517 exit(1);
518 }
519 }
520
521 #if defined(_WIN32) || defined(_WIN64)
522 /* Execute wrapBSDF command (may never return) */
523 static int
524 wrap_up(void)
525 {
526 char cmd[32700];
527
528 if (bsdf_manuf[0]) {
529 add_wbsdf("-f", 1);
530 strcpy(cmd, "m=");
531 strcpy(cmd+2, bsdf_manuf);
532 add_wbsdf(cmd, 0);
533 }
534 if (bsdf_name[0]) {
535 add_wbsdf("-f", 1);
536 strcpy(cmd, "n=");
537 strcpy(cmd+2, bsdf_name);
538 add_wbsdf(cmd, 0);
539 }
540 if (!convert_commandline(cmd, sizeof(cmd), wrapBSDF)) {
541 fputs(progname, stderr);
542 fputs(": command line too long in wrap_up()\n", stderr);
543 return(1);
544 }
545 return(system(cmd));
546 }
547 #else
548 /* Execute wrapBSDF command (may never return) */
549 static int
550 wrap_up(void)
551 {
552 char buf[256];
553 char *compath = getpath((char *)wrapBSDF[0], getenv("PATH"), X_OK);
554
555 if (compath == NULL) {
556 fprintf(stderr, "%s: cannot locate %s\n", progname, wrapBSDF[0]);
557 return(1);
558 }
559 if (bsdf_manuf[0]) {
560 add_wbsdf("-f", 1);
561 strcpy(buf, "m=");
562 strcpy(buf+2, bsdf_manuf);
563 add_wbsdf(buf, 0);
564 }
565 if (bsdf_name[0]) {
566 add_wbsdf("-f", 1);
567 strcpy(buf, "n=");
568 strcpy(buf+2, bsdf_name);
569 add_wbsdf(buf, 0);
570 }
571 execv(compath, wrapBSDF); /* successful call never returns */
572 perror(compath);
573 return(1);
574 }
575 #endif
576
577 #define HEAD_BUFLEN 10240
578 static char head_buf[HEAD_BUFLEN];
579 static int cur_headlen = 0;
580
581 /* Record header line as comment associated with this SIR input */
582 static int
583 record2header(char *s)
584 {
585 int len = strlen(s);
586
587 if (cur_headlen+len >= HEAD_BUFLEN-6)
588 return(0);
589 /* includes EOL */
590 strcpy(head_buf+cur_headlen, s);
591 cur_headlen += len;
592
593 #if defined(_WIN32) || defined(_WIN64)
594 if (head_buf[cur_headlen-1] == '\n')
595 head_buf[cur_headlen-1] = '\t';
596 #endif
597 return(1);
598 }
599
600 /* Finish off header for this file */
601 static void
602 done_header(void)
603 {
604 while (cur_headlen > 0 && isspace(head_buf[cur_headlen-1]))
605 --cur_headlen;
606 head_buf[cur_headlen] = '\0';
607 if (!cur_headlen)
608 return;
609 add_wbsdf("-C", 1);
610 add_wbsdf(head_buf, 0);
611 head_buf[cur_headlen=0] = '\0';
612 }
613
614 /* Read in BSDF and interpolate as Klems matrix representation */
615 int
616 main(int argc, char *argv[])
617 {
618 int dofwd = 0, dobwd = 1;
619 char buf[1024];
620 char *cp;
621 int i, na;
622 /* set global progname */
623 fixargv0(argv[0]);
624 esupport |= E_VARIABLE|E_FUNCTION|E_RCONST;
625 esupport &= ~(E_INCHAN|E_OUTCHAN);
626 scompile("PI:3.14159265358979323846", NULL, 0);
627 biggerlib();
628 for (i = 1; i < argc && (argv[i][0] == '-') | (argv[i][0] == '+'); i++)
629 switch (argv[i][1]) { /* get options */
630 case 'n':
631 npsamps = atoi(argv[++i]);
632 if (npsamps <= 0)
633 goto userr;
634 break;
635 case 'e':
636 scompile(argv[++i], NULL, 0);
637 single_plane_incident = 0;
638 break;
639 case 'f':
640 if ((argv[i][0] == '-') & !argv[i][2]) {
641 if (strchr(argv[++i], '=') != NULL) {
642 add_wbsdf("-f", 1);
643 add_wbsdf(argv[i], 1);
644 } else {
645 char *fpath = getpath(argv[i],
646 getrlibpath(), 0);
647 if (fpath == NULL) {
648 fprintf(stderr,
649 "%s: cannot find file '%s'\n",
650 argv[0], argv[i]);
651 return(1);
652 }
653 fcompile(fpath);
654 single_plane_incident = 0;
655 }
656 } else
657 dofwd = (argv[i][0] == '+');
658 break;
659 case 'b':
660 dobwd = (argv[i][0] == '+');
661 break;
662 case 'h':
663 kbasis = klems_half;
664 add_wbsdf("-a", 1);
665 add_wbsdf("kh", 1);
666 break;
667 case 'q':
668 kbasis = klems_quarter;
669 add_wbsdf("-a", 1);
670 add_wbsdf("kq", 1);
671 break;
672 case 'l':
673 lobe_lim = atoi(argv[++i]);
674 break;
675 case 'p':
676 do_prog = atoi(argv[i]+2);
677 break;
678 case 'C':
679 add_wbsdf(argv[i], 1);
680 add_wbsdf(argv[++i], 1);
681 break;
682 default:
683 goto userr;
684 }
685 if (kbasis == klems_full) { /* default (full) basis? */
686 add_wbsdf("-a", 1);
687 add_wbsdf("kf", 1);
688 }
689 strcpy(buf, "File produced by: ");
690 if (convert_commandline(buf+18, sizeof(buf)-18, argv) != NULL) {
691 add_wbsdf("-C", 1); add_wbsdf(buf, 0);
692 }
693 if (single_plane_incident >= 0) { /* function-based BSDF? */
694 if (i != argc-1 || fundefined(argv[i]) < 3) {
695 fprintf(stderr,
696 "%s: need single function with 6 arguments: bsdf(ix,iy,iz,ox,oy,oz)\n",
697 progname);
698 fprintf(stderr, "\tor 3 arguments using Dx,Dy,Dz: bsdf(ix,iy,iz)\n");
699 goto userr;
700 }
701 doptimize(1); /* optimize definitions */
702 ++eclock;
703 if (dofwd) {
704 input_orient = -1;
705 output_orient = -1;
706 prog_start("Evaluating outside reflectance");
707 eval_function(argv[i]);
708 output_orient = 1;
709 prog_start("Evaluating outside->inside transmission");
710 eval_function(argv[i]);
711 }
712 if (dobwd) {
713 input_orient = 1;
714 output_orient = 1;
715 prog_start("Evaluating inside reflectance");
716 eval_function(argv[i]);
717 output_orient = -1;
718 prog_start("Evaluating inside->outside transmission");
719 eval_function(argv[i]);
720 }
721 return(wrap_up());
722 }
723 /* XML input? */
724 if (i == argc-1 && (cp = argv[i]+strlen(argv[i])-4) > argv[i] &&
725 !strcasecmp(cp, ".xml")) {
726 eval_bsdf(argv[i]); /* load & resample BSDF */
727 return(wrap_up());
728 }
729 if (i < argc) { /* open input files if given */
730 int nbsdf = 0;
731 for ( ; i < argc; i++) { /* interpolate each component */
732 FILE *fpin = fopen(argv[i], "rb");
733 if (fpin == NULL) {
734 fprintf(stderr, "%s: cannot open BSDF interpolant '%s'\n",
735 progname, argv[i]);
736 return(1);
737 }
738 sprintf(buf, "%s:\n", argv[i]);
739 record2header(buf);
740 sir_headshare = &record2header;
741 if (!load_bsdf_rep(fpin))
742 return(1);
743 fclose(fpin);
744 done_header();
745 sprintf(buf, "Interpolating component '%s'", argv[i]);
746 prog_start(buf);
747 eval_rbf();
748 }
749 return(wrap_up());
750 }
751 SET_FILE_BINARY(stdin); /* load from stdin */
752 record2header("<stdin>:\n");
753 sir_headshare = &record2header;
754 if (!load_bsdf_rep(stdin))
755 return(1);
756 done_header();
757 prog_start("Interpolating from standard input");
758 eval_rbf(); /* resample dist. */
759 return(wrap_up());
760 userr:
761 fprintf(stderr,
762 "Usage: %s [-n spp][-h|-q][-l maxlobes] [bsdf.sir ..] > bsdf.xml\n", progname);
763 fprintf(stderr,
764 " or: %s [-n spp][-h|-q] bsdf_in.xml > bsdf_out.xml\n", progname);
765 fprintf(stderr,
766 " or: %s [-n spp][-h|-q][{+|-}for[ward]][{+|-}b[ackward]][-e expr][-f file] bsdf_func > bsdf.xml\n",
767 progname);
768 return(1);
769 }