ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rxtrace.cpp
Revision: 2.2
Committed: Tue Mar 12 16:54:51 2024 UTC (2 months, 1 week ago) by greg
Branch: MAIN
Changes since 2.1: +6 -4 lines
Log Message:
perf: added datavector() call for quicker spectral interpolation

File Contents

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