ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.8
Committed: Wed Aug 7 05:10:09 2013 UTC (10 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.7: +2 -13 lines
Log Message:
Eliminated a number of minor warnings (all innocuous)

File Contents

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