ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.5
Committed: Tue Jun 19 00:12:08 2012 UTC (11 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.4: +3 -2 lines
Log Message:
Added quick-exit mode and fixed bug in recovery option with -c > 1

File Contents

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