ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rtrace.c
Revision: 2.110
Committed: Mon Dec 11 18:33:53 2023 UTC (5 months, 2 weeks ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.109: +5 -5 lines
Log Message:
fix(rtrace): bug for float spectral output

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rtrace.c,v 2.109 2023/11/18 16:24:06 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 RREAL cval[3];
688
689 cval[0] = colval(r->mcol,RED);
690 cval[1] = colval(r->mcol,GRN);
691 cval[2] = colval(r->mcol,BLU);
692 (*putreal)(cval, 3);
693 }
694
695
696
697 static void
698 oputR( /* print mirrored distance */
699 RAY *r
700 )
701 {
702 (*putreal)(&r->rmt, 1);
703 }
704
705
706 static void
707 oputx( /* print unmirrored contribution */
708 RAY *r
709 )
710 {
711 SCOLOR cdiff;
712
713 copyscolor(cdiff, r->rcol);
714 sopscolor(cdiff, -=, r->mcol);
715
716 putscolor(cdiff);
717 }
718
719
720 static void
721 oputX( /* print unmirrored distance */
722 RAY *r
723 )
724 {
725 (*putreal)(&r->rxt, 1);
726 }
727
728
729 static void
730 oputv( /* print value */
731 RAY *r
732 )
733 {
734 putscolor(r->rcol);
735 }
736
737
738 static void
739 oputV( /* print value contribution */
740 RAY *r
741 )
742 {
743 SCOLOR contr;
744
745 raycontrib(contr, r, PRIMARY);
746 smultscolor(contr, r->rcol);
747 putscolor(contr);
748 }
749
750
751 static void
752 oputl( /* print effective distance */
753 RAY *r
754 )
755 {
756 RREAL d = raydistance(r);
757
758 (*putreal)(&d, 1);
759 }
760
761
762 static void
763 oputL( /* print single ray length */
764 RAY *r
765 )
766 {
767 (*putreal)(&r->rot, 1);
768 }
769
770
771 static void
772 oputc( /* print local coordinates */
773 RAY *r
774 )
775 {
776 (*putreal)(r->uv, 2);
777 }
778
779
780 static RREAL vdummy[3] = {0.0, 0.0, 0.0};
781
782
783 static void
784 oputp( /* print intersection point */
785 RAY *r
786 )
787 {
788 (*putreal)(r->rop, 3); /* set to ray origin if distant or no hit */
789 }
790
791
792 static void
793 oputN( /* print unperturbed normal */
794 RAY *r
795 )
796 {
797 if (r->ro == NULL) { /* zero vector if clipped or no hit */
798 (*putreal)(vdummy, 3);
799 return;
800 }
801 if (r->rflips & 1) { /* undo any flippin' flips */
802 FVECT unrm;
803 unrm[0] = -r->ron[0];
804 unrm[1] = -r->ron[1];
805 unrm[2] = -r->ron[2];
806 (*putreal)(unrm, 3);
807 } else
808 (*putreal)(r->ron, 3);
809 }
810
811
812 static void
813 oputn( /* print perturbed normal */
814 RAY *r
815 )
816 {
817 FVECT pnorm;
818
819 if (r->ro == NULL) { /* clipped or no hit */
820 (*putreal)(vdummy, 3);
821 return;
822 }
823 raynormal(pnorm, r);
824 (*putreal)(pnorm, 3);
825 }
826
827
828 static void
829 oputs( /* print name */
830 RAY *r
831 )
832 {
833 if (r->ro != NULL)
834 fputs(r->ro->oname, stdout);
835 else
836 putchar('*');
837 putchar('\t');
838 }
839
840
841 static void
842 oputw( /* print weight */
843 RAY *r
844 )
845 {
846 RREAL rwt = r->rweight;
847
848 (*putreal)(&rwt, 1);
849 }
850
851
852 static void
853 oputW( /* print coefficient */
854 RAY *r
855 )
856 {
857 SCOLOR contr;
858 /* shadow ray not on source? */
859 if (r->rsrc >= 0 && source[r->rsrc].so != r->ro)
860 scolorblack(contr);
861 else
862 raycontrib(contr, r, PRIMARY);
863
864 putscolor(contr);
865 }
866
867
868 static void
869 oputm( /* print modifier */
870 RAY *r
871 )
872 {
873 if (r->ro != NULL)
874 if (r->ro->omod != OVOID)
875 fputs(objptr(r->ro->omod)->oname, stdout);
876 else
877 fputs(VOIDID, stdout);
878 else
879 putchar('*');
880 putchar('\t');
881 }
882
883
884 static void
885 oputM( /* print material */
886 RAY *r
887 )
888 {
889 OBJREC *mat;
890
891 if (r->ro != NULL) {
892 if ((mat = findmaterial(r->ro)) != NULL)
893 fputs(mat->oname, stdout);
894 else
895 fputs(VOIDID, stdout);
896 } else
897 putchar('*');
898 putchar('\t');
899 }
900
901
902 static void
903 oputtilde( /* output tilde (spacer) */
904 RAY *r
905 )
906 {
907 fputs("~\t", stdout);
908 }
909
910
911 static void
912 puta( /* print ascii value(s) */
913 RREAL *v, int n
914 )
915 {
916 if (n == 3) {
917 printf("%e\t%e\t%e\t", v[0], v[1], v[2]);
918 return;
919 }
920 while (n--)
921 printf("%e\t", *v++);
922 }
923
924
925 static void
926 putd(RREAL *v, int n) /* output binary double(s) */
927 {
928 #ifdef SMLFLT
929 double da[MAXCSAMP];
930 int i;
931
932 if (n > MAXCSAMP)
933 error(INTERNAL, "code error in putd()");
934 for (i = n; i--; )
935 da[i] = v[i];
936 putbinary(da, sizeof(double), n, stdout);
937 #else
938 putbinary(v, sizeof(RREAL), n, stdout);
939 #endif
940 }
941
942
943 static void
944 putf(RREAL *v, int n) /* output binary float(s) */
945 {
946 #ifndef SMLFLT
947 float fa[MAXCSAMP];
948 int i;
949
950 if (n > MAXCSAMP)
951 error(INTERNAL, "code error in putf()");
952 for (i = n; i--; )
953 fa[i] = v[i];
954 putbinary(fa, sizeof(float), n, stdout);
955 #else
956 putbinary(v, sizeof(RREAL), n, stdout);
957 #endif
958 }
959
960
961 static void
962 putscolor(COLORV *scol) /* output (spectral) color */
963 {
964 static COLORMAT xyz2myrgbmat;
965 SCOLOR my_scol;
966 COLOR col;
967 /* apply scalefactor if any */
968 if (out_scalefactor != 1.) {
969 copyscolor(my_scol, scol);
970 scalescolor(my_scol, out_scalefactor);
971 scol = my_scol;
972 }
973 if (sens_curve != NULL) { /* single channel output */
974 RREAL v = (*sens_curve)(scol);
975 (*putreal)(&v, 1);
976 return;
977 }
978 if (out_prims == NULL) { /* full spectral reporting */
979 if (outform == 'c') {
980 SCOLR sclr;
981 scolor_scolr(sclr, scol);
982 putbinary(sclr, LSCOLR, 1, stdout);
983 } else if (sizeof(RREAL) != sizeof(COLORV)) {
984 RREAL sreal[MAXCSAMP];
985 int i = NCSAMP;
986 while (i--) sreal[i] = scol[i];
987 (*putreal)(sreal, NCSAMP);
988 } else
989 (*putreal)((RREAL *)scol, NCSAMP);
990 return;
991 }
992 if (out_prims == xyzprims) {
993 scolor_cie(col, scol);
994 } else if (out_prims == stdprims) {
995 scolor_rgb(col, scol);
996 } else {
997 COLOR xyz;
998 if (xyz2myrgbmat[0][0] == 0)
999 compxyz2rgbWBmat(xyz2myrgbmat, out_prims);
1000 scolor_cie(xyz, scol);
1001 colortrans(col, xyz2myrgbmat, xyz);
1002 clipgamut(col, xyz[CIEY], CGAMUT_LOWER, cblack, cwhite);
1003 }
1004 if (outform == 'c') {
1005 COLR clr;
1006 setcolr(clr, colval(col,RED), colval(col,GRN), colval(col,BLU));
1007 putbinary(clr, sizeof(COLR), 1, stdout);
1008 } else if (sizeof(RREAL) != sizeof(COLORV)) {
1009 RREAL creal[3];
1010 copycolor(creal, col);
1011 (*putreal)(creal, 3);
1012 } else
1013 (*putreal)((RREAL *)col, 3);
1014 }