ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.7
Committed: Thu Nov 15 19:41:03 2012 UTC (11 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.6: +4 -4 lines
Log Message:
Tweaks and fixes related to flushing with -c >1

File Contents

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