ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.3
Committed: Mon Jun 11 05:07:55 2012 UTC (11 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.2: +25 -4 lines
Log Message:
Fixed a number of bugs -- still testing

File Contents

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