ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.6
Committed: Thu Jun 21 17:14:32 2012 UTC (11 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.5: +1 -2 lines
Log Message:
Accommodations for Windows

File Contents

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