--- ray/src/util/ranimate.c 1996/01/12 12:16:17 2.1
+++ ray/src/util/ranimate.c 2003/02/22 02:07:30 2.29
@@ -1,67 +1,142 @@
-/* Copyright (c) 1995 Regents of the University of California */
-
#ifndef lint
-static char SCCSid[] = "$SunId$ LBL";
+static const char RCSid[] = "$Id: ranimate.c,v 2.29 2003/02/22 02:07:30 greg Exp $";
#endif
-
/*
* Radiance animation control program
+ *
+ * The main difference between this program and ranimove is that
+ * we have many optimizations here for camera motion in static
+ * environments, calling rpict and pinterp on multiple processors,
+ * where ranimove puts its emphasis on object motion, and does
+ * not use any external programs for image generation.
+ *
+ * See the ranimate(1) man page for further details.
*/
+/* ====================================================================
+ * The Radiance Software License, Version 1.0
+ *
+ * Copyright (c) 1990 - 2002 The Regents of the University of California,
+ * through Lawrence Berkeley National Laboratory. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes Radiance software
+ * (http://radsite.lbl.gov/)
+ * developed by the Lawrence Berkeley National Laboratory
+ * (http://www.lbl.gov/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Radiance," "Lawrence Berkeley National Laboratory"
+ * and "The Regents of the University of California" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact radiance@radsite.lbl.gov.
+ *
+ * 5. Products derived from this software may not be called "Radiance",
+ * nor may "Radiance" appear in their name, without prior written
+ * permission of Lawrence Berkeley National Laboratory.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of Lawrence Berkeley National Laboratory. For more
+ * information on Lawrence Berkeley National Laboratory, please see
+ * .
+ */
+
#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 blur samples */
+#ifndef DEF_NBLUR
+#define DEF_NBLUR 5
+#endif
+ /* 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 /* motion blur parameters */
+#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 +157,35 @@ 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();
+int getblur();
+extern time_t time();
+
main(argc, argv)
int argc;
char *argv[];
@@ -121,6 +216,8 @@ char *argv[];
cfname = argv[i];
/* load variables */
loadvars(cfname);
+ /* check variables */
+ checkvalues();
/* did we get DIRECTORY? */
checkdir();
/* check status */
@@ -138,6 +235,8 @@ char *argv[];
/* print variables */
if (explicate)
printvars(stdout);
+ /* set up process servers */
+ sethosts();
/* run animation */
animate();
/* all done */
@@ -145,10 +244,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 +259,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 +285,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 +298,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 +326,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 +367,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 +383,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 +436,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 +559,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),
@@ -382,7 +578,7 @@ animate() /* run animation */
progname, vnam(INTERP));
vval(INTERP) = "0";
}
- if (atoi(vval(MBLUR))) { /* can't handle this yet */
+ if (strcmp(vval(MBLUR),"0")) { /* can't handle this */
if (!nowarn)
fprintf(stderr,
"%s: resetting %s=0 for animation\n",
@@ -392,8 +588,8 @@ 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 */
+ if ((i=vint(INTERP)) || getblur(NULL) > 1)
+ 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 +597,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 +665,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 +691,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 +702,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 +713,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 +744,7 @@ animrend(frame, vp) /* start animation frame */
int frame;
VIEW *vp;
{
+ extern int recover();
char combuf[2048];
char fname[128];
@@ -546,28 +752,20 @@ 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;
{
+ double blurf;
+ int nblur = getblur(&blurf);
char combuf[2048];
+ register char *inspoint;
register int i;
if (!noaction && vint(INTERP)) /* create dummy frames */
@@ -578,14 +776,27 @@ char *vfn;
close(open(combuf, O_RDONLY|O_CREAT, 0666));
}
/* create command */
- sprintf(combuf, "rpict%s ", rendopt);
- 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, "rpict%s%s -w0", rendopt,
+ viewopt(getview(first>1 ? first-1 : 1)));
+ inspoint = combuf;
+ while (*inspoint) inspoint++;
+ if (nblur) {
+ sprintf(inspoint, " -pm %.3f", blurf/nblur);
+ while (*inspoint) inspoint++;
+ }
+ if (nblur > 1 || vint(INTERP)) {
+ sprintf(inspoint, " -z %s.zbf", vval(BASENAME));
+ while (*inspoint) inspoint++;
+ }
+ sprintf(inspoint, " -o %s.unf %s -S %d",
+ vval(BASENAME), rresopt, first);
+ while (*inspoint) inspoint++;
+ 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,21 +810,36 @@ char *vfn;
}
+int
recover(frame) /* recover the specified frame */
int frame;
{
+ static int *rfrm; /* list of recovered frames */
+ static int nrfrms = 0;
+ double blurf;
+ int nblur = getblur(&blurf);
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);
- cp = combuf + strlen(combuf);
- if (vint(INTERP) || atoi(vval(MBLUR))) {
+ sprintf(combuf, "rpict%s -w0", rendopt);
+ cp = combuf;
+ while (*cp) cp++;
+ if (nblur) {
+ sprintf(cp, " -pm %.3f", blurf/nblur);
+ while (*cp) cp++;
+ }
+ if (nblur > 1 || vint(INTERP)) {
sprintf(cp, " -z %s.zbf", fname);
while (*cp) cp++;
}
@@ -623,136 +849,178 @@ 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;
+ double blurf;
+ int nblur = getblur(&blurf);
+ 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));
+ usepinterp = (nblur > 1);
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 (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,
+ if (rvr == 2 && recover(frseq[1])) /* recover after? */
+ return(1);
+ if (nblur > 1) { /* with pmblur */
+ 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 %.3f %d %s %s; rm -f %s %s) | pinterp -B",
+ blurf, nblur,
+ 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 +1030,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 +1046,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 +1059,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 +1091,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 +1106,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 +1126,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 +1150,12 @@ int n;
if (n == 0) { /* signal to close file */
if (expfp != NULL) {
fclose(expfp);
+ free((void *)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 +1193,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 +1432,57 @@ 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);
+}
+
+
+int
+getblur(double *bf) /* get # blur samples (and fraction) */
+{
+ double blurf;
+ int nblur;
+ char *s;
+
+ if (!vdef(MBLUR)) {
+ if (bf != NULL)
+ *bf = 0.0;
+ return(0);
+ }
+ blurf = atof(vval(MBLUR));
+ if (blurf < 0.0)
+ blurf = 0.0;
+ if (bf != NULL)
+ *bf = blurf;
+ if (blurf <= FTINY)
+ return(0);
+ s = sskip(vval(MBLUR));
+ if (!*s)
+ return(DEF_NBLUR);
+ nblur = atoi(s);
+ if (nblur <= 0)
+ return(1);
+ return(nblur);
}