ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rxtrace.cpp
Revision: 2.5
Committed: Thu May 2 22:10:43 2024 UTC (2 weeks, 2 days ago) by greg
Branch: MAIN
CVS Tags: HEAD
Changes since 2.4: +2 -2 lines
Log Message:
fix(rxtrace): Minor fixes

File Contents

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