ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.8
Committed: Wed Aug 7 05:10:09 2013 UTC (10 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.7: +2 -13 lines
Log Message:
Eliminated a number of minor warnings (all innocuous)

File Contents

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