ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rtrace.c
Revision: 2.99
Committed: Mon Jul 20 15:54:29 2020 UTC (3 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 2.98: +4 -2 lines
Log Message:
fix(mkillum, rcontrib, rtrace, ranimove, rsensor): stall under macOS 10.15
due to broken flockfile() implementation -- workaround is better, anyway

File Contents

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