ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.13
Committed: Thu Jul 24 16:28:17 2014 UTC (9 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R2P2, rad4R2, rad4R2P1
Changes since 2.12: +9 -5 lines
Log Message:
Made NROWS/NCOLS more consistent with resolution string

File Contents

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