ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.9
Committed: Thu May 29 04:56:43 2014 UTC (9 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.8: +8 -6 lines
Log Message:
Added NCOLS= and NCOMP= to header output

File Contents

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