ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimate.c
Revision: 2.53
Committed: Thu Feb 21 01:22:06 2008 UTC (16 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R9
Changes since 2.52: +1 -2 lines
Log Message:
Initial check-in of untested rsensor

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.53 static const char RCSid[] = "$Id: ranimate.c,v 2.52 2006/04/18 04:30:35 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * Radiance animation control program
6 greg 2.29 *
7     * The main difference between this program and ranimove is that
8     * we have many optimizations here for camera motion in static
9     * environments, calling rpict and pinterp on multiple processors,
10     * where ranimove puts its emphasis on object motion, and does
11     * not use any external programs for image generation.
12     *
13     * See the ranimate(1) man page for further details.
14     */
15    
16 greg 2.31 #include "copyright.h"
17 greg 2.1
18 schorsch 2.43 #include <stdio.h>
19 greg 2.2 #include <ctype.h>
20 greg 2.1 #include <sys/stat.h>
21 schorsch 2.43 #include <time.h>
22 schorsch 2.46 #include <signal.h>
23 schorsch 2.39
24 schorsch 2.43 #include "platform.h"
25 schorsch 2.50 #include "rtprocess.h"
26 schorsch 2.39 #include "paths.h"
27 greg 2.47 #include "standard.h"
28 greg 2.1 #include "view.h"
29     #include "vars.h"
30 greg 2.2 #include "netproc.h"
31 greg 2.29 /* default blur samples */
32     #ifndef DEF_NBLUR
33     #define DEF_NBLUR 5
34     #endif
35 greg 2.10 /* default remote shell */
36 greg 2.49 #ifndef REMSH
37     #define REMSH "ssh"
38     #endif
39 gwlarson 2.27 /* input variables (alphabetical by name) */
40     #define ANIMATE 0 /* animation command */
41     #define ARCHIVE 1 /* archiving command */
42     #define BASENAME 2 /* output image base name */
43 greg 2.48 #define DBLUR 3 /* depth of field blur */
44     #define DIRECTORY 4 /* working (sub)directory */
45     #define DISKSPACE 5 /* how much disk space to use */
46     #define END 6 /* ending frame number */
47     #define EXPOSURE 7 /* how to compute exposure */
48     #define HOST 8 /* rendering host machine */
49     #define INTERP 9 /* # frames to interpolate */
50     #define MBLUR 10 /* motion blur parameters */
51     #define NEXTANIM 11 /* next animation file */
52     #define OCTREE 12 /* octree file name */
53     #define OVERSAMP 13 /* # times to oversample image */
54     #define PFILT 14 /* pfilt options */
55     #define PINTERP 15 /* pinterp options */
56     #define RENDER 16 /* rendering options */
57     #define RESOLUTION 17 /* desired final resolution */
58     #define RIF 18 /* rad input file */
59     #define RSH 19 /* remote shell script or program */
60     #define RTRACE 20 /* use rtrace with pinterp? */
61     #define START 21 /* starting frame number */
62     #define TRANSFER 22 /* frame transfer command */
63     #define VIEWFILE 23 /* animation frame views */
64 greg 2.1
65 greg 2.48 int NVARS = 24; /* total number of variables */
66 greg 2.1
67     VARIABLE vv[] = { /* variable-value pairs */
68 gwlarson 2.27 {"ANIMATE", 2, 0, NULL, onevalue},
69     {"ARCHIVE", 2, 0, NULL, onevalue},
70     {"BASENAME", 3, 0, NULL, onevalue},
71 greg 2.48 {"DBLUR", 2, 0, NULL, onevalue},
72 greg 2.1 {"DIRECTORY", 3, 0, NULL, onevalue},
73 gwlarson 2.27 {"DISKSPACE", 3, 0, NULL, fltvalue},
74 greg 2.1 {"END", 2, 0, NULL, intvalue},
75 gwlarson 2.27 {"EXPOSURE", 3, 0, NULL, onevalue},
76     {"host", 4, 0, NULL, NULL},
77     {"INTERPOLATE", 3, 0, NULL, intvalue},
78     {"MBLUR", 2, 0, NULL, onevalue},
79 greg 2.1 {"NEXTANIM", 3, 0, NULL, onevalue},
80 gwlarson 2.27 {"OCTREE", 3, 0, NULL, onevalue},
81 greg 2.5 {"OVERSAMPLE", 2, 0, NULL, fltvalue},
82 gwlarson 2.27 {"pfilt", 2, 0, NULL, catvalues},
83     {"pinterp", 2, 0, NULL, catvalues},
84     {"render", 3, 0, NULL, catvalues},
85 greg 2.1 {"RESOLUTION", 3, 0, NULL, onevalue},
86 gwlarson 2.27 {"RIF", 3, 0, NULL, onevalue},
87 greg 2.10 {"RSH", 3, 0, NULL, onevalue},
88 gwlarson 2.27 {"RTRACE", 2, 0, NULL, boolvalue},
89     {"START", 2, 0, NULL, intvalue},
90     {"TRANSFER", 2, 0, NULL, onevalue},
91     {"VIEWFILE", 2, 0, NULL, onevalue},
92 greg 2.1 };
93    
94     #define SFNAME "STATUS" /* status file name */
95    
96     struct {
97     char host[64]; /* control host name */
98 schorsch 2.50 RT_PID pid; /* control process id */
99 greg 2.1 char cfname[128]; /* control file name */
100     int rnext; /* next frame to render */
101     int fnext; /* next frame to filter */
102     int tnext; /* next frame to transfer */
103     } astat; /* animation status */
104    
105     char *progname; /* our program name */
106     char *cfname; /* our control file name */
107    
108     int nowarn = 0; /* turn warnings off? */
109     int silent = 0; /* silent mode? */
110     int noaction = 0; /* take no action? */
111    
112 greg 2.10 char *remsh; /* remote shell program/script */
113 greg 2.21 char rendopt[2048]; /* rendering options */
114 greg 2.1 char rresopt[32]; /* rendering resolution options */
115     char fresopt[32]; /* filter resolution options */
116     int pfiltalways; /* always use pfilt? */
117    
118 greg 2.7 char arcargs[10240]; /* files to archive */
119     char *arcfirst, *arcnext; /* pointers to first and next argument */
120    
121 greg 2.2 struct pslot {
122 schorsch 2.50 RT_PID pid; /* process ID (0 if empty) */
123 greg 2.2 int fout; /* output frame number */
124     int (*rcvf)(); /* recover function */
125     } *pslot; /* process slots */
126     int npslots; /* number of process slots */
127    
128 greg 2.4 #define phostname(ps) ((ps)->hostname[0] ? (ps)->hostname : astat.host)
129 greg 2.18 PSERVER *lastpserver; /* last process server with error */
130    
131 schorsch 2.50 static struct pslot * findpslot(RT_PID pid);
132 schorsch 2.43 static void checkdir(void);
133     static VIEW * getview(int n);
134    
135     static char * dirfile(char *df, register char *path);
136     static char * getexp(int n);
137 greg 2.48 static int getblur(double *mbf, double *dbf);
138 schorsch 2.43 static int getastat(void);
139     static void getradfile(char *rfargs);
140     static void badvalue(int vc);
141     static int rmfile(char *fn);
142     static int runcom(char *cs);
143     static int pruncom(char *com, char *ppins, int maxcopies);
144     static void bwait(int ncoms);
145 schorsch 2.50 static RT_PID bruncom(char *com, int fout, int (*rf)());
146 schorsch 2.43 static int serverdown(void);
147 schorsch 2.46 static pscompfunc donecom;
148 schorsch 2.43 static int countviews(void);
149     static int dofilt(int frame, int rvr);
150     static void archive(void);
151     static int frecover(int frame);
152     static int recover(int frame);
153     static void sethosts(void);
154     static void walkwait(int first, int last, char *vfn);
155     static void animrend(int frame, VIEW *vp);
156     static void transferframes(void);
157     static void filterframes(void);
158     static void renderframes(int nframes);
159     static void animate(void);
160     static void setdefaults(void);
161     static void putastat(void);
162 greg 2.1
163 greg 2.12
164 schorsch 2.46 int
165     main(
166     int argc,
167     char *argv[]
168     )
169 greg 2.1 {
170     int explicate = 0;
171     int i;
172    
173     progname = argv[0]; /* get arguments */
174     for (i = 1; i < argc && argv[i][0] == '-'; i++)
175     switch (argv[i][1]) {
176     case 'e': /* print variables */
177     explicate++;
178     break;
179     case 'w': /* turn off warnings */
180     nowarn++;
181     break;
182     case 's': /* silent mode */
183     silent++;
184     break;
185     case 'n': /* take no action */
186     noaction++;
187     break;
188     default:
189     goto userr;
190     }
191     if (i != argc-1)
192     goto userr;
193     cfname = argv[i];
194     /* load variables */
195     loadvars(cfname);
196 greg 2.22 /* check variables */
197     checkvalues();
198 greg 2.1 /* did we get DIRECTORY? */
199     checkdir();
200     /* check status */
201     if (getastat() < 0) {
202     fprintf(stderr, "%s: exiting\n", progname);
203     quit(1);
204     }
205     /* pfilt always if options given */
206     pfiltalways = vdef(PFILT);
207     /* load RIF if any */
208     if (vdef(RIF))
209     getradfile(vval(RIF));
210     /* set defaults */
211     setdefaults();
212     /* print variables */
213     if (explicate)
214     printvars(stdout);
215 greg 2.2 /* set up process servers */
216     sethosts();
217 greg 2.1 /* run animation */
218     animate();
219     /* all done */
220     if (vdef(NEXTANIM)) {
221 greg 2.51 char *fullp;
222 greg 2.1 argv[i] = vval(NEXTANIM); /* just change input file */
223     if (!silent)
224     printargs(argc, argv, stdout);
225 greg 2.51 fflush(stdout);
226     if ((fullp = getpath(argv[0],getenv("PATH"),X_OK)) == NULL)
227     fprintf(stderr, "%s: command not found\n", argv[0]);
228 greg 2.11 else
229 greg 2.51 execv(fullp, argv);
230 greg 2.11 quit(1);
231 greg 2.1 }
232     quit(0);
233 greg 2.51 return(0); /* pro forma return */
234 greg 2.1 userr:
235     fprintf(stderr, "Usage: %s [-s][-n][-w][-e] anim_file\n", progname);
236     quit(1);
237 schorsch 2.46 return 1; /* pro forma return */
238 greg 2.1 }
239    
240    
241 schorsch 2.43 static int
242     getastat(void) /* check/set animation status */
243 greg 2.1 {
244 greg 2.12 char sfname[256];
245 greg 2.1 FILE *fp;
246    
247 greg 2.12 sprintf(sfname, "%s/%s", vval(DIRECTORY), SFNAME);
248     if ((fp = fopen(sfname, "r")) == NULL) {
249 greg 2.1 if (errno != ENOENT) {
250 greg 2.12 perror(sfname);
251 greg 2.1 return(-1);
252     }
253     astat.rnext = astat.fnext = astat.tnext = 0;
254     goto setours;
255     }
256     if (fscanf(fp, "Control host: %s\n", astat.host) != 1)
257     goto fmterr;
258     if (fscanf(fp, "Control PID: %d\n", &astat.pid) != 1)
259     goto fmterr;
260     if (fscanf(fp, "Control file: %s\n", astat.cfname) != 1)
261     goto fmterr;
262     if (fscanf(fp, "Next render: %d\n", &astat.rnext) != 1)
263     goto fmterr;
264     if (fscanf(fp, "Next filter: %d\n", &astat.fnext) != 1)
265     goto fmterr;
266     if (fscanf(fp, "Next transfer: %d\n", &astat.tnext) != 1)
267     goto fmterr;
268     fclose(fp);
269     if (astat.pid != 0) { /* thinks it's still running */
270 greg 2.9 if (strcmp(myhostname(), astat.host)) {
271 greg 2.1 fprintf(stderr,
272     "%s: process %d may still be running on host %s\n",
273     progname, astat.pid, astat.host);
274     return(-1);
275     }
276     if (kill(astat.pid, 0) != -1 || errno != ESRCH) {
277     fprintf(stderr, "%s: process %d is still running\n",
278     progname, astat.pid);
279     return(-1);
280     }
281     /* assume it is dead */
282     }
283 greg 2.20 if (strcmp(cfname, astat.cfname) && astat.pid != 0) { /* other's */
284 greg 2.1 fprintf(stderr, "%s: unfinished job \"%s\"\n",
285     progname, astat.cfname);
286     return(-1);
287     }
288 greg 2.12 /* check control file mods. */
289     if (!nowarn && fdate(cfname) > fdate(sfname))
290     fprintf(stderr,
291     "%s: warning - control file modified since last run\n",
292     progname);
293 greg 2.1 setours: /* set our values */
294 greg 2.9 strcpy(astat.host, myhostname());
295 greg 2.1 astat.pid = getpid();
296     strcpy(astat.cfname, cfname);
297     return(0);
298     fmterr:
299     fprintf(stderr, "%s: format error in status file \"%s\"\n",
300 greg 2.12 progname, sfname);
301 greg 2.1 fclose(fp);
302     return(-1);
303     }
304    
305    
306 schorsch 2.43 static void
307     putastat(void) /* put out current status */
308 greg 2.1 {
309     char buf[256];
310     FILE *fp;
311    
312 greg 2.2 if (noaction)
313     return;
314 greg 2.1 sprintf(buf, "%s/%s", vval(DIRECTORY), SFNAME);
315     if ((fp = fopen(buf, "w")) == NULL) {
316     perror(buf);
317     quit(1);
318     }
319     fprintf(fp, "Control host: %s\n", astat.host);
320     fprintf(fp, "Control PID: %d\n", astat.pid);
321     fprintf(fp, "Control file: %s\n", astat.cfname);
322     fprintf(fp, "Next render: %d\n", astat.rnext);
323     fprintf(fp, "Next filter: %d\n", astat.fnext);
324     fprintf(fp, "Next transfer: %d\n", astat.tnext);
325     fclose(fp);
326     }
327    
328    
329 schorsch 2.43 static void
330     checkdir(void) /* make sure we have our directory */
331 greg 2.1 {
332     struct stat stb;
333    
334     if (!vdef(DIRECTORY)) {
335     fprintf(stderr, "%s: %s undefined\n",
336     progname, vnam(DIRECTORY));
337     quit(1);
338     }
339     if (stat(vval(DIRECTORY), &stb) == -1) {
340     if (errno == ENOENT && mkdir(vval(DIRECTORY), 0777) == 0)
341     return;
342     perror(vval(DIRECTORY));
343     quit(1);
344     }
345     if (!(stb.st_mode & S_IFDIR)) {
346     fprintf(stderr, "%s: not a directory\n", vval(DIRECTORY));
347     quit(1);
348     }
349     }
350    
351    
352 schorsch 2.43 static void
353     setdefaults(void) /* set default values */
354 greg 2.1 {
355 greg 2.10 extern char *atos();
356 greg 2.19 int decades;
357 greg 2.1 char buf[256];
358    
359 greg 2.2 if (vdef(ANIMATE)) {
360     vval(OCTREE) = NULL;
361     vdef(OCTREE) = 0;
362     } else if (!vdef(OCTREE)) {
363 greg 2.1 fprintf(stderr, "%s: either %s or %s must be defined\n",
364     progname, vnam(OCTREE), vnam(ANIMATE));
365     quit(1);
366     }
367     if (!vdef(VIEWFILE)) {
368     fprintf(stderr, "%s: %s undefined\n", progname, vnam(VIEWFILE));
369     quit(1);
370     }
371 greg 2.2 if (!vdef(HOST)) {
372     vval(HOST) = LHOSTNAME;
373     vdef(HOST)++;
374     }
375 greg 2.1 if (!vdef(START)) {
376     vval(START) = "1";
377     vdef(START)++;
378     }
379     if (!vdef(END)) {
380 greg 2.5 sprintf(buf, "%d", countviews()+vint(START)-1);
381 greg 2.1 vval(END) = savqstr(buf);
382     vdef(END)++;
383     }
384 greg 2.5 if (vint(END) < vint(START)) {
385     fprintf(stderr, "%s: ending frame less than starting frame\n",
386     progname);
387     quit(1);
388     }
389 greg 2.1 if (!vdef(BASENAME)) {
390 greg 2.19 decades = (int)log10((double)vint(END)) + 1;
391     if (decades < 3) decades = 3;
392     sprintf(buf, "%s/frame%%0%dd", vval(DIRECTORY), decades);
393 greg 2.1 vval(BASENAME) = savqstr(buf);
394     vdef(BASENAME)++;
395     }
396     if (!vdef(RESOLUTION)) {
397     vval(RESOLUTION) = "640";
398     vdef(RESOLUTION)++;
399     }
400     if (!vdef(OVERSAMP)) {
401     vval(OVERSAMP) = "2";
402     vdef(OVERSAMP)++;
403     }
404     if (!vdef(INTERP)) {
405     vval(INTERP) = "0";
406     vdef(INTERP)++;
407     }
408     if (!vdef(MBLUR)) {
409     vval(MBLUR) = "0";
410     vdef(MBLUR)++;
411     }
412     if (!vdef(RTRACE)) {
413     vval(RTRACE) = "F";
414     vdef(RTRACE)++;
415     }
416     if (!vdef(DISKSPACE)) {
417     if (!nowarn)
418     fprintf(stderr,
419     "%s: warning - no %s setting, assuming 100 Mbytes available\n",
420     progname, vnam(DISKSPACE));
421     vval(DISKSPACE) = "100";
422     vdef(DISKSPACE)++;
423     }
424 greg 2.10 if (!vdef(RSH)) {
425     vval(RSH) = REMSH;
426     vdef(RSH)++;
427     }
428     /* locate remote shell program */
429     atos(buf, sizeof(buf), vval(RSH));
430     if ((remsh = getpath(buf, getenv("PATH"), X_OK)) != NULL)
431     remsh = savqstr(remsh);
432     else
433     remsh = vval(RSH); /* will generate error if used */
434    
435 greg 2.1 /* append rendering options */
436     if (vdef(RENDER))
437     sprintf(rendopt+strlen(rendopt), " %s", vval(RENDER));
438     }
439    
440    
441 schorsch 2.43 static void
442     sethosts(void) /* set up process servers */
443 greg 2.2 {
444     extern char *iskip();
445     char buf[256], *dir, *uname;
446     int np;
447     register char *cp;
448     int i;
449    
450     npslots = 0;
451     if (noaction)
452     return;
453     for (i = 0; i < vdef(HOST); i++) { /* add each host */
454     dir = uname = NULL;
455     np = 1;
456     strcpy(cp=buf, nvalue(HOST, i)); /* copy to buffer */
457     cp = sskip(cp); /* skip host name */
458     while (isspace(*cp))
459     *cp++ = '\0';
460     if (*cp) { /* has # processes? */
461     np = atoi(cp);
462     if ((cp = iskip(cp)) == NULL || (*cp && !isspace(*cp)))
463     badvalue(HOST);
464     while (isspace(*cp))
465     cp++;
466     if (*cp) { /* has directory? */
467     dir = cp;
468     cp = sskip(cp); /* skip dir. */
469     while (isspace(*cp))
470     *cp++ = '\0';
471     if (*cp) { /* has user? */
472     uname = cp;
473     if (*sskip(cp))
474     badvalue(HOST);
475     }
476     }
477     }
478     if (addpserver(buf, dir, uname, np) == NULL) {
479     if (!nowarn)
480     fprintf(stderr,
481     "%s: cannot execute on host \"%s\"\n",
482     progname, buf);
483     } else
484     npslots += np;
485     }
486     if (npslots == 0) {
487     fprintf(stderr, "%s: no working process servers\n", progname);
488     quit(1);
489     }
490     pslot = (struct pslot *)calloc(npslots, sizeof(struct pslot));
491     if (pslot == NULL) {
492     perror("malloc");
493     quit(1);
494     }
495     }
496    
497 schorsch 2.43 static void
498     getradfile(char *rfargs) /* run rad and get needed variables */
499 greg 2.1 {
500     static short mvar[] = {OCTREE,PFILT,RESOLUTION,EXPOSURE,-1};
501     char combuf[256];
502     register int i;
503     register char *cp;
504 schorsch 2.46 char *pippt = NULL;
505 greg 2.1 /* create rad command */
506     sprintf(rendopt, " @%s/render.opt", vval(DIRECTORY));
507     sprintf(combuf,
508     "rad -v 0 -s -e -w %s OPTFILE=%s | egrep '^[ \t]*(NOMATCH",
509 greg 2.7 rfargs, rendopt+2);
510 greg 2.1 cp = combuf;
511 gregl 2.23 while (*cp) {
512     if (*cp == '|') pippt = cp;
513     cp++;
514     } /* match unset variables */
515 greg 2.1 for (i = 0; mvar[i] >= 0; i++)
516     if (!vdef(mvar[i])) {
517     *cp++ = '|';
518     strcpy(cp, vnam(mvar[i]));
519     while (*cp) cp++;
520 gregl 2.23 pippt = NULL;
521 greg 2.1 }
522 gregl 2.23 if (pippt != NULL)
523 schorsch 2.39 strcpy(pippt, "> " NULL_DEVICE); /* nothing to match */
524 gregl 2.23 else {
525     sprintf(cp, ")[ \t]*=' > %s/radset.var", vval(DIRECTORY));
526     cp += 11; /* point to file name */
527     }
528 gwlarson 2.28 system(combuf); /* ignore exit code */
529 gregl 2.23 if (pippt == NULL) { /* load variables and remove file */
530     loadvars(cp);
531     unlink(cp);
532     }
533 greg 2.1 }
534    
535    
536 schorsch 2.43 static void
537     animate(void) /* run animation */
538 greg 2.1 {
539     int xres, yres;
540     float pa, mult;
541     int frames_batch;
542     register int i;
543     double d1, d2;
544     /* compute rpict resolution */
545     i = sscanf(vval(RESOLUTION), "%d %d %f", &xres, &yres, &pa);
546     mult = vflt(OVERSAMP);
547     if (i == 3) {
548 greg 2.16 sprintf(rresopt, "-x %d -y %d -pa %.3f", (int)(mult*xres),
549 greg 2.1 (int)(mult*yres), pa);
550 greg 2.16 sprintf(fresopt, "-x %d -y %d -pa %.3f", xres, yres, pa);
551 greg 2.1 } else if (i) {
552     if (i == 1) yres = xres;
553     sprintf(rresopt, "-x %d -y %d", (int)(mult*xres),
554     (int)(mult*yres));
555     sprintf(fresopt, "-x %d -y %d -pa 1", xres, yres);
556     } else
557     badvalue(RESOLUTION);
558     /* consistency checks */
559     if (vdef(ANIMATE)) {
560     if (vint(INTERP)) {
561     if (!nowarn)
562     fprintf(stderr,
563     "%s: resetting %s=0 for animation\n",
564     progname, vnam(INTERP));
565     vval(INTERP) = "0";
566     }
567 greg 2.29 if (strcmp(vval(MBLUR),"0")) { /* can't handle this */
568 greg 2.1 if (!nowarn)
569     fprintf(stderr,
570     "%s: resetting %s=0 for animation\n",
571     progname, vnam(MBLUR));
572     vval(MBLUR) = "0";
573     }
574     }
575     /* figure # frames per batch */
576     d1 = mult*xres*mult*yres*4; /* space for orig. picture */
577 greg 2.48 if ((i=vint(INTERP)) || getblur(NULL, NULL) > 1)
578 greg 2.13 d1 += mult*xres*mult*yres*sizeof(float); /* Z-buffer */
579 greg 2.1 d2 = xres*yres*4; /* space for final picture */
580     frames_batch = (i+1)*(vflt(DISKSPACE)*1048576.-d1)/(d1+i*d2);
581     if (frames_batch < i+2) {
582     fprintf(stderr, "%s: insufficient disk space allocated\n",
583     progname);
584     quit(1);
585     }
586 greg 2.7 /* initialize archive argument list */
587 gwlarson 2.25 i = vdef(ARCHIVE) ? strlen(vval(ARCHIVE))+132 : 132;
588 greg 2.7 arcnext = arcfirst = arcargs + i;
589 greg 2.1 /* initialize status file */
590     if (astat.rnext == 0)
591     astat.rnext = astat.fnext = astat.tnext = vint(START);
592     putastat();
593     /* render in batches */
594 greg 2.2 while (astat.tnext <= vint(END)) {
595 greg 2.1 renderframes(frames_batch);
596     filterframes();
597     transferframes();
598     }
599     /* mark status as finished */
600     astat.pid = 0;
601     putastat();
602     /* close open files */
603     getview(0);
604     getexp(0);
605     }
606    
607    
608 schorsch 2.43 static void
609     renderframes(int nframes) /* render next nframes frames */
610 greg 2.1 {
611     static char vendbuf[16];
612     VIEW *vp;
613     FILE *fp = NULL;
614     char vfname[128];
615     int lastframe;
616     register int i;
617    
618     if (astat.tnext < astat.rnext) /* other work to do first */
619     return;
620     /* create batch view file */
621     if (!vdef(ANIMATE)) {
622     sprintf(vfname, "%s/anim.vf", vval(DIRECTORY));
623     if ((fp = fopen(vfname, "w")) == NULL) {
624     perror(vfname);
625     quit(1);
626     }
627     }
628     /* bound batch properly */
629     lastframe = astat.rnext + nframes - 1;
630     if ((lastframe-1) % (vint(INTERP)+1)) /* need even interval */
631     lastframe += vint(INTERP)+1 - ((lastframe-1)%(vint(INTERP)+1));
632     if (lastframe > vint(END)) /* check for end */
633     lastframe = vint(END);
634     /* render each view */
635     for (i = astat.rnext; i <= lastframe; i++) {
636     if ((vp = getview(i)) == NULL) {
637     if (!nowarn)
638     fprintf(stderr,
639     "%s: ran out of views before last frame\n",
640     progname);
641     sprintf(vval(END)=vendbuf, "%d", i-1);
642     lastframe = i - 1;
643     break;
644     }
645     if (vdef(ANIMATE)) /* animate frame */
646     animrend(i, vp);
647     else { /* else record it */
648     fputs(VIEWSTR, fp);
649     fprintview(vp, fp);
650     putc('\n', fp);
651     }
652     }
653     if (vdef(ANIMATE)) /* wait for renderings to finish */
654 greg 2.2 bwait(0);
655 greg 2.1 else { /* else if walk-through */
656     fclose(fp); /* close view file */
657     walkwait(astat.rnext, lastframe, vfname); /* walk it */
658     unlink(vfname); /* remove view file */
659     }
660     astat.rnext = i; /* update status */
661     putastat();
662     }
663    
664    
665 schorsch 2.43 static void
666     filterframes(void) /* catch up with filtering */
667 greg 2.1 {
668     register int i;
669    
670     if (astat.tnext < astat.fnext) /* other work to do first */
671     return;
672     /* filter each view */
673 greg 2.38 for (i = astat.fnext; i < astat.rnext; i++)
674     dofilt(i, 0);
675    
676 greg 2.2 bwait(0); /* wait for filter processes */
677 greg 2.7 archive(); /* archive originals */
678 greg 2.1 astat.fnext = i; /* update status */
679     putastat();
680     }
681    
682    
683 schorsch 2.43 static void
684     transferframes(void) /* catch up with picture transfers */
685 greg 2.1 {
686 gwlarson 2.25 char combuf[10240], *fbase;
687 greg 2.1 register char *cp;
688     register int i;
689    
690     if (astat.tnext >= astat.fnext) /* nothing to do, yet */
691     return;
692     if (!vdef(TRANSFER)) { /* no transfer function -- leave 'em */
693     astat.tnext = astat.fnext;
694     putastat(); /* update status */
695     return;
696     }
697 gwlarson 2.25 strcpy(combuf, "cd "); /* start transfer command */
698     fbase = dirfile(cp = combuf+3, vval(BASENAME));
699     if (*cp) {
700     while (*++cp) ;
701     *cp++ = ';'; *cp++ = ' ';
702     } else
703     cp = combuf;
704     strcpy(cp, vval(TRANSFER));
705     while (*cp) cp++;
706 greg 2.1 /* make argument list */
707     for (i = astat.tnext; i < astat.fnext; i++) {
708     *cp++ = ' ';
709 gwlarson 2.25 sprintf(cp, fbase, i);
710 greg 2.1 while (*cp) cp++;
711     strcpy(cp, ".pic");
712     cp += 4;
713     }
714     if (runcom(combuf)) { /* transfer frames */
715     fprintf(stderr, "%s: error running transfer command\n",
716     progname);
717     quit(1);
718     }
719     astat.tnext = i; /* update status */
720     putastat();
721     }
722    
723    
724 schorsch 2.43 static void
725     animrend( /* start animation frame */
726     int frame,
727     VIEW *vp
728     )
729 greg 2.1 {
730     char combuf[2048];
731     char fname[128];
732    
733     sprintf(fname, vval(BASENAME), frame);
734     strcat(fname, ".unf");
735     if (access(fname, F_OK) == 0)
736     return;
737 greg 2.2 sprintf(combuf, "%s %d | rpict%s%s -w0 %s > %s", vval(ANIMATE), frame,
738 greg 2.1 rendopt, viewopt(vp), rresopt, fname);
739 greg 2.2 bruncom(combuf, frame, recover); /* run in background */
740 greg 2.1 }
741    
742    
743 schorsch 2.43 static void
744     walkwait( /* walk-through frames */
745     int first,
746     int last,
747     char *vfn
748     )
749 greg 2.1 {
750 greg 2.48 double mblurf, dblurf;
751     int nblur = getblur(&mblurf, &dblurf);
752 greg 2.1 char combuf[2048];
753 greg 2.29 register char *inspoint;
754 greg 2.1 register int i;
755    
756     if (!noaction && vint(INTERP)) /* create dummy frames */
757     for (i = first; i <= last; i++)
758     if (i < vint(END) && (i-1) % (vint(INTERP)+1)) {
759     sprintf(combuf, vval(BASENAME), i);
760     strcat(combuf, ".unf");
761     close(open(combuf, O_RDONLY|O_CREAT, 0666));
762     }
763     /* create command */
764 greg 2.35 sprintf(combuf, "rpict%s%s -w0", rendopt,
765     viewopt(getview(first>1 ? first-1 : 1)));
766 greg 2.29 inspoint = combuf;
767     while (*inspoint) inspoint++;
768     if (nblur) {
769 greg 2.48 sprintf(inspoint, " -pm %.3f", mblurf/nblur);
770     while (*inspoint) inspoint++;
771     sprintf(inspoint, " -pd %.3f", dblurf/nblur);
772 greg 2.29 while (*inspoint) inspoint++;
773     }
774     if (nblur > 1 || vint(INTERP)) {
775     sprintf(inspoint, " -z %s.zbf", vval(BASENAME));
776     while (*inspoint) inspoint++;
777     }
778     sprintf(inspoint, " -o %s.unf %s -S %d",
779 greg 2.4 vval(BASENAME), rresopt, first);
780 greg 2.29 while (*inspoint) inspoint++;
781 greg 2.4 sprintf(inspoint, " %s < %s", vval(OCTREE), vfn);
782 greg 2.2 /* run in parallel */
783 greg 2.7 i = (last-first+1)/(vint(INTERP)+1);
784     if (i < 1) i = 1;
785     if (pruncom(combuf, inspoint, i)) {
786 greg 2.2 fprintf(stderr, "%s: error rendering frames %d through %d\n",
787 greg 2.1 progname, first, last);
788     quit(1);
789     }
790     if (!noaction && vint(INTERP)) /* remove dummy frames */
791     for (i = first; i <= last; i++)
792     if (i < vint(END) && (i-1) % (vint(INTERP)+1)) {
793     sprintf(combuf, vval(BASENAME), i);
794     strcat(combuf, ".unf");
795     unlink(combuf);
796     }
797     }
798    
799    
800 schorsch 2.43 static int
801 greg 2.44 recover(int frame) /* recover the specified frame */
802 greg 2.1 {
803 greg 2.2 static int *rfrm; /* list of recovered frames */
804     static int nrfrms = 0;
805 greg 2.48 double mblurf, dblurf;
806     int nblur = getblur(&mblurf, &dblurf);
807 greg 2.1 char combuf[2048];
808     char fname[128];
809     register char *cp;
810 greg 2.2 register int i;
811     /* check to see if recovered already */
812     for (i = nrfrms; i--; )
813     if (rfrm[i] == frame)
814     return(0);
815     /* build command */
816 greg 2.1 sprintf(fname, vval(BASENAME), frame);
817     if (vdef(ANIMATE))
818 greg 2.2 sprintf(combuf, "%s %d | rpict%s -w0",
819 greg 2.1 vval(ANIMATE), frame, rendopt);
820     else
821 greg 2.2 sprintf(combuf, "rpict%s -w0", rendopt);
822 greg 2.29 cp = combuf;
823     while (*cp) cp++;
824     if (nblur) {
825 greg 2.48 sprintf(cp, " -pm %.3f", mblurf/nblur);
826     while (*cp) cp++;
827     sprintf(cp, " -pd %.3f", dblurf/nblur);
828 greg 2.29 while (*cp) cp++;
829     }
830     if (nblur > 1 || vint(INTERP)) {
831 greg 2.1 sprintf(cp, " -z %s.zbf", fname);
832     while (*cp) cp++;
833     }
834     sprintf(cp, " -ro %s.unf", fname);
835     while (*cp) cp++;
836     if (!vdef(ANIMATE)) {
837     *cp++ = ' ';
838     strcpy(cp, vval(OCTREE));
839     }
840 greg 2.2 if (runcom(combuf)) /* run command */
841     return(1);
842     /* add frame to recovered list */
843     if (nrfrms)
844 greg 2.32 rfrm = (int *)realloc((void *)rfrm, (nrfrms+1)*sizeof(int));
845 greg 2.2 else
846     rfrm = (int *)malloc(sizeof(int));
847     if (rfrm == NULL) {
848     perror("malloc");
849 greg 2.1 quit(1);
850     }
851 greg 2.2 rfrm[nrfrms++] = frame;
852     return(0);
853 greg 2.1 }
854    
855    
856 schorsch 2.43 static int
857     frecover(int frame) /* recover filtered frame */
858 greg 2.2 {
859 greg 2.38 if (dofilt(frame, 2) && dofilt(frame, 1))
860 greg 2.2 return(1);
861     return(0);
862     }
863    
864    
865 schorsch 2.43 static void
866     archive(void) /* archive and remove renderings */
867 greg 2.1 {
868 greg 2.2 #define RMCOML (sizeof(rmcom)-1)
869     static char rmcom[] = "rm -f";
870 gwlarson 2.25 char basedir[128];
871     int dlen, alen;
872     register int j;
873 greg 2.1
874 greg 2.7 if (arcnext == arcfirst)
875     return; /* nothing to do */
876 gwlarson 2.25 dirfile(basedir, vval(BASENAME));
877     dlen = strlen(basedir);
878 greg 2.2 if (vdef(ARCHIVE)) { /* run archive command */
879 gwlarson 2.25 alen = strlen(vval(ARCHIVE));
880     if (dlen) {
881     j = alen + dlen + 5;
882     strncpy(arcfirst-j, "cd ", 3);
883     strncpy(arcfirst-j+3, basedir, dlen);
884     (arcfirst-j)[dlen+3] = ';'; (arcfirst-j)[dlen+4] = ' ';
885     } else
886     j = alen;
887     strncpy(arcfirst-alen, vval(ARCHIVE), alen);
888     if (runcom(arcfirst-j)) {
889 greg 2.7 fprintf(stderr, "%s: error running archive command\n",
890     progname);
891 greg 2.2 quit(1);
892     }
893 greg 2.1 }
894 gwlarson 2.25 if (dlen) {
895     j = RMCOML + dlen + 5;
896     strncpy(arcfirst-j, "cd ", 3);
897     strncpy(arcfirst-j+3, basedir, dlen);
898     (arcfirst-j)[dlen+3] = ';'; (arcfirst-j)[dlen+4] = ' ';
899     } else
900     j = RMCOML;
901 greg 2.2 /* run remove command */
902 greg 2.7 strncpy(arcfirst-RMCOML, rmcom, RMCOML);
903 gwlarson 2.25 runcom(arcfirst-j);
904 greg 2.7 arcnext = arcfirst; /* reset argument list */
905 greg 2.2 #undef RMCOML
906 greg 2.1 }
907    
908    
909 schorsch 2.43 static int
910     dofilt( /* filter frame */
911     int frame,
912     int rvr
913     )
914 greg 2.1 {
915 greg 2.6 static int iter = 0;
916 greg 2.48 double mblurf, dblurf;
917     int nblur = getblur(&mblurf, &dblurf);
918 greg 2.38 VIEW *vp = getview(frame);
919     char *ep = getexp(frame);
920 gwlarson 2.25 char fnbefore[128], fnafter[128], *fbase;
921 greg 2.6 char combuf[1024], fname0[128], fname1[128];
922 greg 2.7 int usepinterp, usepfilt, nora_rgbe;
923 greg 2.2 int frseq[2];
924 greg 2.1 /* check what is needed */
925 greg 2.38 if (vp == NULL) {
926     fprintf(stderr,
927     "%s: unexpected error reading view for frame %d\n",
928     progname, frame);
929     quit(1);
930     }
931 greg 2.29 usepinterp = (nblur > 1);
932 schorsch 2.41 usepfilt = pfiltalways | (ep==NULL);
933 greg 2.7 if (ep != NULL && !strcmp(ep, "1"))
934     ep = "+0";
935     nora_rgbe = strcmp(vval(OVERSAMP),"1") || ep==NULL ||
936     *ep != '+' || *ep != '-' || !isint(ep);
937 greg 2.1 /* compute rendered views */
938 greg 2.2 frseq[0] = frame - ((frame-1) % (vint(INTERP)+1));
939     frseq[1] = frseq[0] + vint(INTERP) + 1;
940 gwlarson 2.25 fbase = dirfile(NULL, vval(BASENAME));
941 greg 2.2 if (frseq[1] > vint(END))
942     frseq[1] = vint(END);
943     if (frseq[1] == frame) { /* pfilt only */
944     frseq[0] = frseq[1];
945 greg 2.1 usepinterp = 0; /* update what's needed */
946 greg 2.7 usepfilt |= nora_rgbe;
947     } else if (frseq[0] == frame) { /* no interpolation needed */
948     if (!rvr && frame > 1+vint(INTERP)) { /* archive previous */
949 greg 2.52 if (arcnext - arcargs +
950     strlen(fbase) >= sizeof(arcargs)-8) {
951     fprintf(stderr,
952     "%s: too many filenames in archive command -- reduce %s variable\n",
953     progname, vnam(DISKSPACE));
954     quit(1);
955     }
956 greg 2.7 *arcnext++ = ' ';
957 gwlarson 2.25 sprintf(arcnext, fbase, frame-vint(INTERP)-1);
958 greg 2.7 while (*arcnext) arcnext++;
959     strcpy(arcnext, ".unf");
960     arcnext += 4;
961 greg 2.13 if (usepinterp || vint(INTERP)) { /* and Z-buf */
962 greg 2.7 *arcnext++ = ' ';
963 gwlarson 2.25 sprintf(arcnext, fbase, frame-vint(INTERP)-1);
964 greg 2.7 while (*arcnext) arcnext++;
965     strcpy(arcnext, ".zbf");
966     arcnext += 4;
967     }
968     }
969     if (!usepinterp) /* update what's needed */
970     usepfilt |= nora_rgbe;
971 greg 2.2 } else /* interpolation needed */
972 greg 2.1 usepinterp++;
973 greg 2.2 if (frseq[1] >= astat.rnext) /* next batch unavailable */
974     frseq[1] = frseq[0];
975     sprintf(fnbefore, vval(BASENAME), frseq[0]);
976     sprintf(fnafter, vval(BASENAME), frseq[1]);
977     if (rvr == 1 && recover(frseq[0])) /* recover before frame? */
978     return(1);
979     /* generate command */
980 greg 2.1 if (usepinterp) { /* using pinterp */
981 greg 2.2 if (rvr == 2 && recover(frseq[1])) /* recover after? */
982     return(1);
983 greg 2.48 if (nblur > 1) { /* with pdmblur */
984 greg 2.6 sprintf(fname0, "%s/vw0%c", vval(DIRECTORY),
985     'a'+(iter%26));
986     sprintf(fname1, "%s/vw1%c", vval(DIRECTORY),
987     'a'+(iter%26));
988 gwlarson 2.25 if (!noaction) {
989     FILE *fp; /* motion blurring */
990     if ((fp = fopen(fname0, "w")) == NULL) {
991     perror(fname0); quit(1);
992     }
993     fputs(VIEWSTR, fp);
994     fprintview(vp, fp);
995     putc('\n', fp); fclose(fp);
996     if ((vp = getview(frame+1)) == NULL) {
997     fprintf(stderr,
998     "%s: unexpected error reading view for frame %d\n",
999     progname, frame+1);
1000     quit(1);
1001     }
1002     if ((fp = fopen(fname1, "w")) == NULL) {
1003     perror(fname1); quit(1);
1004     }
1005     fputs(VIEWSTR, fp);
1006     fprintview(vp, fp);
1007     putc('\n', fp); fclose(fp);
1008 greg 2.1 }
1009     sprintf(combuf,
1010 greg 2.48 "(pmdblur %.3f %.3f %d %s %s; rm -f %s %s) | pinterp -B -a",
1011     mblurf, dblurf, nblur,
1012 greg 2.6 fname0, fname1, fname0, fname1);
1013     iter++;
1014 greg 2.1 } else /* no blurring */
1015     strcpy(combuf, "pinterp");
1016     strcat(combuf, viewopt(vp));
1017     if (vbool(RTRACE))
1018 greg 2.2 sprintf(combuf+strlen(combuf), " -ff -fr '%s -w0 %s'",
1019 greg 2.21 rendopt+1, vval(OCTREE));
1020 greg 2.1 if (vdef(PINTERP))
1021     sprintf(combuf+strlen(combuf), " %s", vval(PINTERP));
1022     if (usepfilt)
1023     sprintf(combuf+strlen(combuf), " %s", rresopt);
1024     else
1025 greg 2.33 sprintf(combuf+strlen(combuf), " -a %s -e %s",
1026 greg 2.1 fresopt, ep);
1027     sprintf(combuf+strlen(combuf), " %s.unf %s.zbf",
1028     fnbefore, fnbefore);
1029 greg 2.2 if (frseq[1] != frseq[0])
1030 greg 2.1 sprintf(combuf+strlen(combuf), " %s.unf %s.zbf",
1031     fnafter, fnafter);
1032     if (usepfilt) { /* also pfilt */
1033     if (vdef(PFILT))
1034     sprintf(combuf+strlen(combuf), " | pfilt %s",
1035     vval(PFILT));
1036     else
1037     strcat(combuf, " | pfilt");
1038     if (ep != NULL)
1039     sprintf(combuf+strlen(combuf), " -1 -e %s %s",
1040     ep, fresopt);
1041     else
1042     sprintf(combuf+strlen(combuf), " %s", fresopt);
1043     }
1044     } else if (usepfilt) { /* pfilt only */
1045 greg 2.2 if (rvr == 2)
1046     return(1);
1047 greg 2.1 if (vdef(PFILT))
1048     sprintf(combuf, "pfilt %s", vval(PFILT));
1049     else
1050     strcpy(combuf, "pfilt");
1051     if (ep != NULL)
1052     sprintf(combuf+strlen(combuf), " -1 -e %s %s %s.unf",
1053     ep, fresopt, fnbefore);
1054     else
1055     sprintf(combuf+strlen(combuf), " %s %s.unf",
1056     fresopt, fnbefore);
1057     } else { /* else just check it */
1058 greg 2.2 if (rvr == 2)
1059     return(1);
1060 greg 2.7 sprintf(combuf, "ra_rgbe -e %s -r %s.unf", ep, fnbefore);
1061 greg 2.1 }
1062     /* output file name */
1063 greg 2.6 sprintf(fname0, vval(BASENAME), frame);
1064     sprintf(combuf+strlen(combuf), " > %s.pic", fname0);
1065 greg 2.2 if (rvr) /* in recovery */
1066     return(runcom(combuf));
1067     bruncom(combuf, frame, frecover); /* else run in background */
1068     return(0);
1069 greg 2.1 }
1070    
1071    
1072 schorsch 2.43 static VIEW *
1073     getview(int n) /* get view number n */
1074 greg 2.1 {
1075     static FILE *viewfp = NULL; /* view file pointer */
1076     static int viewnum = 0; /* current view number */
1077     static VIEW curview = STDVIEW; /* current view */
1078     char linebuf[256];
1079    
1080     if (n == 0) { /* signal to close file and clean up */
1081     if (viewfp != NULL) {
1082     fclose(viewfp);
1083     viewfp = NULL;
1084     viewnum = 0;
1085 schorsch 2.40 curview = stdview;
1086 greg 2.1 }
1087     return(NULL);
1088     }
1089 gwlarson 2.24 if (viewfp == NULL) { /* open file */
1090 greg 2.1 if ((viewfp = fopen(vval(VIEWFILE), "r")) == NULL) {
1091     perror(vval(VIEWFILE));
1092     quit(1);
1093     }
1094 gwlarson 2.24 } else if (n > 0 && n < viewnum) { /* rewind file */
1095 greg 2.8 if (viewnum == 1 && feof(viewfp))
1096     return(&curview); /* just one view */
1097 greg 2.1 if (fseek(viewfp, 0L, 0) == EOF) {
1098     perror(vval(VIEWFILE));
1099     quit(1);
1100     }
1101 schorsch 2.40 curview = stdview;
1102 greg 2.1 viewnum = 0;
1103     }
1104 gwlarson 2.24 if (n < 0) { /* get next view */
1105     register int c = getc(viewfp);
1106     if (c == EOF)
1107     return((VIEW *)NULL); /* that's it */
1108     ungetc(c, viewfp);
1109     n = viewnum + 1;
1110     }
1111 greg 2.1 while (n > viewnum) { /* scan to desired view */
1112     if (fgets(linebuf, sizeof(linebuf), viewfp) == NULL)
1113 greg 2.15 return(viewnum==1 ? &curview : (VIEW *)NULL);
1114 greg 2.1 if (isview(linebuf) && sscanview(&curview, linebuf) > 0)
1115     viewnum++;
1116     }
1117     return(&curview); /* return it */
1118     }
1119    
1120    
1121 schorsch 2.43 static int
1122     countviews(void) /* count views in view file */
1123 greg 2.1 {
1124 gwlarson 2.24 int n;
1125 greg 2.1
1126 gwlarson 2.24 if (getview(n=1) == NULL)
1127     return(0);
1128     while (getview(-1) != NULL)
1129 greg 2.1 n++;
1130     return(n);
1131     }
1132    
1133    
1134 schorsch 2.43 static char *
1135     getexp(int n) /* get exposure for nth frame */
1136 greg 2.1 {
1137     static char expval[32];
1138     static FILE *expfp = NULL;
1139     static long *exppos;
1140     static int curfrm;
1141     register char *cp;
1142    
1143     if (n == 0) { /* signal to close file */
1144     if (expfp != NULL) {
1145     fclose(expfp);
1146 greg 2.29 free((void *)exppos);
1147 greg 2.1 expfp = NULL;
1148     }
1149     return(NULL);
1150 greg 2.14 } else if (n > vint(END)) /* request past end (error?) */
1151     return(NULL);
1152 greg 2.1 if (!vdef(EXPOSURE)) /* no setting (auto) */
1153     return(NULL);
1154     if (isflt(vval(EXPOSURE))) /* always the same */
1155     return(vval(EXPOSURE));
1156     if (expfp == NULL) { /* open exposure file */
1157     if ((expfp = fopen(vval(EXPOSURE), "r")) == NULL) {
1158     fprintf(stderr,
1159     "%s: cannot open exposure file \"%s\"\n",
1160     progname, vval(EXPOSURE));
1161     quit(1);
1162     }
1163     curfrm = vint(END) + 1; /* init lookup tab. */
1164     exppos = (long *)malloc(curfrm*sizeof(long *));
1165     if (exppos == NULL) {
1166     perror(progname);
1167     quit(1);
1168     }
1169     while (curfrm--)
1170     exppos[curfrm] = -1L;
1171     curfrm = 0;
1172     }
1173     /* find position in file */
1174     if (n-1 != curfrm && n != curfrm && exppos[n-1] >= 0 &&
1175     fseek(expfp, exppos[curfrm=n-1], 0) == EOF) {
1176     fprintf(stderr, "%s: seek error on exposure file\n", progname);
1177     quit(1);
1178     }
1179     while (n > curfrm) { /* read exposure */
1180     if (exppos[curfrm] < 0)
1181     exppos[curfrm] = ftell(expfp);
1182     if (fgets(expval, sizeof(expval), expfp) == NULL) {
1183     fprintf(stderr, "%s: too few exposures\n",
1184     vval(EXPOSURE));
1185     quit(1);
1186     }
1187     curfrm++;
1188     cp = fskip(expval); /* check format */
1189 greg 2.14 if (cp != NULL)
1190     while (isspace(*cp))
1191     *cp++ = '\0';
1192     if (cp == NULL || *cp) {
1193 greg 2.1 fprintf(stderr,
1194     "%s: exposure format error on line %d\n",
1195     vval(EXPOSURE), curfrm);
1196     quit(1);
1197     }
1198     }
1199     return(expval); /* return value */
1200     }
1201    
1202    
1203 schorsch 2.43 static struct pslot *
1204 schorsch 2.50 findpslot(RT_PID pid) /* find or allocate a process slot */
1205 greg 2.2 {
1206     register struct pslot *psempty = NULL;
1207     register int i;
1208    
1209     for (i = 0; i < npslots; i++) { /* look for match */
1210     if (pslot[i].pid == pid)
1211     return(pslot+i);
1212     if (psempty == NULL && pslot[i].pid == 0)
1213     psempty = pslot+i;
1214     }
1215     return(psempty); /* return emtpy slot (error if NULL) */
1216     }
1217    
1218    
1219 schorsch 2.43 static int
1220     donecom( /* clean up after finished process */
1221 schorsch 2.46 PSERVER *ps,
1222     int pn,
1223     int status
1224 schorsch 2.43 )
1225 greg 2.2 {
1226 schorsch 2.43 register NETPROC *pp;
1227 greg 2.18 register struct pslot *psl;
1228 greg 2.2
1229     pp = ps->proc + pn;
1230 greg 2.3 if (pp->elen) { /* pass errors */
1231 greg 2.2 if (ps->hostname[0])
1232 greg 2.3 fprintf(stderr, "%s: ", ps->hostname);
1233     fprintf(stderr, "Error output from: %s\n", pp->com);
1234 greg 2.2 fputs(pp->errs, stderr);
1235     fflush(stderr);
1236     if (ps->hostname[0])
1237     status = 1; /* because rsh doesn't return status */
1238     }
1239 greg 2.18 lastpserver = NULL;
1240     psl = findpslot(pp->pid); /* check for bruncom() slot */
1241     if (psl->pid) {
1242     if (status) {
1243     if (psl->rcvf != NULL) /* attempt recovery */
1244     status = (*psl->rcvf)(psl->fout);
1245     if (status) {
1246     fprintf(stderr,
1247     "%s: error rendering frame %d\n",
1248     progname, psl->fout);
1249     quit(1);
1250     }
1251     lastpserver = ps;
1252     }
1253     psl->pid = 0; /* free process slot */
1254     } else if (status)
1255     lastpserver = ps;
1256 greg 2.2 freestr(pp->com); /* free command string */
1257     return(status);
1258     }
1259    
1260    
1261 schorsch 2.43 static int
1262     serverdown(void) /* check status of last process server */
1263 greg 2.2 {
1264 greg 2.18 if (lastpserver == NULL || !lastpserver->hostname[0])
1265     return(0);
1266 greg 2.2 if (pserverOK(lastpserver)) /* server still up? */
1267     return(0);
1268     delpserver(lastpserver); /* else delete it */
1269     if (pslist == NULL) {
1270     fprintf(stderr, "%s: all process servers are down\n",
1271     progname);
1272     quit(1);
1273     }
1274     return(1);
1275     }
1276    
1277    
1278 schorsch 2.50 static RT_PID
1279 schorsch 2.43 bruncom( /* run a command in the background */
1280     char *com,
1281     int fout,
1282     int (*rf)()
1283     )
1284 greg 2.2 {
1285 schorsch 2.50 RT_PID pid;
1286 greg 2.2 register struct pslot *psl;
1287    
1288 greg 2.5 if (noaction) {
1289     if (!silent)
1290     printf("\t%s\n", com); /* echo command */
1291 greg 2.2 return(0);
1292 greg 2.5 }
1293 greg 2.18 com = savestr(com); /* else start it when we can */
1294     while ((pid = startjob(NULL, com, donecom)) == -1)
1295 greg 2.2 bwait(1);
1296 greg 2.5 if (!silent) { /* echo command */
1297 greg 2.3 PSERVER *ps;
1298 schorsch 2.50 RT_PID psn = pid;
1299 greg 2.4 ps = findjob(&psn);
1300 greg 2.5 printf("\t%s\n", com);
1301 greg 2.4 printf("\tProcess started on %s\n", phostname(ps));
1302 greg 2.3 fflush(stdout);
1303     }
1304 greg 2.2 psl = findpslot(pid); /* record info. in appropriate slot */
1305     psl->pid = pid;
1306     psl->fout = fout;
1307     psl->rcvf = rf;
1308     return(pid);
1309     }
1310    
1311    
1312 schorsch 2.43 static void
1313     bwait(int ncoms) /* wait for batch job(s) to finish */
1314 greg 2.2 {
1315     int status;
1316    
1317     if (noaction)
1318     return;
1319     while ((status = wait4job(NULL, -1)) != -1) {
1320 greg 2.18 serverdown(); /* update server status */
1321     if (--ncoms == 0)
1322     break; /* done enough */
1323 greg 2.2 }
1324     }
1325    
1326    
1327 schorsch 2.43 static int
1328     pruncom( /* run a command in parallel over network */
1329     char *com,
1330     char *ppins,
1331     int maxcopies
1332     )
1333 greg 2.2 {
1334     int retstatus = 0;
1335 greg 2.3 int hostcopies;
1336 greg 2.18 char buf[10240], *com1, *s;
1337 greg 2.2 int status;
1338 greg 2.17 int pfd;
1339     register int n;
1340 greg 2.2 register PSERVER *ps;
1341    
1342 greg 2.3 if (!silent)
1343 greg 2.6 printf("\t%s\n", com); /* echo command */
1344 greg 2.3 if (noaction)
1345 greg 2.2 return(0);
1346 greg 2.3 fflush(stdout);
1347 greg 2.2 /* start jobs on each server */
1348 greg 2.3 for (ps = pslist; ps != NULL; ps = ps->next) {
1349     hostcopies = 0;
1350 greg 2.4 if (maxcopies > 1 && ps->nprocs > 1 && ppins != NULL) {
1351 greg 2.17 strcpy(com1=buf, com); /* build -PP command */
1352 greg 2.4 sprintf(com1+(ppins-com), " -PP %s/%s.persist",
1353     vval(DIRECTORY), phostname(ps));
1354 greg 2.36 unlink(com1+(ppins-com)+5);
1355 greg 2.4 strcat(com1, ppins);
1356 greg 2.17 } else
1357 greg 2.4 com1 = com;
1358 greg 2.18 while (maxcopies > 0) {
1359     s = savestr(com1);
1360     if (startjob(ps, s, donecom) != -1) {
1361     sleep(20);
1362     hostcopies++;
1363     maxcopies--;
1364     } else {
1365     freestr(s);
1366     break;
1367     }
1368 greg 2.2 }
1369 greg 2.3 if (!silent && hostcopies) {
1370     if (hostcopies > 1)
1371     printf("\t%d duplicate processes", hostcopies);
1372     else
1373     printf("\tProcess");
1374 greg 2.4 printf(" started on %s\n", phostname(ps));
1375 greg 2.3 fflush(stdout);
1376     }
1377     }
1378 greg 2.2 /* wait for jobs to finish */
1379     while ((status = wait4job(NULL, -1)) != -1)
1380 greg 2.18 retstatus += status && !serverdown();
1381 greg 2.17 /* terminate parallel rpict's */
1382 greg 2.18 for (ps = pslist; ps != NULL; ps = ps->next) {
1383     sprintf(buf, "%s/%s.persist", vval(DIRECTORY), phostname(ps));
1384 greg 2.17 if ((pfd = open(buf, O_RDONLY)) >= 0) {
1385     n = read(pfd, buf, sizeof(buf)-1); /* get PID */
1386     buf[n] = '\0';
1387     close(pfd);
1388     for (n = 0; buf[n] && !isspace(buf[n]); n++)
1389     ;
1390     /* terminate */
1391     sprintf(buf, "kill -ALRM %d", atoi(buf+n));
1392 greg 2.18 wait4job(ps, startjob(ps, buf, NULL));
1393 greg 2.17 }
1394     }
1395 greg 2.2 return(retstatus);
1396     }
1397    
1398    
1399 schorsch 2.43 static int
1400     runcom(char *cs) /* run a command locally and wait for it */
1401 greg 2.1 {
1402     if (!silent) /* echo it */
1403     printf("\t%s\n", cs);
1404     if (noaction)
1405     return(0);
1406     fflush(stdout); /* flush output and pass to shell */
1407     return(system(cs));
1408     }
1409    
1410    
1411 schorsch 2.43 static int
1412     rmfile(char *fn) /* remove a file */
1413 greg 2.1 {
1414     if (!silent)
1415 schorsch 2.37 #ifdef _WIN32
1416 greg 2.1 printf("\tdel %s\n", fn);
1417     #else
1418     printf("\trm -f %s\n", fn);
1419     #endif
1420     if (noaction)
1421     return(0);
1422     return(unlink(fn));
1423     }
1424    
1425    
1426 schorsch 2.43 static void
1427     badvalue(int vc) /* report bad variable value and exit */
1428 greg 2.1 {
1429     fprintf(stderr, "%s: bad value for variable '%s'\n",
1430     progname, vnam(vc));
1431     quit(1);
1432 gwlarson 2.25 }
1433    
1434    
1435 schorsch 2.43 static char *
1436     dirfile( /* separate path into directory and file */
1437     char *df,
1438     register char *path
1439     )
1440 gwlarson 2.25 {
1441     register int i;
1442     int psep;
1443    
1444     for (i = 0, psep = -1; path[i]; i++)
1445     if (path[i] == '/')
1446     psep = i;
1447 schorsch 2.40 if (df != NULL) {
1448 gwlarson 2.25 if (psep == 0) {
1449     df[0] = '/';
1450     df[1] = '\0';
1451     } else if (psep > 0) {
1452     strncpy(df, path, psep);
1453     df[psep] = '\0';
1454     } else
1455     df[0] = '\0';
1456 schorsch 2.40 }
1457 gwlarson 2.25 return(path+psep+1);
1458 greg 2.29 }
1459    
1460    
1461 schorsch 2.43 static int
1462 greg 2.48 getblur(double *mbf, double *dbf) /* get # blur samples (and fraction) */
1463 greg 2.29 {
1464 greg 2.48 double mblurf, dblurf;
1465     int nmblur, ndblur;
1466 greg 2.29 char *s;
1467 greg 2.48 /* get motion blur */
1468     if (!vdef(MBLUR) || (mblurf = atof(vval(MBLUR))) < 0.0)
1469     mblurf = 0.0;
1470     if (mbf != NULL)
1471     *mbf = mblurf;
1472     if (mblurf <= FTINY)
1473     nmblur = 0;
1474     else if (!*(s = sskip(vval(MBLUR))))
1475     nmblur = DEF_NBLUR;
1476     else if ((nmblur = atoi(s)) <= 0)
1477     nmblur = 1;
1478     /* get depth-of-field blur */
1479     if (!vdef(DBLUR) || (dblurf = atof(vval(DBLUR))) < 0.0)
1480     dblurf = 0.0;
1481     if (dbf != NULL)
1482     *dbf = dblurf;
1483     if (dblurf <= FTINY)
1484     ndblur = 0;
1485     else if (!*(s = sskip(vval(DBLUR))))
1486     ndblur = DEF_NBLUR;
1487     else if ((ndblur = atoi(s)) <= 0)
1488     ndblur = 1;
1489     if ((nmblur == 1) & (ndblur == 1))
1490 greg 2.29 return(1);
1491 greg 2.48 /* return combined samples */
1492     return(nmblur + ndblur);
1493 greg 2.1 }