ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.11
Committed: Fri Jun 13 01:16:41 2014 UTC (9 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.10: +18 -6 lines
Log Message:
Added NROWS= setting to header

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rc2.c,v 2.10 2014/05/30 16:05:52 greg Exp $";
3 #endif
4 /*
5 * Accumulate ray contributions for a set of materials
6 * File i/o and recovery
7 */
8
9 #include "rcontrib.h"
10 #include "resolu.h"
11 #include <ctype.h>
12
13 /* Close output stream and free record */
14 static void
15 closestream(void *p)
16 {
17 STREAMOUT *sop = (STREAMOUT *)p;
18
19 if (sop->ofp != NULL) {
20 int status = 0;
21 if (sop->outpipe)
22 status = pclose(sop->ofp);
23 else if (sop->ofp != stdout)
24 status = fclose(sop->ofp);
25 if (status)
26 error(SYSTEM, "error closing output stream");
27 }
28 free(p);
29 }
30
31 LUTAB ofiletab = LU_SINIT(free,closestream); /* output file table */
32
33 #define OF_MODIFIER 01
34 #define OF_BIN 02
35
36 /************************** STREAM & FILE I/O ***************************/
37
38 /* Construct output file name and return flags whether modifier/bin present */
39 static int
40 ofname(char *oname, const char *ospec, const char *mname, int bn)
41 {
42 const char *mnp = NULL;
43 const char *bnp = NULL;
44 const char *cp;
45
46 if (ospec == NULL)
47 return(-1);
48 for (cp = ospec; *cp; cp++) /* check format position(s) */
49 if (*cp == '%') {
50 do
51 ++cp;
52 while (isdigit(*cp));
53 switch (*cp) {
54 case '%':
55 break;
56 case 's':
57 if (mnp != NULL)
58 return(-1);
59 mnp = cp;
60 break;
61 case 'd':
62 case 'i':
63 case 'o':
64 case 'x':
65 case 'X':
66 if (bnp != NULL)
67 return(-1);
68 bnp = cp;
69 break;
70 default:
71 return(-1);
72 }
73 }
74 if (mnp != NULL) { /* create file name */
75 if (bnp != NULL) {
76 if (bnp > mnp)
77 sprintf(oname, ospec, mname, bn);
78 else
79 sprintf(oname, ospec, bn, mname);
80 return(OF_MODIFIER|OF_BIN);
81 }
82 sprintf(oname, ospec, mname);
83 return(OF_MODIFIER);
84 }
85 if (bnp != NULL) {
86 sprintf(oname, ospec, bn);
87 return(OF_BIN);
88 }
89 strcpy(oname, ospec);
90 return(0);
91 }
92
93
94 /* Write header to the given output stream */
95 static void
96 printheader(FILE *fout, const char *info)
97 {
98 extern char VersionID[];
99 /* copy octree header */
100 if (octname[0] == '!') {
101 newheader("RADIANCE", fout);
102 fputs(octname+1, fout);
103 if (octname[strlen(octname)-1] != '\n')
104 fputc('\n', fout);
105 } else {
106 FILE *fin = fopen(octname, (outfmt=='a') ? "r" : "rb");
107 if (fin == NULL)
108 quit(1);
109 checkheader(fin, OCTFMT, fout);
110 fclose(fin);
111 }
112 printargs(gargc-1, gargv, fout); /* add our command */
113 fprintf(fout, "SOFTWARE= %s\n", VersionID);
114 fputnow(fout);
115 fputs("NCOMP=3\n", fout); /* always RGB */
116 if (info != NULL) /* add extra info if given */
117 fputs(info, fout);
118 fputformat(formstr(outfmt), fout);
119 fputc('\n', fout); /* empty line ends header */
120 }
121
122
123 /* Write resolution string to given output stream */
124 static void
125 printresolu(FILE *fout, int xr, int yr)
126 {
127 if ((xr > 0) & (yr > 0)) /* resolution string */
128 fprtresolu(xr, yr, fout);
129 }
130
131
132 /* Get output stream pointer (open and write header if new and noopen==0) */
133 STREAMOUT *
134 getostream(const char *ospec, const char *mname, int bn, int noopen)
135 {
136 static STREAMOUT stdos;
137 char info[1024];
138 int ofl;
139 char oname[1024];
140 LUENT *lep;
141 STREAMOUT *sop;
142 char *cp;
143
144 if (ospec == NULL) { /* use stdout? */
145 if (!noopen & !using_stdout) {
146 if (outfmt != 'a')
147 SET_FILE_BINARY(stdout);
148 if (header) {
149 cp = info;
150 if (yres > 0) {
151 sprintf(cp, "NROWS=%d\n", yres *
152 (xres + !xres) );
153 while (*cp) ++cp;
154 }
155 sprintf(cp, "NCOLS=%d\nNCOMP=3\n",
156 stdos.reclen);
157 printheader(stdout, info);
158 }
159 printresolu(stdout, xres, yres);
160 if (waitflush > 0)
161 fflush(stdout);
162 stdos.xr = xres; stdos.yr = yres;
163 #ifdef getc_unlocked
164 flockfile(stdout); /* avoid lock/unlock overhead */
165 #endif
166 using_stdout = 1;
167 }
168 stdos.ofp = stdout;
169 stdos.reclen += noopen;
170 return(&stdos);
171 }
172 ofl = ofname(oname, ospec, mname, bn); /* get output name */
173 if (ofl < 0) {
174 sprintf(errmsg, "bad output format '%s'", ospec);
175 error(USER, errmsg);
176 }
177 lep = lu_find(&ofiletab, oname); /* look it up */
178 if (lep->key == NULL) /* new entry */
179 lep->key = strcpy((char *)malloc(strlen(oname)+1), oname);
180 sop = (STREAMOUT *)lep->data;
181 if (sop == NULL) { /* allocate stream */
182 sop = (STREAMOUT *)malloc(sizeof(STREAMOUT));
183 if (sop == NULL)
184 error(SYSTEM, "out of memory in getostream");
185 sop->outpipe = oname[0] == '!';
186 sop->reclen = 0;
187 sop->ofp = NULL; /* open iff noopen==0 */
188 sop->xr = xres; sop->yr = yres;
189 lep->data = (char *)sop;
190 if (!sop->outpipe & !force_open & !recover &&
191 access(oname, F_OK) == 0) {
192 errno = EEXIST; /* file exists */
193 goto openerr;
194 }
195 }
196 if (!noopen && sop->ofp == NULL) { /* open output stream */
197 if (oname[0] == '!') /* output to command */
198 sop->ofp = popen(oname+1, "w");
199 else /* else open file */
200 sop->ofp = fopen(oname, "w");
201 if (sop->ofp == NULL)
202 goto openerr;
203 if (outfmt != 'a')
204 SET_FILE_BINARY(sop->ofp);
205 #ifdef getc_unlocked
206 flockfile(sop->ofp); /* avoid lock/unlock overhead */
207 #endif
208 if (accumulate > 0) { /* global resolution */
209 sop->xr = xres; sop->yr = yres;
210 }
211 if (header) {
212 cp = info;
213 if (ofl & OF_MODIFIER || sop->reclen == 1) {
214 sprintf(cp, "MODIFIER=%s\n", mname);
215 while (*cp) ++cp;
216 }
217 if (ofl & OF_BIN) {
218 sprintf(cp, "BIN=%d\n", bn);
219 while (*cp) ++cp;
220 }
221 if (sop->yr > 0) {
222 sprintf(cp, "NROWS=%d\n", sop->yr *
223 (sop->xr + !sop->xr) );
224 while (*cp) ++cp;
225 }
226 sprintf(cp, "NCOLS=%d\nNCOMP=3\n", sop->reclen);
227 printheader(sop->ofp, info);
228 }
229 printresolu(sop->ofp, sop->xr, sop->yr);
230 if (waitflush > 0)
231 fflush(sop->ofp);
232 }
233 sop->reclen += noopen; /* add to length if noopen */
234 return(sop); /* return output stream */
235 openerr:
236 sprintf(errmsg, "cannot open '%s' for writing", oname);
237 error(SYSTEM, errmsg);
238 return(NULL); /* pro forma return */
239 }
240
241
242 /* Get a vector from stdin */
243 int
244 getvec(FVECT vec)
245 {
246 float vf[3];
247 double vd[3];
248 char buf[32];
249 int i;
250
251 switch (inpfmt) {
252 case 'a': /* ascii */
253 for (i = 0; i < 3; i++) {
254 if (fgetword(buf, sizeof(buf), stdin) == NULL ||
255 !isflt(buf))
256 return(-1);
257 vec[i] = atof(buf);
258 }
259 break;
260 case 'f': /* binary float */
261 if (fread((char *)vf, sizeof(float), 3, stdin) != 3)
262 return(-1);
263 VCOPY(vec, vf);
264 break;
265 case 'd': /* binary double */
266 if (fread((char *)vd, sizeof(double), 3, stdin) != 3)
267 return(-1);
268 VCOPY(vec, vd);
269 break;
270 default:
271 error(CONSISTENCY, "botched input format");
272 }
273 return(0);
274 }
275
276
277 /* Put out ray contribution to file */
278 static void
279 put_contrib(const DCOLOR cnt, FILE *fout)
280 {
281 double sf = 1;
282 COLOR fv;
283 COLR cv;
284
285 if (accumulate > 1)
286 sf = 1./(double)accumulate;
287 switch (outfmt) {
288 case 'a':
289 if (accumulate > 1)
290 fprintf(fout, "%.6e\t%.6e\t%.6e\t",
291 sf*cnt[0], sf*cnt[1], sf*cnt[2]);
292 else
293 fprintf(fout, "%.6e\t%.6e\t%.6e\t",
294 cnt[0], cnt[1], cnt[2]);
295 break;
296 case 'f':
297 if (accumulate > 1) {
298 copycolor(fv, cnt);
299 scalecolor(fv, sf);
300 } else
301 copycolor(fv, cnt);
302 fwrite(fv, sizeof(float), 3, fout);
303 break;
304 case 'd':
305 if (accumulate > 1) {
306 DCOLOR dv;
307 copycolor(dv, cnt);
308 scalecolor(dv, sf);
309 fwrite(dv, sizeof(double), 3, fout);
310 } else
311 fwrite(cnt, sizeof(double), 3, fout);
312 break;
313 case 'c':
314 if (accumulate > 1)
315 setcolr(cv, sf*cnt[0], sf*cnt[1], sf*cnt[2]);
316 else
317 setcolr(cv, cnt[0], cnt[1], cnt[2]);
318 fwrite(cv, sizeof(cv), 1, fout);
319 break;
320 default:
321 error(INTERNAL, "botched output format");
322 }
323 }
324
325
326 /* Output modifier values to appropriate stream(s) */
327 void
328 mod_output(MODCONT *mp)
329 {
330 STREAMOUT *sop = getostream(mp->outspec, mp->modname, 0, 0);
331 int j;
332
333 put_contrib(mp->cbin[0], sop->ofp);
334 if (mp->nbins > 3 && /* minor optimization */
335 sop == getostream(mp->outspec, mp->modname, 1, 0)) {
336 for (j = 1; j < mp->nbins; j++)
337 put_contrib(mp->cbin[j], sop->ofp);
338 } else {
339 for (j = 1; j < mp->nbins; j++) {
340 sop = getostream(mp->outspec, mp->modname, j, 0);
341 put_contrib(mp->cbin[j], sop->ofp);
342 }
343 }
344 }
345
346
347 /* callback to output newline to ASCII file and/or flush as requested */
348 static int
349 puteol(const LUENT *e, void *p)
350 {
351 STREAMOUT *sop = (STREAMOUT *)e->data;
352
353 if (outfmt == 'a')
354 putc('\n', sop->ofp);
355 if (!waitflush)
356 fflush(sop->ofp);
357 if (ferror(sop->ofp)) {
358 sprintf(errmsg, "write error on file '%s'", e->key);
359 error(SYSTEM, errmsg);
360 }
361 return(0);
362 }
363
364
365 /* Terminate record output and flush if time */
366 void
367 end_record()
368 {
369 --waitflush;
370 lu_doall(&ofiletab, &puteol, NULL);
371 if (using_stdout & (outfmt == 'a'))
372 putc('\n', stdout);
373 if (!waitflush) {
374 waitflush = (yres > 0) & (xres > 1) ? 0 : xres;
375 if (using_stdout)
376 fflush(stdout);
377 }
378 }
379
380 /************************** PARTIAL RESULTS RECOVERY ***********************/
381
382 /* Get ray contribution from previous file */
383 static int
384 get_contrib(DCOLOR cnt, FILE *finp)
385 {
386 COLOR fv;
387 COLR cv;
388
389 switch (outfmt) {
390 case 'a':
391 return(fscanf(finp,"%lf %lf %lf",&cnt[0],&cnt[1],&cnt[2]) == 3);
392 case 'f':
393 if (fread(fv, sizeof(fv[0]), 3, finp) != 3)
394 return(0);
395 copycolor(cnt, fv);
396 return(1);
397 case 'd':
398 return(fread(cnt, sizeof(cnt[0]), 3, finp) == 3);
399 case 'c':
400 if (fread(cv, sizeof(cv), 1, finp) != 1)
401 return(0);
402 colr_color(fv, cv);
403 copycolor(cnt, fv);
404 return(1);
405 default:
406 error(INTERNAL, "botched output format");
407 }
408 return(0); /* pro forma return */
409 }
410
411
412 /* Close output file opened for input */
413 static int
414 myclose(const LUENT *e, void *p)
415 {
416 STREAMOUT *sop = (STREAMOUT *)e->data;
417
418 if (sop->ofp == NULL)
419 return(0);
420 fclose(sop->ofp);
421 sop->ofp = NULL;
422 return(0);
423 }
424
425
426 /* Load previously accumulated values */
427 void
428 reload_output()
429 {
430 int i, j;
431 MODCONT *mp;
432 int ofl;
433 char oname[1024];
434 char *fmode = "rb";
435 char *outvfmt;
436 LUENT *oent;
437 int xr, yr;
438 STREAMOUT sout;
439 DCOLOR rgbv;
440
441 if (outfmt == 'a')
442 fmode = "r";
443 outvfmt = formstr(outfmt);
444 /* reload modifier values */
445 for (i = 0; i < nmods; i++) {
446 mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
447 if (mp->outspec == NULL)
448 error(USER, "cannot reload from stdout");
449 if (mp->outspec[0] == '!')
450 error(USER, "cannot reload from command");
451 for (j = 0; ; j++) { /* load each modifier bin */
452 ofl = ofname(oname, mp->outspec, mp->modname, j);
453 if (ofl < 0)
454 error(USER, "bad output file specification");
455 oent = lu_find(&ofiletab, oname);
456 if (oent->data != NULL) {
457 sout = *(STREAMOUT *)oent->data;
458 } else {
459 sout.reclen = 0;
460 sout.outpipe = 0;
461 sout.xr = xres; sout.yr = yres;
462 sout.ofp = NULL;
463 }
464 if (sout.ofp == NULL) { /* open output as input */
465 sout.ofp = fopen(oname, fmode);
466 if (sout.ofp == NULL) {
467 if (j == mp->nbins)
468 break; /* assume end of modifier */
469 sprintf(errmsg, "missing reload file '%s'",
470 oname);
471 error(WARNING, errmsg);
472 break;
473 }
474 #ifdef getc_unlocked
475 flockfile(sout.ofp);
476 #endif
477 if (header && checkheader(sout.ofp, outvfmt, NULL) != 1) {
478 sprintf(errmsg, "format mismatch for '%s'",
479 oname);
480 error(USER, errmsg);
481 }
482 if ((sout.xr > 0) & (sout.yr > 0) &&
483 (!fscnresolu(&xr, &yr, sout.ofp) ||
484 (xr != sout.xr) |
485 (yr != sout.yr))) {
486 sprintf(errmsg, "resolution mismatch for '%s'",
487 oname);
488 error(USER, errmsg);
489 }
490 }
491 /* read in RGB value */
492 if (!get_contrib(rgbv, sout.ofp)) {
493 if (!j) {
494 fclose(sout.ofp);
495 break; /* ignore empty file */
496 }
497 if (j < mp->nbins) {
498 sprintf(errmsg, "missing data in '%s'",
499 oname);
500 error(USER, errmsg);
501 }
502 break;
503 }
504 if (j >= mp->nbins) { /* check modifier size */
505 sprintf(errmsg,
506 "mismatched -bn setting for reloading '%s'",
507 modname[i]);
508 error(USER, errmsg);
509 }
510
511 copycolor(mp->cbin[j], rgbv);
512 if (oent->key == NULL) /* new file entry */
513 oent->key = strcpy((char *)
514 malloc(strlen(oname)+1), oname);
515 if (oent->data == NULL)
516 oent->data = (char *)malloc(sizeof(STREAMOUT));
517 *(STREAMOUT *)oent->data = sout;
518 }
519 }
520 lu_doall(&ofiletab, &myclose, NULL); /* close all files */
521 }
522
523
524 /* Seek on the given output file */
525 static int
526 myseeko(const LUENT *e, void *p)
527 {
528 STREAMOUT *sop = (STREAMOUT *)e->data;
529 off_t nbytes = *(off_t *)p;
530
531 if (sop->reclen > 1)
532 nbytes = nbytes * sop->reclen;
533 if (fseeko(sop->ofp, nbytes, SEEK_CUR) < 0) {
534 sprintf(errmsg, "seek error on file '%s'", e->key);
535 error(SYSTEM, errmsg);
536 }
537 return(0);
538 }
539
540
541 /* Recover output if possible */
542 void
543 recover_output()
544 {
545 off_t lastout = -1;
546 int outvsiz, recsiz;
547 char *outvfmt;
548 int i, j;
549 MODCONT *mp;
550 int ofl;
551 char oname[1024];
552 LUENT *oent;
553 STREAMOUT sout;
554 off_t nvals;
555 int xr, yr;
556
557 switch (outfmt) {
558 case 'a':
559 error(USER, "cannot recover ASCII output");
560 return;
561 case 'f':
562 outvsiz = sizeof(float)*3;
563 break;
564 case 'd':
565 outvsiz = sizeof(double)*3;
566 break;
567 case 'c':
568 outvsiz = sizeof(COLR);
569 break;
570 default:
571 error(INTERNAL, "botched output format");
572 return;
573 }
574 outvfmt = formstr(outfmt);
575 /* check modifier outputs */
576 for (i = 0; i < nmods; i++) {
577 mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
578 if (mp->outspec == NULL)
579 error(USER, "cannot recover from stdout");
580 if (mp->outspec[0] == '!')
581 error(USER, "cannot recover from command");
582 for (j = 0; ; j++) { /* check each bin's file */
583 ofl = ofname(oname, mp->outspec, mp->modname, j);
584 if (ofl < 0)
585 error(USER, "bad output file specification");
586 oent = lu_find(&ofiletab, oname);
587 if (oent->data != NULL) {
588 sout = *(STREAMOUT *)oent->data;
589 } else {
590 sout.reclen = 0;
591 sout.outpipe = 0;
592 sout.ofp = NULL;
593 }
594 if (sout.ofp != NULL) { /* already open? */
595 if (ofl & OF_BIN)
596 continue;
597 break;
598 }
599 /* open output */
600 sout.ofp = fopen(oname, "rb+");
601 if (sout.ofp == NULL) {
602 if (j == mp->nbins)
603 break; /* assume end of modifier */
604 sprintf(errmsg, "missing recover file '%s'",
605 oname);
606 error(WARNING, errmsg);
607 break;
608 }
609 nvals = lseek(fileno(sout.ofp), 0, SEEK_END);
610 if (nvals <= 0) {
611 lastout = 0; /* empty output, quit here */
612 fclose(sout.ofp);
613 break;
614 }
615 if (!sout.reclen) {
616 if (!(ofl & OF_BIN)) {
617 sprintf(errmsg,
618 "need -bn to recover file '%s'",
619 oname);
620 error(USER, errmsg);
621 }
622 recsiz = outvsiz;
623 } else
624 recsiz = outvsiz * sout.reclen;
625
626 lseek(fileno(sout.ofp), 0, SEEK_SET);
627 if (header && checkheader(sout.ofp, outvfmt, NULL) != 1) {
628 sprintf(errmsg, "format mismatch for '%s'",
629 oname);
630 error(USER, errmsg);
631 }
632 sout.xr = xres; sout.yr = yres;
633 if ((sout.xr > 0) & (sout.yr > 0) &&
634 (!fscnresolu(&xr, &yr, sout.ofp) ||
635 (xr != sout.xr) |
636 (yr != sout.yr))) {
637 sprintf(errmsg, "resolution mismatch for '%s'",
638 oname);
639 error(USER, errmsg);
640 }
641 nvals = (nvals - (off_t)ftell(sout.ofp)) / recsiz;
642 if ((lastout < 0) | (nvals < lastout))
643 lastout = nvals;
644 if (oent->key == NULL) /* new entry */
645 oent->key = strcpy((char *)
646 malloc(strlen(oname)+1), oname);
647 if (oent->data == NULL)
648 oent->data = (char *)malloc(sizeof(STREAMOUT));
649 *(STREAMOUT *)oent->data = sout;
650 if (!(ofl & OF_BIN))
651 break; /* no bin separation */
652 }
653 if (!lastout) { /* empty output */
654 error(WARNING, "no previous data to recover");
655 lu_done(&ofiletab); /* reclose all outputs */
656 return;
657 }
658 if (j > mp->nbins) { /* check modifier size */
659 sprintf(errmsg,
660 "mismatched -bn setting for recovering '%s'",
661 modname[i]);
662 error(USER, errmsg);
663 }
664 }
665 if (lastout < 0) {
666 error(WARNING, "no output files to recover");
667 return;
668 }
669 if (raysleft && lastout >= raysleft/accumulate) {
670 error(WARNING, "output appears to be complete");
671 /* XXX should read & discard input? */
672 quit(0);
673 }
674 /* seek on all files */
675 nvals = lastout * outvsiz;
676 lu_doall(&ofiletab, &myseeko, &nvals);
677 /* skip repeated input */
678 lastout *= accumulate;
679 for (nvals = 0; nvals < lastout; nvals++) {
680 FVECT vdummy;
681 if (getvec(vdummy) < 0 || getvec(vdummy) < 0)
682 error(USER, "unexpected EOF on input");
683 }
684 lastray = lastdone = (RNUMBER)lastout;
685 if (raysleft)
686 raysleft -= lastray;
687 }