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 (10 days, 7 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

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.8 static const char RCSid[] = "$Id: rxpmain.cpp,v 2.7 2025/01/02 20:19:48 greg Exp $";
3 greg 2.1 #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 greg 2.8 #include "func.h"
17 greg 2.1
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 greg 2.3 quit(int code) /* quit program */
63 greg 2.1 {
64 greg 2.7 exit(code); // don't bother about freeing anything
65 greg 2.1 }
66    
67 greg 2.5 /* 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 greg 2.1
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 greg 2.8 /* initialize calcomp routines */
112     initfunc();
113 greg 2.5 /* set defaults */
114     default_options();
115 greg 2.1 /* 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 greg 2.2 if (pct < 100.-FTINY && tnow - lastReportTime < ralrm)
514 greg 2.1 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 greg 2.6 * If seq is greater than zero, we will render a sequence of
528 greg 2.1 * 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 greg 2.6 return; // all done if not a sequence
574 greg 2.1 }
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 greg 2.6 } while (seq++); // all done if not a sequence
626 greg 2.1 }