ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rxtrace.cpp
Revision: 2.9
Committed: Thu Jan 2 02:59:15 2025 UTC (3 months, 4 weeks ago) by greg
Branch: MAIN
CVS Tags: HEAD
Changes since 2.8: +3 -4 lines
Log Message:
perf(rxtrace): Avoid final freeing of everything on exit

File Contents

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