ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rtrace.c
Revision: 2.103
Committed: Sun Apr 24 15:40:33 2022 UTC (2 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.102: +12 -12 lines
Log Message:
fix(rtrace): Fixed segmentation violation introduced in 2.93 (Apr 2020)

File Contents

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