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 (2 months, 1 week 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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rxtrace.cpp,v 2.8 2025/01/02 01:54:49 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 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 #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 RayReportCall printvals; /* print selected ray values */
73
74 void putscolor(COLORV *scol, double sf = 1.); /* convert/print spectral color */
75
76 static oputf_t *ray_out[32], *every_out[32];
77
78 putf_t *putreal; /* put out real vector */
79
80 void
81 quit( /* quit program */
82 int code
83 )
84 {
85 if (ray_pnprocs < 0)
86 _exit(code); /* avoid flush in child */
87
88 if (ray_pnprocs > 1)
89 myRTmanager.SetThreadCount(1);
90
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 case 'c':
104 if (out_prims == NULL)
105 return(SPECFMT);
106 if (out_prims == xyzprims)
107 return(CIEFMT);
108 return(COLRFMT);
109 }
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 if (castonly || every_out[0] != NULL) {
203 nproc = 1; /* don't bother multiprocessing */
204 } else if (nproc <= 0) { // need to get default for system?
205 nproc = myRTmanager.GetNCores() + nproc;
206 if (nproc <= 0) nproc = 1;
207 }
208 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 #ifdef getc_unlocked
219 flockfile(inpfp); /* avoid lock/unlock overhead */
220 flockfile(stdout);
221 #endif
222 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 if (myRTmanager.FlushQueue() <= 0)
241 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 if (myRTmanager.FlushQueue() < 0 || fflush(stdout) < 0)
255 error(SYSTEM, "final flush error");
256 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 const int nco = (sens_curve != NULL) ? 1 :
269 (out_prims != NULL) ? 3 : NCSAMP;
270 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 ncomp += nco;
309 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 ncomp += nco;
319 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 ncomp += nco;
329 castonly = 0;
330 break;
331 case 'V': /* contribution */
332 *table++ = oputV;
333 ncomp += nco;
334 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 ncomp += nco;
376 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 int
416 printvals( /* print requested ray values */
417 RAY *r, void *cd
418 )
419 {
420 oputf_t **tp;
421
422 if (ray_out[0] == NULL)
423 return 0;
424 for (tp = ray_out; *tp != NULL; tp++)
425 (**tp)(r);
426 if (outform == 'a')
427 putchar('\n');
428 return 1;
429 }
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 static int
460 ourtrace( /* print ray values */
461 RAY *r, void *cd
462 )
463 {
464 oputf_t **tp;
465
466 if (every_out[0] == NULL)
467 return 0;
468 if (r->ro == NULL) {
469 if (traincl == 1)
470 return 0;
471 } else if (traincl != -1 && traincl != inset(traset, r->ro->omod))
472 return 0;
473 tabin(r);
474 for (tp = every_out; *tp != NULL; tp++)
475 (**tp)(r);
476 if (outform == 'a')
477 putchar('\n');
478 return 1;
479 }
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 putscolor(r->mcol, out_scalefactor);
514 }
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 SCOLOR cdiff;
530
531 copyscolor(cdiff, r->rcol);
532 sopscolor(cdiff, -=, r->mcol);
533
534 putscolor(cdiff, out_scalefactor);
535 }
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 putscolor(r->rcol, out_scalefactor);
551 }
552
553 static void
554 oputV( /* print value contribution */
555 RAY *r
556 )
557 {
558 SCOLOR contr;
559
560 raycontrib(contr, r, PRIMARY);
561 smultscolor(contr, r->rcol);
562 putscolor(contr, out_scalefactor);
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 SCOLOR contr;
663 /* shadow ray not on source? */
664 if (r->rsrc >= 0 && source[r->rsrc].so != r->ro)
665 scolorblack(contr);
666 else
667 raycontrib(contr, r, PRIMARY);
668
669 putscolor(contr);
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 }
769
770 void
771 putscolor(COLORV *scol, double sf) /* output (spectral) color */
772 {
773 static COLORMAT xyz2myrgbmat;
774 SCOLOR my_scol;
775 COLOR col;
776 /* single channel output? */
777 if (sens_curve != NULL) {
778 RREAL v = (*sens_curve)(scol) * sf;
779 (*putreal)(&v, 1);
780 return;
781 }
782 if (sf != 1.) { /* apply scalefactor if any */
783 copyscolor(my_scol, scol);
784 scalescolor(my_scol, sf);
785 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 }