ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rxpmain.cpp
Revision: 2.8
Committed: Tue Apr 22 17:12:25 2025 UTC (9 days, 10 hours ago) by greg
Branch: MAIN
CVS Tags: HEAD
Changes since 2.7: +4 -1 lines
Log Message:
feat(rpict,rtrace,rvu,rxpict,rxtrace,rxpiece): Added -e expr and -f file.cal options

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rxpmain.cpp,v 2.7 2025/01/02 20:19:48 greg Exp $";
3 #endif
4 /*
5 * rxpmain.cpp - main for rxpict batch rendering program
6 */
7
8 #include "copyright.h"
9
10 #include <time.h>
11 #include <signal.h>
12
13 #include "rtprocess.h" /* getpid() */
14 #include "platform.h"
15 #include "RpictSimulManager.h"
16 #include "func.h"
17
18 extern char *progname; /* argv[0] */
19 const char *sigerr[NSIG]; /* signal error messages */
20 char *errfile = NULL; /* error output file */
21
22 VIEW ourview = STDVIEW; /* view parameters */
23 int hresolu = 512; /* horizontal resolution */
24 int vresolu = 512; /* vertical resolution */
25 double pixaspect = 1.0; /* pixel aspect ratio */
26 int hres, vres; /* current image resolution for srcdraw.c */
27
28 int psample = 4; /* pixel sample size */
29 double maxdiff = .05; /* max. difference for interpolation */
30 double dstrpix = 0.67; /* square pixel distribution */
31
32 double mblur = 0.; /* motion blur parameter */
33
34 double dblur = 0.; /* depth-of-field blur parameter */
35
36 int nproc = 1; /* number of processes to run */
37
38 int ralrm = 0; /* seconds between reports */
39
40 double pctdone = 0.0; /* percentage done */
41 time_t tlastrept = 0L; /* time at last report */
42 time_t tstart; /* starting time */
43
44 RenderDataType dtype = RDTrgbe; // output data flags
45
46 RpictSimulManager myRPmanager; // global simulation manager
47
48 static void onsig(int signo);
49 static void sigdie(int signo, const char *msg);
50 static void printdefaults(void);
51
52 /* rxpict additional features */
53 #define RXPICT_FEATURES "Recovery\nIrradianceCalc\nViewTypes=v,l,a,h,s,c\n" \
54 "ParticipatingMedia=Mist\n" \
55 "HessianAmbientCache\nAmbientAveraging\nAmbientValueSharing\n" \
56 "PixelJitter\nPixelSampling\nPixelMotion\nPixelDepthOfField\n" \
57 "SmallSourceDrawing\nViewSequence\nProgressReporting\n" \
58 "AdaptiveShadowTesting\nOutputs=v,l\n" \
59 "OutputCS=RGB,XYZ,prims,spec\n"
60
61 void
62 quit(int code) /* quit program */
63 {
64 exit(code); // don't bother about freeing anything
65 }
66
67 /* Set default options */
68 static void
69 default_options(void)
70 {
71 shadthresh = .05;
72 shadcert = .5;
73 srcsizerat = .25;
74 directrelay = 1;
75 ambacc = 0.2;
76 ambres = 64;
77 ambdiv = 512;
78 ambssamp = 128;
79 maxdepth = 7;
80 }
81
82 int
83 main(int argc, char *argv[])
84 {
85 #define check(ol,al) if (argv[i][ol] || \
86 badarg(argc-i-1,argv+i+1,al)) \
87 goto badopt
88 #define check_bool(olen,var) switch (argv[i][olen]) { \
89 case '\0': var = !var; break; \
90 case 'y': case 'Y': case 't': case 'T': \
91 case '+': case '1': var = 1; break; \
92 case 'n': case 'N': case 'f': case 'F': \
93 case '-': case '0': var = 0; break; \
94 default: goto badopt; }
95 RGBPRIMS our_prims; /* private output color primitives */
96 int seqstart = 0;
97 char *recover = NULL;
98 char *outfile = NULL;
99 char *zfile = NULL;
100 int outfmt = 'c';
101 int rval;
102 int i;
103 /* record start time */
104 tstart = time(NULL);
105 /* global program name */
106 progname = argv[0];
107 /* feature check only? */
108 strcat(RFeatureList, RXPICT_FEATURES);
109 if (argc > 1 && !strcmp(argv[1], "-features"))
110 return feature_status(argc-2, argv+2);
111 /* initialize calcomp routines */
112 initfunc();
113 /* set defaults */
114 default_options();
115 /* option city */
116 for (i = 1; i < argc; i++) {
117 /* expand arguments */
118 while ((rval = expandarg(&argc, &argv, i)) > 0)
119 ;
120 if (rval < 0) {
121 sprintf(errmsg, "cannot expand '%s'", argv[i]);
122 error(SYSTEM, errmsg);
123 }
124 if (argv[i] == NULL || argv[i][0] != '-')
125 break; /* break from options */
126 if (!strcmp(argv[i], "-version")) {
127 puts(VersionID);
128 quit(0);
129 }
130 if (!strcmp(argv[i], "-defaults") ||
131 !strcmp(argv[i], "-help")) {
132 printdefaults();
133 quit(0);
134 }
135 rval = getrenderopt(argc-i, argv+i);
136 if (rval >= 0) {
137 i += rval;
138 continue;
139 }
140 rval = getviewopt(&ourview, argc-i, argv+i);
141 if (rval >= 0) {
142 i += rval;
143 continue;
144 }
145 /* rxpict options */
146 switch (argv[i][1]) {
147 case 'v': /* view file */
148 if (argv[i][2] != 'f')
149 goto badopt;
150 check(3,"s");
151 rval = viewfile(argv[++i], &ourview, NULL);
152 if (rval < 0) {
153 sprintf(errmsg,
154 "cannot open view file \"%s\"",
155 argv[i]);
156 error(SYSTEM, errmsg);
157 } else if (rval == 0) {
158 sprintf(errmsg,
159 "bad view file \"%s\"",
160 argv[i]);
161 error(USER, errmsg);
162 }
163 break;
164 case 'n': /* number of processes */
165 check(2,"i");
166 nproc = atoi(argv[++i]);
167 if (nproc < 0 && (nproc += RadSimulManager::GetNCores()) <= 0)
168 nproc = 1;
169 break;
170 case 'f': /* output format */
171 if ((argv[i][2] != 'c') & (argv[i][2] != 'f')
172 || argv[i][3])
173 goto badopt;
174 outfmt = argv[i][2];
175 break;
176 case 'p': /* pixel */
177 switch (argv[i][2]) {
178 case 's': /* sample */
179 check(3,"i");
180 psample = atoi(argv[++i]);
181 if (psample < 1) psample = 1;
182 break;
183 case 't': /* threshold */
184 check(3,"f");
185 maxdiff = atof(argv[++i]);
186 break;
187 case 'j': /* jitter */
188 check(3,"f");
189 dstrpix = atof(argv[++i]);
190 break;
191 case 'a': /* aspect */
192 check(3,"f");
193 pixaspect = atof(argv[++i]);
194 break;
195 case 'm': /* motion */
196 check(3,"f");
197 mblur = atof(argv[++i]);
198 mblur *= (mblur > 0);
199 break;
200 case 'd': /* aperture */
201 check(3,"f");
202 dblur = atof(argv[++i]);
203 dblur *= (dblur > 0);
204 break;
205 case 'R': /* standard RGB output */
206 if (strcmp(argv[i]+2, "RGB"))
207 goto badopt;
208 myRPmanager.prims = stdprims;
209 dtype = RDTnewCT(dtype, RDTrgbe);
210 break;
211 case 'X': /* XYZ output */
212 if (strcmp(argv[i]+2, "XYZ"))
213 goto badopt;
214 myRPmanager.prims = xyzprims;
215 dtype = RDTnewCT(dtype, RDTxyze);
216 break;
217 case 'c': /* chromaticities */
218 check(3,"ffffffff");
219 rval = 0;
220 for (int j = 0; j < 8; j++) {
221 our_prims[0][j] = atof(argv[++i]);
222 rval |= fabs(our_prims[0][j]-stdprims[0][j]) > .001;
223 }
224 if (rval) {
225 if (!colorprimsOK(our_prims))
226 error(USER, "illegal primary chromaticities");
227 myRPmanager.prims = our_prims;
228 } else
229 myRPmanager.prims = stdprims;
230 dtype = RDTnewCT(dtype, RDTrgbe);
231 break;
232 default:
233 goto badopt;
234 }
235 break;
236 case 'd': /* reference depth */
237 if (argv[i][2] || !myRPmanager.SetReferenceDepth(argv[++i]))
238 goto badopt;
239 dtype = RDTnewDT(dtype, RDTdshort);
240 break;
241 case 'x': /* x resolution */
242 check(2,"i");
243 hresolu = atoi(argv[++i]);
244 break;
245 case 'y': /* y resolution */
246 check(2,"i");
247 vresolu = atoi(argv[++i]);
248 break;
249 case 'S': /* start index */
250 check(2,"i");
251 seqstart = atoi(argv[++i]);
252 seqstart *= (seqstart > 0);
253 break;
254 case 'o': /* output file */
255 check(2,"s");
256 outfile = argv[++i];
257 break;
258 case 'z': /* z file */
259 check(2,"s");
260 zfile = argv[++i];
261 break;
262 case 'r': /* recover file */
263 if (argv[i][2] == 'o') { /* +output */
264 check(3,"s");
265 outfile = argv[i+1];
266 } else
267 check(2,"s");
268 recover = argv[++i];
269 break;
270 #if MAXCSAMP>3
271 case 'c': /* output spectral results */
272 if (argv[i][2] != 'o')
273 goto badopt;
274 rval = (myRPmanager.prims == NULL);
275 check_bool(3,rval);
276 if (rval)
277 myRPmanager.prims = NULL;
278 else if (myRPmanager.prims == NULL)
279 myRPmanager.prims = stdprims;
280 dtype = RDTnewCT(dtype, rval ? RDTscolr : RDTrgbe);
281 break;
282 #endif
283 case 't': /* timer */
284 check(2,"i");
285 ralrm = atoi(argv[++i]);
286 break;
287 case 'w': /* warnings */
288 rval = erract[WARNING].pf != NULL;
289 check_bool(2,rval);
290 if (rval) erract[WARNING].pf = wputs;
291 else erract[WARNING].pf = NULL;
292 break;
293 case 'e': /* error file */
294 check(2,"s");
295 errfile = argv[++i];
296 break;
297 default:
298 goto badopt;
299 }
300 }
301 if (maxdiff <= FTINY) /* check for useless sampling */
302 psample = 1;
303 if (zfile == NULL) /* set up depth output */
304 dtype = RDTnewDT(dtype, RDTnone);
305 else if (!RDTdepthT(dtype))
306 dtype = RDTnewDT(dtype, RDTdfloat);
307 /* check pixel output type */
308 if ((myRPmanager.prims == NULL) & (NCSAMP == 3)) {
309 myRPmanager.prims = stdprims;
310 dtype = RDTnewCT(dtype, RDTrgbe);
311 }
312 if (outfmt == 'f')
313 switch (RDTcolorT(dtype)) {
314 case RDTrgbe:
315 dtype = RDTnewCT(dtype, RDTrgb);
316 break;
317 case RDTxyze:
318 dtype = RDTnewCT(dtype, RDTxyz);
319 break;
320 case RDTscolr:
321 dtype = RDTnewCT(dtype, RDTscolor);
322 break;
323 case RDTrgb:
324 case RDTxyz:
325 case RDTscolor:
326 break;
327 default:
328 error(INTERNAL, "botched color output type");
329 }
330 /* set up signal handling */
331 sigdie(SIGINT, "Interrupt");
332 #ifdef SIGHUP
333 sigdie(SIGHUP, "Hangup");
334 #endif
335 sigdie(SIGTERM, "Terminate");
336 #ifdef SIGPIPE
337 sigdie(SIGPIPE, "Broken pipe");
338 #endif
339 #ifdef SIGALRM
340 sigdie(SIGALRM, "Alarm clock");
341 #endif
342 #ifdef SIGXCPU
343 sigdie(SIGXCPU, "CPU limit exceeded");
344 sigdie(SIGXFSZ, "File size exceeded");
345 #endif
346 /* open error file */
347 if (errfile != NULL) {
348 if (freopen(errfile, "a", stderr) == NULL)
349 quit(2);
350 fprintf(stderr, "**************\n*** PID %5d: ",
351 getpid());
352 printargs(argc, argv, stderr);
353 putc('\n', stderr);
354 fflush(stderr);
355 }
356 #ifdef NICE
357 nice(NICE); /* lower priority */
358 #endif
359 if (i < argc-1)
360 goto badopt;
361 // load octree
362 if (!myRPmanager.LoadOctree(argv[i]))
363 error(USER, "missing octree argument");
364 // add new header info
365 myRPmanager.AddHeader(i, argv);
366 {
367 char buf[128] = "SOFTWARE= ";
368 strcpy(buf+10, VersionID);
369 myRPmanager.AddHeader(buf);
370 }
371 // start our engines
372 nproc = myRPmanager.SetThreadCount(nproc);
373 // batch render picture(s)
374 rpict(seqstart, outfile, zfile, recover);
375
376 quit(0); // clean up and exit
377
378 badopt:
379 sprintf(errmsg, "command line error at '%s'", argv[i]);
380 error(USER, errmsg);
381 return 1; /* pro forma return */
382
383 #undef check
384 #undef check_bool
385 }
386
387
388 void
389 wputs( /* warning output function */
390 const char *s
391 )
392 {
393 int lasterrno = errno;
394 eputs(s);
395 errno = lasterrno;
396 }
397
398
399 void
400 eputs( /* put string to stderr */
401 const char *s
402 )
403 {
404 static int midline = 0;
405
406 if (!*s)
407 return;
408 if (!midline++) {
409 fputs(progname, stderr);
410 fputs(": ", stderr);
411 }
412 fputs(s, stderr);
413 if (s[strlen(s)-1] == '\n') {
414 fflush(stderr);
415 midline = 0;
416 }
417 }
418
419
420 static void
421 onsig( /* fatal signal */
422 int signo
423 )
424 {
425 static int gotsig = 0;
426
427 if (gotsig++) /* two signals and we're gone! */
428 _exit(signo);
429
430 #ifdef SIGALRM /* XXX how critical is this? */
431 alarm(30); /* allow 30 seconds to clean up */
432 signal(SIGALRM, SIG_DFL); /* make certain we do die */
433 #endif
434 eputs("signal - ");
435 eputs(sigerr[signo]);
436 eputs("\n");
437 quit(3);
438 }
439
440
441 static void
442 sigdie( /* set fatal signal */
443 int signo,
444 const char *msg
445 )
446 {
447 if (signal(signo, onsig) == SIG_IGN)
448 signal(signo, SIG_IGN);
449 sigerr[signo] = msg;
450 }
451
452
453 static void
454 printdefaults(void) /* print default values to stdout */
455 {
456 printf("-n %-2d\t\t\t\t# number of rendering processes\n", nproc);
457 printf("-vt%c\t\t\t\t# view type %s\n", ourview.type,
458 ourview.type==VT_PER ? "perspective" :
459 ourview.type==VT_PAR ? "parallel" :
460 ourview.type==VT_HEM ? "hemispherical" :
461 ourview.type==VT_ANG ? "angular" :
462 ourview.type==VT_CYL ? "cylindrical" :
463 ourview.type==VT_PLS ? "planisphere" :
464 "unknown");
465 printf("-vp %f %f %f\t# view point\n",
466 ourview.vp[0], ourview.vp[1], ourview.vp[2]);
467 printf("-vd %f %f %f\t# view direction\n",
468 ourview.vdir[0], ourview.vdir[1], ourview.vdir[2]);
469 printf("-vu %f %f %f\t# view up\n",
470 ourview.vup[0], ourview.vup[1], ourview.vup[2]);
471 printf("-vh %f\t\t\t# view horizontal size\n", ourview.horiz);
472 printf("-vv %f\t\t\t# view vertical size\n", ourview.vert);
473 printf("-vo %f\t\t\t# view fore clipping plane\n", ourview.vfore);
474 printf("-va %f\t\t\t# view aft clipping plane\n", ourview.vaft);
475 printf("-vs %f\t\t\t# view shift\n", ourview.hoff);
476 printf("-vl %f\t\t\t# view lift\n", ourview.voff);
477 printf("-x %-9d\t\t\t# x resolution\n", hresolu);
478 printf("-y %-9d\t\t\t# y resolution\n", vresolu);
479 if (myRPmanager.prims == stdprims)
480 printf("-pRGB\t\t\t\t# standard RGB color output\n");
481 else if (myRPmanager.prims == xyzprims)
482 printf("-pXYZ\t\t\t\t# CIE XYZ color output\n");
483 else if (myRPmanager.prims != NULL)
484 printf("-pc %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\t# output color primaries and white point\n",
485 myRPmanager.prims[RED][0], myRPmanager.prims[RED][1],
486 myRPmanager.prims[GRN][0], myRPmanager.prims[GRN][1],
487 myRPmanager.prims[BLU][0], myRPmanager.prims[BLU][1],
488 myRPmanager.prims[WHT][0], myRPmanager.prims[WHT][1]);
489 if (NCSAMP > 3)
490 printf(myRPmanager.prims != NULL ? "-co-\t\t\t\t# output tristimulus colors\n" :
491 "-co+\t\t\t\t# output spectral values\n");
492 printf("-pa %f\t\t\t# pixel aspect ratio\n", pixaspect);
493 printf("-pj %f\t\t\t# pixel jitter\n", dstrpix);
494 printf("-pm %f\t\t\t# pixel motion\n", mblur);
495 printf("-pd %f\t\t\t# pixel depth-of-field\n", dblur);
496 printf("-ps %-9d\t\t\t# pixel sample\n", psample);
497 printf("-pt %f\t\t\t# pixel threshold\n", maxdiff);
498 printf("-t %-9d\t\t\t# time between reports\n", ralrm);
499 printf(erract[WARNING].pf != NULL ?
500 "-w+\t\t\t\t# warning messages on\n" :
501 "-w-\t\t\t\t# warning messages off\n");
502 print_rdefaults();
503 }
504
505
506 // my progress report call-back
507 static void
508 progReporter(double pct)
509 {
510 static time_t lastReportTime = 0;
511 time_t tnow = time(NULL);
512
513 if (pct < 100.-FTINY && tnow - lastReportTime < ralrm)
514 return; // too soon, my Precious...
515
516 sprintf(errmsg, "%7.3f%% done after %7.3f hours\n", pct, (tnow-tstart)/3600.);
517 eputs(errmsg);
518 // reset timer at 100%
519 lastReportTime = tnow * (pct < 100.-FTINY);
520 }
521
522
523 // Principal function for rpict execution (prototype in ray.h for some reason)
524 void
525 rpict(int seq, char *pout, char *zout, char *prvr)
526 /*
527 * If seq is greater than zero, we will render a sequence of
528 * images based on view parameter strings read from the standard input.
529 * If pout is NULL, then all images will be sent to the standard ouput.
530 * If seq is greater than zero and prvr is an integer, then it is the
531 * frame number at which rendering should begin. Preceeding view parameter
532 * strings will be skipped in the input.
533 * Note that pout and zout should contain %d format specifications for
534 * sequenced file naming.
535 */
536 {
537 char fbuf[256], dbuf[256];
538
539 if (!zout ^ !RDTdepthT(dtype))
540 error(INTERNAL, "output depth type requires spec and vice versa");
541
542 if (prvr && isint(prvr)) { // sequence recovery?
543 if (!seq)
544 error(USER, "sequence recovery requires starting frame");
545 if (!pout)
546 error(USER, "need output spec for sequence recovery");
547 int rno = atoi(prvr);
548 if (rno < seq)
549 error(USER, "recovery frame before starting frame");
550 while (seq <= rno) {
551 if (!fgets(fbuf, sizeof(fbuf), stdin))
552 error(USER, "recovery frame past end of sequence");
553 seq += (isview(fbuf) && sscanview(&ourview, fbuf) > 0);
554 }
555 sprintf(prvr=fbuf, pout, rno);
556 }
557 if (ralrm > 0)
558 myRPmanager.prCB = progReporter;
559 else
560 myRPmanager.prCB = NULL;
561 if (prvr) { // recovering partial render?
562 if ((seq > 0) & (prvr != fbuf))
563 error(USER, "recover spec must be number in sequence");
564 if (zout) sprintf(dbuf, zout, seq);
565 if (ralrm > 0) {
566 sprintf(errmsg, "resuming partial rendering '%s'\n", prvr);
567 eputs(errmsg);
568 }
569 dtype = myRPmanager.ResumeFrame(prvr, zout ? dbuf : zout);
570 if (!dtype)
571 error(USER, "ResumeFrame() failed");
572 if (!seq)
573 return; // all done if not a sequence
574 }
575 do {
576 if (prvr) // have view from sequence recovery?
577 prvr = NULL;
578 else if (seq) { // else read next view in sequence
579 while (fgets(fbuf, sizeof(fbuf), stdin))
580 if (isview(fbuf) && sscanview(&ourview, fbuf) > 0)
581 break;
582 if (feof(stdin))
583 return; // reached end of view input
584 }
585 // get (indexed) output file name(s)
586 if (pout) sprintf(fbuf, pout, seq);
587 if (zout) sprintf(dbuf, zout, seq);
588
589 if (ralrm > 0) { // start report if requested
590 if (myRPmanager.NThreads() > 1)
591 sprintf(errmsg, "%2d processes ", myRPmanager.NThreads());
592 else
593 sprintf(errmsg, "PID %6d ", getpid());
594 eputs(errmsg);
595 if (seq) {
596 sprintf(errmsg, "rendering frame %5d ", seq);
597 eputs(errmsg);
598 } else
599 eputs("rendering picture ");
600 if (pout) {
601 sprintf(errmsg, "to '%s'\n", fbuf);
602 eputs(errmsg);
603 } else
604 eputs("to stdout\n");
605 if (zout) {
606 sprintf(errmsg, "\twith %s depth map in '%s'\n",
607 RDTdepthT(dtype)==RDTdshort ?
608 "encoded 16-bit" : "raw float",
609 dbuf);
610 eputs(errmsg);
611 }
612 }
613 // set up view and size
614 int xydim[2] = {hresolu, vresolu};
615 if (!myRPmanager.NewFrame(ourview, xydim, &pixaspect))
616 error(USER, "NewFrame() failed");
617
618 myRPmanager.frameNo = seq;
619
620 errno = 0; // render frame, skipping if it exists
621 if (!myRPmanager.RenderFrame(pout ? fbuf : pout, dtype,
622 zout ? dbuf : zout)
623 && !seq | (errno != EEXIST))
624 error(USER, "RenderFrame() failed");
625 } while (seq++); // all done if not a sequence
626 }