--- ray/src/util/ranimate.c 1996/01/12 12:16:17 2.1 +++ ray/src/util/ranimate.c 1998/07/06 18:17:39 2.28 @@ -1,7 +1,7 @@ -/* Copyright (c) 1995 Regents of the University of California */ +/* Copyright (c) 1998 Silicon Graphics, Inc. */ #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static char SCCSid[] = "$SunId$ SGI"; #endif /* @@ -9,59 +9,69 @@ static char SCCSid[] = "$SunId$ LBL"; */ #include "standard.h" +#include #include #include #include "view.h" #include "vars.h" - /* input variables */ -#define HOST 0 /* rendering host machine */ -#define RENDER 1 /* rendering options */ -#define PFILT 2 /* pfilt options */ -#define PINTERP 3 /* pinterp options */ -#define OCTREE 4 /* octree file name */ -#define DIRECTORY 5 /* working (sub)directory */ -#define BASENAME 6 /* output image base name */ -#define VIEWFILE 7 /* animation frame views */ -#define START 8 /* starting frame number */ -#define END 9 /* ending frame number */ -#define RIF 10 /* rad input file */ -#define NEXTANIM 11 /* next animation file */ -#define ANIMATE 12 /* animation command */ -#define TRANSFER 13 /* frame transfer command */ -#define ARCHIVE 14 /* archiving command */ -#define INTERP 15 /* # frames to interpolate */ -#define OVERSAMP 16 /* # times to oversample image */ -#define MBLUR 17 /* samples for motion blur */ -#define RTRACE 18 /* use rtrace with pinterp? */ -#define DISKSPACE 19 /* how much disk space to use */ -#define RESOLUTION 20 /* desired final resolution */ -#define EXPOSURE 21 /* how to compute exposure */ +#include "netproc.h" + /* default remote shell */ +#ifdef _AUX_SOURCE +#define REMSH "remsh" +#else +#define REMSH "rsh" +#endif + /* input variables (alphabetical by name) */ +#define ANIMATE 0 /* animation command */ +#define ARCHIVE 1 /* archiving command */ +#define BASENAME 2 /* output image base name */ +#define DIRECTORY 3 /* working (sub)directory */ +#define DISKSPACE 4 /* how much disk space to use */ +#define END 5 /* ending frame number */ +#define EXPOSURE 6 /* how to compute exposure */ +#define HOST 7 /* rendering host machine */ +#define INTERP 8 /* # frames to interpolate */ +#define MBLUR 9 /* samples for motion blur */ +#define NEXTANIM 10 /* next animation file */ +#define OCTREE 11 /* octree file name */ +#define OVERSAMP 12 /* # times to oversample image */ +#define PFILT 13 /* pfilt options */ +#define PINTERP 14 /* pinterp options */ +#define RENDER 15 /* rendering options */ +#define RESOLUTION 16 /* desired final resolution */ +#define RIF 17 /* rad input file */ +#define RSH 18 /* remote shell script or program */ +#define RTRACE 19 /* use rtrace with pinterp? */ +#define START 20 /* starting frame number */ +#define TRANSFER 21 /* frame transfer command */ +#define VIEWFILE 22 /* animation frame views */ -int NVARS = 22; /* total number of variables */ +int NVARS = 23; /* total number of variables */ VARIABLE vv[] = { /* variable-value pairs */ + {"ANIMATE", 2, 0, NULL, onevalue}, + {"ARCHIVE", 2, 0, NULL, onevalue}, + {"BASENAME", 3, 0, NULL, onevalue}, + {"DIRECTORY", 3, 0, NULL, onevalue}, + {"DISKSPACE", 3, 0, NULL, fltvalue}, + {"END", 2, 0, NULL, intvalue}, + {"EXPOSURE", 3, 0, NULL, onevalue}, {"host", 4, 0, NULL, NULL}, - {"render", 3, 0, NULL, catvalues}, + {"INTERPOLATE", 3, 0, NULL, intvalue}, + {"MBLUR", 2, 0, NULL, onevalue}, + {"NEXTANIM", 3, 0, NULL, onevalue}, + {"OCTREE", 3, 0, NULL, onevalue}, + {"OVERSAMPLE", 2, 0, NULL, fltvalue}, {"pfilt", 2, 0, NULL, catvalues}, {"pinterp", 2, 0, NULL, catvalues}, - {"OCTREE", 3, 0, NULL, onevalue}, - {"DIRECTORY", 3, 0, NULL, onevalue}, - {"BASENAME", 3, 0, NULL, onevalue}, - {"VIEWFILE", 2, 0, NULL, onevalue}, - {"START", 2, 0, NULL, intvalue}, - {"END", 2, 0, NULL, intvalue}, + {"render", 3, 0, NULL, catvalues}, + {"RESOLUTION", 3, 0, NULL, onevalue}, {"RIF", 3, 0, NULL, onevalue}, - {"NEXTANIM", 3, 0, NULL, onevalue}, - {"ANIMATE", 2, 0, NULL, onevalue}, - {"TRANSFER", 2, 0, NULL, onevalue}, - {"ARCHIVE", 2, 0, NULL, onevalue}, - {"INTERP", 3, 0, NULL, intvalue}, - {"OVERSAMP", 2, 0, NULL, fltvalue}, - {"MBLUR", 2, 0, NULL, onevalue}, + {"RSH", 3, 0, NULL, onevalue}, {"RTRACE", 2, 0, NULL, boolvalue}, - {"DISKSPACE", 3, 0, NULL, fltvalue}, - {"RESOLUTION", 3, 0, NULL, onevalue}, - {"EXPOSURE", 3, 0, NULL, onevalue}, + {"START", 2, 0, NULL, intvalue}, + {"TRANSFER", 2, 0, NULL, onevalue}, + {"VIEWFILE", 2, 0, NULL, onevalue}, }; #define SFNAME "STATUS" /* status file name */ @@ -82,15 +92,34 @@ int nowarn = 0; /* turn warnings off? */ int silent = 0; /* silent mode? */ int noaction = 0; /* take no action? */ -char rendopt[2048] = ""; /* rendering options */ +char *remsh; /* remote shell program/script */ +char rendopt[2048]; /* rendering options */ char rresopt[32]; /* rendering resolution options */ char fresopt[32]; /* filter resolution options */ int pfiltalways; /* always use pfilt? */ +char arcargs[10240]; /* files to archive */ +char *arcfirst, *arcnext; /* pointers to first and next argument */ + +struct pslot { + int pid; /* process ID (0 if empty) */ + int fout; /* output frame number */ + int (*rcvf)(); /* recover function */ +} *pslot; /* process slots */ +int npslots; /* number of process slots */ + +#define phostname(ps) ((ps)->hostname[0] ? (ps)->hostname : astat.host) + +struct pslot *findpslot(); + +PSERVER *lastpserver; /* last process server with error */ + VIEW *getview(); -char *getexp(); +char *getexp(), *dirfile(); +extern time_t fdate(), time(); + main(argc, argv) int argc; char *argv[]; @@ -121,6 +150,8 @@ char *argv[]; cfname = argv[i]; /* load variables */ loadvars(cfname); + /* check variables */ + checkvalues(); /* did we get DIRECTORY? */ checkdir(); /* check status */ @@ -138,6 +169,8 @@ char *argv[]; /* print variables */ if (explicate) printvars(stdout); + /* set up process servers */ + sethosts(); /* run animation */ animate(); /* all done */ @@ -145,10 +178,11 @@ char *argv[]; argv[i] = vval(NEXTANIM); /* just change input file */ if (!silent) printargs(argc, argv, stdout); - if (!noaction) { - execvp(progname, argv); /* pass to next */ - quit(1); /* shouldn't return */ - } + if ((argv[0] = getpath(progname,getenv("PATH"),X_OK)) == NULL) + fprintf(stderr, "%s: command not found\n", progname); + else + execv(progname, argv); + quit(1); } quit(0); userr: @@ -159,13 +193,13 @@ userr: getastat() /* check/set animation status */ { - char buf[256]; + char sfname[256]; FILE *fp; - sprintf(buf, "%s/%s", vval(DIRECTORY), SFNAME); - if ((fp = fopen(buf, "r")) == NULL) { + sprintf(sfname, "%s/%s", vval(DIRECTORY), SFNAME); + if ((fp = fopen(sfname, "r")) == NULL) { if (errno != ENOENT) { - perror(buf); + perror(sfname); return(-1); } astat.rnext = astat.fnext = astat.tnext = 0; @@ -185,8 +219,7 @@ getastat() /* check/set animation status */ goto fmterr; fclose(fp); if (astat.pid != 0) { /* thinks it's still running */ - gethostname(buf, sizeof(buf)); - if (strcmp(buf, astat.host)) { + if (strcmp(myhostname(), astat.host)) { fprintf(stderr, "%s: process %d may still be running on host %s\n", progname, astat.pid, astat.host); @@ -199,19 +232,24 @@ getastat() /* check/set animation status */ } /* assume it is dead */ } - if (strcmp(cfname, astat.cfname) && astat.tnext != 0) { /* other's */ + if (strcmp(cfname, astat.cfname) && astat.pid != 0) { /* other's */ fprintf(stderr, "%s: unfinished job \"%s\"\n", progname, astat.cfname); return(-1); } + /* check control file mods. */ + if (!nowarn && fdate(cfname) > fdate(sfname)) + fprintf(stderr, + "%s: warning - control file modified since last run\n", + progname); setours: /* set our values */ - gethostname(astat.host, sizeof(astat.host)); + strcpy(astat.host, myhostname()); astat.pid = getpid(); strcpy(astat.cfname, cfname); return(0); fmterr: fprintf(stderr, "%s: format error in status file \"%s\"\n", - progname, buf); + progname, sfname); fclose(fp); return(-1); } @@ -222,6 +260,8 @@ putastat() /* put out current status */ char buf[256]; FILE *fp; + if (noaction) + return; sprintf(buf, "%s/%s", vval(DIRECTORY), SFNAME); if ((fp = fopen(buf, "w")) == NULL) { perror(buf); @@ -261,9 +301,14 @@ checkdir() /* make sure we have our directory */ setdefaults() /* set default values */ { + extern char *atos(); + int decades; char buf[256]; - if (vdef(OCTREE) == vdef(ANIMATE)) { + if (vdef(ANIMATE)) { + vval(OCTREE) = NULL; + vdef(OCTREE) = 0; + } else if (!vdef(OCTREE)) { fprintf(stderr, "%s: either %s or %s must be defined\n", progname, vnam(OCTREE), vnam(ANIMATE)); quit(1); @@ -272,17 +317,28 @@ setdefaults() /* set default values */ fprintf(stderr, "%s: %s undefined\n", progname, vnam(VIEWFILE)); quit(1); } + if (!vdef(HOST)) { + vval(HOST) = LHOSTNAME; + vdef(HOST)++; + } if (!vdef(START)) { vval(START) = "1"; vdef(START)++; } if (!vdef(END)) { - sprintf(buf, "%d", countviews()); + sprintf(buf, "%d", countviews()+vint(START)-1); vval(END) = savqstr(buf); vdef(END)++; } + if (vint(END) < vint(START)) { + fprintf(stderr, "%s: ending frame less than starting frame\n", + progname); + quit(1); + } if (!vdef(BASENAME)) { - sprintf(buf, "%s/frame%%03d", vval(DIRECTORY)); + decades = (int)log10((double)vint(END)) + 1; + if (decades < 3) decades = 3; + sprintf(buf, "%s/frame%%0%dd", vval(DIRECTORY), decades); vval(BASENAME) = savqstr(buf); vdef(BASENAME)++; } @@ -314,41 +370,115 @@ setdefaults() /* set default values */ vval(DISKSPACE) = "100"; vdef(DISKSPACE)++; } + if (!vdef(RSH)) { + vval(RSH) = REMSH; + vdef(RSH)++; + } + /* locate remote shell program */ + atos(buf, sizeof(buf), vval(RSH)); + if ((remsh = getpath(buf, getenv("PATH"), X_OK)) != NULL) + remsh = savqstr(remsh); + else + remsh = vval(RSH); /* will generate error if used */ + /* append rendering options */ if (vdef(RENDER)) sprintf(rendopt+strlen(rendopt), " %s", vval(RENDER)); } -getradfile(rfname) /* run rad and get needed variables */ -char *rfname; +sethosts() /* set up process servers */ { + extern char *iskip(); + char buf[256], *dir, *uname; + int np; + register char *cp; + int i; + + npslots = 0; + if (noaction) + return; + for (i = 0; i < vdef(HOST); i++) { /* add each host */ + dir = uname = NULL; + np = 1; + strcpy(cp=buf, nvalue(HOST, i)); /* copy to buffer */ + cp = sskip(cp); /* skip host name */ + while (isspace(*cp)) + *cp++ = '\0'; + if (*cp) { /* has # processes? */ + np = atoi(cp); + if ((cp = iskip(cp)) == NULL || (*cp && !isspace(*cp))) + badvalue(HOST); + while (isspace(*cp)) + cp++; + if (*cp) { /* has directory? */ + dir = cp; + cp = sskip(cp); /* skip dir. */ + while (isspace(*cp)) + *cp++ = '\0'; + if (*cp) { /* has user? */ + uname = cp; + if (*sskip(cp)) + badvalue(HOST); + } + } + } + if (addpserver(buf, dir, uname, np) == NULL) { + if (!nowarn) + fprintf(stderr, + "%s: cannot execute on host \"%s\"\n", + progname, buf); + } else + npslots += np; + } + if (npslots == 0) { + fprintf(stderr, "%s: no working process servers\n", progname); + quit(1); + } + pslot = (struct pslot *)calloc(npslots, sizeof(struct pslot)); + if (pslot == NULL) { + perror("malloc"); + quit(1); + } +} + + +getradfile(rfargs) /* run rad and get needed variables */ +char *rfargs; +{ static short mvar[] = {OCTREE,PFILT,RESOLUTION,EXPOSURE,-1}; char combuf[256]; register int i; register char *cp; + char *pippt; /* create rad command */ sprintf(rendopt, " @%s/render.opt", vval(DIRECTORY)); sprintf(combuf, "rad -v 0 -s -e -w %s OPTFILE=%s | egrep '^[ \t]*(NOMATCH", - rfname, rendopt+2); + rfargs, rendopt+2); cp = combuf; - while (*cp) cp++; /* match unset variables */ + while (*cp) { + if (*cp == '|') pippt = cp; + cp++; + } /* match unset variables */ for (i = 0; mvar[i] >= 0; i++) if (!vdef(mvar[i])) { *cp++ = '|'; strcpy(cp, vnam(mvar[i])); while (*cp) cp++; + pippt = NULL; } - sprintf(cp, ")[ \t]*=' > %s/radset.var", vval(DIRECTORY)); - cp += 11; /* point to file name */ - if (system(combuf)) { - fprintf(stderr, "%s: bad rad input file \"%s\"\n", - progname, rfname); - quit(1); + if (pippt != NULL) + strcpy(pippt, "> /dev/null"); /* nothing to match */ + else { + sprintf(cp, ")[ \t]*=' > %s/radset.var", vval(DIRECTORY)); + cp += 11; /* point to file name */ } - loadvars(cp); /* load variables and remove file */ - unlink(cp); + system(combuf); /* ignore exit code */ + if (pippt == NULL) { /* load variables and remove file */ + loadvars(cp); + unlink(cp); + } } @@ -363,9 +493,9 @@ animate() /* run animation */ i = sscanf(vval(RESOLUTION), "%d %d %f", &xres, &yres, &pa); mult = vflt(OVERSAMP); if (i == 3) { - sprintf(rresopt, "-x %d -y %d -pa %f", (int)(mult*xres), + sprintf(rresopt, "-x %d -y %d -pa %.3f", (int)(mult*xres), (int)(mult*yres), pa); - sprintf(fresopt, "-x %d -y %d -pa %f", xres, yres, pa); + sprintf(fresopt, "-x %d -y %d -pa %.3f", xres, yres, pa); } else if (i) { if (i == 1) yres = xres; sprintf(rresopt, "-x %d -y %d", (int)(mult*xres), @@ -393,7 +523,7 @@ animate() /* run animation */ /* figure # frames per batch */ d1 = mult*xres*mult*yres*4; /* space for orig. picture */ if ((i=vint(INTERP)) || atoi(vval(MBLUR))) - d1 += mult*xres*mult*yres*4; /* space for z-buffer */ + d1 += mult*xres*mult*yres*sizeof(float); /* Z-buffer */ d2 = xres*yres*4; /* space for final picture */ frames_batch = (i+1)*(vflt(DISKSPACE)*1048576.-d1)/(d1+i*d2); if (frames_batch < i+2) { @@ -401,12 +531,15 @@ animate() /* run animation */ progname); quit(1); } + /* initialize archive argument list */ + i = vdef(ARCHIVE) ? strlen(vval(ARCHIVE))+132 : 132; + arcnext = arcfirst = arcargs + i; /* initialize status file */ if (astat.rnext == 0) astat.rnext = astat.fnext = astat.tnext = vint(START); putastat(); /* render in batches */ - while (astat.rnext <= vint(END)) { + while (astat.tnext <= vint(END)) { renderframes(frames_batch); filterframes(); transferframes(); @@ -466,14 +599,12 @@ int nframes; } } if (vdef(ANIMATE)) /* wait for renderings to finish */ - animwait(0); + bwait(0); else { /* else if walk-through */ fclose(fp); /* close view file */ walkwait(astat.rnext, lastframe, vfname); /* walk it */ unlink(vfname); /* remove view file */ } - if (vdef(ARCHIVE)) /* archive results */ - archive(astat.rnext, lastframe); astat.rnext = i; /* update status */ putastat(); } @@ -494,9 +625,10 @@ filterframes() /* catch up with filtering */ progname, i); quit(1); } - dofilt(i, vp, getexp(i)); /* filter frame */ + dofilt(i, vp, getexp(i), 0); /* filter frame */ } - filtwait(0); /* wait for filter processes */ + bwait(0); /* wait for filter processes */ + archive(); /* archive originals */ astat.fnext = i; /* update status */ putastat(); } @@ -504,7 +636,7 @@ filterframes() /* catch up with filtering */ transferframes() /* catch up with picture transfers */ { - char combuf[10240]; + char combuf[10240], *fbase; register char *cp; register int i; @@ -515,12 +647,19 @@ transferframes() /* catch up with picture transfers putastat(); /* update status */ return; } - strcpy(combuf, vval(TRANSFER)); /* start transfer command */ - cp = combuf + strlen(combuf); + strcpy(combuf, "cd "); /* start transfer command */ + fbase = dirfile(cp = combuf+3, vval(BASENAME)); + if (*cp) { + while (*++cp) ; + *cp++ = ';'; *cp++ = ' '; + } else + cp = combuf; + strcpy(cp, vval(TRANSFER)); + while (*cp) cp++; /* make argument list */ for (i = astat.tnext; i < astat.fnext; i++) { *cp++ = ' '; - sprintf(cp, vval(BASENAME), i); + sprintf(cp, fbase, i); while (*cp) cp++; strcpy(cp, ".pic"); cp += 4; @@ -539,6 +678,7 @@ animrend(frame, vp) /* start animation frame */ int frame; VIEW *vp; { + extern int recover(); char combuf[2048]; char fname[128]; @@ -546,28 +686,18 @@ VIEW *vp; strcat(fname, ".unf"); if (access(fname, F_OK) == 0) return; - sprintf(combuf, "%s %d | rpict%s%s %s > %s", vval(ANIMATE), frame, + sprintf(combuf, "%s %d | rpict%s%s -w0 %s > %s", vval(ANIMATE), frame, rendopt, viewopt(vp), rresopt, fname); - if (runcom(combuf)) { - fprintf(stderr, "%s: error rendering frame %d\n", - progname, frame); - quit(1); - } + bruncom(combuf, frame, recover); /* run in background */ } -animwait(nwait) /* wait for renderings to finish */ -int nwait; -{ - /* currently does nothing since parallel rendering not working */ -} - - walkwait(first, last, vfn) /* walk-through frames */ int first, last; char *vfn; { char combuf[2048]; + char *inspoint; register int i; if (!noaction && vint(INTERP)) /* create dummy frames */ @@ -578,14 +708,19 @@ char *vfn; close(open(combuf, O_RDONLY|O_CREAT, 0666)); } /* create command */ - sprintf(combuf, "rpict%s ", rendopt); + sprintf(combuf, "rpict%s%s -w0", rendopt, + viewopt(getview(first>1 ? first-1 : 1))); if (vint(INTERP) || atoi(vval(MBLUR))) - sprintf(combuf+strlen(combuf), "-z %s.zbf ", vval(BASENAME)); - sprintf(combuf+strlen(combuf), "-o %s.unf %s -S %d %s < %s", - vval(BASENAME), rresopt, first, vval(OCTREE), vfn); - if (runcom(combuf)) { - fprintf(stderr, - "%s: error rendering walk-through frames %d through %d\n", + sprintf(combuf+strlen(combuf), " -z %s.zbf", vval(BASENAME)); + sprintf(combuf+strlen(combuf), " -o %s.unf %s -S %d", + vval(BASENAME), rresopt, first); + inspoint = combuf + strlen(combuf); + sprintf(inspoint, " %s < %s", vval(OCTREE), vfn); + /* run in parallel */ + i = (last-first+1)/(vint(INTERP)+1); + if (i < 1) i = 1; + if (pruncom(combuf, inspoint, i)) { + fprintf(stderr, "%s: error rendering frames %d through %d\n", progname, first, last); quit(1); } @@ -599,19 +734,27 @@ char *vfn; } +int recover(frame) /* recover the specified frame */ int frame; { + static int *rfrm; /* list of recovered frames */ + static int nrfrms = 0; char combuf[2048]; char fname[128]; register char *cp; - + register int i; + /* check to see if recovered already */ + for (i = nrfrms; i--; ) + if (rfrm[i] == frame) + return(0); + /* build command */ sprintf(fname, vval(BASENAME), frame); if (vdef(ANIMATE)) - sprintf(combuf, "%s %d | rpict%s", + sprintf(combuf, "%s %d | rpict%s -w0", vval(ANIMATE), frame, rendopt); else - sprintf(combuf, "rpict%s", rendopt); + sprintf(combuf, "rpict%s -w0", rendopt); cp = combuf + strlen(combuf); if (vint(INTERP) || atoi(vval(MBLUR))) { sprintf(cp, " -z %s.zbf", fname); @@ -623,136 +766,177 @@ int frame; *cp++ = ' '; strcpy(cp, vval(OCTREE)); } - if (runcom(combuf)) { - fprintf(stderr, "%s: error recovering frame %d\n", - progname, frame); + if (runcom(combuf)) /* run command */ + return(1); + /* add frame to recovered list */ + if (nrfrms) + rfrm = (int *)realloc((char *)rfrm, (nrfrms+1)*sizeof(int)); + else + rfrm = (int *)malloc(sizeof(int)); + if (rfrm == NULL) { + perror("malloc"); quit(1); } + rfrm[nrfrms++] = frame; + return(0); } -archive(first, last) /* archive finished renderings */ -int first, last; +int +frecover(frame) /* recover filtered frame */ +int frame; { - char combuf[10240]; - int offset; - struct stat stb; - register char *cp; - register int i; + VIEW *vp; + char *ex; - strcpy(cp=combuf, vval(ARCHIVE)); - while (*cp) cp++; - offset = cp - combuf; - *cp++ = ' '; /* make argument list */ - for (i = first; i <= last; i++) { - sprintf(cp, vval(BASENAME), i); - strcat(cp, ".unf"); - if (stat(cp, &stb) == 0 && stb.st_size > 0) { /* non-zero? */ - while (*cp) cp++; - *cp++ = ' '; - sprintf(cp, vval(BASENAME), i); - strcat(cp, ".zbf"); - if (access(cp, F_OK) == 0) { /* exists? */ - while (*cp) cp++; - *cp++ = ' '; - } + vp = getview(frame); + ex = getexp(frame); + if (dofilt(frame, vp, ex, 2) && dofilt(frame, vp, ex, 1)) + return(1); + return(0); +} + + +archive() /* archive and remove renderings */ +{ +#define RMCOML (sizeof(rmcom)-1) + static char rmcom[] = "rm -f"; + char basedir[128]; + int dlen, alen; + register int j; + + if (arcnext == arcfirst) + return; /* nothing to do */ + dirfile(basedir, vval(BASENAME)); + dlen = strlen(basedir); + if (vdef(ARCHIVE)) { /* run archive command */ + alen = strlen(vval(ARCHIVE)); + if (dlen) { + j = alen + dlen + 5; + strncpy(arcfirst-j, "cd ", 3); + strncpy(arcfirst-j+3, basedir, dlen); + (arcfirst-j)[dlen+3] = ';'; (arcfirst-j)[dlen+4] = ' '; + } else + j = alen; + strncpy(arcfirst-alen, vval(ARCHIVE), alen); + if (runcom(arcfirst-j)) { + fprintf(stderr, "%s: error running archive command\n", + progname); + quit(1); } } - *--cp = '\0'; - if (cp <= combuf + offset) /* no files? */ - return; - if (runcom(combuf)) { /* run archive command */ - fprintf(stderr, - "%s: error running archive command on frames %d through %d\n", - progname, first, last); - quit(1); - } + if (dlen) { + j = RMCOML + dlen + 5; + strncpy(arcfirst-j, "cd ", 3); + strncpy(arcfirst-j+3, basedir, dlen); + (arcfirst-j)[dlen+3] = ';'; (arcfirst-j)[dlen+4] = ' '; + } else + j = RMCOML; + /* run remove command */ + strncpy(arcfirst-RMCOML, rmcom, RMCOML); + runcom(arcfirst-j); + arcnext = arcfirst; /* reset argument list */ +#undef RMCOML } -dofilt(frame, vp, ep) /* filter frame */ +int +dofilt(frame, vp, ep, rvr) /* filter frame */ int frame; VIEW *vp; char *ep; +int rvr; { - char fnbefore[128], fnafter[128]; - char combuf[1024], fname[128]; - int usepinterp, usepfilt; - int frbefore, frafter, triesleft; + extern int frecover(); + static int iter = 0; + char fnbefore[128], fnafter[128], *fbase; + char combuf[1024], fname0[128], fname1[128]; + int usepinterp, usepfilt, nora_rgbe; + int frseq[2]; /* check what is needed */ usepinterp = atoi(vval(MBLUR)); usepfilt = pfiltalways | ep==NULL; + if (ep != NULL && !strcmp(ep, "1")) + ep = "+0"; + nora_rgbe = strcmp(vval(OVERSAMP),"1") || ep==NULL || + *ep != '+' || *ep != '-' || !isint(ep); /* compute rendered views */ - frbefore = frame - ((frame-1) % (vint(INTERP)+1)); - frafter = frbefore + vint(INTERP) + 1; - if (frafter > vint(END)) - frafter = vint(END); - if (frafter == frame) { /* pfilt only */ - frbefore = frafter; + frseq[0] = frame - ((frame-1) % (vint(INTERP)+1)); + frseq[1] = frseq[0] + vint(INTERP) + 1; + fbase = dirfile(NULL, vval(BASENAME)); + if (frseq[1] > vint(END)) + frseq[1] = vint(END); + if (frseq[1] == frame) { /* pfilt only */ + frseq[0] = frseq[1]; usepinterp = 0; /* update what's needed */ - usepfilt |= vflt(OVERSAMP)>1.01 || strcmp(ep,"1"); - triesleft = 2; - } else if (frbefore == frame) { /* no interpolation */ - /* remove unneeded files */ - if (frbefore-vint(INTERP)-1 >= 1) { - sprintf(fname, vval(BASENAME), frbefore-vint(INTERP)-1); - sprintf(combuf, "rm -f %s.unf %s.zbf", fname, fname); - runcom(combuf); + usepfilt |= nora_rgbe; + } else if (frseq[0] == frame) { /* no interpolation needed */ + if (!rvr && frame > 1+vint(INTERP)) { /* archive previous */ + *arcnext++ = ' '; + sprintf(arcnext, fbase, frame-vint(INTERP)-1); + while (*arcnext) arcnext++; + strcpy(arcnext, ".unf"); + arcnext += 4; + if (usepinterp || vint(INTERP)) { /* and Z-buf */ + *arcnext++ = ' '; + sprintf(arcnext, fbase, frame-vint(INTERP)-1); + while (*arcnext) arcnext++; + strcpy(arcnext, ".zbf"); + arcnext += 4; + } } - /* update what's needed */ - if (usepinterp) - triesleft = 3; - else { - usepfilt |= vflt(OVERSAMP)>1.01 || strcmp(ep,"1"); - triesleft = 2; - } - } else { /* interpolation needed */ + if (!usepinterp) /* update what's needed */ + usepfilt |= nora_rgbe; + } else /* interpolation needed */ usepinterp++; - triesleft = 3; - } - if (frafter >= astat.rnext) { /* next batch unavailable */ - frafter = frbefore; - if (triesleft > 2) - triesleft = 2; - } - sprintf(fnbefore, vval(BASENAME), frbefore); - sprintf(fnafter, vval(BASENAME), frafter); -tryit: /* generate command */ + if (frseq[1] >= astat.rnext) /* next batch unavailable */ + frseq[1] = frseq[0]; + sprintf(fnbefore, vval(BASENAME), frseq[0]); + sprintf(fnafter, vval(BASENAME), frseq[1]); + if (rvr == 1 && recover(frseq[0])) /* recover before frame? */ + return(1); + /* generate command */ if (usepinterp) { /* using pinterp */ + if (rvr == 2 && recover(frseq[1])) /* recover after? */ + return(1); if (atoi(vval(MBLUR))) { - FILE *fp; /* motion blurring */ - sprintf(fname, "%s/vw0", vval(DIRECTORY)); - if ((fp = fopen(fname, "w")) == NULL) { - perror(fname); quit(1); - } - fputs(VIEWSTR, fp); - fprintview(vp, fp); - putc('\n', fp); fclose(fp); - if ((vp = getview(frame+1)) == NULL) { - fprintf(stderr, + sprintf(fname0, "%s/vw0%c", vval(DIRECTORY), + 'a'+(iter%26)); + sprintf(fname1, "%s/vw1%c", vval(DIRECTORY), + 'a'+(iter%26)); + if (!noaction) { + FILE *fp; /* motion blurring */ + if ((fp = fopen(fname0, "w")) == NULL) { + perror(fname0); quit(1); + } + fputs(VIEWSTR, fp); + fprintview(vp, fp); + putc('\n', fp); fclose(fp); + if ((vp = getview(frame+1)) == NULL) { + fprintf(stderr, "%s: unexpected error reading view for frame %d\n", - progname, frame+1); - quit(1); + progname, frame+1); + quit(1); + } + if ((fp = fopen(fname1, "w")) == NULL) { + perror(fname1); quit(1); + } + fputs(VIEWSTR, fp); + fprintview(vp, fp); + putc('\n', fp); fclose(fp); } - sprintf(fname, "%s/vw1", vval(DIRECTORY)); - if ((fp = fopen(fname, "w")) == NULL) { - perror(fname); quit(1); - } - fputs(VIEWSTR, fp); - fprintview(vp, fp); - putc('\n', fp); fclose(fp); sprintf(combuf, - "(pmblur %s %d %s/vw0 %s/vw1; rm -f %s/vw0 %s/vw1) | pinterp -B", - *sskip(vval(MBLUR)) ? sskip(vval(MBLUR)) : "1", - atoi(vval(MBLUR)), vval(DIRECTORY), - vval(DIRECTORY), vval(DIRECTORY), - vval(DIRECTORY), vval(DIRECTORY)); + "(pmblur %s %d %s %s; rm -f %s %s) | pinterp -B", + *sskip(vval(MBLUR)) ? sskip2(vval(MBLUR),1) : "1", + atoi(vval(MBLUR)), + fname0, fname1, fname0, fname1); + iter++; } else /* no blurring */ strcpy(combuf, "pinterp"); strcat(combuf, viewopt(vp)); if (vbool(RTRACE)) - sprintf(combuf+strlen(combuf), " -ff -fr '%s %s'", - rendopt, vval(OCTREE)); + sprintf(combuf+strlen(combuf), " -ff -fr '%s -w0 %s'", + rendopt+1, vval(OCTREE)); if (vdef(PINTERP)) sprintf(combuf+strlen(combuf), " %s", vval(PINTERP)); if (usepfilt) @@ -762,7 +946,7 @@ tryit: /* generate command */ fresopt, ep); sprintf(combuf+strlen(combuf), " %s.unf %s.zbf", fnbefore, fnbefore); - if (frafter != frbefore) + if (frseq[1] != frseq[0]) sprintf(combuf+strlen(combuf), " %s.unf %s.zbf", fnafter, fnafter); if (usepfilt) { /* also pfilt */ @@ -778,6 +962,8 @@ tryit: /* generate command */ sprintf(combuf+strlen(combuf), " %s", fresopt); } } else if (usepfilt) { /* pfilt only */ + if (rvr == 2) + return(1); if (vdef(PFILT)) sprintf(combuf, "pfilt %s", vval(PFILT)); else @@ -789,35 +975,20 @@ tryit: /* generate command */ sprintf(combuf+strlen(combuf), " %s %s.unf", fresopt, fnbefore); } else { /* else just check it */ - sprintf(combuf, "ra_rgbe -r %s.unf", fnbefore); + if (rvr == 2) + return(1); + sprintf(combuf, "ra_rgbe -e %s -r %s.unf", ep, fnbefore); } /* output file name */ - sprintf(fname, vval(BASENAME), frame); - sprintf(combuf+strlen(combuf), " > %s.pic", fname); - if (runcom(combuf)) /* run filter command */ - switch (--triesleft) { - case 2: /* try to recover frafter */ - recover(frafter); - goto tryit; - case 1: /* try to recover frbefore */ - recover(frbefore); - goto tryit; - default: /* we've really failed */ - fprintf(stderr, - "%s: unrecoverable filtering error on frame %d\n", - progname, frame); - quit(1); - } + sprintf(fname0, vval(BASENAME), frame); + sprintf(combuf+strlen(combuf), " > %s.pic", fname0); + if (rvr) /* in recovery */ + return(runcom(combuf)); + bruncom(combuf, frame, frecover); /* else run in background */ + return(0); } -filtwait(nwait) /* wait for filtering processes to finish */ -int nwait; -{ - /* currently does nothing since parallel filtering not working */ -} - - VIEW * getview(n) /* get view number n */ int n; @@ -836,12 +1007,14 @@ int n; } return(NULL); } - if (viewfp == NULL) { /* open file */ + if (viewfp == NULL) { /* open file */ if ((viewfp = fopen(vval(VIEWFILE), "r")) == NULL) { perror(vval(VIEWFILE)); quit(1); } - } else if (n < viewnum) { /* rewind file */ + } else if (n > 0 && n < viewnum) { /* rewind file */ + if (viewnum == 1 && feof(viewfp)) + return(&curview); /* just one view */ if (fseek(viewfp, 0L, 0) == EOF) { perror(vval(VIEWFILE)); quit(1); @@ -849,9 +1022,16 @@ int n; copystruct(&curview, &stdview); viewnum = 0; } + if (n < 0) { /* get next view */ + register int c = getc(viewfp); + if (c == EOF) + return((VIEW *)NULL); /* that's it */ + ungetc(c, viewfp); + n = viewnum + 1; + } while (n > viewnum) { /* scan to desired view */ if (fgets(linebuf, sizeof(linebuf), viewfp) == NULL) - return(NULL); + return(viewnum==1 ? &curview : (VIEW *)NULL); if (isview(linebuf) && sscanview(&curview, linebuf) > 0) viewnum++; } @@ -862,9 +1042,11 @@ int n; int countviews() /* count views in view file */ { - register int n = 0; + int n; - while (getview(n+1) != NULL) + if (getview(n=1) == NULL) + return(0); + while (getview(-1) != NULL) n++; return(n); } @@ -884,10 +1066,12 @@ int n; if (n == 0) { /* signal to close file */ if (expfp != NULL) { fclose(expfp); + free((char *)exppos); expfp = NULL; } return(NULL); - } + } else if (n > vint(END)) /* request past end (error?) */ + return(NULL); if (!vdef(EXPOSURE)) /* no setting (auto) */ return(NULL); if (isflt(vval(EXPOSURE))) /* always the same */ @@ -925,19 +1109,213 @@ int n; } curfrm++; cp = fskip(expval); /* check format */ - if (cp == NULL || *cp != '\n') { + if (cp != NULL) + while (isspace(*cp)) + *cp++ = '\0'; + if (cp == NULL || *cp) { fprintf(stderr, "%s: exposure format error on line %d\n", vval(EXPOSURE), curfrm); quit(1); } - *cp = '\0'; } return(expval); /* return value */ } -runcom(cs) /* run command */ +struct pslot * +findpslot(pid) /* find or allocate a process slot */ +int pid; +{ + register struct pslot *psempty = NULL; + register int i; + + for (i = 0; i < npslots; i++) { /* look for match */ + if (pslot[i].pid == pid) + return(pslot+i); + if (psempty == NULL && pslot[i].pid == 0) + psempty = pslot+i; + } + return(psempty); /* return emtpy slot (error if NULL) */ +} + + +int +donecom(ps, pn, status) /* clean up after finished process */ +PSERVER *ps; +int pn; +int status; +{ + register PROC *pp; + register struct pslot *psl; + + pp = ps->proc + pn; + if (pp->elen) { /* pass errors */ + if (ps->hostname[0]) + fprintf(stderr, "%s: ", ps->hostname); + fprintf(stderr, "Error output from: %s\n", pp->com); + fputs(pp->errs, stderr); + fflush(stderr); + if (ps->hostname[0]) + status = 1; /* because rsh doesn't return status */ + } + lastpserver = NULL; + psl = findpslot(pp->pid); /* check for bruncom() slot */ + if (psl->pid) { + if (status) { + if (psl->rcvf != NULL) /* attempt recovery */ + status = (*psl->rcvf)(psl->fout); + if (status) { + fprintf(stderr, + "%s: error rendering frame %d\n", + progname, psl->fout); + quit(1); + } + lastpserver = ps; + } + psl->pid = 0; /* free process slot */ + } else if (status) + lastpserver = ps; + freestr(pp->com); /* free command string */ + return(status); +} + + +int +serverdown() /* check status of last process server */ +{ + if (lastpserver == NULL || !lastpserver->hostname[0]) + return(0); + if (pserverOK(lastpserver)) /* server still up? */ + return(0); + delpserver(lastpserver); /* else delete it */ + if (pslist == NULL) { + fprintf(stderr, "%s: all process servers are down\n", + progname); + quit(1); + } + return(1); +} + + +int +bruncom(com, fout, rf) /* run a command in the background */ +char *com; +int fout; +int (*rf)(); +{ + int pid; + register struct pslot *psl; + + if (noaction) { + if (!silent) + printf("\t%s\n", com); /* echo command */ + return(0); + } + com = savestr(com); /* else start it when we can */ + while ((pid = startjob(NULL, com, donecom)) == -1) + bwait(1); + if (!silent) { /* echo command */ + PSERVER *ps; + int psn = pid; + ps = findjob(&psn); + printf("\t%s\n", com); + printf("\tProcess started on %s\n", phostname(ps)); + fflush(stdout); + } + psl = findpslot(pid); /* record info. in appropriate slot */ + psl->pid = pid; + psl->fout = fout; + psl->rcvf = rf; + return(pid); +} + + +bwait(ncoms) /* wait for batch job(s) to finish */ +int ncoms; +{ + int status; + + if (noaction) + return; + while ((status = wait4job(NULL, -1)) != -1) { + serverdown(); /* update server status */ + if (--ncoms == 0) + break; /* done enough */ + } +} + + +int +pruncom(com, ppins, maxcopies) /* run a command in parallel over network */ +char *com, *ppins; +int maxcopies; +{ + int retstatus = 0; + int hostcopies; + char buf[10240], *com1, *s; + int status; + int pfd; + register int n; + register PSERVER *ps; + + if (!silent) + printf("\t%s\n", com); /* echo command */ + if (noaction) + return(0); + fflush(stdout); + /* start jobs on each server */ + for (ps = pslist; ps != NULL; ps = ps->next) { + hostcopies = 0; + if (maxcopies > 1 && ps->nprocs > 1 && ppins != NULL) { + strcpy(com1=buf, com); /* build -PP command */ + sprintf(com1+(ppins-com), " -PP %s/%s.persist", + vval(DIRECTORY), phostname(ps)); + strcat(com1, ppins); + } else + com1 = com; + while (maxcopies > 0) { + s = savestr(com1); + if (startjob(ps, s, donecom) != -1) { + sleep(20); + hostcopies++; + maxcopies--; + } else { + freestr(s); + break; + } + } + if (!silent && hostcopies) { + if (hostcopies > 1) + printf("\t%d duplicate processes", hostcopies); + else + printf("\tProcess"); + printf(" started on %s\n", phostname(ps)); + fflush(stdout); + } + } + /* wait for jobs to finish */ + while ((status = wait4job(NULL, -1)) != -1) + retstatus += status && !serverdown(); + /* terminate parallel rpict's */ + for (ps = pslist; ps != NULL; ps = ps->next) { + sprintf(buf, "%s/%s.persist", vval(DIRECTORY), phostname(ps)); + if ((pfd = open(buf, O_RDONLY)) >= 0) { + n = read(pfd, buf, sizeof(buf)-1); /* get PID */ + buf[n] = '\0'; + close(pfd); + for (n = 0; buf[n] && !isspace(buf[n]); n++) + ; + /* terminate */ + sprintf(buf, "kill -ALRM %d", atoi(buf+n)); + wait4job(ps, startjob(ps, buf, NULL)); + } + } + return(retstatus); +} + + +runcom(cs) /* run a command locally and wait for it */ char *cs; { if (!silent) /* echo it */ @@ -970,4 +1348,28 @@ int vc; fprintf(stderr, "%s: bad value for variable '%s'\n", progname, vnam(vc)); quit(1); +} + + +char * +dirfile(df, path) /* separate path into directory and file */ +char *df; +register char *path; +{ + register int i; + int psep; + + for (i = 0, psep = -1; path[i]; i++) + if (path[i] == '/') + psep = i; + if (df != NULL) + if (psep == 0) { + df[0] = '/'; + df[1] = '\0'; + } else if (psep > 0) { + strncpy(df, path, psep); + df[psep] = '\0'; + } else + df[0] = '\0'; + return(path+psep+1); }