ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.22
Committed: Tue Feb 7 16:48:14 2017 UTC (7 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R2, rad5R1
Changes since 2.21: +2 -2 lines
Log Message:
Minor changes

File Contents

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