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

# Content
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 }