ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rtrace.c
Revision: 2.95
Committed: Thu May 7 17:13:08 2020 UTC (4 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.94: +1 -2 lines
Log Message:
Removed superfluous declaration

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rtrace.c,v 2.94 2020/04/06 21:09:07 greg Exp $";
3 #endif
4 /*
5 * rtrace.c - program and variables for individual ray tracing.
6 */
7
8 #include "copyright.h"
9
10 /*
11 * Input is in the form:
12 *
13 * xorg yorg zorg xdir ydir zdir
14 *
15 * The direction need not be normalized. Output is flexible.
16 * If the direction vector is (0,0,0), then the output is flushed.
17 * All values default to ascii representation of real
18 * numbers. Binary representations can be selected
19 * with '-ff' for float or '-fd' for double. By default,
20 * radiance is computed. The '-i' or '-I' options indicate that
21 * irradiance values are desired.
22 */
23
24 #include <time.h>
25
26 #include "platform.h"
27 #include "ray.h"
28 #include "ambient.h"
29 #include "source.h"
30 #include "otypes.h"
31 #include "otspecial.h"
32 #include "resolu.h"
33 #include "random.h"
34
35 extern int inform; /* input format */
36 extern int outform; /* output format */
37 extern char *outvals; /* output values */
38
39 extern int imm_irrad; /* compute immediate irradiance? */
40 extern int lim_dist; /* limit distance? */
41
42 extern char *tralist[]; /* list of modifers to trace (or no) */
43 extern int traincl; /* include == 1, exclude == 0 */
44
45 extern int hresolu; /* horizontal resolution */
46 extern int vresolu; /* vertical resolution */
47
48 int castonly = 0; /* only doing ray-casting? */
49
50 #ifndef MAXTSET
51 #define MAXTSET 8191 /* maximum number in trace set */
52 #endif
53 OBJECT traset[MAXTSET+1]={0}; /* trace include/exclude set */
54
55 static RAY thisray; /* for our convenience */
56
57 static FILE *inpfp = NULL; /* input stream pointer */
58
59 static FVECT *inp_queue = NULL; /* ray input queue if flushing */
60 static int inp_qpos = 0; /* next ray to return */
61 static int inp_qend = 0; /* number of rays in this work group */
62
63 typedef void putf_t(RREAL *v, int n);
64 static putf_t puta, putd, putf, putrgbe;
65
66 typedef void oputf_t(RAY *r);
67 static oputf_t oputo, oputd, oputv, oputV, oputl, oputL, oputc, oputp,
68 oputr, oputR, oputx, oputX, oputn, oputN, oputs,
69 oputw, oputW, oputm, oputM, oputtilde;
70
71 extern void tranotify(OBJECT obj);
72 static int is_fifo(FILE *fp);
73 static void bogusray(void);
74 static void raycast(RAY *r);
75 static void rayirrad(RAY *r);
76 static void rtcompute(FVECT org, FVECT dir, double dmax);
77 static int printvals(RAY *r);
78 static int getvec(FVECT vec, int fmt, FILE *fp);
79 static int iszerovec(const FVECT vec);
80 static double nextray(FVECT org, FVECT dir);
81 static void tabin(RAY *r);
82 static void ourtrace(RAY *r);
83
84 static oputf_t *ray_out[32], *every_out[32];
85 static putf_t *putreal;
86
87
88 void
89 quit( /* quit program */
90 int code
91 )
92 {
93 if (ray_pnprocs > 0) /* close children if any */
94 ray_pclose(0);
95 #ifndef NON_POSIX
96 else if (!ray_pnprocs) {
97 headclean(); /* delete header file */
98 pfclean(); /* clean up persist files */
99 }
100 #endif
101 exit(code);
102 }
103
104
105 char *
106 formstr( /* return format identifier */
107 int f
108 )
109 {
110 switch (f) {
111 case 'a': return("ascii");
112 case 'f': return("float");
113 case 'd': return("double");
114 case 'c': return(COLRFMT);
115 }
116 return("unknown");
117 }
118
119
120 void
121 rtrace( /* trace rays from file */
122 char *fname,
123 int nproc
124 )
125 {
126 unsigned long vcount = (hresolu > 1) ? (unsigned long)hresolu*vresolu
127 : (unsigned long)vresolu;
128 long nextflush = (!vresolu | (hresolu <= 1)) * hresolu;
129 int something2flush = 0;
130 FILE *fp;
131 double d;
132 FVECT orig, direc;
133 /* set up input */
134 if (fname == NULL)
135 inpfp = stdin;
136 else if ((inpfp = fopen(fname, "r")) == NULL) {
137 sprintf(errmsg, "cannot open input file \"%s\"", fname);
138 error(SYSTEM, errmsg);
139 }
140 #ifdef getc_unlocked
141 flockfile(inpfp); /* avoid lock/unlock overhead */
142 flockfile(stdout);
143 #endif
144 if (inform != 'a')
145 SET_FILE_BINARY(inpfp);
146 /* set up output */
147 if (castonly || every_out[0] != NULL)
148 nproc = 1; /* don't bother multiprocessing */
149 if ((nextflush > 0) & (nproc > nextflush)) {
150 error(WARNING, "reducing number of processes to match flush interval");
151 nproc = nextflush;
152 }
153 switch (outform) {
154 case 'a': putreal = puta; break;
155 case 'f': putreal = putf; break;
156 case 'd': putreal = putd; break;
157 case 'c':
158 if (outvals[1] || !strchr("vrx", outvals[0]))
159 error(USER, "color format only with -ov, -or, -ox");
160 putreal = putrgbe; break;
161 default:
162 error(CONSISTENCY, "botched output format");
163 }
164 if (nproc > 1) { /* start multiprocessing */
165 ray_popen(nproc);
166 ray_fifo_out = printvals;
167 }
168 if (hresolu > 0) {
169 if (vresolu > 0)
170 fprtresolu(hresolu, vresolu, stdout);
171 else
172 fflush(stdout);
173 }
174 /* process input rays */
175 while ((d = nextray(orig, direc)) >= 0.0) {
176 if (d == 0.0) { /* flush request? */
177 if (something2flush) {
178 if (ray_pnprocs > 1 && ray_fifo_flush() < 0)
179 error(USER, "child(ren) died");
180 bogusray();
181 fflush(stdout);
182 nextflush = (!vresolu | (hresolu <= 1)) * hresolu;
183 something2flush = 0;
184 } else
185 bogusray();
186 } else { /* compute and print */
187 rtcompute(orig, direc, lim_dist ? d : 0.0);
188 if (!--nextflush) { /* flush if time */
189 if (ray_pnprocs > 1 && ray_fifo_flush() < 0)
190 error(USER, "child(ren) died");
191 fflush(stdout);
192 nextflush = hresolu;
193 } else
194 something2flush = 1;
195 }
196 if (ferror(stdout))
197 error(SYSTEM, "write error");
198 if (vcount && !--vcount) /* check for end */
199 break;
200 }
201 if (ray_pnprocs > 1) { /* clean up children */
202 if (ray_fifo_flush() < 0)
203 error(USER, "unable to complete processing");
204 ray_pclose(0);
205 }
206 if (vcount)
207 error(WARNING, "unexpected EOF on input");
208 if (fflush(stdout) < 0)
209 error(SYSTEM, "write error");
210 if (fname != NULL) {
211 fclose(inpfp);
212 inpfp = NULL;
213 }
214 nextray(NULL, NULL);
215 }
216
217
218 static void
219 trace_sources(void) /* trace rays to light sources, also */
220 {
221 int sn;
222
223 for (sn = 0; sn < nsources; sn++)
224 source[sn].sflags |= SFOLLOW;
225 }
226
227
228 int
229 setrtoutput(void) /* set up output tables, return #comp */
230 {
231 char *vs = outvals;
232 oputf_t **table = ray_out;
233 int ncomp = 0;
234
235 if (!*vs)
236 error(USER, "empty output specification");
237
238 castonly = 1; /* sets castonly as side-effect */
239 do
240 switch (*vs) {
241 case 'T': /* trace sources */
242 if (!vs[1]) break;
243 trace_sources();
244 /* fall through */
245 case 't': /* trace */
246 if (!vs[1]) break;
247 *table = NULL;
248 table = every_out;
249 trace = ourtrace;
250 castonly = 0;
251 break;
252 case 'o': /* origin */
253 *table++ = oputo;
254 ncomp += 3;
255 break;
256 case 'd': /* direction */
257 *table++ = oputd;
258 ncomp += 3;
259 break;
260 case 'r': /* reflected contrib. */
261 *table++ = oputr;
262 ncomp += 3;
263 castonly = 0;
264 break;
265 case 'R': /* reflected distance */
266 *table++ = oputR;
267 ncomp++;
268 castonly = 0;
269 break;
270 case 'x': /* xmit contrib. */
271 *table++ = oputx;
272 ncomp += 3;
273 castonly = 0;
274 break;
275 case 'X': /* xmit distance */
276 *table++ = oputX;
277 ncomp++;
278 castonly = 0;
279 break;
280 case 'v': /* value */
281 *table++ = oputv;
282 ncomp += 3;
283 castonly = 0;
284 break;
285 case 'V': /* contribution */
286 *table++ = oputV;
287 ncomp += 3;
288 castonly = 0;
289 if (ambounce > 0 && (ambacc > FTINY || ambssamp > 0))
290 error(WARNING,
291 "-otV accuracy depends on -aa 0 -as 0");
292 break;
293 case 'l': /* effective distance */
294 *table++ = oputl;
295 ncomp++;
296 castonly = 0;
297 break;
298 case 'c': /* local coordinates */
299 *table++ = oputc;
300 ncomp += 2;
301 break;
302 case 'L': /* single ray length */
303 *table++ = oputL;
304 ncomp++;
305 break;
306 case 'p': /* point */
307 *table++ = oputp;
308 ncomp += 3;
309 break;
310 case 'n': /* perturbed normal */
311 *table++ = oputn;
312 ncomp += 3;
313 castonly = 0;
314 break;
315 case 'N': /* unperturbed normal */
316 *table++ = oputN;
317 ncomp += 3;
318 break;
319 case 's': /* surface */
320 *table++ = oputs;
321 ncomp++;
322 break;
323 case 'w': /* weight */
324 *table++ = oputw;
325 ncomp++;
326 break;
327 case 'W': /* coefficient */
328 *table++ = oputW;
329 ncomp += 3;
330 castonly = 0;
331 if (ambounce > 0 && (ambacc > FTINY) | (ambssamp > 0))
332 error(WARNING,
333 "-otW accuracy depends on -aa 0 -as 0");
334 break;
335 case 'm': /* modifier */
336 *table++ = oputm;
337 ncomp++;
338 break;
339 case 'M': /* material */
340 *table++ = oputM;
341 ncomp++;
342 break;
343 case '~': /* tilde */
344 *table++ = oputtilde;
345 break;
346 default:
347 sprintf(errmsg, "unrecognized output option '%c'", *vs);
348 error(USER, errmsg);
349 }
350 while (*++vs);
351
352 *table = NULL;
353 if (*every_out != NULL)
354 ncomp = 0;
355 /* compatibility */
356 if ((do_irrad | imm_irrad) && castonly)
357 error(USER, "-I+ and -i+ options require some value output");
358 for (table = ray_out; *table != NULL; table++) {
359 if ((*table == oputV) | (*table == oputW))
360 error(WARNING, "-oVW options require trace mode");
361 if ((do_irrad | imm_irrad) &&
362 (*table == oputr) | (*table == oputR) |
363 (*table == oputx) | (*table == oputX))
364 error(WARNING, "-orRxX options incompatible with -I+ and -i+");
365 }
366 return(ncomp);
367 }
368
369
370 static void
371 bogusray(void) /* print out empty record */
372 {
373 rayorigin(&thisray, PRIMARY, NULL, NULL);
374 printvals(&thisray);
375 }
376
377
378 static void
379 raycast( /* compute first ray intersection only */
380 RAY *r
381 )
382 {
383 if (!localhit(r, &thescene)) {
384 if (r->ro == &Aftplane) { /* clipped */
385 r->ro = NULL;
386 r->rot = FHUGE;
387 } else
388 sourcehit(r);
389 }
390 }
391
392
393 static void
394 rayirrad( /* compute irradiance rather than radiance */
395 RAY *r
396 )
397 {
398 void (*old_revf)(RAY *) = r->revf;
399 /* pretend we hit surface */
400 r->rxt = r->rot = 1e-5;
401 VSUM(r->rop, r->rorg, r->rdir, r->rot);
402 r->ron[0] = -r->rdir[0];
403 r->ron[1] = -r->rdir[1];
404 r->ron[2] = -r->rdir[2];
405 r->rod = 1.0;
406 /* compute result */
407 r->revf = raytrace;
408 (*ofun[Lamb.otype].funp)(&Lamb, r);
409 r->revf = old_revf;
410 }
411
412
413 static void
414 rtcompute( /* compute and print ray value(s) */
415 FVECT org,
416 FVECT dir,
417 double dmax
418 )
419 {
420 /* set up ray */
421 rayorigin(&thisray, PRIMARY, NULL, NULL);
422 if (imm_irrad) {
423 VSUM(thisray.rorg, org, dir, 1.1e-4);
424 thisray.rdir[0] = -dir[0];
425 thisray.rdir[1] = -dir[1];
426 thisray.rdir[2] = -dir[2];
427 thisray.rmax = 0.0;
428 thisray.revf = rayirrad;
429 } else {
430 VCOPY(thisray.rorg, org);
431 VCOPY(thisray.rdir, dir);
432 thisray.rmax = dmax;
433 if (castonly)
434 thisray.revf = raycast;
435 }
436 if (ray_pnprocs > 1) { /* multiprocessing FIFO? */
437 if (ray_fifo_in(&thisray) < 0)
438 error(USER, "lost children");
439 return;
440 }
441 samplendx++; /* else do it ourselves */
442 rayvalue(&thisray);
443 printvals(&thisray);
444 }
445
446
447 static int
448 printvals( /* print requested ray values */
449 RAY *r
450 )
451 {
452 oputf_t **tp;
453
454 if (ray_out[0] == NULL)
455 return(0);
456 for (tp = ray_out; *tp != NULL; tp++)
457 (**tp)(r);
458 if (outform == 'a')
459 putchar('\n');
460 return(1);
461 }
462
463
464 static int
465 is_fifo( /* check if file pointer connected to pipe */
466 FILE *fp
467 )
468 {
469 #ifdef S_ISFIFO
470 struct stat sbuf;
471
472 if (fstat(fileno(fp), &sbuf) < 0)
473 error(SYSTEM, "fstat() failed on input stream");
474 return(S_ISFIFO(sbuf.st_mode));
475 #else
476 return (fp == stdin); /* just a guess, really */
477 #endif
478 }
479
480
481 static int
482 getvec( /* get a vector from fp */
483 FVECT vec,
484 int fmt,
485 FILE *fp
486 )
487 {
488 static float vf[3];
489 static double vd[3];
490 char buf[32];
491 int i;
492
493 switch (fmt) {
494 case 'a': /* ascii */
495 for (i = 0; i < 3; i++) {
496 if (fgetword(buf, sizeof(buf), fp) == NULL ||
497 !isflt(buf))
498 return(-1);
499 vec[i] = atof(buf);
500 }
501 break;
502 case 'f': /* binary float */
503 if (getbinary(vf, sizeof(float), 3, fp) != 3)
504 return(-1);
505 VCOPY(vec, vf);
506 break;
507 case 'd': /* binary double */
508 if (getbinary(vd, sizeof(double), 3, fp) != 3)
509 return(-1);
510 VCOPY(vec, vd);
511 break;
512 default:
513 error(CONSISTENCY, "botched input format");
514 }
515 return(0);
516 }
517
518
519 static int
520 iszerovec(const FVECT vec)
521 {
522 return (vec[0] == 0.0) & (vec[1] == 0.0) & (vec[2] == 0.0);
523 }
524
525
526 static double
527 nextray( /* return next ray in work group (-1.0 if EOF) */
528 FVECT org,
529 FVECT dir
530 )
531 {
532 const size_t qlength = !vresolu * hresolu;
533
534 if ((org == NULL) | (dir == NULL)) {
535 if (inp_queue != NULL) /* asking to free queue */
536 free(inp_queue);
537 inp_queue = NULL;
538 inp_qpos = inp_qend = 0;
539 return(-1.);
540 }
541 if (!inp_qend) { /* initialize FIFO queue */
542 int rsiz = 6*20; /* conservative ascii ray size */
543 if (inform == 'f') rsiz = 6*sizeof(float);
544 else if (inform == 'd') rsiz = 6*sizeof(double);
545 /* check against pipe limit */
546 if (qlength*rsiz > 512 && is_fifo(inpfp))
547 inp_queue = (FVECT *)malloc(sizeof(FVECT)*2*qlength);
548 inp_qend = -(inp_queue == NULL); /* flag for no queue */
549 }
550 if (inp_qend < 0) { /* not queuing? */
551 if (getvec(org, inform, inpfp) < 0 ||
552 getvec(dir, inform, inpfp) < 0)
553 return(-1.);
554 return normalize(dir);
555 }
556 if (inp_qpos >= inp_qend) { /* need to refill input queue? */
557 for (inp_qend = 0; inp_qend < qlength; inp_qend++) {
558 if (getvec(inp_queue[2*inp_qend], inform, inpfp) < 0
559 || getvec(inp_queue[2*inp_qend+1],
560 inform, inpfp) < 0)
561 break; /* hit EOF */
562 if (iszerovec(inp_queue[2*inp_qend+1])) {
563 ++inp_qend; /* flush request */
564 break;
565 }
566 }
567 inp_qpos = 0;
568 }
569 if (inp_qpos >= inp_qend) /* unexpected EOF? */
570 return(-1.);
571 VCOPY(org, inp_queue[2*inp_qpos]);
572 VCOPY(dir, inp_queue[2*inp_qpos+1]);
573 ++inp_qpos;
574 return normalize(dir);
575 }
576
577
578 void
579 tranotify( /* record new modifier */
580 OBJECT obj
581 )
582 {
583 static int hitlimit = 0;
584 OBJREC *o = objptr(obj);
585 char **tralp;
586
587 if (obj == OVOID) { /* starting over */
588 traset[0] = 0;
589 hitlimit = 0;
590 return;
591 }
592 if (hitlimit || !ismodifier(o->otype))
593 return;
594 for (tralp = tralist; *tralp != NULL; tralp++)
595 if (!strcmp(o->oname, *tralp)) {
596 if (traset[0] >= MAXTSET) {
597 error(WARNING, "too many modifiers in trace list");
598 hitlimit++;
599 return; /* should this be fatal? */
600 }
601 insertelem(traset, obj);
602 return;
603 }
604 }
605
606
607 static void
608 ourtrace( /* print ray values */
609 RAY *r
610 )
611 {
612 oputf_t **tp;
613
614 if (every_out[0] == NULL)
615 return;
616 if (r->ro == NULL) {
617 if (traincl == 1)
618 return;
619 } else if (traincl != -1 && traincl != inset(traset, r->ro->omod))
620 return;
621 tabin(r);
622 for (tp = every_out; *tp != NULL; tp++)
623 (**tp)(r);
624 if (outform == 'a')
625 putchar('\n');
626 }
627
628
629 static void
630 tabin( /* tab in appropriate amount */
631 RAY *r
632 )
633 {
634 const RAY *rp;
635
636 for (rp = r->parent; rp != NULL; rp = rp->parent)
637 putchar('\t');
638 }
639
640
641 static void
642 oputo( /* print origin */
643 RAY *r
644 )
645 {
646 (*putreal)(r->rorg, 3);
647 }
648
649
650 static void
651 oputd( /* print direction */
652 RAY *r
653 )
654 {
655 (*putreal)(r->rdir, 3);
656 }
657
658
659 static void
660 oputr( /* print mirrored contribution */
661 RAY *r
662 )
663 {
664 RREAL cval[3];
665
666 cval[0] = colval(r->mcol,RED);
667 cval[1] = colval(r->mcol,GRN);
668 cval[2] = colval(r->mcol,BLU);
669 (*putreal)(cval, 3);
670 }
671
672
673
674 static void
675 oputR( /* print mirrored distance */
676 RAY *r
677 )
678 {
679 (*putreal)(&r->rmt, 1);
680 }
681
682
683 static void
684 oputx( /* print unmirrored contribution */
685 RAY *r
686 )
687 {
688 RREAL cval[3];
689
690 cval[0] = colval(r->rcol,RED) - colval(r->mcol,RED);
691 cval[1] = colval(r->rcol,GRN) - colval(r->mcol,GRN);
692 cval[2] = colval(r->rcol,BLU) - colval(r->mcol,BLU);
693 (*putreal)(cval, 3);
694 }
695
696
697 static void
698 oputX( /* print unmirrored distance */
699 RAY *r
700 )
701 {
702 (*putreal)(&r->rxt, 1);
703 }
704
705
706 static void
707 oputv( /* print value */
708 RAY *r
709 )
710 {
711 RREAL cval[3];
712
713 cval[0] = colval(r->rcol,RED);
714 cval[1] = colval(r->rcol,GRN);
715 cval[2] = colval(r->rcol,BLU);
716 (*putreal)(cval, 3);
717 }
718
719
720 static void
721 oputV( /* print value contribution */
722 RAY *r
723 )
724 {
725 RREAL contr[3];
726
727 raycontrib(contr, r, PRIMARY);
728 multcolor(contr, r->rcol);
729 (*putreal)(contr, 3);
730 }
731
732
733 static void
734 oputl( /* print effective distance */
735 RAY *r
736 )
737 {
738 RREAL d = raydistance(r);
739
740 (*putreal)(&d, 1);
741 }
742
743
744 static void
745 oputL( /* print single ray length */
746 RAY *r
747 )
748 {
749 (*putreal)(&r->rot, 1);
750 }
751
752
753 static void
754 oputc( /* print local coordinates */
755 RAY *r
756 )
757 {
758 (*putreal)(r->uv, 2);
759 }
760
761
762 static RREAL vdummy[3] = {0.0, 0.0, 0.0};
763
764
765 static void
766 oputp( /* print point */
767 RAY *r
768 )
769 {
770 if (r->rot < FHUGE*.99)
771 (*putreal)(r->rop, 3);
772 else
773 (*putreal)(vdummy, 3);
774 }
775
776
777 static void
778 oputN( /* print unperturbed normal */
779 RAY *r
780 )
781 {
782 if (r->rot < FHUGE*.99) {
783 if (r->rflips & 1) { /* undo any flippin' flips */
784 FVECT unrm;
785 unrm[0] = -r->ron[0];
786 unrm[1] = -r->ron[1];
787 unrm[2] = -r->ron[2];
788 (*putreal)(unrm, 3);
789 } else
790 (*putreal)(r->ron, 3);
791 } else
792 (*putreal)(vdummy, 3);
793 }
794
795
796 static void
797 oputn( /* print perturbed normal */
798 RAY *r
799 )
800 {
801 FVECT pnorm;
802
803 if (r->rot >= FHUGE*.99) {
804 (*putreal)(vdummy, 3);
805 return;
806 }
807 raynormal(pnorm, r);
808 (*putreal)(pnorm, 3);
809 }
810
811
812 static void
813 oputs( /* print name */
814 RAY *r
815 )
816 {
817 if (r->ro != NULL)
818 fputs(r->ro->oname, stdout);
819 else
820 putchar('*');
821 putchar('\t');
822 }
823
824
825 static void
826 oputw( /* print weight */
827 RAY *r
828 )
829 {
830 RREAL rwt = r->rweight;
831
832 (*putreal)(&rwt, 1);
833 }
834
835
836 static void
837 oputW( /* print coefficient */
838 RAY *r
839 )
840 {
841 RREAL contr[3];
842 /* shadow ray not on source? */
843 if (r->rsrc >= 0 && source[r->rsrc].so != r->ro)
844 setcolor(contr, 0.0, 0.0, 0.0);
845 else
846 raycontrib(contr, r, PRIMARY);
847
848 (*putreal)(contr, 3);
849 }
850
851
852 static void
853 oputm( /* print modifier */
854 RAY *r
855 )
856 {
857 if (r->ro != NULL)
858 if (r->ro->omod != OVOID)
859 fputs(objptr(r->ro->omod)->oname, stdout);
860 else
861 fputs(VOIDID, stdout);
862 else
863 putchar('*');
864 putchar('\t');
865 }
866
867
868 static void
869 oputM( /* print material */
870 RAY *r
871 )
872 {
873 OBJREC *mat;
874
875 if (r->ro != NULL) {
876 if ((mat = findmaterial(r->ro)) != NULL)
877 fputs(mat->oname, stdout);
878 else
879 fputs(VOIDID, stdout);
880 } else
881 putchar('*');
882 putchar('\t');
883 }
884
885
886 static void
887 oputtilde( /* output tilde (spacer) */
888 RAY *r
889 )
890 {
891 fputs("~\t", stdout);
892 }
893
894
895 static void
896 puta( /* print ascii value(s) */
897 RREAL *v, int n
898 )
899 {
900 if (n == 3) {
901 printf("%e\t%e\t%e\t", v[0], v[1], v[2]);
902 return;
903 }
904 while (n--)
905 printf("%e\t", *v++);
906 }
907
908
909 static void
910 putd(RREAL *v, int n) /* output binary double(s) */
911 {
912 #ifdef SMLFLT
913 double da[3];
914 int i;
915
916 if (n > 3)
917 error(INTERNAL, "code error in putd()");
918 for (i = n; i--; )
919 da[i] = v[i];
920 putbinary(da, sizeof(double), n, stdout);
921 #else
922 putbinary(v, sizeof(RREAL), n, stdout);
923 #endif
924 }
925
926
927 static void
928 putf(RREAL *v, int n) /* output binary float(s) */
929 {
930 #ifndef SMLFLT
931 float fa[3];
932 int i;
933
934 if (n > 3)
935 error(INTERNAL, "code error in putf()");
936 for (i = n; i--; )
937 fa[i] = v[i];
938 putbinary(fa, sizeof(float), n, stdout);
939 #else
940 putbinary(v, sizeof(RREAL), n, stdout);
941 #endif
942 }
943
944
945 static void
946 putrgbe(RREAL *v, int n) /* output RGBE color */
947 {
948 COLR cout;
949
950 if (n != 3)
951 error(INTERNAL, "putrgbe() not called with 3 components");
952 setcolr(cout, v[0], v[1], v[2]);
953 putbinary(cout, sizeof(cout), 1, stdout);
954 }