ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.1
Committed: Sat Jun 9 07:16:47 2012 UTC (11 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Created rcontrib program (eventually to replace rtcontrib)

File Contents

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