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 (7 weeks, 3 days ago) by greg
Branch: MAIN
Changes since 2.1: +6 -4 lines
Log Message:
perf: added datavector() call for quicker spectral interpolation

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rxtrace.cpp,v 2.1 2023/08/21 22:39:05 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.GetNCores() + nproc;
194 if (nproc <= 0) nproc = 1;
195 }
196 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 }