ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rtrace.c
Revision: 2.112
Committed: Sat Jan 6 01:21:34 2024 UTC (3 months, 3 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.111: +8 -8 lines
Log Message:
perf(rtrace): minor optimization

File Contents

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