ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.10
Committed: Fri May 30 16:05:52 2014 UTC (9 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.9: +4 -3 lines
Log Message:
Added NCOMP to header

File Contents

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