ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rtrace.c
Revision: 2.91
Committed: Sun Apr 5 15:47:02 2020 UTC (4 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.90: +40 -11 lines
Log Message:
Added NCOMP= to header and better checking of -o* options

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rtrace.c,v 2.90 2020/04/04 15:38:52 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 static int castonly = 0;
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 static void setoutput(char *vs);
72 extern void tranotify(OBJECT obj);
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 extern 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 (imm_irrad)
148 castonly = 0;
149 else 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;
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 if (ambounce > 0 && (ambacc > FTINY || ambssamp > 0))
291 error(WARNING,
292 "-otV accuracy depends on -aa 0 -as 0");
293 break;
294 case 'l': /* effective distance */
295 *table++ = oputl;
296 ncomp++;
297 castonly = 0;
298 break;
299 case 'c': /* local coordinates */
300 *table++ = oputc;
301 ncomp += 2;
302 break;
303 case 'L': /* single ray length */
304 *table++ = oputL;
305 ncomp++;
306 break;
307 case 'p': /* point */
308 *table++ = oputp;
309 ncomp += 3;
310 break;
311 case 'n': /* perturbed normal */
312 *table++ = oputn;
313 ncomp += 3;
314 castonly = 0;
315 break;
316 case 'N': /* unperturbed normal */
317 *table++ = oputN;
318 ncomp += 3;
319 break;
320 case 's': /* surface */
321 *table++ = oputs;
322 ncomp++;
323 break;
324 case 'w': /* weight */
325 *table++ = oputw;
326 ncomp++;
327 break;
328 case 'W': /* coefficient */
329 *table++ = oputW;
330 ncomp += 3;
331 castonly = 0;
332 if (ambounce > 0 && (ambacc > FTINY) | (ambssamp > 0))
333 error(WARNING,
334 "-otW accuracy depends on -aa 0 -as 0");
335 break;
336 case 'm': /* modifier */
337 *table++ = oputm;
338 ncomp++;
339 break;
340 case 'M': /* material */
341 *table++ = oputM;
342 ncomp++;
343 break;
344 case '~': /* tilde */
345 *table++ = oputtilde;
346 break;
347 default:
348 sprintf(errmsg, "unrecognized output option '%c'", *vs);
349 error(USER, errmsg);
350 }
351 while (*++vs);
352
353 *table = NULL;
354 if (*every_out != NULL)
355 ncomp = 0;
356 /* compatibility */
357 for (table = ray_out; *table != NULL; table++) {
358 if ((*table == oputV) | (*table == oputW))
359 error(WARNING, "-oVW options require trace mode");
360 if ((do_irrad | imm_irrad) &&
361 (*table == oputr) | (*table == oputR) |
362 (*table == oputx) | (*table == oputX))
363 error(WARNING, "-orRxX options incompatible with -I+ and -i+");
364 }
365 return(ncomp);
366 }
367
368
369 static void
370 bogusray(void) /* print out empty record */
371 {
372 rayorigin(&thisray, PRIMARY, NULL, NULL);
373 printvals(&thisray);
374 }
375
376
377 static void
378 raycast( /* compute first ray intersection only */
379 RAY *r
380 )
381 {
382 if (!localhit(r, &thescene)) {
383 if (r->ro == &Aftplane) { /* clipped */
384 r->ro = NULL;
385 r->rot = FHUGE;
386 } else
387 sourcehit(r);
388 }
389 }
390
391
392 static void
393 rayirrad( /* compute irradiance rather than radiance */
394 RAY *r
395 )
396 {
397 void (*old_revf)(RAY *) = r->revf;
398 /* pretend we hit surface */
399 r->rxt = r->rot = 1e-5;
400 VSUM(r->rop, r->rorg, r->rdir, r->rot);
401 r->ron[0] = -r->rdir[0];
402 r->ron[1] = -r->rdir[1];
403 r->ron[2] = -r->rdir[2];
404 r->rod = 1.0;
405 /* compute result */
406 r->revf = raytrace;
407 (*ofun[Lamb.otype].funp)(&Lamb, r);
408 r->revf = old_revf;
409 }
410
411
412 static void
413 rtcompute( /* compute and print ray value(s) */
414 FVECT org,
415 FVECT dir,
416 double dmax
417 )
418 {
419 /* set up ray */
420 rayorigin(&thisray, PRIMARY, NULL, NULL);
421 if (imm_irrad) {
422 VSUM(thisray.rorg, org, dir, 1.1e-4);
423 thisray.rdir[0] = -dir[0];
424 thisray.rdir[1] = -dir[1];
425 thisray.rdir[2] = -dir[2];
426 thisray.rmax = 0.0;
427 thisray.revf = rayirrad;
428 } else {
429 VCOPY(thisray.rorg, org);
430 VCOPY(thisray.rdir, dir);
431 thisray.rmax = dmax;
432 if (castonly)
433 thisray.revf = raycast;
434 }
435 if (ray_pnprocs > 1) { /* multiprocessing FIFO? */
436 if (ray_fifo_in(&thisray) < 0)
437 error(USER, "lost children");
438 return;
439 }
440 samplendx++; /* else do it ourselves */
441 rayvalue(&thisray);
442 printvals(&thisray);
443 }
444
445
446 static int
447 printvals( /* print requested ray values */
448 RAY *r
449 )
450 {
451 oputf_t **tp;
452
453 if (ray_out[0] == NULL)
454 return(0);
455 for (tp = ray_out; *tp != NULL; tp++)
456 (**tp)(r);
457 if (outform == 'a')
458 putchar('\n');
459 return(1);
460 }
461
462
463 static int
464 getvec( /* get a vector from fp */
465 FVECT vec,
466 int fmt,
467 FILE *fp
468 )
469 {
470 static float vf[3];
471 static double vd[3];
472 char buf[32];
473 int i;
474
475 switch (fmt) {
476 case 'a': /* ascii */
477 for (i = 0; i < 3; i++) {
478 if (fgetword(buf, sizeof(buf), fp) == NULL ||
479 !isflt(buf))
480 return(-1);
481 vec[i] = atof(buf);
482 }
483 break;
484 case 'f': /* binary float */
485 if (getbinary(vf, sizeof(float), 3, fp) != 3)
486 return(-1);
487 VCOPY(vec, vf);
488 break;
489 case 'd': /* binary double */
490 if (getbinary(vd, sizeof(double), 3, fp) != 3)
491 return(-1);
492 VCOPY(vec, vd);
493 break;
494 default:
495 error(CONSISTENCY, "botched input format");
496 }
497 return(0);
498 }
499
500
501 static int
502 iszerovec(const FVECT vec)
503 {
504 return (vec[0] == 0.0) & (vec[1] == 0.0) & (vec[2] == 0.0);
505 }
506
507
508 static double
509 nextray( /* return next ray in work group (-1.0 if EOF) */
510 FVECT org,
511 FVECT dir
512 )
513 {
514 const size_t qlength = !vresolu * hresolu;
515
516 if ((org == NULL) | (dir == NULL)) {
517 if (inp_queue != NULL) /* asking to free queue */
518 free(inp_queue);
519 inp_queue = NULL;
520 inp_qpos = inp_qend = 0;
521 return(-1.);
522 }
523 if (!inp_qend) { /* initialize FIFO queue */
524 int rsiz = 6*20; /* conservative ascii ray size */
525 if (inform == 'f') rsiz = 6*sizeof(float);
526 else if (inform == 'd') rsiz = 6*sizeof(double);
527 if ((inpfp == stdin) & (qlength*rsiz > 512)) /* pipe limit */
528 inp_queue = (FVECT *)malloc(sizeof(FVECT)*2*qlength);
529 inp_qend = -(inp_queue == NULL); /* flag for no queue */
530 }
531 if (inp_qend < 0) { /* not queuing? */
532 if (getvec(org, inform, inpfp) < 0 ||
533 getvec(dir, inform, inpfp) < 0)
534 return(-1.);
535 return normalize(dir);
536 }
537 if (inp_qpos >= inp_qend) { /* need to refill input queue? */
538 for (inp_qend = 0; inp_qend < qlength; inp_qend++) {
539 if (getvec(inp_queue[2*inp_qend], inform, inpfp) < 0
540 || getvec(inp_queue[2*inp_qend+1],
541 inform, inpfp) < 0)
542 break; /* hit EOF */
543 if (iszerovec(inp_queue[2*inp_qend+1])) {
544 ++inp_qend; /* flush request */
545 break;
546 }
547 }
548 inp_qpos = 0;
549 }
550 if (inp_qpos >= inp_qend) /* unexpected EOF? */
551 return(-1.);
552 VCOPY(org, inp_queue[2*inp_qpos]);
553 VCOPY(dir, inp_queue[2*inp_qpos+1]);
554 ++inp_qpos;
555 return normalize(dir);
556 }
557
558
559 void
560 tranotify( /* record new modifier */
561 OBJECT obj
562 )
563 {
564 static int hitlimit = 0;
565 OBJREC *o = objptr(obj);
566 char **tralp;
567
568 if (obj == OVOID) { /* starting over */
569 traset[0] = 0;
570 hitlimit = 0;
571 return;
572 }
573 if (hitlimit || !ismodifier(o->otype))
574 return;
575 for (tralp = tralist; *tralp != NULL; tralp++)
576 if (!strcmp(o->oname, *tralp)) {
577 if (traset[0] >= MAXTSET) {
578 error(WARNING, "too many modifiers in trace list");
579 hitlimit++;
580 return; /* should this be fatal? */
581 }
582 insertelem(traset, obj);
583 return;
584 }
585 }
586
587
588 static void
589 ourtrace( /* print ray values */
590 RAY *r
591 )
592 {
593 oputf_t **tp;
594
595 if (every_out[0] == NULL)
596 return;
597 if (r->ro == NULL) {
598 if (traincl == 1)
599 return;
600 } else if (traincl != -1 && traincl != inset(traset, r->ro->omod))
601 return;
602 tabin(r);
603 for (tp = every_out; *tp != NULL; tp++)
604 (**tp)(r);
605 if (outform == 'a')
606 putchar('\n');
607 }
608
609
610 static void
611 tabin( /* tab in appropriate amount */
612 RAY *r
613 )
614 {
615 const RAY *rp;
616
617 for (rp = r->parent; rp != NULL; rp = rp->parent)
618 putchar('\t');
619 }
620
621
622 static void
623 oputo( /* print origin */
624 RAY *r
625 )
626 {
627 (*putreal)(r->rorg, 3);
628 }
629
630
631 static void
632 oputd( /* print direction */
633 RAY *r
634 )
635 {
636 (*putreal)(r->rdir, 3);
637 }
638
639
640 static void
641 oputr( /* print mirrored contribution */
642 RAY *r
643 )
644 {
645 RREAL cval[3];
646
647 cval[0] = colval(r->mcol,RED);
648 cval[1] = colval(r->mcol,GRN);
649 cval[2] = colval(r->mcol,BLU);
650 (*putreal)(cval, 3);
651 }
652
653
654
655 static void
656 oputR( /* print mirrored distance */
657 RAY *r
658 )
659 {
660 (*putreal)(&r->rmt, 1);
661 }
662
663
664 static void
665 oputx( /* print unmirrored contribution */
666 RAY *r
667 )
668 {
669 RREAL cval[3];
670
671 cval[0] = colval(r->rcol,RED) - colval(r->mcol,RED);
672 cval[1] = colval(r->rcol,GRN) - colval(r->mcol,GRN);
673 cval[2] = colval(r->rcol,BLU) - colval(r->mcol,BLU);
674 (*putreal)(cval, 3);
675 }
676
677
678 static void
679 oputX( /* print unmirrored distance */
680 RAY *r
681 )
682 {
683 (*putreal)(&r->rxt, 1);
684 }
685
686
687 static void
688 oputv( /* print value */
689 RAY *r
690 )
691 {
692 RREAL cval[3];
693
694 cval[0] = colval(r->rcol,RED);
695 cval[1] = colval(r->rcol,GRN);
696 cval[2] = colval(r->rcol,BLU);
697 (*putreal)(cval, 3);
698 }
699
700
701 static void
702 oputV( /* print value contribution */
703 RAY *r
704 )
705 {
706 RREAL contr[3];
707
708 raycontrib(contr, r, PRIMARY);
709 multcolor(contr, r->rcol);
710 (*putreal)(contr, 3);
711 }
712
713
714 static void
715 oputl( /* print effective distance */
716 RAY *r
717 )
718 {
719 RREAL d = raydistance(r);
720
721 (*putreal)(&d, 1);
722 }
723
724
725 static void
726 oputL( /* print single ray length */
727 RAY *r
728 )
729 {
730 (*putreal)(&r->rot, 1);
731 }
732
733
734 static void
735 oputc( /* print local coordinates */
736 RAY *r
737 )
738 {
739 (*putreal)(r->uv, 2);
740 }
741
742
743 static RREAL vdummy[3] = {0.0, 0.0, 0.0};
744
745
746 static void
747 oputp( /* print point */
748 RAY *r
749 )
750 {
751 if (r->rot < FHUGE*.99)
752 (*putreal)(r->rop, 3);
753 else
754 (*putreal)(vdummy, 3);
755 }
756
757
758 static void
759 oputN( /* print unperturbed normal */
760 RAY *r
761 )
762 {
763 if (r->rot < FHUGE*.99) {
764 if (r->rflips & 1) { /* undo any flippin' flips */
765 FVECT unrm;
766 unrm[0] = -r->ron[0];
767 unrm[1] = -r->ron[1];
768 unrm[2] = -r->ron[2];
769 (*putreal)(unrm, 3);
770 } else
771 (*putreal)(r->ron, 3);
772 } else
773 (*putreal)(vdummy, 3);
774 }
775
776
777 static void
778 oputn( /* print perturbed normal */
779 RAY *r
780 )
781 {
782 FVECT pnorm;
783
784 if (r->rot >= FHUGE*.99) {
785 (*putreal)(vdummy, 3);
786 return;
787 }
788 raynormal(pnorm, r);
789 (*putreal)(pnorm, 3);
790 }
791
792
793 static void
794 oputs( /* print name */
795 RAY *r
796 )
797 {
798 if (r->ro != NULL)
799 fputs(r->ro->oname, stdout);
800 else
801 putchar('*');
802 putchar('\t');
803 }
804
805
806 static void
807 oputw( /* print weight */
808 RAY *r
809 )
810 {
811 RREAL rwt = r->rweight;
812
813 (*putreal)(&rwt, 1);
814 }
815
816
817 static void
818 oputW( /* print coefficient */
819 RAY *r
820 )
821 {
822 RREAL contr[3];
823 /* shadow ray not on source? */
824 if (r->rsrc >= 0 && source[r->rsrc].so != r->ro)
825 setcolor(contr, 0.0, 0.0, 0.0);
826 else
827 raycontrib(contr, r, PRIMARY);
828
829 (*putreal)(contr, 3);
830 }
831
832
833 static void
834 oputm( /* print modifier */
835 RAY *r
836 )
837 {
838 if (r->ro != NULL)
839 if (r->ro->omod != OVOID)
840 fputs(objptr(r->ro->omod)->oname, stdout);
841 else
842 fputs(VOIDID, stdout);
843 else
844 putchar('*');
845 putchar('\t');
846 }
847
848
849 static void
850 oputM( /* print material */
851 RAY *r
852 )
853 {
854 OBJREC *mat;
855
856 if (r->ro != NULL) {
857 if ((mat = findmaterial(r->ro)) != NULL)
858 fputs(mat->oname, stdout);
859 else
860 fputs(VOIDID, stdout);
861 } else
862 putchar('*');
863 putchar('\t');
864 }
865
866
867 static void
868 oputtilde( /* output tilde (spacer) */
869 RAY *r
870 )
871 {
872 fputs("~\t", stdout);
873 }
874
875
876 static void
877 puta( /* print ascii value(s) */
878 RREAL *v, int n
879 )
880 {
881 if (n == 3) {
882 printf("%e\t%e\t%e\t", v[0], v[1], v[2]);
883 return;
884 }
885 while (n--)
886 printf("%e\t", *v++);
887 }
888
889
890 static void
891 putd(RREAL *v, int n) /* output binary double(s) */
892 {
893 #ifdef SMLFLT
894 double da[3];
895 int i;
896
897 if (n > 3)
898 error(INTERNAL, "code error in putd()");
899 for (i = n; i--; )
900 da[i] = v[i];
901 putbinary(da, sizeof(double), n, stdout);
902 #else
903 putbinary(v, sizeof(RREAL), n, stdout);
904 #endif
905 }
906
907
908 static void
909 putf(RREAL *v, int n) /* output binary float(s) */
910 {
911 #ifndef SMLFLT
912 float fa[3];
913 int i;
914
915 if (n > 3)
916 error(INTERNAL, "code error in putf()");
917 for (i = n; i--; )
918 fa[i] = v[i];
919 putbinary(fa, sizeof(float), n, stdout);
920 #else
921 putbinary(v, sizeof(RREAL), n, stdout);
922 #endif
923 }
924
925
926 static void
927 putrgbe(RREAL *v, int n) /* output RGBE color */
928 {
929 COLR cout;
930
931 if (n != 3)
932 error(INTERNAL, "putrgbe() not called with 3 components");
933 setcolr(cout, v[0], v[1], v[2]);
934 putbinary(cout, sizeof(cout), 1, stdout);
935 }