ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.12
Committed: Wed Jul 9 21:09:28 2014 UTC (9 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.11: +2 -3 lines
Log Message:
Removed redundant NCOLS= line in header

File Contents

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