ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimate.c
Revision: 2.50
Committed: Mon Sep 12 14:40:14 2005 UTC (19 years, 1 month ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.49: +10 -9 lines
Log Message:
Using RT_PID instead of int.

File Contents

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