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

File Contents

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