ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rxtrace.cpp
Revision: 2.6
Committed: Tue Nov 19 16:28:18 2024 UTC (5 months, 2 weeks ago) by greg
Branch: MAIN
Changes since 2.5: +6 -4 lines
Log Message:
feat: Exposed some formerly static variables for Stephen Wasilewski

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.6 static const char RCSid[] = "$Id: rxtrace.cpp,v 2.5 2024/05/02 22:10:43 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * C++ module for individual ray tracing.
6     */
7    
8     /*
9     * Input is in the form:
10     *
11     * xorg yorg zorg xdir ydir zdir
12     *
13     * The direction need not be normalized. Output is flexible.
14     * If the direction vector is (0,0,0), then the output is flushed.
15     * All values default to ascii representation of real
16     * numbers. Binary representations can be selected
17     * with '-ff' for float or '-fd' for double. By default,
18     * radiance is computed. The '-i' or '-I' options indicate that
19     * irradiance values are desired.
20     */
21    
22     #include "copyright.h"
23    
24     #include "RtraceSimulManager.h"
25     #include "platform.h"
26     #include "otypes.h"
27     #include "otspecial.h"
28     #include "source.h"
29     #include "resolu.h"
30    
31     extern int inform; /* input format */
32     extern int outform; /* output format */
33    
34     extern char *tralist[]; /* list of modifers to trace (or no) */
35     extern int traincl; /* include == 1, exclude == 0 */
36    
37     extern int hresolu; /* horizontal resolution */
38     extern int vresolu; /* vertical resolution */
39    
40     extern int castonly; /* only doing ray-casting? */
41    
42 greg 2.3 extern double (*sens_curve)(SCOLOR scol); /* spectral conversion for 1-channel */
43     extern double out_scalefactor; /* output calibration scale factor */
44     extern RGBPRIMP out_prims; /* output color primitives (NULL if spectral) */
45    
46 greg 2.1 #ifndef MAXTSET
47     #define MAXTSET 8191 /* maximum number in trace set */
48     #endif
49     OBJECT traset[MAXTSET+1]={0}; /* trace include/exclude set */
50    
51     // global simulation manager
52     extern RtraceSimulManager myRTmanager;
53    
54     static FILE *inpfp = NULL; /* input stream pointer */
55    
56     static FVECT *inp_queue = NULL; /* ray input queue if flushing */
57     static int inp_qpos = 0; /* next ray to return */
58     static int inp_qend = 0; /* number of rays in this work group */
59    
60     typedef void putf_t(RREAL *v, int n);
61     static putf_t puta, putd, putf, putrgbe;
62    
63     typedef void oputf_t(RAY *r);
64     static oputf_t oputo, oputd, oputv, oputV, oputl, oputL, oputc, oputp,
65     oputr, oputR, oputx, oputX, oputn, oputN, oputs,
66     oputw, oputW, oputm, oputM, oputtilde;
67    
68     extern void tranotify(OBJECT obj);
69     static void tabin(RAY *r);
70     static RayReportCall ourtrace;
71    
72 greg 2.6 RayReportCall printvals; /* print selected ray values */
73    
74     void putscolor(COLORV *scol); /* convert/print spectral color */
75 greg 2.3
76 greg 2.1 static oputf_t *ray_out[32], *every_out[32];
77 greg 2.6
78     putf_t *putreal; /* put out real vector */
79 greg 2.1
80     void
81     quit( /* quit program */
82     int code
83     )
84     {
85 greg 2.3 if (ray_pnprocs < 0)
86     _exit(code); /* avoid flush in child */
87    
88 greg 2.1 int ec = myRTmanager.Cleanup();
89    
90     if (ec) code = ec;
91    
92     exit(code);
93     }
94    
95     const char *
96     formstr( /* return format identifier */
97     int f
98     )
99     {
100     switch (f) {
101     case 'a': return("ascii");
102     case 'f': return("float");
103     case 'd': return("double");
104 greg 2.3 case 'c':
105     if (out_prims == NULL)
106     return(SPECFMT);
107     if (out_prims == xyzprims)
108     return(CIEFMT);
109     return(COLRFMT);
110 greg 2.1 }
111     return("unknown");
112     }
113    
114     static bool
115     getvec( /* get a vector from fp */
116     FVECT vec,
117     int fmt,
118     FILE *fp
119     )
120     {
121     static char buf[32];
122     float * vf = (float *)buf;
123     double * vd = (double *)buf;
124     int i;
125    
126     switch (fmt) {
127     case 'a': /* ascii */
128     for (i = 0; i < 3; i++) {
129     if (fgetword(buf, sizeof(buf), fp) == NULL ||
130     !isflt(buf))
131     return false;
132     vec[i] = atof(buf);
133     }
134     break;
135     #ifdef SMLFLT
136     case 'f': /* binary float */
137     if (getbinary(vec, sizeof(RREAL), 3, fp) != 3)
138     return false;
139     break;
140     case 'd': /* binary double */
141     if (getbinary(vd, sizeof(double), 3, fp) != 3)
142     return false;
143     VCOPY(vec, vd);
144     break;
145     #else
146     case 'f': /* binary float */
147     if (getbinary(vf, sizeof(float), 3, fp) != 3)
148     return false;
149     VCOPY(vec, vf);
150     break;
151     case 'd': /* binary double */
152     if (getbinary(vec, sizeof(RREAL), 3, fp) != 3)
153     return false;
154     break;
155     #endif
156     default:
157     error(CONSISTENCY, "botched input format");
158     }
159     return true;
160     }
161    
162     // read ray list from inpfp
163     static int
164     getrays(FVECT org_dir[], int n)
165     {
166     int nread = 0;
167    
168     while (n-- > 0) {
169     if (!getvec(org_dir[0], inform, inpfp) ||
170     !getvec(org_dir[1], inform, inpfp))
171     break;
172     ++nread;
173     if (IsZeroVec(org_dir[1]))
174     break;
175     org_dir += 2;
176     }
177     return nread;
178     }
179    
180     void
181     rtrace( /* trace rays from stdin or file */
182     char *fname,
183     int nproc
184     )
185     {
186     RNUMBER vcount = (hresolu > 1) ? (RNUMBER)hresolu*vresolu
187     : (RNUMBER)vresolu;
188     const int flushIntvl = (!vresolu | (hresolu <= 1)) * hresolu;
189     FVECT * ivbuf = (FVECT *)malloc(2*sizeof(FVECT) *
190     (flushIntvl + !flushIntvl));
191     if (ivbuf == NULL)
192     error(SYSTEM, "cannot allocate input vector buffer");
193     /* set up input */
194     if (fname == NULL)
195     inpfp = stdin;
196     else if ((inpfp = fopen(fname, "r")) == NULL) {
197     sprintf(errmsg, "cannot open input file \"%s\"", fname);
198     error(SYSTEM, errmsg);
199     }
200     if (inform != 'a')
201     SET_FILE_BINARY(inpfp);
202     /* set up output */
203 greg 2.2 if (castonly || every_out[0] != NULL) {
204 greg 2.1 nproc = 1; /* don't bother multiprocessing */
205 greg 2.2 } else if (nproc <= 0) { // need to get default for system?
206     nproc = myRTmanager.GetNCores() + nproc;
207     if (nproc <= 0) nproc = 1;
208     }
209 greg 2.1 if ((flushIntvl > 0) & (nproc > flushIntvl)) {
210     error(WARNING, "reducing number of processes to match flush interval");
211     nproc = flushIntvl;
212     }
213     nproc = myRTmanager.SetThreadCount(nproc);
214     if (ray_out[0])
215     myRTmanager.SetCookedCall(printvals);
216     if (every_out[0])
217     myRTmanager.SetTraceCall(ourtrace);
218     myRTmanager.rtFlags |= RTdoFIFO;
219 greg 2.3 #ifdef getc_unlocked
220     flockfile(inpfp); /* avoid lock/unlock overhead */
221     flockfile(stdout);
222     #endif
223 greg 2.1 if (hresolu > 0) { // print resolution string if appropriate
224     if (vresolu > 0)
225     fprtresolu(hresolu, vresolu, stdout);
226     else
227     fflush(stdout);
228     }
229     int n; /* process input rays */
230     bool pending = false;
231     while ((n = getrays(ivbuf, flushIntvl + !flushIntvl)) > 0) {
232     if ((vcount > 0) & (n > vcount)) {
233     error(WARNING, "extra ray(s) past end of input");
234     n = vcount;
235     } // put ray(s) into queue
236     if (myRTmanager.EnqueueBundle(ivbuf, n) < n)
237     error(USER, "ray queuing failure");
238     pending |= (n > 1); // time to flush output?
239     bool atZero = IsZeroVec(ivbuf[2*n-1]);
240     if (pending & (atZero | (n == flushIntvl))) {
241 greg 2.5 if (myRTmanager.FlushQueue() <= 0)
242 greg 2.1 error(USER, "ray flush error");
243     fflush(stdout);
244     pending = false;
245     } else
246     pending |= !atZero;
247     if (ferror(stdout))
248     error(SYSTEM, "write error");
249     if (vcount && !(vcount -= n)) /* check for end */
250     break;
251     }
252     if (vcount)
253     error(WARNING, feof(inpfp) ? "unexpected EOF on input" :
254     "input read error");
255 greg 2.4 if (myRTmanager.FlushQueue() < 0 || fflush(stdout) < 0)
256     error(SYSTEM, "final flush error");
257 greg 2.1 if (fname != NULL) {
258     fclose(inpfp);
259     inpfp = NULL;
260     }
261     free(ivbuf);
262     }
263    
264     int
265     setrtoutput(const char *outvals) /* set up output tables, return #comp */
266     {
267     const char *vs = outvals;
268     oputf_t **table = ray_out;
269 greg 2.3 const int nco = (sens_curve != NULL) ? 1 :
270     (out_prims != NULL) ? 3 : NCSAMP;
271 greg 2.1 int ncomp = 0;
272    
273     if (!*vs)
274     error(USER, "empty output specification");
275    
276     switch (outform) { /* make sure (*putreal)() calls someone! */
277     case 'a': putreal = puta; break;
278     case 'f': putreal = putf; break;
279     case 'd': putreal = putd; break;
280     case 'c':
281     if (outvals[1] || !strchr("vrx", outvals[0]))
282     error(USER, "color format only with -ov, -or, -ox");
283     putreal = putrgbe; break;
284     default:
285     error(CONSISTENCY, "botched output format");
286     }
287     castonly = 1; /* sets castonly as side-effect */
288     do
289     switch (*vs) {
290     case 'T': /* trace sources */
291     myRTmanager.rtFlags |= RTtraceSources;
292     /* fall through */
293     case 't': /* trace */
294     if (!vs[1]) break;
295     *table = NULL;
296     table = every_out;
297     castonly = 0;
298     break;
299     case 'o': /* origin */
300     *table++ = oputo;
301     ncomp += 3;
302     break;
303     case 'd': /* direction */
304     *table++ = oputd;
305     ncomp += 3;
306     break;
307     case 'r': /* reflected contrib. */
308     *table++ = oputr;
309 greg 2.3 ncomp += nco;
310 greg 2.1 castonly = 0;
311     break;
312     case 'R': /* reflected distance */
313     *table++ = oputR;
314     ncomp++;
315     castonly = 0;
316     break;
317     case 'x': /* xmit contrib. */
318     *table++ = oputx;
319 greg 2.3 ncomp += nco;
320 greg 2.1 castonly = 0;
321     break;
322     case 'X': /* xmit distance */
323     *table++ = oputX;
324     ncomp++;
325     castonly = 0;
326     break;
327     case 'v': /* value */
328     *table++ = oputv;
329 greg 2.3 ncomp += nco;
330 greg 2.1 castonly = 0;
331     break;
332     case 'V': /* contribution */
333     *table++ = oputV;
334 greg 2.3 ncomp += nco;
335 greg 2.1 castonly = 0;
336     if (ambounce > 0 && (ambacc > FTINY || ambssamp > 0))
337     error(WARNING,
338     "-otV accuracy depends on -aa 0 -as 0");
339     break;
340     case 'l': /* effective distance */
341     *table++ = oputl;
342     ncomp++;
343     castonly = 0;
344     break;
345     case 'c': /* local coordinates */
346     *table++ = oputc;
347     ncomp += 2;
348     break;
349     case 'L': /* single ray length */
350     *table++ = oputL;
351     ncomp++;
352     break;
353     case 'p': /* point */
354     *table++ = oputp;
355     ncomp += 3;
356     break;
357     case 'n': /* perturbed normal */
358     *table++ = oputn;
359     ncomp += 3;
360     castonly = 0;
361     break;
362     case 'N': /* unperturbed normal */
363     *table++ = oputN;
364     ncomp += 3;
365     break;
366     case 's': /* surface */
367     *table++ = oputs;
368     ncomp++;
369     break;
370     case 'w': /* weight */
371     *table++ = oputw;
372     ncomp++;
373     break;
374     case 'W': /* coefficient */
375     *table++ = oputW;
376 greg 2.3 ncomp += nco;
377 greg 2.1 castonly = 0;
378     if (ambounce > 0 && (ambacc > FTINY) | (ambssamp > 0))
379     error(WARNING,
380     "-otW accuracy depends on -aa 0 -as 0");
381     break;
382     case 'm': /* modifier */
383     *table++ = oputm;
384     ncomp++;
385     break;
386     case 'M': /* material */
387     *table++ = oputM;
388     ncomp++;
389     break;
390     case '~': /* tilde */
391     *table++ = oputtilde;
392     break;
393     default:
394     sprintf(errmsg, "unrecognized output option '%c'", *vs);
395     error(USER, errmsg);
396     }
397     while (*++vs);
398    
399     *table = NULL;
400     if (*every_out != NULL)
401     ncomp = 0;
402     /* compatibility */
403     if ((do_irrad | (myRTmanager.rtFlags & RTimmIrrad)) && castonly)
404     error(USER, "-I+ and -i+ options require some value output");
405     for (table = ray_out; *table != NULL; table++) {
406     if ((*table == oputV) | (*table == oputW))
407     error(WARNING, "-oVW options require trace mode");
408     if ((do_irrad | (myRTmanager.rtFlags & RTimmIrrad)) &&
409     (*table == oputr) | (*table == oputR) |
410     (*table == oputx) | (*table == oputX))
411     error(WARNING, "-orRxX options incompatible with -I+ and -i+");
412     }
413     return(ncomp);
414     }
415    
416 greg 2.3 static int
417 greg 2.1 printvals( /* print requested ray values */
418     RAY *r, void *cd
419     )
420     {
421     oputf_t **tp;
422    
423     if (ray_out[0] == NULL)
424 greg 2.3 return 0;
425 greg 2.1 for (tp = ray_out; *tp != NULL; tp++)
426     (**tp)(r);
427     if (outform == 'a')
428     putchar('\n');
429 greg 2.3 return 1;
430 greg 2.1 }
431    
432     void
433     tranotify( /* record new modifier */
434     OBJECT obj
435     )
436     {
437     static int hitlimit = 0;
438     OBJREC *o = objptr(obj);
439     char **tralp;
440    
441     if (obj == OVOID) { /* starting over */
442     traset[0] = 0;
443     hitlimit = 0;
444     return;
445     }
446     if (hitlimit || !ismodifier(o->otype))
447     return;
448     for (tralp = tralist; *tralp != NULL; tralp++)
449     if (!strcmp(o->oname, *tralp)) {
450     if (traset[0] >= MAXTSET) {
451     error(WARNING, "too many modifiers in trace list");
452     hitlimit++;
453     return; /* should this be fatal? */
454     }
455     insertelem(traset, obj);
456     return;
457     }
458     }
459    
460 greg 2.3 static int
461 greg 2.1 ourtrace( /* print ray values */
462     RAY *r, void *cd
463     )
464     {
465     oputf_t **tp;
466    
467     if (every_out[0] == NULL)
468 greg 2.3 return 0;
469 greg 2.1 if (r->ro == NULL) {
470     if (traincl == 1)
471 greg 2.3 return 0;
472 greg 2.1 } else if (traincl != -1 && traincl != inset(traset, r->ro->omod))
473 greg 2.3 return 0;
474 greg 2.1 tabin(r);
475     for (tp = every_out; *tp != NULL; tp++)
476     (**tp)(r);
477     if (outform == 'a')
478     putchar('\n');
479 greg 2.3 return 1;
480 greg 2.1 }
481    
482     static void
483     tabin( /* tab in appropriate amount */
484     RAY *r
485     )
486     {
487     const RAY *rp;
488    
489     for (rp = r->parent; rp != NULL; rp = rp->parent)
490     putchar('\t');
491     }
492    
493     static void
494     oputo( /* print origin */
495     RAY *r
496     )
497     {
498     (*putreal)(r->rorg, 3);
499     }
500    
501     static void
502     oputd( /* print direction */
503     RAY *r
504     )
505     {
506     (*putreal)(r->rdir, 3);
507     }
508    
509     static void
510     oputr( /* print mirrored contribution */
511     RAY *r
512     )
513     {
514 greg 2.3 putscolor(r->mcol);
515 greg 2.1 }
516    
517     static void
518     oputR( /* print mirrored distance */
519     RAY *r
520     )
521     {
522     (*putreal)(&r->rmt, 1);
523     }
524    
525     static void
526     oputx( /* print unmirrored contribution */
527     RAY *r
528     )
529     {
530 greg 2.3 SCOLOR cdiff;
531    
532     copyscolor(cdiff, r->rcol);
533     sopscolor(cdiff, -=, r->mcol);
534 greg 2.1
535 greg 2.3 putscolor(cdiff);
536 greg 2.1 }
537    
538     static void
539     oputX( /* print unmirrored distance */
540     RAY *r
541     )
542     {
543     (*putreal)(&r->rxt, 1);
544     }
545    
546     static void
547     oputv( /* print value */
548     RAY *r
549     )
550     {
551 greg 2.3 putscolor(r->rcol);
552 greg 2.1 }
553    
554     static void
555     oputV( /* print value contribution */
556     RAY *r
557     )
558     {
559 greg 2.3 SCOLOR contr;
560 greg 2.1
561     raycontrib(contr, r, PRIMARY);
562 greg 2.3 smultscolor(contr, r->rcol);
563     putscolor(contr);
564 greg 2.1 }
565    
566     static void
567     oputl( /* print effective distance */
568     RAY *r
569     )
570     {
571     RREAL d = raydistance(r);
572    
573     (*putreal)(&d, 1);
574     }
575    
576     static void
577     oputL( /* print single ray length */
578     RAY *r
579     )
580     {
581     (*putreal)(&r->rot, 1);
582     }
583    
584     static void
585     oputc( /* print local coordinates */
586     RAY *r
587     )
588     {
589     (*putreal)(r->uv, 2);
590     }
591    
592     static RREAL vdummy[3] = {0.0, 0.0, 0.0};
593    
594     static void
595     oputp( /* print intersection point */
596     RAY *r
597     )
598     {
599     (*putreal)(r->rop, 3); /* set to ray origin if distant or no hit */
600     }
601    
602     static void
603     oputN( /* print unperturbed normal */
604     RAY *r
605     )
606     {
607     if (r->ro == NULL) { /* zero vector if clipped or no hit */
608     (*putreal)(vdummy, 3);
609     return;
610     }
611     if (r->rflips & 1) { /* undo any flippin' flips */
612     FVECT unrm;
613     unrm[0] = -r->ron[0];
614     unrm[1] = -r->ron[1];
615     unrm[2] = -r->ron[2];
616     (*putreal)(unrm, 3);
617     } else
618     (*putreal)(r->ron, 3);
619     }
620    
621     static void
622     oputn( /* print perturbed normal */
623     RAY *r
624     )
625     {
626     FVECT pnorm;
627    
628     if (r->ro == NULL) { /* clipped or no hit */
629     (*putreal)(vdummy, 3);
630     return;
631     }
632     raynormal(pnorm, r);
633     (*putreal)(pnorm, 3);
634     }
635    
636     static void
637     oputs( /* print name */
638     RAY *r
639     )
640     {
641     if (r->ro != NULL)
642     fputs(r->ro->oname, stdout);
643     else
644     putchar('*');
645     putchar('\t');
646     }
647    
648     static void
649     oputw( /* print weight */
650     RAY *r
651     )
652     {
653     RREAL rwt = r->rweight;
654    
655     (*putreal)(&rwt, 1);
656     }
657    
658     static void
659     oputW( /* print coefficient */
660     RAY *r
661     )
662     {
663 greg 2.3 SCOLOR contr;
664 greg 2.1 /* shadow ray not on source? */
665     if (r->rsrc >= 0 && source[r->rsrc].so != r->ro)
666 greg 2.3 scolorblack(contr);
667 greg 2.1 else
668     raycontrib(contr, r, PRIMARY);
669    
670 greg 2.3 putscolor(contr);
671 greg 2.1 }
672    
673     static void
674     oputm( /* print modifier */
675     RAY *r
676     )
677     {
678     if (r->ro != NULL)
679     if (r->ro->omod != OVOID)
680     fputs(objptr(r->ro->omod)->oname, stdout);
681     else
682     fputs(VOIDID, stdout);
683     else
684     putchar('*');
685     putchar('\t');
686     }
687    
688     static void
689     oputM( /* print material */
690     RAY *r
691     )
692     {
693     OBJREC *mat;
694    
695     if (r->ro != NULL) {
696     if ((mat = findmaterial(r->ro)) != NULL)
697     fputs(mat->oname, stdout);
698     else
699     fputs(VOIDID, stdout);
700     } else
701     putchar('*');
702     putchar('\t');
703     }
704    
705     static void
706     oputtilde( /* output tilde (spacer) */
707     RAY *r
708     )
709     {
710     fputs("~\t", stdout);
711     }
712    
713     static void
714     puta( /* print ascii value(s) */
715     RREAL *v, int n
716     )
717     {
718     if (n == 3) {
719     printf("%e\t%e\t%e\t", v[0], v[1], v[2]);
720     return;
721     }
722     while (n--)
723     printf("%e\t", *v++);
724     }
725    
726     static void
727     putd(RREAL *v, int n) /* output binary double(s) */
728     {
729     #ifdef SMLFLT
730     double da[3];
731     int i;
732    
733     if (n > 3)
734     error(INTERNAL, "code error in putd()");
735     for (i = n; i--; )
736     da[i] = v[i];
737     putbinary(da, sizeof(double), n, stdout);
738     #else
739     putbinary(v, sizeof(RREAL), n, stdout);
740     #endif
741     }
742    
743     static void
744     putf(RREAL *v, int n) /* output binary float(s) */
745     {
746     #ifndef SMLFLT
747     float fa[3];
748     int i;
749    
750     if (n > 3)
751     error(INTERNAL, "code error in putf()");
752     for (i = n; i--; )
753     fa[i] = v[i];
754     putbinary(fa, sizeof(float), n, stdout);
755     #else
756     putbinary(v, sizeof(RREAL), n, stdout);
757     #endif
758     }
759    
760     static void
761     putrgbe(RREAL *v, int n) /* output RGBE color */
762     {
763     COLR cout;
764    
765     if (n != 3)
766     error(INTERNAL, "putrgbe() not called with 3 components");
767     setcolr(cout, v[0], v[1], v[2]);
768     putbinary(cout, sizeof(cout), 1, stdout);
769     }
770 greg 2.3
771     static void
772     putscolor(COLORV *scol) /* output (spectral) color */
773     {
774     static COLORMAT xyz2myrgbmat;
775     SCOLOR my_scol;
776     COLOR col;
777     /* single channel output? */
778     if (sens_curve != NULL) {
779     RREAL v = (*sens_curve)(scol) * out_scalefactor;
780     (*putreal)(&v, 1);
781     return;
782     }
783     if (out_scalefactor != 1.) { /* apply scalefactor if any */
784     copyscolor(my_scol, scol);
785     scalescolor(my_scol, out_scalefactor);
786     scol = my_scol;
787     }
788     if (out_prims == NULL) { /* full spectral reporting */
789     if (outform == 'c') {
790     SCOLR sclr;
791     scolor_scolr(sclr, scol);
792     putbinary(sclr, LSCOLR, 1, stdout);
793     } else if (sizeof(RREAL) != sizeof(COLORV)) {
794     RREAL sreal[MAXCSAMP];
795     int i = NCSAMP;
796     while (i--) sreal[i] = scol[i];
797     (*putreal)(sreal, NCSAMP);
798     } else
799     (*putreal)((RREAL *)scol, NCSAMP);
800     return;
801     }
802     if (out_prims == xyzprims) {
803     scolor_cie(col, scol);
804     } else if (out_prims == stdprims) {
805     scolor_rgb(col, scol);
806     } else {
807     COLOR xyz;
808     if (xyz2myrgbmat[0][0] == 0)
809     compxyz2rgbWBmat(xyz2myrgbmat, out_prims);
810     scolor_cie(xyz, scol);
811     colortrans(col, xyz2myrgbmat, xyz);
812     clipgamut(col, xyz[CIEY], CGAMUT_LOWER, cblack, cwhite);
813     }
814     if (outform == 'c') {
815     COLR clr;
816     setcolr(clr, colval(col,RED), colval(col,GRN), colval(col,BLU));
817     putbinary(clr, sizeof(COLR), 1, stdout);
818     } else if (sizeof(RREAL) != sizeof(COLORV)) {
819     RREAL creal[3];
820     copycolor(creal, col);
821     (*putreal)(creal, 3);
822     } else
823     (*putreal)((RREAL *)col, 3);
824     }