ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.11
Committed: Fri Jun 13 01:16:41 2014 UTC (9 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.10: +18 -6 lines
Log Message:
Added NROWS= setting to header

File Contents

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