--- ray/src/cv/bsdf2klems.c 2013/08/01 16:10:13 2.7 +++ ray/src/cv/bsdf2klems.c 2024/02/23 03:47:57 2.36 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: bsdf2klems.c,v 2.7 2013/08/01 16:10:13 greg Exp $"; +static const char RCSid[] = "$Id: bsdf2klems.c,v 2.36 2024/02/23 03:47:57 greg Exp $"; #endif /* * Load measured BSDF interpolant and write out as XML file with Klems matrix. @@ -8,275 +8,372 @@ static const char RCSid[] = "$Id: bsdf2klems.c,v 2.7 2 */ #define _USE_MATH_DEFINES -#include #include -#include #include +#include #include "random.h" #include "platform.h" +#include "paths.h" +#include "rtio.h" #include "calcomp.h" #include "bsdfrep.h" #include "bsdf_m.h" + /* tristimulus components */ +enum {CIE_X, CIE_Y, CIE_Z}; /* assumed maximum # Klems patches */ #define MAXPATCHES 145 /* global argv[0] */ char *progname; /* selected basis function name */ -static const char *kbasis = "LBNL/Klems Full"; +static const char klems_full[] = "LBNL/Klems Full"; +static const char klems_half[] = "LBNL/Klems Half"; +static const char klems_quarter[] = "LBNL/Klems Quarter"; +static const char *kbasis = klems_full; /* number of BSDF samples per patch */ -static int npsamps = 256; +static int npsamps = 1024; + /* limit on number of RBF lobes */ +static int lobe_lim = 15000; + /* progress bar length */ +static int do_prog = 79; -/* Return angle basis corresponding to the given name */ -ANGLE_BASIS * -get_basis(const char *bn) -{ - int n = nabases; - - while (n-- > 0) - if (!strcasecmp(bn, abase_list[n].name)) - return &abase_list[n]; - return NULL; -} +#define MAXCARG 512 /* wrapBSDF command */ +static char *wrapBSDF[MAXCARG] = {"wrapBSDF", "-W", "-UU"}; +static int wbsdfac = 3; -/* Output XML header to stdout */ +/* Add argument to wrapBSDF, allocating space if !isstatic */ static void -xml_header(int ac, char *av[]) +add_wbsdf(const char *arg, int isstatic) { - puts(""); - puts(""); - fputs(""); + if (!*arg) + arg = ""; + else if (!isstatic) + arg = savqstr((char *)arg); + + wrapBSDF[wbsdfac++] = (char *)arg; } -/* Output XML prologue to stdout */ +/* Start new progress bar */ +#define prog_start(s) if (do_prog) fprintf(stderr, "%s: %s...\n", progname, s); else + +/* Draw progress bar of the appropriate length */ static void -xml_prologue(const SDData *sd) +prog_show(double frac) { - const char *matn = (sd && sd->matn[0]) ? sd->matn : "Name"; - const char *makr = (sd && sd->makr[0]) ? sd->makr : "Manufacturer"; - ANGLE_BASIS *abp = get_basis(kbasis); - int i; + static unsigned call_cnt = 0; + static char lastc[] = "-\\|/"; + char pbar[256]; + int nchars; - if (abp == NULL) { - fprintf(stderr, "%s: unknown angle basis '%s'\n", progname, kbasis); - exit(1); - } - puts("System"); - puts("BSDF"); - puts(""); - puts(""); - puts("\t"); - printf("\t\t%s\n", matn); - printf("\t\t%s\n", makr); - if (sd && sd->dim[2] > .001) { - printf("\t\t%.3f\n", sd->dim[2]); - printf("\t\t%.3f\n", sd->dim[0]); - printf("\t\t%.3f\n", sd->dim[1]); - } - puts("\t\tOther"); - puts("\t"); - if (sd && sd->mgf != NULL) { - puts("\t"); - puts("\t\t"); - fputs(sd->mgf, stdout); - puts(""); - puts("\t"); - } - puts("\t"); - puts("\t\tColumns"); - puts("\t\t"); - printf("\t\t\t%s\n", kbasis); - for (i = 0; abp->lat[i].nphis; i++) { - puts("\t\t\t"); - printf("\t\t\t%g\n", i ? - .5*(abp->lat[i].tmin + abp->lat[i+1].tmin) : - .0 ); - printf("\t\t\t%d\n", abp->lat[i].nphis); - puts("\t\t\t"); - printf("\t\t\t\t%g\n", abp->lat[i].tmin); - printf("\t\t\t\t%g\n", abp->lat[i+1].tmin); - puts("\t\t\t"); - puts("\t\t\t"); - } - puts("\t\t"); - puts("\t"); + if (do_prog <= 1) return; + if (do_prog > sizeof(pbar)-2) + do_prog = sizeof(pbar)-2; + if (frac < 0) frac = 0; + else if (frac >= 1) frac = .9999; + nchars = do_prog*frac; + pbar[0] = '\r'; + memset(pbar+1, '*', nchars); + pbar[nchars+1] = lastc[call_cnt++ & 3]; + memset(pbar+2+nchars, '-', do_prog-nchars-1); + pbar[do_prog+1] = '\0'; + fputs(pbar, stderr); } -/* Output XML data prologue to stdout */ +/* Finish progress bar */ static void -data_prologue() +prog_done(void) { - static const char *bsdf_type[4] = { - "Reflection Front", - "Transmission Front", - "Transmission Back", - "Reflection Back" - }; + int n = do_prog; - puts("\t"); - puts("\t\tSystem"); - puts("\t\tVisible"); - puts("\t\tCIE Illuminant D65 1nm.ssp"); - puts("\t\tASTM E308 1931 Y.dsp"); - puts("\t\t"); - printf("\t\t\t%s\n", - bsdf_type[(input_orient>0)<<1 | (output_orient>0)]); - printf("\t\t\t%s\n", kbasis); - printf("\t\t\t%s\n", kbasis); - puts("\t\t\tBTDF"); - puts("\t\t\t"); + if (n <= 1) return; + fputc('\r', stderr); + while (n--) + fputc(' ', stderr); + fputc('\r', stderr); } -/* Output XML data epilogue to stdout */ -static void -data_epilogue(void) +/* Return angle basis corresponding to the given name */ +static ANGLE_BASIS * +get_basis(const char *bn) { - puts("\t\t\t"); - puts("\t\t"); - puts("\t"); + int n = nabases; + + while (n-- > 0) + if (!strcasecmp(bn, abase_list[n].name)) + return &abase_list[n]; + return NULL; } -/* Output XML epilogue to stdout */ -static void -xml_epilogue(void) +/* Copy geometry string to file for wrapBSDF */ +static char * +save_geom(const char *mgf) { - puts(""); - puts(""); - puts(""); + char *tfname = mktemp(savqstr(TEMPLATE)); + int fd = open(tfname, O_CREAT|O_WRONLY, 0600); + + if (fd < 0) + return(NULL); + write(fd, mgf, strlen(mgf)); + close(fd); + add_wbsdf("-g", 1); + add_wbsdf(tfname, 1); + return(tfname); } +/* Open XYZ component file for output and add appropriate arguments */ +static FILE * +open_component_file(int c) +{ + static const char sname[3][6] = {"CIE-X", "CIE-Y", "CIE-Z"}; + static const char cname[4][4] = {"-rf", "-tf", "-tb", "-rb"}; + char *tfname = mktemp(savqstr(TEMPLATE)); + FILE *fp = fopen(tfname, "w"); + + if (fp == NULL) { + fprintf(stderr, "%s: cannot open '%s' for writing\n", + progname, tfname); + exit(1); + } + add_wbsdf("-s", 1); add_wbsdf(sname[c], 1); + add_wbsdf(cname[(input_orient>0)<<1 | (output_orient>0)], 1); + add_wbsdf(tfname, 1); + return(fp); +} + /* Load and resample XML BSDF description using Klems basis */ static void eval_bsdf(const char *fname) { ANGLE_BASIS *abp = get_basis(kbasis); - float *trans_mtx = NULL; + FILE *cfp[3]; SDData bsd; SDError ec; FVECT vin, vout; - SDValue sv; - double sum; + SDValue sdv; + double sum, xsum, ysum; int i, j, n; + initurand(npsamps); SDclearBSDF(&bsd, fname); /* load BSDF file */ if ((ec = SDloadFile(&bsd, fname)) != SDEnone) goto err; - xml_prologue(&bsd); /* pass geometry */ + if (bsd.mgf != NULL) /* save geometry */ + save_geom(bsd.mgf); + if (bsd.matn[0]) /* save identifier(s) */ + strcpy(bsdf_name, bsd.matn); + if (bsd.makr[0]) + strcpy(bsdf_manuf, bsd.makr); + if (bsd.dim[2] > 0) { /* save dimension(s) */ + char buf[64]; + if ((bsd.dim[0] > 0) & (bsd.dim[1] > 0)) + sprintf(buf, "w=%g;h=%g;t=%g", + bsd.dim[0], bsd.dim[1], bsd.dim[2]); + else + sprintf(buf, "t=%g", bsd.dim[2]); + add_wbsdf("-f", 1); + add_wbsdf(buf, 0); + } /* front reflection */ if (bsd.rf != NULL || bsd.rLambFront.cieY > .002) { input_orient = 1; output_orient = 1; - data_prologue(); + cfp[CIE_Y] = open_component_file(CIE_Y); + if (bsd.rf != NULL && bsd.rf->comp[0].cspec[2].flags) { + rbf_colorimetry = RBCtristimulus; + cfp[CIE_X] = open_component_file(CIE_X); + cfp[CIE_Z] = open_component_file(CIE_Z); + } else + rbf_colorimetry = RBCphotopic; for (j = 0; j < abp->nangles; j++) { for (i = 0; i < abp->nangles; i++) { sum = 0; /* average over patches */ + xsum = ysum = 0; for (n = npsamps; n-- > 0; ) { fo_getvec(vout, j+(n+frandom())/npsamps, abp); fi_getvec(vin, i+urand(n), abp); - ec = SDevalBSDF(&sv, vout, vin, &bsd); + ec = SDevalBSDF(&sdv, vin, vout, &bsd); if (ec != SDEnone) goto err; - sum += sv.cieY; + sum += sdv.cieY; + if (rbf_colorimetry == RBCtristimulus) { + xsum += sdv.cieY * sdv.spec.cx; + ysum += sdv.cieY * sdv.spec.cy; + } } - printf("\t%.3e\n", sum/npsamps); + fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps); + if (rbf_colorimetry == RBCtristimulus) { + fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum)); + fprintf(cfp[CIE_Z], "\t%.3e\n", + (sum - xsum - ysum)*sum/(npsamps*ysum)); + } } - putchar('\n'); /* extra space between rows */ + fputc('\n', cfp[CIE_Y]); /* extra space between rows */ + if (rbf_colorimetry == RBCtristimulus) { + fputc('\n', cfp[CIE_X]); + fputc('\n', cfp[CIE_Z]); + } } - data_epilogue(); + if (fclose(cfp[CIE_Y])) { + fprintf(stderr, "%s: error writing Y output\n", progname); + exit(1); + } + if (rbf_colorimetry == RBCtristimulus && + (fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z]))) { + fprintf(stderr, "%s: error writing X/Z output\n", progname); + exit(1); + } } /* back reflection */ if (bsd.rb != NULL || bsd.rLambBack.cieY > .002) { input_orient = -1; output_orient = -1; - data_prologue(); + cfp[CIE_Y] = open_component_file(CIE_Y); + if (bsd.rb != NULL && bsd.rb->comp[0].cspec[2].flags) { + rbf_colorimetry = RBCtristimulus; + cfp[CIE_X] = open_component_file(CIE_X); + cfp[CIE_Z] = open_component_file(CIE_Z); + } else + rbf_colorimetry = RBCphotopic; for (j = 0; j < abp->nangles; j++) { for (i = 0; i < abp->nangles; i++) { sum = 0; /* average over patches */ + xsum = ysum = 0; for (n = npsamps; n-- > 0; ) { bo_getvec(vout, j+(n+frandom())/npsamps, abp); bi_getvec(vin, i+urand(n), abp); - ec = SDevalBSDF(&sv, vout, vin, &bsd); + ec = SDevalBSDF(&sdv, vin, vout, &bsd); if (ec != SDEnone) goto err; - sum += sv.cieY; + sum += sdv.cieY; + if (rbf_colorimetry == RBCtristimulus) { + xsum += sdv.cieY * sdv.spec.cx; + ysum += sdv.cieY * sdv.spec.cy; + } } - printf("\t%.3e\n", sum/npsamps); + fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps); + if (rbf_colorimetry == RBCtristimulus) { + fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum)); + fprintf(cfp[CIE_Z], "\t%.3e\n", + (sum - xsum - ysum)*sum/(npsamps*ysum)); + } } - putchar('\n'); /* extra space between rows */ + if (rbf_colorimetry == RBCtristimulus) { + fputc('\n', cfp[CIE_X]); + fputc('\n', cfp[CIE_Z]); + } } - data_epilogue(); + if (fclose(cfp[CIE_Y])) { + fprintf(stderr, "%s: error writing Y output\n", progname); + exit(1); + } + if (rbf_colorimetry == RBCtristimulus && + (fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z]))) { + fprintf(stderr, "%s: error writing X/Z output\n", progname); + exit(1); + } } /* front transmission */ - if (bsd.tf != NULL || bsd.tLamb.cieY > .002) { - if (bsd.tb == NULL) - trans_mtx = (float *)malloc(sizeof(float) * - abp->nangles*abp->nangles); + if (bsd.tf != NULL || bsd.tLambFront.cieY > .002) { input_orient = 1; output_orient = -1; - data_prologue(); + cfp[CIE_Y] = open_component_file(CIE_Y); + if (bsd.tf != NULL && bsd.tf->comp[0].cspec[2].flags) { + rbf_colorimetry = RBCtristimulus; + cfp[CIE_X] = open_component_file(CIE_X); + cfp[CIE_Z] = open_component_file(CIE_Z); + } else + rbf_colorimetry = RBCphotopic; for (j = 0; j < abp->nangles; j++) { for (i = 0; i < abp->nangles; i++) { sum = 0; /* average over patches */ + xsum = ysum = 0; for (n = npsamps; n-- > 0; ) { bo_getvec(vout, j+(n+frandom())/npsamps, abp); fi_getvec(vin, i+urand(n), abp); - ec = SDevalBSDF(&sv, vout, vin, &bsd); + ec = SDevalBSDF(&sdv, vin, vout, &bsd); if (ec != SDEnone) goto err; - sum += sv.cieY; + sum += sdv.cieY; + if (rbf_colorimetry == RBCtristimulus) { + xsum += sdv.cieY * sdv.spec.cx; + ysum += sdv.cieY * sdv.spec.cy; + } } - printf("\t%.3e\n", sum/npsamps); - if (trans_mtx != NULL) - trans_mtx[j*abp->nangles + i] = sum/npsamps; + fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps); + if (rbf_colorimetry == RBCtristimulus) { + fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum)); + fprintf(cfp[CIE_Z], "\t%.3e\n", + (sum - xsum - ysum)*sum/(npsamps*ysum)); + } } - putchar('\n'); /* extra space between rows */ + if (rbf_colorimetry == RBCtristimulus) { + fputc('\n', cfp[CIE_X]); + fputc('\n', cfp[CIE_Z]); + } } - data_epilogue(); + if (fclose(cfp[CIE_Y])) { + fprintf(stderr, "%s: error writing Y output\n", progname); + exit(1); + } + if (rbf_colorimetry == RBCtristimulus && + (fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z]))) { + fprintf(stderr, "%s: error writing X/Z output\n", progname); + exit(1); + } } /* back transmission */ - if (bsd.tb != NULL || trans_mtx != NULL) { - if (bsd.tf == NULL) - trans_mtx = (float *)malloc(sizeof(float) * - abp->nangles*abp->nangles); + if ((bsd.tb != NULL) | (bsd.tf != NULL)) { input_orient = -1; output_orient = 1; - data_prologue(); + cfp[CIE_Y] = open_component_file(CIE_Y); + if (bsd.tb != NULL) + rbf_colorimetry = bsd.tb->comp[0].cspec[2].flags + ? RBCtristimulus : RBCphotopic ; + if (rbf_colorimetry == RBCtristimulus) { + cfp[CIE_X] = open_component_file(CIE_X); + cfp[CIE_Z] = open_component_file(CIE_Z); + } for (j = 0; j < abp->nangles; j++) { - for (i = 0; i < abp->nangles; i++) - if (bsd.tb != NULL) { /* use tb if we have it */ - sum = 0; /* average over patches */ - for (n = npsamps; n-- > 0; ) { - fo_getvec(vout, j+(n+frandom())/npsamps, abp); - bi_getvec(vin, i+urand(n), abp); - ec = SDevalBSDF(&sv, vout, vin, &bsd); - if (ec != SDEnone) + for (i = 0; i < abp->nangles; i++) { + sum = 0; /* average over patches */ + xsum = ysum = 0; + for (n = npsamps; n-- > 0; ) { + fo_getvec(vout, j+(n+frandom())/npsamps, abp); + bi_getvec(vin, i+urand(n), abp); + ec = SDevalBSDF(&sdv, vin, vout, &bsd); + if (ec != SDEnone) goto err; - sum += sv.cieY; + sum += sdv.cieY; + if (rbf_colorimetry == RBCtristimulus) { + xsum += sdv.cieY * sdv.spec.cx; + ysum += sdv.cieY * sdv.spec.cy; } - printf("\t%.3e\n", sum/npsamps); - if (trans_mtx != NULL) - trans_mtx[i*abp->nangles + j] = sum/npsamps; - } else { /* else transpose tf */ - printf("\t%.3e\n", trans_mtx[i*abp->nangles + j]); } - putchar('\n'); /* extra space between rows */ + fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps); + if (rbf_colorimetry == RBCtristimulus) { + fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum)); + fprintf(cfp[CIE_Z], "\t%.3e\n", + (sum - xsum - ysum)*sum/(npsamps*ysum)); + } + } + if (rbf_colorimetry == RBCtristimulus) { + fputc('\n', cfp[CIE_X]); + fputc('\n', cfp[CIE_Z]); + } } - data_epilogue(); - } - /* derived front transmission */ - if (bsd.tf == NULL && trans_mtx != NULL) { - input_orient = 1; output_orient = -1; - data_prologue(); - for (j = 0; j < abp->nangles; j++) { - for (i = 0; i < abp->nangles; i++) - printf("\t%.3e\n", trans_mtx[j*abp->nangles + i]); - putchar('\n'); /* extra space between rows */ + if (fclose(cfp[CIE_Y])) { + fprintf(stderr, "%s: error writing Y output\n", progname); + exit(1); } - data_epilogue(); + if (rbf_colorimetry == RBCtristimulus && + (fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z]))) { + fprintf(stderr, "%s: error writing X/Z output\n", progname); + exit(1); + } } SDfreeBSDF(&bsd); /* all done */ - if (trans_mtx != NULL) - free(trans_mtx); return; err: SDreportError(ec, stderr); @@ -288,12 +385,13 @@ static void eval_function(char *funame) { ANGLE_BASIS *abp = get_basis(kbasis); + int assignD = (fundefined(funame) < 6); + FILE *ofp = open_component_file(CIE_Y); double iovec[6]; double sum; int i, j, n; initurand(npsamps); - data_prologue(); /* begin output */ for (j = 0; j < abp->nangles; j++) { /* run through directions */ for (i = 0; i < abp->nangles; i++) { sum = 0; @@ -308,68 +406,219 @@ eval_function(char *funame) else bi_getvec(iovec, i+urand(n), abp); + if (assignD) { + varset("Dx", '=', -iovec[3]); + varset("Dy", '=', -iovec[4]); + varset("Dz", '=', -iovec[5]); + ++eclock; + } sum += funvalue(funame, 6, iovec); } - printf("\t%.3e\n", sum/npsamps); + fprintf(ofp, "\t%.3e\n", sum/npsamps); } - putchar('\n'); + fputc('\n', ofp); + prog_show((j+1.)/abp->nangles); } - data_epilogue(); /* finish output */ + prog_done(); + if (fclose(ofp)) { + fprintf(stderr, "%s: error writing Y output\n", progname); + exit(1); + } } /* Interpolate and output a radial basis function BSDF representation */ static void eval_rbf(void) { - ANGLE_BASIS *abp = get_basis(kbasis); - float bsdfarr[MAXPATCHES*MAXPATCHES]; - FVECT vin, vout; - RBFNODE *rbf; - double sum; - int i, j, n; - /* sanity check */ - if (abp->nangles > MAXPATCHES) { - fprintf(stderr, "%s: too many patches!\n", progname); - exit(1); - } - data_prologue(); /* begin output */ - for (i = 0; i < abp->nangles; i++) { - if (input_orient > 0) /* use incident patch center */ - fi_getvec(vin, i+.5*(i>0), abp); - else - bi_getvec(vin, i+.5*(i>0), abp); + ANGLE_BASIS *abp = get_basis(kbasis); + float (*XZarr)[2] = NULL; + float bsdfarr[MAXPATCHES*MAXPATCHES]; + FILE *cfp[3]; + FVECT vin, vout; + double sum, xsum, ysum, normf; + int i, j, ni, no, nisamps, nosamps; + /* sanity check */ + if (abp->nangles > MAXPATCHES) { + fprintf(stderr, "%s: too many patches!\n", progname); + exit(1); + } + memset(bsdfarr, 0, sizeof(bsdfarr)); + if (rbf_colorimetry == RBCtristimulus) + XZarr = (float (*)[2])calloc(abp->nangles*abp->nangles, 2*sizeof(float)); + nosamps = (int)(pow((double)npsamps, 0.67) + .5); + nisamps = (npsamps + (nosamps>>1)) / nosamps; + normf = 1./(double)(nisamps*nosamps); + for (i = 0; i < abp->nangles; i++) { + for (ni = nisamps; ni--; ) { /* sample over incident patch */ + RBFNODE *rbf; + if (input_orient > 0) /* vary incident patch loc. */ + fi_getvec(vin, i+urand(ni), abp); + else + bi_getvec(vin, i+urand(ni), abp); - rbf = advect_rbf(vin); /* compute radial basis func */ + rbf = advect_rbf(vin, lobe_lim); /* compute radial basis func */ - for (j = 0; j < abp->nangles; j++) { - sum = 0; /* sample over exiting patch */ - for (n = npsamps; n--; ) { + for (j = 0; j < abp->nangles; j++) { + sum = 0; /* sample over exiting patch */ + xsum = ysum = 0; + for (no = nosamps; no--; ) { + SDValue sdv; if (output_orient > 0) - fo_getvec(vout, j+(n+frandom())/npsamps, abp); + fo_getvec(vout, j+(no+frandom())/nosamps, abp); else - bo_getvec(vout, j+(n+frandom())/npsamps, abp); + bo_getvec(vout, j+(no+frandom())/nosamps, abp); - sum += eval_rbfrep(rbf, vout) / vout[2]; + eval_rbfcol(&sdv, rbf, vout); + sum += sdv.cieY; + if (rbf_colorimetry == RBCtristimulus) { + xsum += sdv.cieY * sdv.spec.cx; + ysum += sdv.cieY * sdv.spec.cy; + } } - bsdfarr[j*abp->nangles + i] = sum*output_orient/npsamps; + no = j*abp->nangles + i; + bsdfarr[no] += sum * normf; + if (rbf_colorimetry == RBCtristimulus) { + XZarr[no][0] += xsum*sum*normf/ysum; + XZarr[no][1] += (sum - xsum - ysum)*sum*normf/ysum; + } } - if (rbf != NULL) + if (rbf != NULL) free(rbf); } - n = 0; /* write out our matrix */ - for (j = 0; j < abp->nangles; j++) { - for (i = 0; i < abp->nangles; i++) - printf("\t%.3e\n", bsdfarr[n++]); - putchar('\n'); + prog_show((i+1.)/abp->nangles); + } + /* write out our matrix */ + cfp[CIE_Y] = open_component_file(CIE_Y); + no = 0; + for (j = 0; j < abp->nangles; j++) { + for (i = 0; i < abp->nangles; i++, no++) + fprintf(cfp[CIE_Y], "\t%.3e\n", bsdfarr[no]); + fputc('\n', cfp[CIE_Y]); + } + prog_done(); + if (fclose(cfp[CIE_Y])) { + fprintf(stderr, "%s: error writing Y output\n", progname); + exit(1); + } + if (XZarr == NULL) /* no color? */ + return; + cfp[CIE_X] = open_component_file(CIE_X); + cfp[CIE_Z] = open_component_file(CIE_Z); + no = 0; + for (j = 0; j < abp->nangles; j++) { + for (i = 0; i < abp->nangles; i++, no++) { + fprintf(cfp[CIE_X], "\t%.3e\n", XZarr[no][0]); + fprintf(cfp[CIE_Z], "\t%.3e\n", XZarr[no][1]); + } + fputc('\n', cfp[CIE_X]); + fputc('\n', cfp[CIE_Z]); + } + free(XZarr); + if (fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z])) { + fprintf(stderr, "%s: error writing X/Z output\n", progname); + exit(1); + } +} + +#if defined(_WIN32) || defined(_WIN64) +/* Execute wrapBSDF command (may never return) */ +static int +wrap_up(void) +{ + char cmd[32700]; + + if (bsdf_manuf[0]) { + add_wbsdf("-f", 1); + strcpy(cmd, "m="); + strcpy(cmd+2, bsdf_manuf); + add_wbsdf(cmd, 0); } - data_epilogue(); /* finish output */ + if (bsdf_name[0]) { + add_wbsdf("-f", 1); + strcpy(cmd, "n="); + strcpy(cmd+2, bsdf_name); + add_wbsdf(cmd, 0); + } + if (!convert_commandline(cmd, sizeof(cmd), wrapBSDF)) { + fputs(progname, stderr); + fputs(": command line too long in wrap_up()\n", stderr); + return(1); + } + return(system(cmd)); } +#else +/* Execute wrapBSDF command (may never return) */ +static int +wrap_up(void) +{ + char buf[256]; + char *compath = getpath((char *)wrapBSDF[0], getenv("PATH"), X_OK); + if (compath == NULL) { + fprintf(stderr, "%s: cannot locate %s\n", progname, wrapBSDF[0]); + return(1); + } + if (bsdf_manuf[0]) { + add_wbsdf("-f", 1); + strcpy(buf, "m="); + strcpy(buf+2, bsdf_manuf); + add_wbsdf(buf, 0); + } + if (bsdf_name[0]) { + add_wbsdf("-f", 1); + strcpy(buf, "n="); + strcpy(buf+2, bsdf_name); + add_wbsdf(buf, 0); + } + execv(compath, wrapBSDF); /* successful call never returns */ + perror(compath); + return(1); +} +#endif + +#define HEAD_BUFLEN 10240 +static char head_buf[HEAD_BUFLEN]; +static int cur_headlen = 0; + +/* Record header line as comment associated with this SIR input */ +static int +record2header(char *s) +{ + int len = strlen(s); + + if (cur_headlen+len >= HEAD_BUFLEN-6) + return(0); + /* includes EOL */ + strcpy(head_buf+cur_headlen, s); + cur_headlen += len; + +#if defined(_WIN32) || defined(_WIN64) + if (head_buf[cur_headlen-1] == '\n') + head_buf[cur_headlen-1] = '\t'; +#endif + return(1); +} + +/* Finish off header for this file */ +static void +done_header(void) +{ + while (cur_headlen > 0 && isspace(head_buf[cur_headlen-1])) + --cur_headlen; + head_buf[cur_headlen] = '\0'; + if (!cur_headlen) + return; + add_wbsdf("-C", 1); + add_wbsdf(head_buf, 0); + head_buf[cur_headlen=0] = '\0'; +} + /* Read in BSDF and interpolate as Klems matrix representation */ int main(int argc, char *argv[]) { int dofwd = 0, dobwd = 1; + char buf[1024]; char *cp; int i, na; @@ -390,9 +639,22 @@ main(int argc, char *argv[]) single_plane_incident = 0; break; case 'f': - if (!argv[i][2]) { - fcompile(argv[++i]); - single_plane_incident = 0; + if ((argv[i][0] == '-') & !argv[i][2]) { + if (strchr(argv[++i], '=') != NULL) { + add_wbsdf("-f", 1); + add_wbsdf(argv[i], 1); + } else { + char *fpath = getpath(argv[i], + getrlibpath(), 0); + if (fpath == NULL) { + fprintf(stderr, + "%s: cannot find file '%s'\n", + argv[0], argv[i]); + return(1); + } + fcompile(fpath); + single_plane_incident = 0; + } } else dofwd = (argv[i][0] == '+'); break; @@ -400,47 +662,71 @@ main(int argc, char *argv[]) dobwd = (argv[i][0] == '+'); break; case 'h': - kbasis = "LBNL/Klems Half"; + kbasis = klems_half; + add_wbsdf("-a", 1); + add_wbsdf("kh", 1); break; case 'q': - kbasis = "LBNL/Klems Quarter"; + kbasis = klems_quarter; + add_wbsdf("-a", 1); + add_wbsdf("kq", 1); break; + case 'l': + lobe_lim = atoi(argv[++i]); + break; + case 'p': + do_prog = atoi(argv[i]+2); + break; + case 'C': + add_wbsdf(argv[i], 1); + add_wbsdf(argv[++i], 1); + break; default: goto userr; } + if (kbasis == klems_full) { /* default (full) basis? */ + add_wbsdf("-a", 1); + add_wbsdf("kf", 1); + } + strcpy(buf, "File produced by: "); + if (convert_commandline(buf+18, sizeof(buf)-18, argv) != NULL) { + add_wbsdf("-C", 1); add_wbsdf(buf, 0); + } if (single_plane_incident >= 0) { /* function-based BSDF? */ - if (i != argc-1 || fundefined(argv[i]) != 6) { + if (i != argc-1 || fundefined(argv[i]) < 3) { fprintf(stderr, "%s: need single function with 6 arguments: bsdf(ix,iy,iz,ox,oy,oz)\n", progname); + fprintf(stderr, "\tor 3 arguments using Dx,Dy,Dz: bsdf(ix,iy,iz)\n"); goto userr; } - xml_header(argc, argv); /* start XML output */ - xml_prologue(NULL); + doptimize(1); /* optimize definitions */ + ++eclock; if (dofwd) { input_orient = -1; output_orient = -1; - eval_function(argv[i]); /* outside reflectance */ + prog_start("Evaluating outside reflectance"); + eval_function(argv[i]); output_orient = 1; - eval_function(argv[i]); /* outside -> inside */ + prog_start("Evaluating outside->inside transmission"); + eval_function(argv[i]); } if (dobwd) { input_orient = 1; output_orient = 1; - eval_function(argv[i]); /* inside reflectance */ + prog_start("Evaluating inside reflectance"); + eval_function(argv[i]); output_orient = -1; - eval_function(argv[i]); /* inside -> outside */ + prog_start("Evaluating inside->outside transmission"); + eval_function(argv[i]); } - xml_epilogue(); /* finish XML output & exit */ - return(0); + return(wrap_up()); } /* XML input? */ if (i == argc-1 && (cp = argv[i]+strlen(argv[i])-4) > argv[i] && !strcasecmp(cp, ".xml")) { - xml_header(argc, argv); /* start XML output */ eval_bsdf(argv[i]); /* load & resample BSDF */ - xml_epilogue(); /* finish XML output & exit */ - return(0); + return(wrap_up()); } if (i < argc) { /* open input files if given */ int nbsdf = 0; @@ -451,29 +737,31 @@ main(int argc, char *argv[]) progname, argv[i]); return(1); } + sprintf(buf, "%s:\n", argv[i]); + record2header(buf); + sir_headshare = &record2header; if (!load_bsdf_rep(fpin)) return(1); fclose(fpin); - if (!nbsdf++) { /* start XML on first dist. */ - xml_header(argc, argv); - xml_prologue(NULL); - } + done_header(); + sprintf(buf, "Interpolating component '%s'", argv[i]); + prog_start(buf); eval_rbf(); } - xml_epilogue(); /* finish XML output & exit */ - return(0); + return(wrap_up()); } SET_FILE_BINARY(stdin); /* load from stdin */ + record2header(":\n"); + sir_headshare = &record2header; if (!load_bsdf_rep(stdin)) return(1); - xml_header(argc, argv); /* start XML output */ - xml_prologue(NULL); + done_header(); + prog_start("Interpolating from standard input"); eval_rbf(); /* resample dist. */ - xml_epilogue(); /* finish XML output & exit */ - return(0); + return(wrap_up()); userr: fprintf(stderr, - "Usage: %s [-n spp][-h|-q][bsdf.sir ..] > bsdf.xml\n", progname); + "Usage: %s [-n spp][-h|-q][-l maxlobes] [bsdf.sir ..] > bsdf.xml\n", progname); fprintf(stderr, " or: %s [-n spp][-h|-q] bsdf_in.xml > bsdf_out.xml\n", progname); fprintf(stderr,