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 (4 days, 3 hours ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.36: +3 -5 lines
Log Message:
refactor: More consistent use of global char * progname and fixargv0()

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.37 static const char RCSid[] = "$Id: bsdf2klems.c,v 2.36 2024/02/23 03:47:57 greg Exp $";
3 greg 2.1 #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 greg 2.29 #include <ctype.h>
14 greg 2.1 #include "random.h"
15     #include "platform.h"
16 greg 2.20 #include "paths.h"
17     #include "rtio.h"
18 greg 2.1 #include "calcomp.h"
19     #include "bsdfrep.h"
20     #include "bsdf_m.h"
21 greg 2.20 /* tristimulus components */
22     enum {CIE_X, CIE_Y, CIE_Z};
23 greg 2.4 /* assumed maximum # Klems patches */
24     #define MAXPATCHES 145
25 greg 2.1 /* selected basis function name */
26 greg 2.20 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 greg 2.1 /* number of BSDF samples per patch */
31 greg 2.26 static int npsamps = 1024;
32 greg 2.10 /* limit on number of RBF lobes */
33     static int lobe_lim = 15000;
34 greg 2.13 /* progress bar length */
35     static int do_prog = 79;
36    
37 greg 2.20 #define MAXCARG 512 /* wrapBSDF command */
38     static char *wrapBSDF[MAXCARG] = {"wrapBSDF", "-W", "-UU"};
39     static int wbsdfac = 3;
40    
41 greg 2.23 /* Add argument to wrapBSDF, allocating space if !isstatic */
42 greg 2.20 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 greg 2.13
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 greg 2.17 static unsigned call_cnt = 0;
68     static char lastc[] = "-\\|/";
69     char pbar[256];
70     int nchars;
71 greg 2.13
72 greg 2.14 if (do_prog <= 1) return;
73 greg 2.13 if (do_prog > sizeof(pbar)-2)
74     do_prog = sizeof(pbar)-2;
75     if (frac < 0) frac = 0;
76 greg 2.17 else if (frac >= 1) frac = .9999;
77     nchars = do_prog*frac;
78 greg 2.13 pbar[0] = '\r';
79     memset(pbar+1, '*', nchars);
80 greg 2.17 pbar[nchars+1] = lastc[call_cnt++ & 3];
81     memset(pbar+2+nchars, '-', do_prog-nchars-1);
82 greg 2.13 pbar[do_prog+1] = '\0';
83     fputs(pbar, stderr);
84     }
85    
86     /* Finish progress bar */
87 greg 2.14 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 greg 2.1
99     /* Return angle basis corresponding to the given name */
100 greg 2.13 static ANGLE_BASIS *
101 greg 2.1 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 greg 2.20 /* 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 greg 2.1 exit(1);
140     }
141 greg 2.20 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 greg 2.1 }
146    
147 greg 2.2 /* Load and resample XML BSDF description using Klems basis */
148 greg 2.1 static void
149     eval_bsdf(const char *fname)
150     {
151     ANGLE_BASIS *abp = get_basis(kbasis);
152 greg 2.20 FILE *cfp[3];
153 greg 2.1 SDData bsd;
154     SDError ec;
155     FVECT vin, vout;
156 greg 2.20 SDValue sdv;
157     double sum, xsum, ysum;
158 greg 2.1 int i, j, n;
159    
160 greg 2.18 initurand(npsamps);
161 greg 2.1 SDclearBSDF(&bsd, fname); /* load BSDF file */
162     if ((ec = SDloadFile(&bsd, fname)) != SDEnone)
163     goto err;
164 greg 2.20 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 greg 2.1 /* front reflection */
181     if (bsd.rf != NULL || bsd.rLambFront.cieY > .002) {
182     input_orient = 1; output_orient = 1;
183 greg 2.20 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 greg 2.1 for (j = 0; j < abp->nangles; j++) {
191     for (i = 0; i < abp->nangles; i++) {
192     sum = 0; /* average over patches */
193 greg 2.20 xsum = ysum = 0;
194 greg 2.1 for (n = npsamps; n-- > 0; ) {
195     fo_getvec(vout, j+(n+frandom())/npsamps, abp);
196 greg 2.5 fi_getvec(vin, i+urand(n), abp);
197 greg 2.34 ec = SDevalBSDF(&sdv, vin, vout, &bsd);
198 greg 2.1 if (ec != SDEnone)
199     goto err;
200 greg 2.20 sum += sdv.cieY;
201     if (rbf_colorimetry == RBCtristimulus) {
202 greg 2.21 xsum += sdv.cieY * sdv.spec.cx;
203     ysum += sdv.cieY * sdv.spec.cy;
204 greg 2.20 }
205     }
206     fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps);
207     if (rbf_colorimetry == RBCtristimulus) {
208 greg 2.21 fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum));
209     fprintf(cfp[CIE_Z], "\t%.3e\n",
210 greg 2.20 (sum - xsum - ysum)*sum/(npsamps*ysum));
211 greg 2.1 }
212     }
213 greg 2.20 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 greg 2.1 }
228     }
229     /* back reflection */
230     if (bsd.rb != NULL || bsd.rLambBack.cieY > .002) {
231     input_orient = -1; output_orient = -1;
232 greg 2.20 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 greg 2.1 for (j = 0; j < abp->nangles; j++) {
240     for (i = 0; i < abp->nangles; i++) {
241     sum = 0; /* average over patches */
242 greg 2.20 xsum = ysum = 0;
243 greg 2.1 for (n = npsamps; n-- > 0; ) {
244     bo_getvec(vout, j+(n+frandom())/npsamps, abp);
245 greg 2.5 bi_getvec(vin, i+urand(n), abp);
246 greg 2.34 ec = SDevalBSDF(&sdv, vin, vout, &bsd);
247 greg 2.1 if (ec != SDEnone)
248     goto err;
249 greg 2.20 sum += sdv.cieY;
250     if (rbf_colorimetry == RBCtristimulus) {
251 greg 2.21 xsum += sdv.cieY * sdv.spec.cx;
252     ysum += sdv.cieY * sdv.spec.cy;
253 greg 2.20 }
254     }
255     fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps);
256     if (rbf_colorimetry == RBCtristimulus) {
257 greg 2.21 fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum));
258     fprintf(cfp[CIE_Z], "\t%.3e\n",
259 greg 2.20 (sum - xsum - ysum)*sum/(npsamps*ysum));
260 greg 2.1 }
261     }
262 greg 2.20 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 greg 2.1 }
276     }
277     /* front transmission */
278 greg 2.33 if (bsd.tf != NULL || bsd.tLambFront.cieY > .002) {
279 greg 2.1 input_orient = 1; output_orient = -1;
280 greg 2.20 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 greg 2.1 for (j = 0; j < abp->nangles; j++) {
288     for (i = 0; i < abp->nangles; i++) {
289     sum = 0; /* average over patches */
290 greg 2.20 xsum = ysum = 0;
291 greg 2.1 for (n = npsamps; n-- > 0; ) {
292     bo_getvec(vout, j+(n+frandom())/npsamps, abp);
293 greg 2.5 fi_getvec(vin, i+urand(n), abp);
294 greg 2.34 ec = SDevalBSDF(&sdv, vin, vout, &bsd);
295 greg 2.1 if (ec != SDEnone)
296     goto err;
297 greg 2.20 sum += sdv.cieY;
298     if (rbf_colorimetry == RBCtristimulus) {
299 greg 2.21 xsum += sdv.cieY * sdv.spec.cx;
300     ysum += sdv.cieY * sdv.spec.cy;
301 greg 2.20 }
302 greg 2.1 }
303 greg 2.20 fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps);
304     if (rbf_colorimetry == RBCtristimulus) {
305 greg 2.21 fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum));
306     fprintf(cfp[CIE_Z], "\t%.3e\n",
307 greg 2.20 (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 greg 2.1 }
314     }
315 greg 2.20 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 greg 2.1 }
325     /* back transmission */
326 greg 2.9 if ((bsd.tb != NULL) | (bsd.tf != NULL)) {
327 greg 2.1 input_orient = -1; output_orient = 1;
328 greg 2.20 cfp[CIE_Y] = open_component_file(CIE_Y);
329 greg 2.21 if (bsd.tb != NULL)
330     rbf_colorimetry = bsd.tb->comp[0].cspec[2].flags
331     ? RBCtristimulus : RBCphotopic ;
332     if (rbf_colorimetry == RBCtristimulus) {
333 greg 2.20 cfp[CIE_X] = open_component_file(CIE_X);
334     cfp[CIE_Z] = open_component_file(CIE_Z);
335 greg 2.21 }
336 greg 2.1 for (j = 0; j < abp->nangles; j++) {
337 greg 2.9 for (i = 0; i < abp->nangles; i++) {
338     sum = 0; /* average over patches */
339 greg 2.20 xsum = ysum = 0;
340 greg 2.9 for (n = npsamps; n-- > 0; ) {
341     fo_getvec(vout, j+(n+frandom())/npsamps, abp);
342     bi_getvec(vin, i+urand(n), abp);
343 greg 2.34 ec = SDevalBSDF(&sdv, vin, vout, &bsd);
344 greg 2.9 if (ec != SDEnone)
345 greg 2.1 goto err;
346 greg 2.20 sum += sdv.cieY;
347     if (rbf_colorimetry == RBCtristimulus) {
348 greg 2.21 xsum += sdv.cieY * sdv.spec.cx;
349     ysum += sdv.cieY * sdv.spec.cy;
350 greg 2.20 }
351     }
352     fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps);
353     if (rbf_colorimetry == RBCtristimulus) {
354 greg 2.21 fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum));
355     fprintf(cfp[CIE_Z], "\t%.3e\n",
356 greg 2.20 (sum - xsum - ysum)*sum/(npsamps*ysum));
357 greg 2.1 }
358 greg 2.9 }
359 greg 2.20 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 greg 2.1 }
373     }
374     SDfreeBSDF(&bsd); /* all done */
375     return;
376     err:
377     SDreportError(ec, stderr);
378     exit(1);
379     }
380    
381 greg 2.2 /* Interpolate and output a BSDF function using Klems basis */
382 greg 2.1 static void
383     eval_function(char *funame)
384     {
385     ANGLE_BASIS *abp = get_basis(kbasis);
386 greg 2.8 int assignD = (fundefined(funame) < 6);
387 greg 2.20 FILE *ofp = open_component_file(CIE_Y);
388 greg 2.1 double iovec[6];
389     double sum;
390     int i, j, n;
391    
392 greg 2.4 initurand(npsamps);
393 greg 2.1 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 greg 2.4 fi_getvec(iovec, i+urand(n), abp);
404 greg 2.1 else
405 greg 2.4 bi_getvec(iovec, i+urand(n), abp);
406 greg 2.1
407 greg 2.8 if (assignD) {
408     varset("Dx", '=', -iovec[3]);
409     varset("Dy", '=', -iovec[4]);
410     varset("Dz", '=', -iovec[5]);
411     ++eclock;
412     }
413 greg 2.1 sum += funvalue(funame, 6, iovec);
414     }
415 greg 2.20 fprintf(ofp, "\t%.3e\n", sum/npsamps);
416 greg 2.1 }
417 greg 2.20 fputc('\n', ofp);
418 greg 2.13 prog_show((j+1.)/abp->nangles);
419 greg 2.1 }
420 greg 2.13 prog_done();
421 greg 2.20 if (fclose(ofp)) {
422     fprintf(stderr, "%s: error writing Y output\n", progname);
423     exit(1);
424     }
425 greg 2.1 }
426    
427     /* Interpolate and output a radial basis function BSDF representation */
428     static void
429     eval_rbf(void)
430     {
431 greg 2.27 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 greg 2.2
457 greg 2.27 rbf = advect_rbf(vin, lobe_lim); /* compute radial basis func */
458 greg 2.2
459 greg 2.27 for (j = 0; j < abp->nangles; j++) {
460     sum = 0; /* sample over exiting patch */
461 greg 2.20 xsum = ysum = 0;
462 greg 2.27 for (no = nosamps; no--; ) {
463 greg 2.20 SDValue sdv;
464 greg 2.2 if (output_orient > 0)
465 greg 2.27 fo_getvec(vout, j+(no+frandom())/nosamps, abp);
466 greg 2.2 else
467 greg 2.27 bo_getvec(vout, j+(no+frandom())/nosamps, abp);
468 greg 2.1
469 greg 2.20 eval_rbfcol(&sdv, rbf, vout);
470     sum += sdv.cieY;
471 greg 2.23 if (rbf_colorimetry == RBCtristimulus) {
472 greg 2.21 xsum += sdv.cieY * sdv.spec.cx;
473     ysum += sdv.cieY * sdv.spec.cy;
474 greg 2.27 }
475 greg 2.20 }
476 greg 2.27 no = j*abp->nangles + i;
477     bsdfarr[no] += sum * normf;
478 greg 2.23 if (rbf_colorimetry == RBCtristimulus) {
479 greg 2.27 XZarr[no][0] += xsum*sum*normf/ysum;
480     XZarr[no][1] += (sum - xsum - ysum)*sum*normf/ysum;
481 greg 2.2 }
482     }
483 greg 2.27 if (rbf != NULL)
484 greg 2.6 free(rbf);
485 greg 2.20 }
486 greg 2.27 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 greg 2.1 }
520    
521 schorsch 2.22 #if defined(_WIN32) || defined(_WIN64)
522 greg 2.20 /* Execute wrapBSDF command (may never return) */
523     static int
524     wrap_up(void)
525     {
526 greg 2.31 char cmd[32700];
527 greg 2.20
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 greg 2.32 #define HEAD_BUFLEN 10240
578 greg 2.29 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 greg 2.30 #if defined(_WIN32) || defined(_WIN64)
594     if (head_buf[cur_headlen-1] == '\n')
595     head_buf[cur_headlen-1] = '\t';
596     #endif
597 greg 2.29 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 greg 2.1 /* 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 greg 2.32 char buf[1024];
620 greg 2.1 char *cp;
621     int i, na;
622 greg 2.37 /* set global progname */
623     fixargv0(argv[0]);
624 greg 2.1 esupport |= E_VARIABLE|E_FUNCTION|E_RCONST;
625     esupport &= ~(E_INCHAN|E_OUTCHAN);
626     scompile("PI:3.14159265358979323846", NULL, 0);
627     biggerlib();
628 greg 2.2 for (i = 1; i < argc && (argv[i][0] == '-') | (argv[i][0] == '+'); i++)
629 greg 2.1 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 greg 2.35 if ((argv[i][0] == '-') & !argv[i][2]) {
641 greg 2.20 if (strchr(argv[++i], '=') != NULL) {
642     add_wbsdf("-f", 1);
643     add_wbsdf(argv[i], 1);
644     } else {
645 greg 2.25 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 greg 2.20 single_plane_incident = 0;
655     }
656 greg 2.1 } else
657     dofwd = (argv[i][0] == '+');
658     break;
659     case 'b':
660     dobwd = (argv[i][0] == '+');
661     break;
662     case 'h':
663 greg 2.20 kbasis = klems_half;
664     add_wbsdf("-a", 1);
665     add_wbsdf("kh", 1);
666 greg 2.1 break;
667     case 'q':
668 greg 2.20 kbasis = klems_quarter;
669     add_wbsdf("-a", 1);
670     add_wbsdf("kq", 1);
671 greg 2.1 break;
672 greg 2.10 case 'l':
673     lobe_lim = atoi(argv[++i]);
674     break;
675 greg 2.13 case 'p':
676     do_prog = atoi(argv[i]+2);
677     break;
678 greg 2.20 case 'C':
679     add_wbsdf(argv[i], 1);
680     add_wbsdf(argv[++i], 1);
681     break;
682 greg 2.1 default:
683     goto userr;
684     }
685 greg 2.20 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 greg 2.1 if (single_plane_incident >= 0) { /* function-based BSDF? */
694 greg 2.19 if (i != argc-1 || fundefined(argv[i]) < 3) {
695 greg 2.1 fprintf(stderr,
696     "%s: need single function with 6 arguments: bsdf(ix,iy,iz,ox,oy,oz)\n",
697     progname);
698 greg 2.13 fprintf(stderr, "\tor 3 arguments using Dx,Dy,Dz: bsdf(ix,iy,iz)\n");
699 greg 2.1 goto userr;
700     }
701 greg 2.36 doptimize(1); /* optimize definitions */
702 greg 2.8 ++eclock;
703 greg 2.1 if (dofwd) {
704     input_orient = -1;
705     output_orient = -1;
706 greg 2.13 prog_start("Evaluating outside reflectance");
707     eval_function(argv[i]);
708 greg 2.1 output_orient = 1;
709 greg 2.13 prog_start("Evaluating outside->inside transmission");
710     eval_function(argv[i]);
711 greg 2.1 }
712     if (dobwd) {
713     input_orient = 1;
714     output_orient = 1;
715 greg 2.13 prog_start("Evaluating inside reflectance");
716     eval_function(argv[i]);
717 greg 2.1 output_orient = -1;
718 greg 2.13 prog_start("Evaluating inside->outside transmission");
719     eval_function(argv[i]);
720 greg 2.1 }
721 greg 2.20 return(wrap_up());
722 greg 2.1 }
723 greg 2.2 /* XML input? */
724     if (i == argc-1 && (cp = argv[i]+strlen(argv[i])-4) > argv[i] &&
725     !strcasecmp(cp, ".xml")) {
726 greg 2.1 eval_bsdf(argv[i]); /* load & resample BSDF */
727 greg 2.20 return(wrap_up());
728 greg 2.1 }
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 greg 2.32 sprintf(buf, "%s:\n", argv[i]);
739     record2header(buf);
740 greg 2.29 sir_headshare = &record2header;
741 greg 2.1 if (!load_bsdf_rep(fpin))
742     return(1);
743     fclose(fpin);
744 greg 2.29 done_header();
745 greg 2.32 sprintf(buf, "Interpolating component '%s'", argv[i]);
746     prog_start(buf);
747 greg 2.1 eval_rbf();
748     }
749 greg 2.20 return(wrap_up());
750 greg 2.1 }
751     SET_FILE_BINARY(stdin); /* load from stdin */
752 greg 2.32 record2header("<stdin>:\n");
753     sir_headshare = &record2header;
754 greg 2.1 if (!load_bsdf_rep(stdin))
755     return(1);
756 greg 2.32 done_header();
757 greg 2.13 prog_start("Interpolating from standard input");
758 greg 2.1 eval_rbf(); /* resample dist. */
759 greg 2.20 return(wrap_up());
760 greg 2.1 userr:
761     fprintf(stderr,
762 greg 2.10 "Usage: %s [-n spp][-h|-q][-l maxlobes] [bsdf.sir ..] > bsdf.xml\n", progname);
763 greg 2.1 fprintf(stderr,
764 greg 2.3 " or: %s [-n spp][-h|-q] bsdf_in.xml > bsdf_out.xml\n", progname);
765 greg 2.1 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     }