ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/bsdf2klems.c
Revision: 2.36
Committed: Fri Feb 23 03:47:57 2024 UTC (2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.35: +2 -1 lines
Log Message:
perf: Added array index optimization to calcomp routines

File Contents

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