ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ratrace.cpp
Revision: 2.1
Committed: Wed Feb 8 17:41:48 2023 UTC (2 years, 2 months ago) by greg
Branch: MAIN
Log Message:
feat(ratrace): First working version of new C++ rendering tool

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2     static const char RCSid[] = "$Id: rtrace.c,v 2.105 2023/02/02 18:45:23 greg Exp $";
3     #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     if (castonly || every_out[0] != NULL)
191     nproc = 1; /* don't bother multiprocessing */
192     else if (nproc <= 0) // need to get default for system?
193     nproc = myRTmanager.SetThreadCount();
194     if (ray_out[0])
195     myRTmanager.SetCookedCall(printvals);
196     if (every_out[0])
197     myRTmanager.SetTraceCall(ourtrace);
198     if ((flushIntvl > 0) & (nproc > flushIntvl)) {
199     error(WARNING, "reducing number of processes to match flush interval");
200     nproc = flushIntvl;
201     }
202     nproc = myRTmanager.SetThreadCount(nproc);
203     myRTmanager.rtFlags |= RTdoFIFO;
204     if (hresolu > 0) { // print resolution string if appropriate
205     if (vresolu > 0)
206     fprtresolu(hresolu, vresolu, stdout);
207     else
208     fflush(stdout);
209     }
210     int n; /* process input rays */
211     bool pending = false;
212     while ((n = getrays(ivbuf, flushIntvl + !flushIntvl)) > 0) {
213     if ((vcount > 0) & (n > vcount)) {
214     error(WARNING, "extra ray(s) past end of input");
215     n = vcount;
216     } // put ray(s) into queue
217     if (myRTmanager.EnqueueBundle(ivbuf, n) < 0)
218     error(USER, "ray queuing failure");
219     pending |= (n > 1); // time to flush output?
220     bool atZero = IsZeroVec(ivbuf[2*n-1]);
221     if (pending & (atZero | (n == flushIntvl))) {
222     if (!myRTmanager.FlushQueue())
223     error(USER, "ray flush error");
224     fflush(stdout);
225     pending = false;
226     } else
227     pending |= !atZero;
228     if (ferror(stdout))
229     error(SYSTEM, "write error");
230     if (vcount && !(vcount -= n)) /* check for end */
231     break;
232     }
233     if (vcount)
234     error(WARNING, feof(inpfp) ? "unexpected EOF on input" :
235     "input read error");
236     if (fflush(stdout) < 0)
237     error(SYSTEM, "write error");
238     if (fname != NULL) {
239     fclose(inpfp);
240     inpfp = NULL;
241     }
242     free(ivbuf);
243     }
244    
245     int
246     setrtoutput(const char *outvals) /* set up output tables, return #comp */
247     {
248     const char *vs = outvals;
249     oputf_t **table = ray_out;
250     int ncomp = 0;
251    
252     if (!*vs)
253     error(USER, "empty output specification");
254    
255     switch (outform) { /* make sure (*putreal)() calls someone! */
256     case 'a': putreal = puta; break;
257     case 'f': putreal = putf; break;
258     case 'd': putreal = putd; break;
259     case 'c':
260     if (outvals[1] || !strchr("vrx", outvals[0]))
261     error(USER, "color format only with -ov, -or, -ox");
262     putreal = putrgbe; break;
263     default:
264     error(CONSISTENCY, "botched output format");
265     }
266     castonly = 1; /* sets castonly as side-effect */
267     do
268     switch (*vs) {
269     case 'T': /* trace sources */
270     myRTmanager.rtFlags |= RTtraceSources;
271     /* fall through */
272     case 't': /* trace */
273     if (!vs[1]) break;
274     *table = NULL;
275     table = every_out;
276     castonly = 0;
277     break;
278     case 'o': /* origin */
279     *table++ = oputo;
280     ncomp += 3;
281     break;
282     case 'd': /* direction */
283     *table++ = oputd;
284     ncomp += 3;
285     break;
286     case 'r': /* reflected contrib. */
287     *table++ = oputr;
288     ncomp += 3;
289     castonly = 0;
290     break;
291     case 'R': /* reflected distance */
292     *table++ = oputR;
293     ncomp++;
294     castonly = 0;
295     break;
296     case 'x': /* xmit contrib. */
297     *table++ = oputx;
298     ncomp += 3;
299     castonly = 0;
300     break;
301     case 'X': /* xmit distance */
302     *table++ = oputX;
303     ncomp++;
304     castonly = 0;
305     break;
306     case 'v': /* value */
307     *table++ = oputv;
308     ncomp += 3;
309     castonly = 0;
310     break;
311     case 'V': /* contribution */
312     *table++ = oputV;
313     ncomp += 3;
314     castonly = 0;
315     if (ambounce > 0 && (ambacc > FTINY || ambssamp > 0))
316     error(WARNING,
317     "-otV accuracy depends on -aa 0 -as 0");
318     break;
319     case 'l': /* effective distance */
320     *table++ = oputl;
321     ncomp++;
322     castonly = 0;
323     break;
324     case 'c': /* local coordinates */
325     *table++ = oputc;
326     ncomp += 2;
327     break;
328     case 'L': /* single ray length */
329     *table++ = oputL;
330     ncomp++;
331     break;
332     case 'p': /* point */
333     *table++ = oputp;
334     ncomp += 3;
335     break;
336     case 'n': /* perturbed normal */
337     *table++ = oputn;
338     ncomp += 3;
339     castonly = 0;
340     break;
341     case 'N': /* unperturbed normal */
342     *table++ = oputN;
343     ncomp += 3;
344     break;
345     case 's': /* surface */
346     *table++ = oputs;
347     ncomp++;
348     break;
349     case 'w': /* weight */
350     *table++ = oputw;
351     ncomp++;
352     break;
353     case 'W': /* coefficient */
354     *table++ = oputW;
355     ncomp += 3;
356     castonly = 0;
357     if (ambounce > 0 && (ambacc > FTINY) | (ambssamp > 0))
358     error(WARNING,
359     "-otW accuracy depends on -aa 0 -as 0");
360     break;
361     case 'm': /* modifier */
362     *table++ = oputm;
363     ncomp++;
364     break;
365     case 'M': /* material */
366     *table++ = oputM;
367     ncomp++;
368     break;
369     case '~': /* tilde */
370     *table++ = oputtilde;
371     break;
372     default:
373     sprintf(errmsg, "unrecognized output option '%c'", *vs);
374     error(USER, errmsg);
375     }
376     while (*++vs);
377    
378     *table = NULL;
379     if (*every_out != NULL)
380     ncomp = 0;
381     /* compatibility */
382     if ((do_irrad | (myRTmanager.rtFlags & RTimmIrrad)) && castonly)
383     error(USER, "-I+ and -i+ options require some value output");
384     for (table = ray_out; *table != NULL; table++) {
385     if ((*table == oputV) | (*table == oputW))
386     error(WARNING, "-oVW options require trace mode");
387     if ((do_irrad | (myRTmanager.rtFlags & RTimmIrrad)) &&
388     (*table == oputr) | (*table == oputR) |
389     (*table == oputx) | (*table == oputX))
390     error(WARNING, "-orRxX options incompatible with -I+ and -i+");
391     }
392     return(ncomp);
393     }
394    
395     static void
396     printvals( /* print requested ray values */
397     RAY *r, void *cd
398     )
399     {
400     oputf_t **tp;
401    
402     if (ray_out[0] == NULL)
403     return;
404     #ifdef getc_unlocked
405     flockfile(stdout);
406     #endif
407     for (tp = ray_out; *tp != NULL; tp++)
408     (**tp)(r);
409     if (outform == 'a')
410     putchar('\n');
411     #ifdef getc_unlocked
412     funlockfile(stdout);
413     #endif
414     }
415    
416     void
417     tranotify( /* record new modifier */
418     OBJECT obj
419     )
420     {
421     static int hitlimit = 0;
422     OBJREC *o = objptr(obj);
423     char **tralp;
424    
425     if (obj == OVOID) { /* starting over */
426     traset[0] = 0;
427     hitlimit = 0;
428     return;
429     }
430     if (hitlimit || !ismodifier(o->otype))
431     return;
432     for (tralp = tralist; *tralp != NULL; tralp++)
433     if (!strcmp(o->oname, *tralp)) {
434     if (traset[0] >= MAXTSET) {
435     error(WARNING, "too many modifiers in trace list");
436     hitlimit++;
437     return; /* should this be fatal? */
438     }
439     insertelem(traset, obj);
440     return;
441     }
442     }
443    
444     static void
445     ourtrace( /* print ray values */
446     RAY *r, void *cd
447     )
448     {
449     oputf_t **tp;
450    
451     if (every_out[0] == NULL)
452     return;
453     if (r->ro == NULL) {
454     if (traincl == 1)
455     return;
456     } else if (traincl != -1 && traincl != inset(traset, r->ro->omod))
457     return;
458     #ifdef getc_unlocked
459     flockfile(stdout);
460     #endif
461     tabin(r);
462     for (tp = every_out; *tp != NULL; tp++)
463     (**tp)(r);
464     if (outform == 'a')
465     putchar('\n');
466     #ifdef getc_unlocked
467     funlockfile(stdout);
468     #endif
469     }
470    
471     static void
472     tabin( /* tab in appropriate amount */
473     RAY *r
474     )
475     {
476     const RAY *rp;
477    
478     for (rp = r->parent; rp != NULL; rp = rp->parent)
479     putchar('\t');
480     }
481    
482     static void
483     oputo( /* print origin */
484     RAY *r
485     )
486     {
487     (*putreal)(r->rorg, 3);
488     }
489    
490     static void
491     oputd( /* print direction */
492     RAY *r
493     )
494     {
495     (*putreal)(r->rdir, 3);
496     }
497    
498     static void
499     oputr( /* print mirrored contribution */
500     RAY *r
501     )
502     {
503     RREAL cval[3];
504    
505     cval[0] = colval(r->mcol,RED);
506     cval[1] = colval(r->mcol,GRN);
507     cval[2] = colval(r->mcol,BLU);
508     (*putreal)(cval, 3);
509     }
510    
511     static void
512     oputR( /* print mirrored distance */
513     RAY *r
514     )
515     {
516     (*putreal)(&r->rmt, 1);
517     }
518    
519     static void
520     oputx( /* print unmirrored contribution */
521     RAY *r
522     )
523     {
524     RREAL cval[3];
525    
526     cval[0] = colval(r->rcol,RED) - colval(r->mcol,RED);
527     cval[1] = colval(r->rcol,GRN) - colval(r->mcol,GRN);
528     cval[2] = colval(r->rcol,BLU) - colval(r->mcol,BLU);
529     (*putreal)(cval, 3);
530     }
531    
532     static void
533     oputX( /* print unmirrored distance */
534     RAY *r
535     )
536     {
537     (*putreal)(&r->rxt, 1);
538     }
539    
540     static void
541     oputv( /* print value */
542     RAY *r
543     )
544     {
545     RREAL cval[3];
546    
547     cval[0] = colval(r->rcol,RED);
548     cval[1] = colval(r->rcol,GRN);
549     cval[2] = colval(r->rcol,BLU);
550     (*putreal)(cval, 3);
551     }
552    
553     static void
554     oputV( /* print value contribution */
555     RAY *r
556     )
557     {
558     RREAL contr[3];
559    
560     raycontrib(contr, r, PRIMARY);
561     multcolor(contr, r->rcol);
562     (*putreal)(contr, 3);
563     }
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     RREAL contr[3];
663     /* shadow ray not on source? */
664     if (r->rsrc >= 0 && source[r->rsrc].so != r->ro)
665     setcolor(contr, 0.0, 0.0, 0.0);
666     else
667     raycontrib(contr, r, PRIMARY);
668    
669     (*putreal)(contr, 3);
670     }
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     }