ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.10
Committed: Fri May 30 16:05:52 2014 UTC (9 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.9: +4 -3 lines
Log Message:
Added NCOMP to header

File Contents

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