| 107 |  | static CMATRIX * | 
| 108 |  | cm_load(const char *fname, int nrows, int ncols, int dtype) | 
| 109 |  | { | 
| 110 | – | CMATRIX *cm; | 
| 110 |  | FILE    *fp = stdin; | 
| 111 | + | CMATRIX *cm; | 
| 112 |  |  | 
| 113 |  | if (ncols <= 0) | 
| 114 |  | error(USER, "Non-positive number of columns"); | 
| 118 |  | sprintf(errmsg, "cannot open file '%s'", fname); | 
| 119 |  | error(SYSTEM, errmsg); | 
| 120 |  | } | 
| 121 | + | #ifdef getc_unlocked | 
| 122 | + | flockfile(fp); | 
| 123 | + | #endif | 
| 124 |  | if (dtype != DTascii) | 
| 125 | < | SET_FILE_BINARY(fp); | 
| 125 | > | SET_FILE_BINARY(fp);            /* doesn't really work */ | 
| 126 |  | if (dtype == DTfromHeader) | 
| 127 |  | dtype = getDTfromHeader(fp); | 
| 128 |  | switch (dtype) { | 
| 161 |  | cm = cm_alloc(guessrows, ncols); | 
| 162 |  | } else | 
| 163 |  | cm = cm_alloc(nrows, ncols); | 
| 164 | < | if (cm == NULL) | 
| 164 | > | if (cm == NULL)                                 /* XXX never happens */ | 
| 165 |  | return(NULL); | 
| 166 |  | if (dtype == DTascii) {                         /* read text file */ | 
| 167 |  | int     maxrow = (nrows > 0 ? nrows : 32000); | 
| 236 |  | cvp += 3; | 
| 237 |  | } | 
| 238 |  | } | 
| 239 | < | if (getc(fp) != EOF) { | 
| 239 | > | if (fgetc(fp) != EOF) { | 
| 240 |  | sprintf(errmsg, | 
| 241 |  | "unexpected data at end of binary file %s", | 
| 242 |  | fname); | 
| 245 |  | } | 
| 246 |  | if (fp != stdin) | 
| 247 |  | fclose(fp); | 
| 248 | + | #ifdef getc_unlocked | 
| 249 | + | else | 
| 250 | + | funlockfile(fp); | 
| 251 | + | #endif | 
| 252 |  | return(cm); | 
| 253 |  | EOFerror: | 
| 254 | < | sprintf(errmsg, "unexpected EOF reading %s", | 
| 248 | < | fname); | 
| 254 | > | sprintf(errmsg, "unexpected EOF reading %s", fname); | 
| 255 |  | error(USER, errmsg); | 
| 256 |  | not_handled: | 
| 257 |  | error(INTERNAL, "unhandled data size or length in cm_load()"); | 
| 258 |  | return(NULL);   /* gratis return */ | 
| 259 |  | } | 
| 260 |  |  | 
| 261 | < | /* Multiply two matrices (or a matrix and a vector) and allocate the result*/ | 
| 261 | > | /* Extract a column vector from a matrix */ | 
| 262 |  | static CMATRIX * | 
| 263 | + | cm_column(const CMATRIX *cm, int c) | 
| 264 | + | { | 
| 265 | + | CMATRIX *cvr; | 
| 266 | + | int     dr; | 
| 267 | + |  | 
| 268 | + | if ((c < 0) | (c >= cm->ncols)) | 
| 269 | + | error(INTERNAL, "column requested outside matrix"); | 
| 270 | + | cvr = cm_alloc(cm->nrows, 1); | 
| 271 | + | if (cvr == NULL) | 
| 272 | + | return(NULL); | 
| 273 | + | for (dr = 0; dr < cm->nrows; dr++) { | 
| 274 | + | const COLORV    *sp = cm_lval(cm,dr,c); | 
| 275 | + | COLORV          *dp = cv_lval(cvr,dr); | 
| 276 | + | dp[0] = sp[0]; | 
| 277 | + | dp[1] = sp[1]; | 
| 278 | + | dp[2] = sp[2]; | 
| 279 | + | } | 
| 280 | + | return(cvr); | 
| 281 | + | } | 
| 282 | + |  | 
| 283 | + | /* Scale a matrix by a single value */ | 
| 284 | + | static CMATRIX * | 
| 285 | + | cm_scale(const CMATRIX *cm1, const COLOR sca) | 
| 286 | + | { | 
| 287 | + | CMATRIX *cmr; | 
| 288 | + | int     dr, dc; | 
| 289 | + |  | 
| 290 | + | cmr = cm_alloc(cm1->nrows, cm1->ncols); | 
| 291 | + | if (cmr == NULL) | 
| 292 | + | return(NULL); | 
| 293 | + | for (dr = 0; dr < cmr->nrows; dr++) | 
| 294 | + | for (dc = 0; dc < cmr->ncols; dc++) { | 
| 295 | + | const COLORV    *sp = cm_lval(cm1,dr,dc); | 
| 296 | + | COLORV          *dp = cm_lval(cmr,dr,dc); | 
| 297 | + | dp[0] = sp[0] * sca[0]; | 
| 298 | + | dp[1] = sp[1] * sca[1]; | 
| 299 | + | dp[2] = sp[2] * sca[2]; | 
| 300 | + | } | 
| 301 | + | return(cmr); | 
| 302 | + | } | 
| 303 | + |  | 
| 304 | + | /* Multiply two matrices (or a matrix and a vector) and allocate the result */ | 
| 305 | + | static CMATRIX * | 
| 306 |  | cm_multiply(const CMATRIX *cm1, const CMATRIX *cm2) | 
| 307 |  | { | 
| 308 | + | char    *rowcheck=NULL, *colcheck=NULL; | 
| 309 |  | CMATRIX *cmr; | 
| 310 |  | int     dr, dc, i; | 
| 311 |  |  | 
| 314 |  | cmr = cm_alloc(cm1->nrows, cm2->ncols); | 
| 315 |  | if (cmr == NULL) | 
| 316 |  | return(NULL); | 
| 317 | + | /* optimization: check for zero rows & cols */ | 
| 318 | + | if (((cm1->nrows > 5) | (cm2->ncols > 5)) & (cm1->ncols > 5)) { | 
| 319 | + | static const COLOR      czero; | 
| 320 | + | rowcheck = (char *)calloc(cmr->nrows, 1); | 
| 321 | + | for (dr = cm1->nrows*(rowcheck != NULL); dr--; ) | 
| 322 | + | for (dc = cm1->ncols; dc--; ) | 
| 323 | + | if (memcmp(cm_lval(cm1,dr,dc), czero, sizeof(COLOR))) { | 
| 324 | + | rowcheck[dr] = 1; | 
| 325 | + | break; | 
| 326 | + | } | 
| 327 | + | colcheck = (char *)calloc(cmr->ncols, 1); | 
| 328 | + | for (dc = cm2->ncols*(colcheck != NULL); dc--; ) | 
| 329 | + | for (dr = cm2->nrows; dr--; ) | 
| 330 | + | if (memcmp(cm_lval(cm2,dr,dc), czero, sizeof(COLOR))) { | 
| 331 | + | colcheck[dc] = 1; | 
| 332 | + | break; | 
| 333 | + | } | 
| 334 | + | } | 
| 335 |  | for (dr = 0; dr < cmr->nrows; dr++) | 
| 336 |  | for (dc = 0; dc < cmr->ncols; dc++) { | 
| 337 |  | COLORV  *dp = cm_lval(cmr,dr,dc); | 
| 338 |  | dp[0] = dp[1] = dp[2] = 0; | 
| 339 | + | if (rowcheck != NULL && !rowcheck[dr]) | 
| 340 | + | continue; | 
| 341 | + | if (colcheck != NULL && !colcheck[dc]) | 
| 342 | + | continue; | 
| 343 |  | for (i = 0; i < cm1->ncols; i++) { | 
| 344 |  | const COLORV        *cp1 = cm_lval(cm1,dr,i); | 
| 345 |  | const COLORV        *cp2 = cm_lval(cm2,i,dc); | 
| 348 |  | dp[2] += cp1[2] * cp2[2]; | 
| 349 |  | } | 
| 350 |  | } | 
| 351 | + | if (rowcheck != NULL) free(rowcheck); | 
| 352 | + | if (colcheck != NULL) free(colcheck); | 
| 353 |  | return(cmr); | 
| 354 |  | } | 
| 355 |  |  | 
| 375 |  | int     nbadohm = 0; | 
| 376 |  | int     nneg = 0; | 
| 377 |  | int     r, c; | 
| 378 | < | /* reciprocity is "transparent" */ | 
| 378 | > | /* loop over incident angles */ | 
| 379 |  | for (c = 0; c < cm->ncols; c++) { | 
| 380 |  | const double    dom = mBSDF_incohm(bsdf,c); | 
| 381 |  | /* projected solid angle */ | 
| 404 |  | return(cm); | 
| 405 |  | } | 
| 406 |  |  | 
| 407 | + | /* Convert between input and output indices for reciprocity */ | 
| 408 | + | static int | 
| 409 | + | recip_out_from_in(const SDMat *bsdf, int in_recip) | 
| 410 | + | { | 
| 411 | + | FVECT   v; | 
| 412 | + |  | 
| 413 | + | if (!mBSDF_incvec(v, bsdf, in_recip+.5)) | 
| 414 | + | return(in_recip);               /* XXX should be error! */ | 
| 415 | + | v[2] = -v[2]; | 
| 416 | + | return(mBSDF_outndx(bsdf, v)); | 
| 417 | + | } | 
| 418 | + |  | 
| 419 | + | /* Convert between output and input indices for reciprocity */ | 
| 420 | + | static int | 
| 421 | + | recip_in_from_out(const SDMat *bsdf, int out_recip) | 
| 422 | + | { | 
| 423 | + | FVECT   v; | 
| 424 | + |  | 
| 425 | + | if (!mBSDF_outvec(v, bsdf, out_recip+.5)) | 
| 426 | + | return(out_recip);              /* XXX should be error! */ | 
| 427 | + | v[2] = -v[2]; | 
| 428 | + | return(mBSDF_incndx(bsdf, v)); | 
| 429 | + | } | 
| 430 | + |  | 
| 431 | + | /* Convert a BSDF to our matrix representation, applying reciprocity */ | 
| 432 | + | static CMATRIX * | 
| 433 | + | cm_bsdf_recip(const COLOR bsdfLamb, const COLOR specCol, const SDMat *bsdf) | 
| 434 | + | { | 
| 435 | + | CMATRIX *cm = cm_alloc(bsdf->ninc, bsdf->nout); | 
| 436 | + | int     nbadohm = 0; | 
| 437 | + | int     nneg = 0; | 
| 438 | + | int     r, c; | 
| 439 | + | /* loop over incident angles */ | 
| 440 | + | for (c = 0; c < cm->ncols; c++) { | 
| 441 | + | const int       ro = recip_out_from_in(bsdf,c); | 
| 442 | + | const double    dom = mBSDF_outohm(bsdf,ro); | 
| 443 | + | /* projected solid angle */ | 
| 444 | + | nbadohm += (dom <= 0); | 
| 445 | + |  | 
| 446 | + | for (r = 0; r < cm->nrows; r++) { | 
| 447 | + | const int       ri = recip_in_from_out(bsdf,r); | 
| 448 | + | float           f = mBSDF_value(bsdf,ri,ro); | 
| 449 | + | COLORV          *mp = cm_lval(cm,r,c); | 
| 450 | + | /* check BSDF value */ | 
| 451 | + | if ((f <= 0) | (dom <= 0)) { | 
| 452 | + | nneg += (f < -FTINY); | 
| 453 | + | f = .0f; | 
| 454 | + | } | 
| 455 | + | copycolor(mp, specCol); | 
| 456 | + | scalecolor(mp, f); | 
| 457 | + | addcolor(mp, bsdfLamb); | 
| 458 | + | scalecolor(mp, dom); | 
| 459 | + | } | 
| 460 | + | } | 
| 461 | + | if (nneg | nbadohm) { | 
| 462 | + | sprintf(errmsg, | 
| 463 | + | "BTDF has %d negatives and %d bad incoming solid angles", | 
| 464 | + | nneg, nbadohm); | 
| 465 | + | error(WARNING, errmsg); | 
| 466 | + | } | 
| 467 | + | return(cm); | 
| 468 | + | } | 
| 469 | + |  | 
| 470 |  | /* Load and convert a matrix BSDF from the given XML file */ | 
| 471 |  | static CMATRIX * | 
| 472 | < | cm_loadBSDF(char *fname) | 
| 472 | > | cm_loadBSDF(char *fname, COLOR cLamb) | 
| 473 |  | { | 
| 474 | < | CMATRIX *Tmat; | 
| 475 | < | char    *fpath; | 
| 476 | < | SDError ec; | 
| 477 | < | SDData  myBSDF; | 
| 478 | < | COLOR   bsdfLamb, specCol; | 
| 474 | > | CMATRIX         *Tmat; | 
| 475 | > | char            *fpath; | 
| 476 | > | int             recip; | 
| 477 | > | SDError         ec; | 
| 478 | > | SDData          myBSDF; | 
| 479 | > | SDSpectralDF    *tdf; | 
| 480 | > | COLOR           bsdfLamb, specCol; | 
| 481 |  | /* find path to BSDF file */ | 
| 482 |  | fpath = getpath(fname, getrlibpath(), R_OK); | 
| 483 |  | if (fpath == NULL) { | 
| 488 |  | ec = SDloadFile(&myBSDF, fpath); | 
| 489 |  | if (ec) | 
| 490 |  | error(USER, transSDError(ec)); | 
| 491 | < | if (myBSDF.tf == NULL || myBSDF.tf->ncomp != 1 || | 
| 492 | < | myBSDF.tf->comp[0].func != &SDhandleMtx) { | 
| 491 | > | ccy2rgb(&myBSDF.tLamb.spec, myBSDF.tLamb.cieY/PI, bsdfLamb); | 
| 492 | > | recip = (myBSDF.tb == NULL); | 
| 493 | > | tdf = recip ? myBSDF.tf : myBSDF.tb; | 
| 494 | > | if (tdf == NULL) {              /* no non-Lambertian transmission? */ | 
| 495 | > | if (cLamb != NULL) | 
| 496 | > | copycolor(cLamb, bsdfLamb); | 
| 497 | > | SDfreeBSDF(&myBSDF); | 
| 498 | > | return(NULL); | 
| 499 | > | } | 
| 500 | > | if (tdf->ncomp != 1 || tdf->comp[0].func != &SDhandleMtx) { | 
| 501 |  | sprintf(errmsg, "unsupported BSDF '%s'", fpath); | 
| 502 |  | error(USER, errmsg); | 
| 503 |  | } | 
| 504 |  | /* convert BTDF to matrix */ | 
| 505 | < | ccy2rgb(&myBSDF.tLamb.spec, myBSDF.tLamb.cieY/PI, bsdfLamb); | 
| 506 | < | ccy2rgb(&myBSDF.tf->comp[0].cspec[0], 1., specCol); | 
| 507 | < | Tmat = cm_bsdf(bsdfLamb, specCol, (SDMat *)myBSDF.tf->comp[0].dist); | 
| 505 | > | ccy2rgb(&tdf->comp[0].cspec[0], 1., specCol); | 
| 506 | > | Tmat = recip ? cm_bsdf_recip(bsdfLamb, specCol, (SDMat *)tdf->comp[0].dist) | 
| 507 | > | : cm_bsdf(bsdfLamb, specCol, (SDMat *)tdf->comp[0].dist); | 
| 508 | > | if (cLamb != NULL)              /* Lambertian is included */ | 
| 509 | > | setcolor(cLamb, .0, .0, .0); | 
| 510 |  | /* free BSDF and return */ | 
| 511 |  | SDfreeBSDF(&myBSDF); | 
| 512 |  | return(Tmat); | 
| 513 |  | } | 
| 514 |  |  | 
| 515 | < | /* Sum together a set of images and write result to stdout */ | 
| 515 | > | /* Sum together a set of images and write result to fout */ | 
| 516 |  | static int | 
| 517 |  | sum_images(const char *fspec, const CMATRIX *cv, FILE *fout) | 
| 518 |  | { | 
| 519 |  | int     myDT = DTfromHeader; | 
| 520 | < | CMATRIX *pmat; | 
| 521 | < | COLOR   *scanline; | 
| 522 | < | int     myXR, myYR; | 
| 520 | > | COLOR   *scanline = NULL; | 
| 521 | > | CMATRIX *pmat = NULL; | 
| 522 | > | int     myXR=0, myYR=0; | 
| 523 |  | int     i, y; | 
| 524 |  |  | 
| 525 |  | if (cv->ncols != 1) | 
| 531 |  | int             dt, xr, yr; | 
| 532 |  | COLORV          *psp; | 
| 533 |  | /* check for zero */ | 
| 534 | < | if ((scv[RED] == 0) & (scv[GRN] == 0) & (scv[BLU] == 0)) | 
| 534 | > | if ((scv[RED] == 0) & (scv[GRN] == 0) & (scv[BLU] == 0) && | 
| 535 | > | (myDT != DTfromHeader) | (i < cv->nrows-1)) | 
| 536 |  | continue; | 
| 537 |  | /* open next picture */ | 
| 538 |  | sprintf(fname, fspec, i); | 
| 594 |  | static int | 
| 595 |  | hasNumberFormat(const char *s) | 
| 596 |  | { | 
| 597 | < | while (*s && *s != '%') | 
| 448 | < | s++; | 
| 449 | < | if (!*s) | 
| 597 | > | if (s == NULL) | 
| 598 |  | return(0); | 
| 451 | – | do | 
| 452 | – | ++s; | 
| 453 | – | while (isdigit(*s)); | 
| 599 |  |  | 
| 600 | < | return((*s == 'd') | (*s == 'i') | (*s == 'o') | | 
| 601 | < | (*s == 'x') | (*s == 'X')); | 
| 600 | > | while (*s) { | 
| 601 | > | while (*s != '%') | 
| 602 | > | if (!*s++) | 
| 603 | > | return(0); | 
| 604 | > | if (*++s == '%') {              /* ignore "%%" */ | 
| 605 | > | ++s; | 
| 606 | > | continue; | 
| 607 | > | } | 
| 608 | > | while (isdigit(*s))             /* field length */ | 
| 609 | > | ++s; | 
| 610 | > | /* field we'll use? */ | 
| 611 | > | if ((*s == 'd') | (*s == 'i') | (*s == 'o') | | 
| 612 | > | (*s == 'x') | (*s == 'X')) | 
| 613 | > | return(1); | 
| 614 | > | } | 
| 615 | > | return(0);                              /* didn't find one */ | 
| 616 |  | } | 
| 617 |  |  | 
| 618 |  | int | 
| 619 |  | main(int argc, char *argv[]) | 
| 620 |  | { | 
| 621 | < | CMATRIX                 *cvec; | 
| 621 | > | int             skyfmt = DTascii; | 
| 622 | > | int             nsteps = 1; | 
| 623 | > | char            *ofspec = NULL; | 
| 624 | > | FILE            *ofp = stdout; | 
| 625 | > | CMATRIX         *cmtx;          /* component vector/matrix result */ | 
| 626 | > | char            fnbuf[256]; | 
| 627 | > | int             a, i; | 
| 628 |  |  | 
| 629 |  | progname = argv[0]; | 
| 630 | + | /* get options */ | 
| 631 | + | for (a = 1; a < argc && argv[a][0] == '-'; a++) | 
| 632 | + | switch (argv[a][1]) { | 
| 633 | + | case 'n': | 
| 634 | + | nsteps = atoi(argv[++a]); | 
| 635 | + | if (nsteps <= 0) | 
| 636 | + | goto userr; | 
| 637 | + | break; | 
| 638 | + | case 'o': | 
| 639 | + | ofspec = argv[++a]; | 
| 640 | + | break; | 
| 641 | + | case 'i': | 
| 642 | + | switch (argv[a][2]) { | 
| 643 | + | case 'f': | 
| 644 | + | skyfmt = DTfloat; | 
| 645 | + | break; | 
| 646 | + | case 'd': | 
| 647 | + | skyfmt = DTdouble; | 
| 648 | + | break; | 
| 649 | + | case 'a': | 
| 650 | + | skyfmt = DTascii; | 
| 651 | + | break; | 
| 652 | + | default: | 
| 653 | + | goto userr; | 
| 654 | + | } | 
| 655 | + | break; | 
| 656 | + | default: | 
| 657 | + | goto userr; | 
| 658 | + | } | 
| 659 | + | if ((argc-a < 1) | (argc-a > 4)) | 
| 660 | + | goto userr; | 
| 661 |  |  | 
| 662 | < | if ((argc < 2) | (argc > 5)) { | 
| 663 | < | fprintf(stderr, "Usage: %s DCspec [tregvec]\n", progname); | 
| 664 | < | fprintf(stderr, "   or: %s Vspec Tbsdf.xml Dmat.dat [tregvec]\n", | 
| 665 | < | progname); | 
| 666 | < | return(1); | 
| 471 | < | } | 
| 472 | < |  | 
| 473 | < | if (argc > 3) {                         /* VTDs expression */ | 
| 474 | < | CMATRIX *svec, *Dmat, *Tmat, *ivec; | 
| 475 | < | /* get sky vector */ | 
| 476 | < | svec = cm_load(argv[4], 0, 1, DTascii); | 
| 662 | > | if (argc-a > 2) {                       /* VTDs expression */ | 
| 663 | > | CMATRIX *smtx, *Dmat, *Tmat, *imtx; | 
| 664 | > | COLOR   tLamb; | 
| 665 | > | /* get sky vector/matrix */ | 
| 666 | > | smtx = cm_load(argv[a+3], 0, nsteps, skyfmt); | 
| 667 |  | /* load BSDF */ | 
| 668 | < | Tmat = cm_loadBSDF(argv[2]); | 
| 668 | > | Tmat = cm_loadBSDF(argv[a+1], tLamb); | 
| 669 |  | /* load Daylight matrix */ | 
| 670 | < | Dmat = cm_load(argv[3], Tmat->ncols, svec->nrows, DTfromHeader); | 
| 670 | > | Dmat = cm_load(argv[a+2], Tmat==NULL ? 0 : Tmat->ncols, | 
| 671 | > | smtx->nrows, DTfromHeader); | 
| 672 |  | /* multiply vector through */ | 
| 673 | < | ivec = cm_multiply(Dmat, svec); | 
| 674 | < | cm_free(Dmat); cm_free(svec); | 
| 675 | < | cvec = cm_multiply(Tmat, ivec); /* cvec = component vector */ | 
| 676 | < | cm_free(Tmat); cm_free(ivec); | 
| 677 | < | } else {                                /* else just use sky vector */ | 
| 678 | < | cvec = cm_load(argv[2], 0, 1, DTascii); | 
| 673 | > | imtx = cm_multiply(Dmat, smtx); | 
| 674 | > | cm_free(Dmat); cm_free(smtx); | 
| 675 | > | if (Tmat == NULL) {             /* diffuse only */ | 
| 676 | > | cmtx = cm_scale(imtx, tLamb); | 
| 677 | > | } else {                        /* else apply BTDF matrix */ | 
| 678 | > | cmtx = cm_multiply(Tmat, imtx); | 
| 679 | > | cm_free(Tmat); | 
| 680 | > | } | 
| 681 | > | cm_free(imtx); | 
| 682 | > | } else {                                /* sky vector/matrix only */ | 
| 683 | > | cmtx = cm_load(argv[a+1], 0, nsteps, skyfmt); | 
| 684 |  | } | 
| 685 | < |  | 
| 686 | < | if (hasNumberFormat(argv[1])) {         /* generating image */ | 
| 687 | < | SET_FILE_BINARY(stdout); | 
| 688 | < | newheader("RADIANCE", stdout); | 
| 689 | < | printargs(argc, argv, stdout); | 
| 690 | < | fputnow(stdout); | 
| 691 | < | if (!sum_images(argv[1], cvec, stdout)) | 
| 685 | > | /* prepare output stream */ | 
| 686 | > | if ((ofspec != NULL) & (nsteps == 1) && hasNumberFormat(ofspec)) { | 
| 687 | > | sprintf(fnbuf, ofspec, 1); | 
| 688 | > | ofspec = fnbuf; | 
| 689 | > | } | 
| 690 | > | if (ofspec != NULL && !hasNumberFormat(ofspec)) { | 
| 691 | > | if ((ofp = fopen(ofspec, "w")) == NULL) { | 
| 692 | > | fprintf(stderr, "%s: cannot open '%s' for output\n", | 
| 693 | > | progname, ofspec); | 
| 694 |  | return(1); | 
| 695 | < | } else {                                /* generating vector */ | 
| 696 | < | CMATRIX *Vmat = cm_load(argv[1], 0, cvec->nrows, DTfromHeader); | 
| 697 | < | CMATRIX *rvec = cm_multiply(Vmat, cvec); | 
| 695 | > | } | 
| 696 | > | ofspec = NULL;                  /* only need to open once */ | 
| 697 | > | } | 
| 698 | > | if (hasNumberFormat(argv[a])) {         /* generating image(s) */ | 
| 699 | > | if (ofspec == NULL) { | 
| 700 | > | SET_FILE_BINARY(ofp); | 
| 701 | > | newheader("RADIANCE", ofp); | 
| 702 | > | printargs(argc, argv, ofp); | 
| 703 | > | fputnow(ofp); | 
| 704 | > | } | 
| 705 | > | if (nsteps > 1)                 /* multiple output frames? */ | 
| 706 | > | for (i = 0; i < nsteps; i++) { | 
| 707 | > | CMATRIX *cvec = cm_column(cmtx, i); | 
| 708 | > | if (ofspec != NULL) { | 
| 709 | > | sprintf(fnbuf, ofspec, i+1); | 
| 710 | > | if ((ofp = fopen(fnbuf, "wb")) == NULL) { | 
| 711 | > | fprintf(stderr, | 
| 712 | > | "%s: cannot open '%s' for output\n", | 
| 713 | > | progname, fnbuf); | 
| 714 | > | return(1); | 
| 715 | > | } | 
| 716 | > | newheader("RADIANCE", ofp); | 
| 717 | > | printargs(argc, argv, ofp); | 
| 718 | > | fputnow(ofp); | 
| 719 | > | } | 
| 720 | > | fprintf(ofp, "FRAME=%d\n", i+1); | 
| 721 | > | if (!sum_images(argv[a], cvec, ofp)) | 
| 722 | > | return(1); | 
| 723 | > | if (ofspec != NULL) { | 
| 724 | > | if (fclose(ofp) == EOF) { | 
| 725 | > | fprintf(stderr, | 
| 726 | > | "%s: error writing to '%s'\n", | 
| 727 | > | progname, fnbuf); | 
| 728 | > | return(1); | 
| 729 | > | } | 
| 730 | > | ofp = stdout; | 
| 731 | > | } | 
| 732 | > | cm_free(cvec); | 
| 733 | > | } | 
| 734 | > | else if (!sum_images(argv[a], cmtx, ofp)) | 
| 735 | > | return(1); | 
| 736 | > | } else {                                /* generating vector/matrix */ | 
| 737 | > | CMATRIX *Vmat = cm_load(argv[a], 0, cmtx->nrows, DTfromHeader); | 
| 738 | > | CMATRIX *rmtx = cm_multiply(Vmat, cmtx); | 
| 739 |  | cm_free(Vmat); | 
| 740 | < | cm_print(rvec, stdout); | 
| 741 | < | cm_free(rvec); | 
| 740 | > | if (ofspec != NULL)             /* multiple vector files? */ | 
| 741 | > | for (i = 0; i < nsteps; i++) { | 
| 742 | > | CMATRIX *rvec = cm_column(rmtx, i); | 
| 743 | > | sprintf(fnbuf, ofspec, i+1); | 
| 744 | > | if ((ofp = fopen(fnbuf, "w")) == NULL) { | 
| 745 | > | fprintf(stderr, | 
| 746 | > | "%s: cannot open '%s' for output\n", | 
| 747 | > | progname, fnbuf); | 
| 748 | > | return(1); | 
| 749 | > | } | 
| 750 | > | cm_print(rvec, ofp); | 
| 751 | > | if (fclose(ofp) == EOF) { | 
| 752 | > | fprintf(stderr, | 
| 753 | > | "%s: error writing to '%s'\n", | 
| 754 | > | progname, fnbuf); | 
| 755 | > | return(1); | 
| 756 | > | } | 
| 757 | > | ofp = stdout; | 
| 758 | > | cm_free(rvec); | 
| 759 | > | } | 
| 760 | > | else | 
| 761 | > | cm_print(rmtx, ofp); | 
| 762 | > | cm_free(rmtx); | 
| 763 |  | } | 
| 764 | < | cm_free(cvec);                          /* final clean-up */ | 
| 764 | > | if (fflush(ofp) == EOF) {               /* final clean-up */ | 
| 765 | > | fprintf(stderr, "%s: write error on output\n", progname); | 
| 766 | > | return(1); | 
| 767 | > | } | 
| 768 | > | cm_free(cmtx); | 
| 769 |  | return(0); | 
| 770 | + | userr: | 
| 771 | + | fprintf(stderr, "Usage: %s [-n nsteps][-o ospec][-i{f|d}] DCspec [skyf]\n", | 
| 772 | + | progname); | 
| 773 | + | fprintf(stderr, "   or: %s [-n nsteps][-o ospec][-i{f|d}] Vspec Tbsdf.xml Dmat.dat [skyf]\n", | 
| 774 | + | progname); | 
| 775 | + | return(1); | 
| 776 |  | } |