ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhcopy.c
Revision: 3.37
Committed: Tue Dec 19 20:22:36 2023 UTC (4 months, 1 week ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 3.36: +2 -2 lines
Log Message:
perf(rhcopy): Increased default memory cache size

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rhcopy.c,v 3.36 2023/02/06 22:40:21 greg Exp $";
3 #endif
4 /*
5 * Copy data into a holodeck file
6 */
7
8 #include "platform.h"
9 #include "rterror.h"
10 #include "holo.h"
11 #include "view.h"
12
13 #ifndef BKBSIZE
14 #define BKBSIZE 256 /* beam clump size (kilobytes) */
15 #endif
16 /* possible operations */
17 #define FROM_HOLO 1 /* copy between holodecks */
18 #define FROM_PICZ 2 /* copy from HDR + depth to holodeck */
19 #define FROM_STDIN 3 /* copy from stdin to holodeck */
20 #define TO_STDOUT 4 /* copy rays from holodeck to stdout */
21
22 int operation = 0; /* what we are doing */
23 char *rspec = ""; /* ray details for i/o */
24 int checkdepth = 1; /* check depth (!-d option)? */
25 int checkrepeats = 0; /* check for repeats (-u option)? */
26 int nholosects; /* number of original holodeck sections */
27 int iofmt = 'a'; /* input/output format for rays */
28
29 /* holodeck flags */
30 #define H_BADF 01 /* bad format */
31 #define H_OBST 02 /* OBSTRUCTIONS= True */
32 #define H_OBSF 04 /* OBSTRUCTIONS= False */
33 #define H_VDST 010 /* VDISTANCE= True */
34 #define H_SWAP 020 /* byte order is different */
35
36 char *progname; /* global argv[0] */
37
38 struct phead {
39 VIEW vw;
40 double expos;
41 short gotview;
42 short badfmt;
43 short altprims;
44 };
45
46 typedef struct {
47 FVECT ro;
48 FVECT rd;
49 RREAL d;
50 COLR cv;
51 } RAYPAR;
52
53 static int openholo(char *fname, int append);
54 static void addray(RAYPAR *rp);
55 static int readval(RREAL *v, int n, FILE *fp);
56 static void readrays(FILE *fp);
57 static int writeval(RREAL *v, int n, FILE *fp);
58 static int write_ray(RAYPAR *rp, FILE *fp);
59 static void writerays(FILE *fp);
60 static gethfunc holheadline;
61 static int bpcmp(const void *b1p, const void *b2p);
62 static int addclump(HOLO *hp, int *bq, int nb);
63 static void addholo(char *hdf);
64 static gethfunc picheadline;
65 static void addpicz(char *pcf, char *zbf);
66
67
68 int
69 main(
70 int argc,
71 char *argv[]
72 )
73 {
74 int i;
75
76 progname = argv[0];
77 for (i = 2; i < argc && argv[i][0] == '-'; i++)
78 switch (argv[i][1]) {
79 case 'u':
80 checkrepeats = 1;
81 break;
82 case 'd':
83 checkdepth = 0;
84 break;
85 case 'f':
86 iofmt = argv[i][2];
87 if (!strchr("afd", iofmt))
88 error(USER, "-f? i/o format must be 'a', 'f', or 'd'");
89 break;
90 case 'h':
91 operation = FROM_HOLO;
92 break;
93 case 'p':
94 operation = FROM_PICZ;
95 break;
96 case 'i':
97 operation = FROM_STDIN;
98 rspec = argv[i]+2;
99 break;
100 case 'o':
101 operation = TO_STDOUT;
102 rspec = argv[i]+2;
103 break;
104 default:
105 goto userr;
106 }
107 if (!operation | (i > argc-((operation==FROM_HOLO)|(operation==FROM_PICZ))))
108 goto userr;
109 if (operation == FROM_PICZ && (argc-i)%2)
110 goto userr;
111 nholosects = openholo(argv[1], (operation != TO_STDOUT));
112 /* check requested i/o is compatible */
113 if (strchr(rspec, 'l') && !(*(int *)hdlist[0]->priv & H_VDST))
114 error(USER, "i/o parameter 'l' incompatible with VDISTANCE=False");
115 if (strchr(rspec, 'L') && *(int *)hdlist[0]->priv & H_VDST)
116 error(USER, "i/o parameter 'L' incompatible with VDISTANCE=True");
117
118 switch (operation) { /* perform requested operation */
119 case FROM_PICZ:
120 for ( ; i < argc; i += 2)
121 addpicz(argv[i], argv[i+1]);
122 break;
123 case FROM_HOLO:
124 if (BKBSIZE*1024*1.5 > hdcachesize)
125 hdcachesize = BKBSIZE*1024*1.5;
126 for ( ; i < argc; i++)
127 addholo(argv[i]);
128 break;
129 case FROM_STDIN:
130 readrays(stdin);
131 break;
132 case TO_STDOUT:
133 writerays(stdout);
134 break;
135 }
136 quit(0);
137 userr:
138 fprintf(stderr, "Usage: %s dest.hdk [-u][-d] -h inp1.hdk ..\n",
139 progname);
140 fprintf(stderr, " Or: %s dest.hdk [-u][-d] -p inp1.hdr inp1.zbf ..\n",
141 progname);
142 fprintf(stderr, " Or: %s dest.hdk [-f{a|f|d}][-u][-d] -i[odplLv]\n",
143 progname);
144 fprintf(stderr, " Or: %s src.hdk [-f{a|f|d}] -o[odplLv] ..\n",
145 progname);
146 exit(1);
147 }
148
149 static int
150 holheadline( /* check holodeck header line */
151 char *s,
152 void *vhf
153 )
154 {
155 int be;
156 char fmt[MAXFMTLEN];
157 int *hf = (int *)vhf;
158
159 if (formatval(fmt, s)) {
160 if (strcmp(fmt, HOLOFMT))
161 *hf |= H_BADF;
162 else
163 *hf &= ~H_BADF;
164 return(0);
165 }
166 if (!strncmp(s, "OBSTRUCTIONS=", 13)) {
167 s += 13;
168 while (*s == ' ') s++;
169 if ((*s == 't') | (*s == 'T'))
170 *hf |= H_OBST;
171 else if ((*s == 'f') | (*s == 'F'))
172 *hf |= H_OBSF;
173 else
174 error(WARNING, "bad OBSTRUCTIONS value in holodeck");
175 return(0);
176 }
177 if (!strncmp(s, "VDISTANCE=", 10)) {
178 s += 10;
179 while (*s == ' ') s++;
180 if ((*s == 't') | (*s == 'T'))
181 *hf |= H_VDST;
182 else if ((*s != 'f') % (*s != 'F'))
183 error(WARNING, "bad VDISTANCE value in holodeck");
184 return(0);
185 }
186 if ((be = isbigendian(s)) >= 0) {
187 if (be != nativebigendian())
188 *hf |= H_SWAP;
189 return(0);
190 }
191 return(0);
192 }
193
194 int
195 openholo( /* open existing holodeck file for i/o */
196 char *fname,
197 int append
198 )
199 {
200 FILE *fp;
201 int fd;
202 int hflags = 0;
203 int *hfstore;
204 off_t nextloc;
205 int n;
206 /* open holodeck file */
207 if ((fp = fopen(fname, append ? "rb+" : "rb")) == NULL) {
208 sprintf(errmsg, "cannot open \"%s\" for %s", fname,
209 append ? "appending" : "reading");
210 error(SYSTEM, errmsg);
211 }
212 /* check header and magic number */
213 if (getheader(fp, holheadline, &hflags) < 0 ||
214 hflags&(H_BADF|H_SWAP) || getw(fp) != HOLOMAGIC) {
215 sprintf(errmsg, "holodeck \"%s\" not in expected format", fname);
216 error(USER, errmsg);
217 }
218 fd = dup(fileno(fp)); /* dup file handle */
219 nextloc = ftell(fp); /* get stdio position */
220 fclose(fp); /* done with stdio */
221 hfstore = (int *)malloc(sizeof(int)); /* tiny memory leak but who cares? */
222 *hfstore = hflags;
223 for (n = 0; nextloc > 0L; n++) { /* initialize each section */
224 lseek(fd, nextloc, SEEK_SET);
225 read(fd, (char *)&nextloc, sizeof(nextloc));
226 hdinit(fd, NULL)->priv = hfstore;
227 }
228 return(n);
229 }
230
231 void
232 addray( /* add a ray to our output holodeck */
233 RAYPAR *rp
234 )
235 {
236 int sn, bi, n;
237 HOLO *hp;
238 GCOORD gc[2];
239 uby8 rr[2][2];
240 BEAM *bp;
241 double d0, d1;
242 unsigned dc;
243 RAYVAL *rv;
244 /* check each output section */
245 for (sn = nholosects; sn--; ) {
246 hp = hdlist[sn];
247 d0 = hdinter(gc, rr, &d1, hp, rp->ro, rp->rd);
248 if (rp->d <= d0 || d1 < -0.001)
249 continue; /* missed section */
250 if (checkdepth) { /* check depth */
251 if (*(int *)hp->priv & H_OBST && d0 < -0.001)
252 continue; /* ray starts too late */
253 if (*(int *)hp->priv & H_OBSF && rp->d < 0.999*d1)
254 continue; /* ray ends too soon */
255 }
256 dc = hdcode(hp, rp->d-d0);
257 bi = hdbindex(hp, gc); /* check for duplicates */
258 if (checkrepeats && (bp = hdgetbeam(hp, bi)) != NULL) {
259 for (n = bp->nrm, rv = hdbray(bp); n--; rv++)
260 if ((rv->d == dc || *(int *)hp->priv & (H_OBST|H_OBSF)) &&
261 rv->r[0][0] == rr[0][0] &&
262 rv->r[0][1] == rr[0][1] &&
263 rv->r[1][0] == rr[1][0] &&
264 rv->r[1][1] == rr[1][1])
265 break;
266 if (n >= 0)
267 continue; /* found a matching ray */
268 }
269 rv = hdnewrays(hp, bi, 1);
270 rv->d = dc;
271 rv->r[0][0] = rr[0][0]; rv->r[0][1] = rr[0][1];
272 rv->r[1][0] = rr[1][0]; rv->r[1][1] = rr[1][1];
273 copycolr(rv->v, rp->cv);
274 }
275 }
276
277 /* Read n-vector from file stream */
278 static int
279 readval(RREAL *v, int n, FILE *fp)
280 {
281 int i;
282 #ifdef SMLFLT
283 double vd[3];
284 switch (iofmt) {
285 case 'f':
286 return getbinary(v, sizeof(float), n, fp);
287 case 'd':
288 n = getbinary(vd, sizeof(double), n, fp);
289 for (i = n; i-- > 0; ) v[i] = vd[i];
290 return n;
291 case 'a':
292 for (i = 0; i < n; i++)
293 if (fscanf(fp, "%f ", &v[i]) != 1)
294 break;
295 return i;
296 }
297 #else
298 float vf[3];
299 switch (iofmt) {
300 case 'd':
301 return getbinary(v, sizeof(double), n, fp);
302 case 'f':
303 n = getbinary(vf, sizeof(float), n, fp);
304 for (i = n; i-- > 0; ) v[i] = vf[i];
305 return n;
306 case 'a':
307 for (i = 0; i < n; i++)
308 if (fscanf(fp, "%lf ", &v[i]) != 1)
309 break;
310 return i;
311 }
312 #endif
313 return -1;
314 }
315
316 #define GOT_ORG 0x01
317 #define GOT_DIR 0x02
318 #define GOT_LEN 0x04
319 #define GOT_VAL 0x10
320 #define ALSO_POS 0x20
321 #define BAD_DIR 0x40
322 #define BAD_LEN 0x80
323
324 /* Read rays from stream and add to holodeck */
325 static void
326 readrays(FILE *fp)
327 {
328 if (iofmt != 'a')
329 SET_FILE_BINARY(fp);
330 #ifdef getc_unlocked
331 flockfile(fp);
332 #endif
333 while (!feof(fp)) { /* read entirety of input */
334 RAYPAR ryp;
335 FVECT pos;
336 FVECT col;
337 int flags = 0;
338 int i;
339 for (i = 0; rspec[i]; i++) {
340 switch (rspec[i]) {
341 case 'o': /* ray origin */
342 if (readval(ryp.ro, 3, fp) < 3)
343 break;
344 flags |= GOT_ORG;
345 continue;
346 case 'd': /* ray direction */
347 if (readval(ryp.rd, 3, fp) < 3)
348 break;
349 if (normalize(ryp.rd) == 0)
350 flags |= BAD_DIR;
351 else
352 flags |= GOT_DIR;
353 continue;
354 case 'p': /* ray intersection */
355 if (readval(pos, 3, fp) < 3)
356 break;
357 flags |= ALSO_POS;
358 continue;
359 case 'L': /* ray first length */
360 case 'l': /* ray virtual length */
361 if (readval(&ryp.d, 1, fp) < 1)
362 break;
363 if (ryp.d <= FTINY)
364 flags |= BAD_LEN;
365 else
366 flags |= GOT_LEN;
367 continue;
368 case 'v': /* ray value */
369 if (readval(col, 3, fp) < 3)
370 break;
371 setcolr(ryp.cv, col[0], col[1], col[2]);
372 flags |= GOT_VAL;
373 continue;
374 default:
375 sprintf(errmsg, "unsupported parameter '%c' in -i%s",
376 rspec[i], rspec);
377 error(USER, errmsg);
378 }
379 if (!flags) /* got nothing, so may be normal EOF */
380 return;
381 }
382 if (flags & (BAD_DIR|BAD_LEN))
383 continue; /* just a bad ray is all -- skip */
384 if (!(flags & GOT_VAL))
385 goto missingData;
386 if ((flags & (GOT_ORG|GOT_DIR|GOT_LEN)) != (GOT_ORG|GOT_DIR|GOT_LEN)) {
387 if (!(flags & ALSO_POS))
388 goto missingData;
389 if (flags & GOT_ORG) {
390 VSUB(ryp.rd, pos, ryp.ro);
391 ryp.d = normalize(ryp.rd);
392 if (ryp.d == 0)
393 continue;
394 } else if ((flags & (GOT_DIR|GOT_LEN)) == (GOT_DIR|GOT_LEN)) {
395 VSUM(ryp.ro, pos, ryp.rd, -ryp.d);
396 } else
397 goto missingData;
398 }
399 addray(&ryp); /* add our ray to holodeck */
400 }
401 return;
402 missingData:
403 sprintf(errmsg, "insufficient data or read error for -i%s", rspec);
404 error(USER, errmsg);
405 }
406
407 /* Write vector value to file stream */
408 static int
409 writeval(RREAL *v, int n, FILE *fp)
410 {
411 int i;
412
413 if (iofmt == 'a') {
414 for (i = 0; i < n; i++)
415 if (fprintf(fp, "\t%.4e", v[i]) < 0)
416 break;
417 return i;
418 }
419 #ifdef SMLFLT
420 if (iofmt == 'd') {
421 double vd[3];
422 for (i = n; i--; ) vd[i] = v[i];
423 return putbinary(vd, sizeof(double), n, fp);
424 }
425 #else
426 if (iofmt == 'f') {
427 float vf[3];
428 for (i = n; i--; ) vf[i] = v[i];
429 return putbinary(vf, sizeof(float), n, fp);
430 }
431 #endif
432 return putbinary(v, sizeof(*v), n, fp);
433 }
434
435 /* Write out an individual ray as requested */
436 static int
437 write_ray(RAYPAR *rp, FILE *fp)
438 {
439 COLOR cval;
440 FVECT v3;
441 char *typ = rspec;
442
443 for ( ; ; ) {
444 switch (*typ++) {
445 case 'o': /* ray origin */
446 if (writeval(rp->ro, 3, fp) < 3)
447 break;
448 continue;
449 case 'd': /* ray direction */
450 if (writeval(rp->rd, 3, fp) < 3)
451 break;
452 continue;
453 case 'p': /* ray intersection */
454 VSUM(v3, rp->ro, rp->rd, rp->d);
455 if (writeval(v3, 3, fp) < 3)
456 break;
457 continue;
458 case 'L': /* ray first length */
459 case 'l': /* ray virtual length */
460 if (writeval(&rp->d, 1, fp) < 1)
461 break;
462 continue;
463 case 'v': /* ray value */
464 colr_color(cval, rp->cv);
465 VCOPY(v3, cval);
466 if (writeval(v3, 3, fp) < 3)
467 break;
468 continue;
469 case '\0': /* end of spec -- success */
470 if (iofmt == 'a')
471 fputc('\n', fp);
472 return(1);
473 default:
474 sprintf(errmsg, "unsupported parameter '%c' in -o%s", typ[-1], rspec);
475 }
476 break; /* land here on error */
477 }
478 return 0; /* write error? */
479 }
480
481 static BEAMI *beamdir;
482
483 static int
484 bpcmp( /* compare beam positions on disk */
485 const void *b1p,
486 const void *b2p
487 )
488 {
489 off_t pdif = beamdir[*(int *)b1p].fo - beamdir[*(int *)b2p].fo;
490
491 if (pdif > 0L) return(1);
492 if (pdif < 0L) return(-1);
493 return(0);
494 }
495
496 /* Write all rays from holodeck to stream */
497 static void
498 writerays(FILE *fp)
499 {
500 int sn, bi, k;
501 GCOORD gc[2];
502 RAYVAL *rv;
503 RAYPAR ryp;
504
505 if (!*rspec) {
506 error(WARNING, "empty -o* output spec, quitting");
507 return;
508 }
509 if (iofmt != 'a')
510 SET_FILE_BINARY(fp);
511 #ifdef getc_unlocked
512 flockfile(fp);
513 #endif
514 for (sn = 0; sn < nholosects; sn++) { /* write each holodeck section */
515 HOLO *hp = hdlist[sn];
516 int nb = nbeams(hp); /* sort beams by file location */
517 int *bq = (int *)malloc(nb*sizeof(int));
518 if (!bq)
519 error(SYSTEM, "out of memory in writerays()");
520 for (bi = nb; bi--; ) bq[bi] = bi+1;
521 beamdir = hp->bi;
522 qsort(bq, nb, sizeof(*bq), bpcmp);
523 for (bi = 0; bi < nb; bi++) {
524 BEAM *bp = hdgetbeam(hp, bq[bi]);
525 if (!bp) /* empty beam? */
526 continue;
527 hdbcoord(gc, hp, bq[bi]);
528 rv = hdbray(bp);
529 for (k = bp->nrm; k--; rv++) {
530 ryp.d = hdray(ryp.ro, ryp.rd, hp, gc, rv->r);
531 if (*(int *)hp->priv & H_OBSF)
532 VSUM(ryp.ro, ryp.ro, ryp.rd, ryp.d);
533 else
534 ryp.d = 0.;
535 ryp.d = hddepth(hp, rv->d) - ryp.d;
536 copycolr(ryp.cv, rv->v);
537 if (!write_ray(&ryp, fp)) {
538 free(bq);
539 goto writError;
540 }
541 }
542 hdfreebeam(hp, bq[bi]);
543 }
544 free(bq);
545 }
546 if (fflush(fp) != EOF)
547 return;
548 writError:
549 error(SYSTEM, "error writing holodeck rays");
550 }
551
552 static int
553 addclump( /* transfer the given clump and free */
554 HOLO *hp,
555 int *bq,
556 int nb
557 )
558 {
559 GCOORD gc[2];
560 RAYPAR ryp;
561 RAYVAL *rv;
562 int i;
563 int k;
564 BEAM *bp;
565 /* sort based on file position */
566 beamdir = hp->bi;
567 qsort(bq, nb, sizeof(*bq), bpcmp);
568 /* transfer each beam */
569 for (i = 0; i < nb; i++) {
570 bp = hdgetbeam(hp, bq[i]);
571 hdbcoord(gc, hp, bq[i]);
572 rv = hdbray(bp); /* add each ray to output */
573 for (k = bp->nrm; k--; rv++) {
574 ryp.d = hdray(ryp.ro, ryp.rd, hp, gc, rv->r);
575 if (*(int *)hp->priv & H_OBSF)
576 VSUM(ryp.ro, ryp.ro, ryp.rd, ryp.d);
577 else
578 ryp.d = 0.;
579 ryp.d = hddepth(hp, rv->d) - ryp.d;
580 copycolr(ryp.cv, rv->v);
581 addray(&ryp);
582 }
583 hdfreebeam(hp, bq[i]); /* free the beam */
584 }
585 return(0);
586 }
587
588
589 void
590 addholo( /* add a holodeck file */
591 char *hdf
592 )
593 {
594 int fd;
595 /* open the holodeck for reading */
596 openholo(hdf, 0);
597 fd = hdlist[nholosects]->fd; /* remember the file handle */
598 while (hdlist[nholosects] != NULL) { /* load each section */
599 /* clump the beams */
600 clumpbeams(hdlist[nholosects], 0, BKBSIZE*1024, addclump);
601 hddone(hdlist[nholosects]); /* free the section */
602 }
603 close(fd); /* close input file */
604 hdflush(NULL); /* flush output */
605 }
606
607
608
609 static int
610 picheadline( /* process picture header line */
611 char *s,
612 void *vph
613 )
614 {
615 char fmt[32];
616 struct phead *ph = (struct phead *)vph;
617
618 if (formatval(fmt, s)) {
619 ph->badfmt = strcmp(fmt, COLRFMT);
620 return(0);
621 }
622 if (isprims(s)) {
623 ph->altprims++; /* don't want to deal with this */
624 return(0);
625 }
626 if (isexpos(s)) {
627 ph->expos *= exposval(s);
628 return(0);
629 }
630 if (isview(s)) {
631 ph->gotview += sscanview(&ph->vw, s);
632 return(0);
633 }
634 return(0);
635 }
636
637
638 void
639 addpicz( /* add a picture + depth-buffer */
640 char *pcf,
641 char *zbf
642 )
643 {
644 FILE *pfp;
645 int zfd;
646 COLR *cscn;
647 float *zscn;
648 struct phead phd;
649 int eshft;
650 double emult;
651 RESOLU prs;
652 RREAL vl[2];
653 RAYPAR ryp;
654 double aftd;
655 int j, i;
656 /* open picture & get header */
657 if ((pfp = fopen(pcf, "rb")) == NULL) {
658 sprintf(errmsg, "cannot open picture file \"%s\"", pcf);
659 error(SYSTEM, pcf);
660 }
661 phd.vw = stdview;
662 phd.expos = 1.0;
663 phd.badfmt = phd.gotview = phd.altprims = 0;
664 if (getheader(pfp, picheadline, &phd) < 0 ||
665 phd.badfmt || !fgetsresolu(&prs, pfp)) {
666 sprintf(errmsg, "bad format for picture file \"%s\"", pcf);
667 error(USER, errmsg);
668 }
669 if (!phd.gotview || setview(&phd.vw) != NULL) {
670 sprintf(errmsg, "missing/illegal view in picture \"%s\"",
671 pcf);
672 error(USER, errmsg);
673 }
674 if (phd.altprims) {
675 sprintf(errmsg, "ignoring color primaries in picture \"%s\"",
676 pcf);
677 error(WARNING, errmsg);
678 }
679 /* open depth buffer */
680 if ((zfd = open_float_depth(zbf, prs.xr*prs.yr)) < 0)
681 quit(1);
682 /* figure out what to do about exposure */
683 if ((phd.expos < 0.99) | (phd.expos > 1.01)) {
684 emult = -log(phd.expos)/log(2.);
685 eshft = emult >= 0. ? emult+.5 : emult-.5;
686 emult -= (double)eshft;
687 if ((emult <= 0.01) & (emult >= -0.01))
688 emult = -1.;
689 else {
690 emult = 1./phd.expos;
691 eshft = 0;
692 }
693 } else {
694 emult = -1.;
695 eshft = 0;
696 }
697 /* allocate buffers */
698 cscn = (COLR *)malloc(scanlen(&prs)*sizeof(COLR));
699 zscn = (float *)malloc(scanlen(&prs)*sizeof(float));
700 if ((cscn == NULL) | (zscn == NULL))
701 error(SYSTEM, "out of memory in addpicz");
702 /* read and process each scanline */
703 for (j = 0; j < numscans(&prs); j++) {
704 i = scanlen(&prs); /* read colrs */
705 if (freadcolrs(cscn, i, pfp) < 0) {
706 sprintf(errmsg, "error reading picture \"%s\"", pcf);
707 error(USER, errmsg);
708 }
709 if (eshft) /* shift exposure */
710 shiftcolrs(cscn, i, eshft);
711 /* read depth */
712 if (read(zfd, zscn, i*sizeof(float)) != i*sizeof(float)) {
713 sprintf(errmsg, "error reading depth file \"%s\"", zbf);
714 error(USER, errmsg);
715 }
716 while (i--) { /* process each pixel */
717 if (zscn[i] <= 0.0)
718 continue; /* illegal depth */
719 pix2loc(vl, &prs, i, j);
720 aftd = viewray(ryp.ro, ryp.rd, &phd.vw, vl[0], vl[1]);
721 if (aftd < -FTINY)
722 continue; /* off view */
723 if (aftd > FTINY && zscn[i] > aftd)
724 continue; /* aft clipped */
725 ryp.d = (RREAL)zscn[i];
726 copycolr(ryp.cv, cscn[i]);
727 if (emult > 0.) { /* whatta pain */
728 COLOR ctmp;
729 colr_color(ctmp, ryp.cv);
730 scalecolor(ctmp, emult);
731 setcolr(ryp.cv, colval(ctmp,RED),
732 colval(ctmp,GRN), colval(ctmp,BLU));
733 }
734 addray(&ryp);
735 }
736 }
737 /* write output and free beams */
738 hdflush(NULL);
739 /* clean up */
740 free((void *)cscn);
741 free((void *)zscn);
742 fclose(pfp);
743 close(zfd);
744 }
745
746
747 void
748 eputs( /* put error message to stderr */
749 const char *s
750 )
751 {
752 static int midline = 0;
753
754 if (!*s)
755 return;
756 if (!midline++) { /* prepend line with program name */
757 fputs(progname, stderr);
758 fputs(": ", stderr);
759 }
760 fputs(s, stderr);
761 if (s[strlen(s)-1] == '\n') {
762 fflush(stderr);
763 midline = 0;
764 }
765 }
766
767
768 void
769 quit( /* exit the program gracefully */
770 int code
771 )
772 {
773 hdsync(NULL, 1); /* write out any buffered data */
774 exit(code);
775 }