ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimate.c
Revision: 2.49
Committed: Mon Feb 7 17:08:17 2005 UTC (19 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1
Changes since 2.48: +4 -2 lines
Log Message:
Switched from using "rsh" to "ssh" in ranimate

File Contents

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