Back to index

radiance  4R0+20100331
ranimate.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: ranimate.c,v 2.54 2008/11/10 19:08:20 greg Exp $";
00003 #endif
00004 /*
00005  * Radiance animation control program
00006  *
00007  * The main difference between this program and ranimove is that
00008  * we have many optimizations here for camera motion in static
00009  * environments, calling rpict and pinterp on multiple processors,
00010  * where ranimove puts its emphasis on object motion, and does
00011  * not use any external programs for image generation.
00012  *
00013  * See the ranimate(1) man page for further details.
00014  */
00015 
00016 #include "copyright.h"
00017 
00018 #include <stdio.h>
00019 #include <ctype.h>
00020 #include <sys/stat.h>
00021 #include <time.h>
00022 #include <signal.h>
00023 
00024 #include "platform.h"
00025 #include "rtprocess.h"
00026 #include "paths.h"
00027 #include "standard.h"
00028 #include "view.h"
00029 #include "vars.h"
00030 #include "netproc.h"
00031                             /* default blur samples */
00032 #ifndef DEF_NBLUR
00033 #define DEF_NBLUR    5
00034 #endif
00035                             /* default remote shell */
00036 #ifndef REMSH
00037 #define REMSH        "ssh"
00038 #endif
00039                             /* input variables (alphabetical by name) */
00040 #define ANIMATE             0             /* animation command */
00041 #define ARCHIVE             1             /* archiving command */
00042 #define BASENAME     2             /* output image base name */
00043 #define DBLUR        3             /* depth of field blur */
00044 #define DIRECTORY    4             /* working (sub)directory */
00045 #define DISKSPACE    5             /* how much disk space to use */
00046 #define END          6             /* ending frame number */
00047 #define EXPOSURE     7             /* how to compute exposure */
00048 #define HOST         8             /* rendering host machine */
00049 #define INTERP              9             /* # frames to interpolate */
00050 #define MBLUR        10            /* motion blur parameters */
00051 #define NEXTANIM     11            /* next animation file */
00052 #define OCTREE              12            /* octree file name */
00053 #define OVERSAMP     13            /* # times to oversample image */
00054 #define PFILT        14            /* pfilt options */
00055 #define PINTERP             15            /* pinterp options */
00056 #define RENDER              16            /* rendering options */
00057 #define RESOLUTION   17            /* desired final resolution */
00058 #define RIF          18            /* rad input file */
00059 #define RSH          19            /* remote shell script or program */
00060 #define RTRACE              20            /* use rtrace with pinterp? */
00061 #define START        21            /* starting frame number */
00062 #define TRANSFER     22            /* frame transfer command */
00063 #define VIEWFILE     23            /* animation frame views */
00064 
00065 int    NVARS = 24;          /* total number of variables */
00066 
00067 VARIABLE      vv[] = {             /* variable-value pairs */
00068        {"ANIMATE",   2,     0,     NULL,  onevalue},
00069        {"ARCHIVE",   2,     0,     NULL,  onevalue},
00070        {"BASENAME",  3,     0,     NULL,  onevalue},
00071        {"DBLUR",     2,     0,     NULL,  onevalue},
00072        {"DIRECTORY", 3,     0,     NULL,  onevalue},
00073        {"DISKSPACE", 3,     0,     NULL,  fltvalue},
00074        {"END",              2,     0,     NULL,  intvalue},
00075        {"EXPOSURE",  3,     0,     NULL,  onevalue},
00076        {"host",      4,     0,     NULL,  NULL},
00077        {"INTERPOLATE",      3,     0,     NULL,  intvalue},
00078        {"MBLUR",     2,     0,     NULL,  onevalue},
00079        {"NEXTANIM",  3,     0,     NULL,  onevalue},
00080        {"OCTREE",    3,     0,     NULL,  onevalue},
00081        {"OVERSAMPLE",       2,     0,     NULL,  fltvalue},
00082        {"pfilt",     2,     0,     NULL,  catvalues},
00083        {"pinterp",   2,     0,     NULL,  catvalues},
00084        {"render",    3,     0,     NULL,  catvalues},
00085        {"RESOLUTION",       3,     0,     NULL,  onevalue},
00086        {"RIF",              3,     0,     NULL,  onevalue},
00087        {"RSH",              3,     0,     NULL,  onevalue},
00088        {"RTRACE",    2,     0,     NULL,  boolvalue},
00089        {"START",     2,     0,     NULL,  intvalue},
00090        {"TRANSFER",  2,     0,     NULL,  onevalue},
00091        {"VIEWFILE",  2,     0,     NULL,  onevalue},
00092 };
00093 
00094 #define SFNAME       "STATUS"             /* status file name */
00095 
00096 struct {
00097        char   host[64];            /* control host name */
00098        RT_PID pid;                 /* control process id */
00099        char   cfname[128];         /* control file name */
00100        int    rnext;               /* next frame to render */
00101        int    fnext;               /* next frame to filter */
00102        int    tnext;               /* next frame to transfer */
00103 }      astat;               /* animation status */
00104 
00105 char   *progname;           /* our program name */
00106 char   *cfname;             /* our control file name */
00107 
00108 int    nowarn = 0;          /* turn warnings off? */
00109 int    silent = 0;          /* silent mode? */
00110 int    noaction = 0;        /* take no action? */
00111 
00112 char   *remsh;                     /* remote shell program/script */
00113 char   rendopt[2048];              /* rendering options */
00114 char   rresopt[32];         /* rendering resolution options */
00115 char   fresopt[32];         /* filter resolution options */
00116 int    pfiltalways;         /* always use pfilt? */
00117 
00118 char   arcargs[10240];             /* files to archive */
00119 char   *arcfirst, *arcnext; /* pointers to first and next argument */
00120 
00121 struct pslot {
00122        RT_PID pid;                 /* process ID (0 if empty) */
00123        int    fout;                /* output frame number */
00124        int    (*rcvf)();           /* recover function */
00125 }      *pslot;                     /* process slots */
00126 int    npslots;             /* number of process slots */
00127 
00128 #define phostname(ps)       ((ps)->hostname[0] ? (ps)->hostname : astat.host)
00129 PSERVER       *lastpserver;        /* last process server with error */
00130 
00131 static struct pslot * findpslot(RT_PID pid);
00132 static void checkdir(void);
00133 static VIEW * getview(int n);
00134 
00135 static char * dirfile(char *df, register char *path);
00136 static char * getexp(int n);
00137 static int getblur(double *mbf, double *dbf);
00138 static int getastat(void);
00139 static void getradfile(char *rfargs);
00140 static void badvalue(int vc);
00141 static int rmfile(char *fn);
00142 static int runcom(char *cs);
00143 static int pruncom(char *com, char *ppins, int maxcopies);
00144 static void bwait(int ncoms);
00145 static RT_PID bruncom(char *com, int fout, int (*rf)());
00146 static int serverdown(void);
00147 static pscompfunc donecom;
00148 static int countviews(void);
00149 static int dofilt(int frame, int rvr);
00150 static void archive(void);
00151 static int frecover(int frame);
00152 static int recover(int frame);
00153 static void sethosts(void);
00154 static void walkwait(int first, int last, char *vfn);
00155 static void animrend(int frame, VIEW *vp);
00156 static void transferframes(void);
00157 static void filterframes(void);
00158 static void renderframes(int nframes);
00159 static void animate(void);
00160 static void setdefaults(void);
00161 static void putastat(void);
00162 
00163 
00164 int
00165 main(
00166        int    argc,
00167        char   *argv[]
00168 )
00169 {
00170        int    explicate = 0;
00171        int    i;
00172 
00173        progname = argv[0];                /* get arguments */
00174        for (i = 1; i < argc && argv[i][0] == '-'; i++)
00175               switch (argv[i][1]) {
00176               case 'e':                   /* print variables */
00177                      explicate++;
00178                      break;
00179               case 'w':                   /* turn off warnings */
00180                      nowarn++;
00181                      break;
00182               case 's':                   /* silent mode */
00183                      silent++;
00184                      break;
00185               case 'n':                   /* take no action */
00186                      noaction++;
00187                      break;
00188               default:
00189                      goto userr;
00190               }
00191        if (i != argc-1)
00192               goto userr;
00193        cfname = argv[i];
00194                                           /* load variables */
00195        loadvars(cfname);
00196                                           /* check variables */
00197        checkvalues();
00198                                           /* did we get DIRECTORY? */
00199        checkdir();
00200                                           /* check status */
00201        if (getastat() < 0) {
00202               fprintf(stderr, "%s: exiting\n", progname);
00203               quit(1);
00204        }
00205                                           /* pfilt always if options given */
00206        pfiltalways = vdef(PFILT);
00207                                           /* load RIF if any */
00208        if (vdef(RIF))
00209               getradfile(vval(RIF));
00210                                           /* set defaults */
00211        setdefaults();
00212                                           /* print variables */
00213        if (explicate)
00214               printvars(stdout);
00215                                           /* set up process servers */
00216        sethosts();
00217                                           /* run animation */
00218        animate();
00219                                           /* all done */
00220        if (vdef(NEXTANIM)) {
00221               char   *fullp;
00222               argv[i] = vval(NEXTANIM);   /* just change input file */
00223               if (!silent)
00224                      printargs(argc, argv, stdout);
00225               fflush(stdout);
00226               if ((fullp = getpath(argv[0],getenv("PATH"),X_OK)) == NULL)
00227                      fprintf(stderr, "%s: command not found\n", argv[0]);
00228               else
00229                      execv(fullp, argv);
00230               quit(1);
00231        }
00232        quit(0);
00233        return(0); /* pro forma return */
00234 userr:
00235        fprintf(stderr, "Usage: %s [-s][-n][-w][-e] anim_file\n", progname);
00236        quit(1);
00237        return 1; /* pro forma return */
00238 }
00239 
00240 
00241 static int
00242 getastat(void)                     /* check/set animation status */
00243 {
00244        char   sfname[256];
00245        FILE   *fp;
00246 
00247        sprintf(sfname, "%s/%s", vval(DIRECTORY), SFNAME);
00248        if ((fp = fopen(sfname, "r")) == NULL) {
00249               if (errno != ENOENT) {
00250                      perror(sfname);
00251                      return(-1);
00252               }
00253               astat.rnext = astat.fnext = astat.tnext = 0;
00254               goto setours;
00255        }
00256        if (fscanf(fp, "Control host: %s\n", astat.host) != 1)
00257               goto fmterr;
00258        if (fscanf(fp, "Control PID: %d\n", &astat.pid) != 1)
00259               goto fmterr;
00260        if (fscanf(fp, "Control file: %s\n", astat.cfname) != 1)
00261               goto fmterr;
00262        if (fscanf(fp, "Next render: %d\n", &astat.rnext) != 1)
00263               goto fmterr;
00264        if (fscanf(fp, "Next filter: %d\n", &astat.fnext) != 1)
00265               goto fmterr;
00266        if (fscanf(fp, "Next transfer: %d\n", &astat.tnext) != 1)
00267               goto fmterr;
00268        fclose(fp);
00269        if (astat.pid != 0) {                     /* thinks it's still running */
00270               if (strcmp(myhostname(), astat.host)) {
00271                      fprintf(stderr,
00272                      "%s: process %d may still be running on host %s\n",
00273                                    progname, astat.pid, astat.host);
00274                      return(-1);
00275               }
00276               if (kill(astat.pid, 0) != -1 || errno != ESRCH) {
00277                      fprintf(stderr, "%s: process %d is still running\n",
00278                                    progname, astat.pid);
00279                      return(-1);
00280               }
00281               /* assume it is dead */
00282        }
00283        if (strcmp(cfname, astat.cfname) && astat.pid != 0) {   /* other's */
00284               fprintf(stderr, "%s: unfinished job \"%s\"\n",
00285                             progname, astat.cfname);
00286               return(-1);
00287        }
00288                                           /* check control file mods. */
00289        if (!nowarn && fdate(cfname) > fdate(sfname))
00290               fprintf(stderr,
00291                      "%s: warning - control file modified since last run\n",
00292                             progname);
00293 setours:                                  /* set our values */
00294        strcpy(astat.host, myhostname());
00295        astat.pid = getpid();
00296        strcpy(astat.cfname, cfname);
00297        return(0);
00298 fmterr:
00299        fprintf(stderr, "%s: format error in status file \"%s\"\n",
00300                      progname, sfname);
00301        fclose(fp);
00302        return(-1);
00303 }
00304 
00305 
00306 static void
00307 putastat(void)                     /* put out current status */
00308 {
00309        char   buf[256];
00310        FILE   *fp;
00311 
00312        if (noaction)
00313               return;
00314        sprintf(buf, "%s/%s", vval(DIRECTORY), SFNAME);
00315        if ((fp = fopen(buf, "w")) == NULL) {
00316               perror(buf);
00317               quit(1);
00318        }
00319        fprintf(fp, "Control host: %s\n", astat.host);
00320        fprintf(fp, "Control PID: %d\n", astat.pid);
00321        fprintf(fp, "Control file: %s\n", astat.cfname);
00322        fprintf(fp, "Next render: %d\n", astat.rnext);
00323        fprintf(fp, "Next filter: %d\n", astat.fnext);
00324        fprintf(fp, "Next transfer: %d\n", astat.tnext);
00325        fclose(fp);
00326 }
00327 
00328 
00329 static void
00330 checkdir(void)                     /* make sure we have our directory */
00331 {
00332        struct stat   stb;
00333 
00334        if (!vdef(DIRECTORY)) {
00335               fprintf(stderr, "%s: %s undefined\n",
00336                             progname, vnam(DIRECTORY));
00337               quit(1);
00338        }
00339        if (stat(vval(DIRECTORY), &stb) == -1) {
00340               if (errno == ENOENT && mkdir(vval(DIRECTORY), 0777) == 0)
00341                      return;
00342               perror(vval(DIRECTORY));
00343               quit(1);
00344        }
00345        if (!(stb.st_mode & S_IFDIR)) {
00346               fprintf(stderr, "%s: not a directory\n", vval(DIRECTORY));
00347               quit(1);
00348        }
00349 }
00350 
00351 
00352 static void
00353 setdefaults(void)                  /* set default values */
00354 {
00355        extern char   *atos();
00356        int    decades;
00357        char   buf[256];
00358 
00359        if (vdef(ANIMATE)) {
00360               vval(OCTREE) = NULL;
00361               vdef(OCTREE) = 0;
00362        } else if (!vdef(OCTREE)) {
00363               fprintf(stderr, "%s: either %s or %s must be defined\n",
00364                             progname, vnam(OCTREE), vnam(ANIMATE));
00365               quit(1);
00366        }
00367        if (!vdef(VIEWFILE)) {
00368               fprintf(stderr, "%s: %s undefined\n", progname, vnam(VIEWFILE));
00369               quit(1);
00370        }
00371        if (!vdef(HOST)) {
00372               vval(HOST) = LHOSTNAME;
00373               vdef(HOST)++;
00374        }
00375        if (!vdef(START)) {
00376               vval(START) = "1";
00377               vdef(START)++;
00378        }
00379        if (!vdef(END)) {
00380               sprintf(buf, "%d", countviews()+vint(START)-1);
00381               vval(END) = savqstr(buf);
00382               vdef(END)++;
00383        }
00384        if (vint(END) < vint(START)) {
00385               fprintf(stderr, "%s: ending frame less than starting frame\n",
00386                             progname);
00387               quit(1);
00388        }
00389        if (!vdef(BASENAME)) {
00390               decades = (int)log10((double)vint(END)) + 1;
00391               if (decades < 3) decades = 3;
00392               sprintf(buf, "%s/frame%%0%dd", vval(DIRECTORY), decades);
00393               vval(BASENAME) = savqstr(buf);
00394               vdef(BASENAME)++;
00395        }
00396        if (!vdef(RESOLUTION)) {
00397               vval(RESOLUTION) = "640";
00398               vdef(RESOLUTION)++;
00399        }
00400        if (!vdef(OVERSAMP)) {
00401               vval(OVERSAMP) = "2";
00402               vdef(OVERSAMP)++;
00403        }
00404        if (!vdef(INTERP)) {
00405               vval(INTERP) = "0";
00406               vdef(INTERP)++;
00407        }
00408        if (!vdef(MBLUR)) {
00409               vval(MBLUR) = "0";
00410               vdef(MBLUR)++;
00411        }
00412        if (!vdef(RTRACE)) {
00413               vval(RTRACE) = "F";
00414               vdef(RTRACE)++;
00415        }
00416        if (!vdef(DISKSPACE)) {
00417               if (!nowarn)
00418                      fprintf(stderr,
00419               "%s: warning - no %s setting, assuming 100 Mbytes available\n",
00420                                    progname, vnam(DISKSPACE));
00421               vval(DISKSPACE) = "100";
00422               vdef(DISKSPACE)++;
00423        }
00424        if (!vdef(RSH)) {
00425               vval(RSH) = REMSH;
00426               vdef(RSH)++;
00427        }
00428                             /* locate remote shell program */
00429        atos(buf, sizeof(buf), vval(RSH));
00430        if ((remsh = getpath(buf, getenv("PATH"), X_OK)) != NULL)
00431               remsh = savqstr(remsh);
00432        else
00433               remsh = vval(RSH);   /* will generate error if used */
00434 
00435                             /* append rendering options */
00436        if (vdef(RENDER))
00437               sprintf(rendopt+strlen(rendopt), " %s", vval(RENDER));
00438 }
00439 
00440 
00441 static void
00442 sethosts(void)                     /* set up process servers */
00443 {
00444        extern char   *iskip();
00445        char   buf[256], *dir, *uname;
00446        int    np;
00447        register char *cp;
00448        int    i;
00449 
00450        npslots = 0;
00451        if (noaction)
00452               return;
00453        for (i = 0; i < vdef(HOST); i++) { /* add each host */
00454               dir = uname = NULL;
00455               np = 1;
00456               strcpy(cp=buf, nvalue(HOST, i));   /* copy to buffer */
00457               cp = sskip(cp);                           /* skip host name */
00458               while (isspace(*cp))
00459                      *cp++ = '\0';
00460               if (*cp) {                         /* has # processes? */
00461                      np = atoi(cp);
00462                      if ((cp = iskip(cp)) == NULL || (*cp && !isspace(*cp)))
00463                             badvalue(HOST);
00464                      while (isspace(*cp))
00465                             cp++;
00466                      if (*cp) {                  /* has directory? */
00467                             dir = cp;
00468                             cp = sskip(cp);                    /* skip dir. */
00469                             while (isspace(*cp))
00470                                    *cp++ = '\0';
00471                             if (*cp) {                  /* has user? */
00472                                    uname = cp;
00473                                    if (*sskip(cp))
00474                                           badvalue(HOST);
00475                             }
00476                      }
00477               }
00478               if (addpserver(buf, dir, uname, np) == NULL) {
00479                      if (!nowarn)
00480                             fprintf(stderr,
00481                                    "%s: cannot execute on host \"%s\"\n",
00482                                           progname, buf);
00483               } else
00484                      npslots += np;
00485        }
00486        if (npslots == 0) {
00487               fprintf(stderr, "%s: no working process servers\n", progname);
00488               quit(1);
00489        }
00490        pslot = (struct pslot *)calloc(npslots, sizeof(struct pslot));
00491        if (pslot == NULL) {
00492               perror("malloc");
00493               quit(1);
00494        }
00495 }
00496 
00497 static void
00498 getradfile(char *rfargs)           /* run rad and get needed variables */
00499 {
00500        static short  mvar[] = {OCTREE,PFILT,RESOLUTION,EXPOSURE,-1};
00501        char   combuf[256];
00502        register int  i;
00503        register char *cp;
00504        char   *pippt = NULL;
00505                                    /* create rad command */
00506        sprintf(rendopt, " @%s/render.opt", vval(DIRECTORY));
00507        sprintf(combuf,
00508        "rad -v 0 -s -e -w %s OPTFILE=%s | egrep '^[ \t]*(NOMATCH",
00509                      rfargs, rendopt+2);
00510        cp = combuf;
00511        while (*cp) {
00512               if (*cp == '|') pippt = cp;
00513               cp++;
00514        }                           /* match unset variables */
00515        for (i = 0; mvar[i] >= 0; i++)
00516               if (!vdef(mvar[i])) {
00517                      *cp++ = '|';
00518                      strcpy(cp, vnam(mvar[i]));
00519                      while (*cp) cp++;
00520                      pippt = NULL;
00521               }
00522        if (pippt != NULL)
00523               strcpy(pippt, "> " NULL_DEVICE);   /* nothing to match */
00524        else {
00525               sprintf(cp, ")[ \t]*=' > %s/radset.var", vval(DIRECTORY));
00526               cp += 11;            /* point to file name */
00527        }
00528        system(combuf);                    /* ignore exit code */
00529        if (pippt == NULL) {        /* load variables and remove file */
00530               loadvars(cp);
00531               unlink(cp);
00532        }
00533 }
00534 
00535 
00536 static void
00537 animate(void)               /* run animation */
00538 {
00539        int    xres, yres;
00540        float  pa, mult;
00541        int    frames_batch;
00542        register int  i;
00543        double d1, d2;
00544                                    /* compute rpict resolution */
00545        i = sscanf(vval(RESOLUTION), "%d %d %f", &xres, &yres, &pa);
00546        mult = vflt(OVERSAMP);
00547        if (i == 3) {
00548               sprintf(rresopt, "-x %d -y %d -pa %.3f", (int)(mult*xres),
00549                             (int)(mult*yres), pa);
00550               sprintf(fresopt, "-x %d -y %d -pa %.3f", xres, yres, pa);
00551        } else if (i) {
00552               if (i == 1) yres = xres;
00553               sprintf(rresopt, "-x %d -y %d", (int)(mult*xres),
00554                             (int)(mult*yres));
00555               sprintf(fresopt, "-x %d -y %d -pa 1", xres, yres);
00556        } else
00557               badvalue(RESOLUTION);
00558                                    /* consistency checks */
00559        if (vdef(ANIMATE)) {
00560               if (vint(INTERP)) {
00561                      if (!nowarn)
00562                             fprintf(stderr,
00563                                    "%s: resetting %s=0 for animation\n",
00564                                           progname, vnam(INTERP));
00565                      vval(INTERP) = "0";
00566               }
00567               if (strcmp(vval(MBLUR),"0")) {     /* can't handle this */
00568                      if (!nowarn)
00569                             fprintf(stderr,
00570                                    "%s: resetting %s=0 for animation\n",
00571                                           progname, vnam(MBLUR));
00572                      vval(MBLUR) = "0";
00573               }
00574        }
00575                                    /* figure # frames per batch */
00576        d1 = mult*xres*mult*yres*4;        /* space for orig. picture */
00577        if ((i=vint(INTERP)) || getblur(NULL, NULL) > 1)
00578               d1 += mult*xres*mult*yres*sizeof(float);  /* Z-buffer */
00579        d2 = xres*yres*4;                  /* space for final picture */
00580        frames_batch = (i+1)*(vflt(DISKSPACE)*1048576.-d1)/(d1+i*d2);
00581        if (frames_batch < i+2) {
00582               fprintf(stderr, "%s: insufficient disk space allocated\n",
00583                             progname);
00584               quit(1);
00585        }
00586                                    /* initialize archive argument list */
00587        i = vdef(ARCHIVE) ? strlen(vval(ARCHIVE))+132 : 132;
00588        arcnext = arcfirst = arcargs + i;
00589                                    /* initialize status file */
00590        if (astat.rnext == 0)
00591               astat.rnext = astat.fnext = astat.tnext = vint(START);
00592        putastat();
00593                                    /* render in batches */
00594        while (astat.tnext <= vint(END)) {
00595               renderframes(frames_batch);
00596               filterframes();
00597               transferframes();
00598        }
00599                                    /* mark status as finished */
00600        astat.pid = 0;
00601        putastat();
00602                                    /* close open files */
00603        getview(0);
00604        getexp(0);
00605 }
00606 
00607 
00608 static void
00609 renderframes(int nframes)          /* render next nframes frames */
00610 {
00611        static char   vendbuf[16];
00612        VIEW   *vp;
00613        FILE   *fp = NULL;
00614        char   vfname[128];
00615        int    lastframe;
00616        register int  i;
00617 
00618        if (astat.tnext < astat.rnext)     /* other work to do first */
00619               return;
00620                                    /* create batch view file */
00621        if (!vdef(ANIMATE)) {
00622               sprintf(vfname, "%s/anim.vf", vval(DIRECTORY));
00623               if ((fp = fopen(vfname, "w")) == NULL) {
00624                      perror(vfname);
00625                      quit(1);
00626               }
00627        }
00628                                    /* bound batch properly */
00629        lastframe = astat.rnext + nframes - 1;
00630        if ((lastframe-1) % (vint(INTERP)+1))     /* need even interval */
00631               lastframe += vint(INTERP)+1 - ((lastframe-1)%(vint(INTERP)+1));
00632        if (lastframe > vint(END))         /* check for end */
00633               lastframe = vint(END);
00634                                    /* render each view */
00635        for (i = astat.rnext; i <= lastframe; i++) {
00636               if ((vp = getview(i)) == NULL) {
00637                      if (!nowarn)
00638                             fprintf(stderr,
00639                             "%s: ran out of views before last frame\n",
00640                                    progname);
00641                      sprintf(vval(END)=vendbuf, "%d", i-1);
00642                      lastframe = i - 1;
00643                      break;
00644               }
00645               if (vdef(ANIMATE))          /* animate frame */
00646                      animrend(i, vp);
00647               else {                      /* else record it */
00648                      fputs(VIEWSTR, fp);
00649                      fprintview(vp, fp);
00650                      putc('\n', fp);
00651               }
00652        }
00653        if (vdef(ANIMATE))          /* wait for renderings to finish */
00654               bwait(0);
00655        else {                      /* else if walk-through */
00656               fclose(fp);          /* close view file */
00657               walkwait(astat.rnext, lastframe, vfname); /* walk it */
00658               unlink(vfname);             /* remove view file */
00659        }
00660        astat.rnext = i;            /* update status */
00661        putastat();
00662 }
00663 
00664 
00665 static void
00666 filterframes(void)                        /* catch up with filtering */
00667 {
00668        register int  i;
00669 
00670        if (astat.tnext < astat.fnext)     /* other work to do first */
00671               return;
00672                                    /* filter each view */
00673        for (i = astat.fnext; i < astat.rnext; i++)
00674               dofilt(i, 0);
00675 
00676        bwait(0);                   /* wait for filter processes */
00677        archive();                  /* archive originals */
00678        astat.fnext = i;            /* update status */
00679        putastat();
00680 }
00681 
00682 
00683 static void
00684 transferframes(void)               /* catch up with picture transfers */
00685 {
00686        char   combuf[10240], *fbase;
00687        register char *cp;
00688        register int  i;
00689 
00690        if (astat.tnext >= astat.fnext)    /* nothing to do, yet */
00691               return;
00692        if (!vdef(TRANSFER)) {             /* no transfer function -- leave 'em */
00693               astat.tnext = astat.fnext;
00694               putastat();          /* update status */
00695               return;
00696        }
00697        strcpy(combuf, "cd ");             /* start transfer command */
00698        fbase = dirfile(cp = combuf+3, vval(BASENAME));
00699        if (*cp) {
00700               while (*++cp) ;
00701               *cp++ = ';'; *cp++ = ' ';
00702        } else
00703               cp = combuf;
00704        strcpy(cp, vval(TRANSFER));
00705        while (*cp) cp++;
00706                                    /* make argument list */
00707        for (i = astat.tnext; i < astat.fnext; i++) {
00708               *cp++ = ' ';
00709               sprintf(cp, fbase, i);
00710               while (*cp) cp++;
00711               strcpy(cp, ".hdr");
00712               cp += 4;
00713        }
00714        if (runcom(combuf)) {              /* transfer frames */
00715               fprintf(stderr, "%s: error running transfer command\n",
00716                             progname);
00717               quit(1);
00718        }
00719        astat.tnext = i;            /* update status */
00720        putastat();
00721 }
00722 
00723 
00724 static void
00725 animrend(                   /* start animation frame */
00726 int    frame,
00727 VIEW   *vp
00728 )
00729 {
00730        char   combuf[2048];
00731        char   fname[128];
00732 
00733        sprintf(fname, vval(BASENAME), frame);
00734        strcat(fname, ".unf");
00735        if (access(fname, F_OK) == 0)
00736               return;
00737        sprintf(combuf, "%s %d | rpict%s%s -w0 %s > %s", vval(ANIMATE), frame,
00738                      rendopt, viewopt(vp), rresopt, fname);
00739        bruncom(combuf, frame, recover);   /* run in background */
00740 }
00741 
00742 
00743 static void
00744 walkwait(            /* walk-through frames */
00745 int    first,
00746 int last,
00747 char   *vfn
00748 )
00749 {
00750        double mblurf, dblurf;
00751        int    nblur = getblur(&mblurf, &dblurf);
00752        char   combuf[2048];
00753        register char *inspoint;
00754        register int  i;
00755 
00756        if (!noaction && vint(INTERP))            /* create dummy frames */
00757               for (i = first; i <= last; i++)
00758                      if (i < vint(END) && (i-1) % (vint(INTERP)+1)) {
00759                             sprintf(combuf, vval(BASENAME), i);
00760                             strcat(combuf, ".unf");
00761                             close(open(combuf, O_RDONLY|O_CREAT, 0666));
00762                      }
00763                                    /* create command */
00764        sprintf(combuf, "rpict%s%s -w0", rendopt,
00765                      viewopt(getview(first>1 ? first-1 : 1)));
00766        inspoint = combuf;
00767        while (*inspoint) inspoint++;
00768        if (nblur) {
00769               sprintf(inspoint, " -pm %.3f", mblurf/nblur);
00770               while (*inspoint) inspoint++;
00771               sprintf(inspoint, " -pd %.3f", dblurf/nblur);
00772               while (*inspoint) inspoint++;
00773        }
00774        if (nblur > 1 || vint(INTERP)) {
00775               sprintf(inspoint, " -z %s.zbf", vval(BASENAME));
00776               while (*inspoint) inspoint++;
00777        }
00778        sprintf(inspoint, " -o %s.unf %s -S %d",
00779                      vval(BASENAME), rresopt, first);
00780        while (*inspoint) inspoint++;
00781        sprintf(inspoint, " %s < %s", vval(OCTREE), vfn);
00782                                    /* run in parallel */
00783        i = (last-first+1)/(vint(INTERP)+1);
00784        if (i < 1) i = 1;
00785        if (pruncom(combuf, inspoint, i)) {
00786               fprintf(stderr, "%s: error rendering frames %d through %d\n",
00787                             progname, first, last);
00788               quit(1);
00789        }
00790        if (!noaction && vint(INTERP))            /* remove dummy frames */
00791               for (i = first; i <= last; i++)
00792                      if (i < vint(END) && (i-1) % (vint(INTERP)+1)) {
00793                             sprintf(combuf, vval(BASENAME), i);
00794                             strcat(combuf, ".unf");
00795                             unlink(combuf);
00796                      }
00797 }
00798 
00799 
00800 static int
00801 recover(int frame)                 /* recover the specified frame */
00802 {
00803        static int    *rfrm;        /* list of recovered frames */
00804        static int    nrfrms = 0;
00805        double mblurf, dblurf;
00806        int    nblur = getblur(&mblurf, &dblurf);
00807        char   combuf[2048];
00808        char   fname[128];
00809        register char *cp;
00810        register int  i;
00811                                    /* check to see if recovered already */
00812        for (i = nrfrms; i--; )
00813               if (rfrm[i] == frame)
00814                      return(0);
00815                                    /* build command */
00816        sprintf(fname, vval(BASENAME), frame);
00817        if (vdef(ANIMATE))
00818               sprintf(combuf, "%s %d | rpict%s -w0",
00819                             vval(ANIMATE), frame, rendopt);
00820        else
00821               sprintf(combuf, "rpict%s -w0", rendopt);
00822        cp = combuf;
00823        while (*cp) cp++;
00824        if (nblur) {
00825               sprintf(cp, " -pm %.3f", mblurf/nblur);
00826               while (*cp) cp++;
00827               sprintf(cp, " -pd %.3f", dblurf/nblur);
00828               while (*cp) cp++;
00829        }
00830        if (nblur > 1 || vint(INTERP)) {
00831               sprintf(cp, " -z %s.zbf", fname);
00832               while (*cp) cp++;
00833        }
00834        sprintf(cp, " -ro %s.unf", fname);
00835        while (*cp) cp++;
00836        if (!vdef(ANIMATE)) {
00837               *cp++ = ' ';
00838               strcpy(cp, vval(OCTREE));
00839        }
00840        if (runcom(combuf))         /* run command */
00841               return(1);
00842                                    /* add frame to recovered list */
00843        if (nrfrms)
00844               rfrm = (int *)realloc((void *)rfrm, (nrfrms+1)*sizeof(int));
00845        else
00846               rfrm = (int *)malloc(sizeof(int));
00847        if (rfrm == NULL) {
00848               perror("malloc");
00849               quit(1);
00850        }
00851        rfrm[nrfrms++] = frame;
00852        return(0);
00853 }
00854 
00855 
00856 static int
00857 frecover(int frame)                       /* recover filtered frame */
00858 {
00859        if (dofilt(frame, 2) && dofilt(frame, 1))
00860               return(1);
00861        return(0);
00862 }
00863 
00864 
00865 static void
00866 archive(void)               /* archive and remove renderings */
00867 {
00868 #define RMCOML       (sizeof(rmcom)-1)
00869        static char   rmcom[] = "rm -f";
00870        char   basedir[128];
00871        int    dlen, alen;
00872        register int  j;
00873 
00874        if (arcnext == arcfirst)
00875               return;                            /* nothing to do */
00876        dirfile(basedir, vval(BASENAME));
00877        dlen = strlen(basedir);
00878        if (vdef(ARCHIVE)) {               /* run archive command */
00879               alen = strlen(vval(ARCHIVE));
00880               if (dlen) {
00881                      j = alen + dlen + 5;
00882                      strncpy(arcfirst-j, "cd ", 3);
00883                      strncpy(arcfirst-j+3, basedir, dlen);
00884                      (arcfirst-j)[dlen+3] = ';'; (arcfirst-j)[dlen+4] = ' ';
00885               } else
00886                      j = alen;
00887               strncpy(arcfirst-alen, vval(ARCHIVE), alen);
00888               if (runcom(arcfirst-j)) {
00889                      fprintf(stderr, "%s: error running archive command\n",
00890                                    progname);
00891                      quit(1);
00892               }
00893        }
00894        if (dlen) {
00895               j = RMCOML + dlen + 5;
00896               strncpy(arcfirst-j, "cd ", 3);
00897               strncpy(arcfirst-j+3, basedir, dlen);
00898               (arcfirst-j)[dlen+3] = ';'; (arcfirst-j)[dlen+4] = ' ';
00899        } else
00900               j = RMCOML;
00901                                           /* run remove command */
00902        strncpy(arcfirst-RMCOML, rmcom, RMCOML);
00903        runcom(arcfirst-j);
00904        arcnext = arcfirst;                /* reset argument list */
00905 #undef RMCOML
00906 }
00907 
00908 
00909 static int
00910 dofilt(                            /* filter frame */
00911 int    frame,
00912 int    rvr
00913 )
00914 {
00915        static int    iter = 0;
00916        double mblurf, dblurf;
00917        int    nblur = getblur(&mblurf, &dblurf);
00918        VIEW   *vp = getview(frame);
00919        char   *ep = getexp(frame);
00920        char   fnbefore[128], fnafter[128], *fbase;
00921        char   combuf[1024], fname0[128], fname1[128];
00922        int    usepinterp, usepfilt, nora_rgbe;
00923        int    frseq[2];
00924                                           /* check what is needed */
00925        if (vp == NULL) {
00926                fprintf(stderr,
00927                      "%s: unexpected error reading view for frame %d\n",
00928                                         progname, frame);
00929               quit(1);
00930        }
00931        usepinterp = (nblur > 1);
00932        usepfilt = pfiltalways | (ep==NULL);
00933        if (ep != NULL && !strcmp(ep, "1"))
00934               ep = "+0";
00935        nora_rgbe = strcmp(vval(OVERSAMP),"1") || ep==NULL ||
00936                      *ep != '+' || *ep != '-' || !isint(ep);
00937                                           /* compute rendered views */
00938        frseq[0] = frame - ((frame-1) % (vint(INTERP)+1));
00939        frseq[1] = frseq[0] + vint(INTERP) + 1;
00940        fbase = dirfile(NULL, vval(BASENAME));
00941        if (frseq[1] > vint(END))
00942               frseq[1] = vint(END);
00943        if (frseq[1] == frame) {                  /* pfilt only */
00944               frseq[0] = frseq[1];
00945               usepinterp = 0;                    /* update what's needed */
00946               usepfilt |= nora_rgbe;
00947        } else if (frseq[0] == frame) {           /* no interpolation needed */
00948               if (!rvr && frame > 1+vint(INTERP)) {     /* archive previous */
00949                      if (arcnext - arcargs +
00950                                    strlen(fbase) >= sizeof(arcargs)-8) {
00951                             fprintf(stderr,
00952 "%s: too many filenames in archive command -- reduce %s variable\n",
00953                                           progname, vnam(DISKSPACE));
00954                             quit(1);
00955                      }
00956                      *arcnext++ = ' ';
00957                      sprintf(arcnext, fbase, frame-vint(INTERP)-1);
00958                      while (*arcnext) arcnext++;
00959                      strcpy(arcnext, ".unf");
00960                      arcnext += 4;
00961                      if (usepinterp || vint(INTERP)) {  /* and Z-buf */
00962                             *arcnext++ = ' ';
00963                             sprintf(arcnext, fbase, frame-vint(INTERP)-1);
00964                             while (*arcnext) arcnext++;
00965                             strcpy(arcnext, ".zbf");
00966                             arcnext += 4;
00967                      }
00968               }
00969               if (!usepinterp)            /* update what's needed */
00970                      usepfilt |= nora_rgbe;
00971        } else                             /* interpolation needed */
00972               usepinterp++;
00973        if (frseq[1] >= astat.rnext)              /* next batch unavailable */
00974               frseq[1] = frseq[0];
00975        sprintf(fnbefore, vval(BASENAME), frseq[0]);
00976        sprintf(fnafter, vval(BASENAME), frseq[1]);
00977        if (rvr == 1 && recover(frseq[0])) /* recover before frame? */
00978               return(1);
00979                                           /* generate command */
00980        if (usepinterp) {                  /* using pinterp */
00981               if (rvr == 2 && recover(frseq[1])) /* recover after? */
00982                      return(1);
00983               if (nblur > 1) {            /* with pdmblur */
00984                      sprintf(fname0, "%s/vw0%c", vval(DIRECTORY),
00985                                    'a'+(iter%26));
00986                      sprintf(fname1, "%s/vw1%c", vval(DIRECTORY),
00987                                    'a'+(iter%26));
00988                      if (!noaction) {
00989                             FILE   *fp;          /* motion blurring */
00990                             if ((fp = fopen(fname0, "w")) == NULL) {
00991                                    perror(fname0); quit(1);
00992                             }
00993                             fputs(VIEWSTR, fp);
00994                             fprintview(vp, fp);
00995                             putc('\n', fp); fclose(fp);
00996                             if ((vp = getview(frame+1)) == NULL) {
00997                                    fprintf(stderr,
00998                      "%s: unexpected error reading view for frame %d\n",
00999                                                  progname, frame+1);
01000                                    quit(1);
01001                             }
01002                             if ((fp = fopen(fname1, "w")) == NULL) {
01003                                    perror(fname1); quit(1);
01004                             }
01005                             fputs(VIEWSTR, fp);
01006                             fprintview(vp, fp);
01007                             putc('\n', fp); fclose(fp);
01008                      }
01009                      sprintf(combuf,
01010                      "(pmdblur %.3f %.3f %d %s %s; rm -f %s %s) | pinterp -B -a",
01011                                    mblurf, dblurf, nblur,
01012                                    fname0, fname1, fname0, fname1);
01013                      iter++;
01014               } else                      /* no blurring */
01015                      strcpy(combuf, "pinterp");
01016               strcat(combuf, viewopt(vp));
01017               if (vbool(RTRACE))
01018                      sprintf(combuf+strlen(combuf), " -ff -fr '%s -w0 %s'",
01019                                    rendopt+1, vval(OCTREE));
01020               if (vdef(PINTERP))
01021                      sprintf(combuf+strlen(combuf), " %s", vval(PINTERP));
01022               if (usepfilt)
01023                      sprintf(combuf+strlen(combuf), " %s", rresopt);
01024               else
01025                      sprintf(combuf+strlen(combuf), " -a %s -e %s",
01026                                    fresopt, ep);
01027               sprintf(combuf+strlen(combuf), " %s.unf %s.zbf",
01028                             fnbefore, fnbefore);
01029               if (frseq[1] != frseq[0])
01030                       sprintf(combuf+strlen(combuf), " %s.unf %s.zbf",
01031                                    fnafter, fnafter);
01032               if (usepfilt) {                    /* also pfilt */
01033                      if (vdef(PFILT))
01034                             sprintf(combuf+strlen(combuf), " | pfilt %s",
01035                                           vval(PFILT));
01036                      else
01037                             strcat(combuf, " | pfilt");
01038                      if (ep != NULL)
01039                             sprintf(combuf+strlen(combuf), " -1 -e %s %s",
01040                                           ep, fresopt);
01041                      else
01042                             sprintf(combuf+strlen(combuf), " %s", fresopt);
01043               }
01044        } else if (usepfilt) {                    /* pfilt only */
01045               if (rvr == 2)
01046                      return(1);
01047               if (vdef(PFILT))
01048                      sprintf(combuf, "pfilt %s", vval(PFILT));
01049               else
01050                      strcpy(combuf, "pfilt");
01051               if (ep != NULL)
01052                      sprintf(combuf+strlen(combuf), " -1 -e %s %s %s.unf",
01053                             ep, fresopt, fnbefore);
01054               else
01055                      sprintf(combuf+strlen(combuf), " %s %s.unf",
01056                                    fresopt, fnbefore);
01057        } else {                           /* else just check it */
01058               if (rvr == 2)
01059                      return(1);
01060               sprintf(combuf, "ra_rgbe -e %s -r %s.unf", ep, fnbefore);
01061        }
01062                                           /* output file name */
01063        sprintf(fname0, vval(BASENAME), frame);
01064        sprintf(combuf+strlen(combuf), " > %s.hdr", fname0);
01065        if (rvr)                           /* in recovery */
01066               return(runcom(combuf));
01067        bruncom(combuf, frame, frecover);  /* else run in background */
01068        return(0);
01069 }
01070 
01071 
01072 static VIEW *
01073 getview(int n)                     /* get view number n */
01074 {
01075        static FILE   *viewfp = NULL;             /* view file pointer */
01076        static int    viewnum = 0;         /* current view number */
01077        static VIEW   curview = STDVIEW;   /* current view */
01078        char   linebuf[256];
01079 
01080        if (n == 0) {               /* signal to close file and clean up */
01081               if (viewfp != NULL) {
01082                      fclose(viewfp);
01083                      viewfp = NULL;
01084                      viewnum = 0;
01085                      curview = stdview;
01086               }
01087               return(NULL);
01088        }
01089        if (viewfp == NULL) {                     /* open file */
01090               if ((viewfp = fopen(vval(VIEWFILE), "r")) == NULL) {
01091                      perror(vval(VIEWFILE));
01092                      quit(1);
01093               }
01094        } else if (n > 0 && n < viewnum) { /* rewind file */
01095               if (viewnum == 1 && feof(viewfp))
01096                      return(&curview);           /* just one view */
01097               if (fseek(viewfp, 0L, 0) == EOF) {
01098                      perror(vval(VIEWFILE));
01099                      quit(1);
01100               }
01101               curview = stdview;
01102               viewnum = 0;
01103        }
01104        if (n < 0) {                       /* get next view */
01105               register int  c = getc(viewfp);
01106               if (c == EOF)
01107                      return((VIEW *)NULL);              /* that's it */
01108               ungetc(c, viewfp);
01109               n = viewnum + 1;
01110        }
01111        while (n > viewnum) {              /* scan to desired view */
01112               if (fgets(linebuf, sizeof(linebuf), viewfp) == NULL)
01113                      return(viewnum==1 ? &curview : (VIEW *)NULL);
01114               if (isview(linebuf) && sscanview(&curview, linebuf) > 0)
01115                      viewnum++;
01116        }
01117        return(&curview);           /* return it */
01118 }
01119 
01120 
01121 static int
01122 countviews(void)                   /* count views in view file */
01123 {
01124        int    n;
01125 
01126        if (getview(n=1) == NULL)
01127               return(0);
01128        while (getview(-1) != NULL)
01129               n++;
01130        return(n);
01131 }
01132 
01133 
01134 static char *
01135 getexp(int n)               /* get exposure for nth frame */
01136 {
01137        static char   expval[32];
01138        static FILE   *expfp = NULL;
01139        static long   *exppos;
01140        static int    curfrm;
01141        register char *cp;
01142 
01143        if (n == 0) {                      /* signal to close file */
01144               if (expfp != NULL) {
01145                      fclose(expfp);
01146                      free((void *)exppos);
01147                      expfp = NULL;
01148               }
01149               return(NULL);
01150        } else if (n > vint(END))          /* request past end (error?) */
01151               return(NULL);
01152        if (!vdef(EXPOSURE))               /* no setting (auto) */
01153               return(NULL);
01154        if (isflt(vval(EXPOSURE)))         /* always the same */
01155               return(vval(EXPOSURE));
01156        if (expfp == NULL) {               /* open exposure file */
01157               if ((expfp = fopen(vval(EXPOSURE), "r")) == NULL) {
01158                      fprintf(stderr,
01159                      "%s: cannot open exposure file \"%s\"\n",
01160                                    progname, vval(EXPOSURE));
01161                      quit(1);
01162               }
01163               curfrm = vint(END) + 1;            /* init lookup tab. */
01164               exppos = (long *)malloc(curfrm*sizeof(long *));
01165               if (exppos == NULL) {
01166                      perror(progname);
01167                      quit(1);
01168               }
01169               while (curfrm--)
01170                      exppos[curfrm] = -1L;
01171               curfrm = 0;
01172        }
01173                                           /* find position in file */
01174        if (n-1 != curfrm && n != curfrm && exppos[n-1] >= 0 &&
01175                             fseek(expfp, exppos[curfrm=n-1], 0) == EOF) {
01176               fprintf(stderr, "%s: seek error on exposure file\n", progname);
01177               quit(1);
01178        }
01179        while (n > curfrm) {               /* read exposure */
01180               if (exppos[curfrm] < 0)
01181                      exppos[curfrm] = ftell(expfp);
01182               if (fgets(expval, sizeof(expval), expfp) == NULL) {
01183                      fprintf(stderr, "%s: too few exposures\n",
01184                                    vval(EXPOSURE));
01185                      quit(1);
01186               }
01187               curfrm++;
01188               cp = fskip(expval);                /* check format */
01189               if (cp != NULL)
01190                      while (isspace(*cp))
01191                             *cp++ = '\0';
01192               if (cp == NULL || *cp) {
01193                      fprintf(stderr,
01194                             "%s: exposure format error on line %d\n",
01195                                    vval(EXPOSURE), curfrm);
01196                      quit(1);
01197               }
01198        }
01199        return(expval);                           /* return value */
01200 }
01201 
01202 
01203 static struct pslot *
01204 findpslot(RT_PID pid)                     /* find or allocate a process slot */
01205 {
01206        register struct pslot       *psempty = NULL;
01207        register int  i;
01208 
01209        for (i = 0; i < npslots; i++) {           /* look for match */
01210               if (pslot[i].pid == pid)
01211                      return(pslot+i);
01212               if (psempty == NULL && pslot[i].pid == 0)
01213                      psempty = pslot+i;
01214        }
01215        return(psempty);            /* return emtpy slot (error if NULL) */
01216 }
01217 
01218 
01219 static int
01220 donecom(             /* clean up after finished process */
01221        PSERVER       *ps,
01222        int    pn,
01223        int    status
01224 )
01225 {
01226        register NETPROC     *pp;
01227        register struct pslot       *psl;
01228 
01229        pp = ps->proc + pn;
01230        if (pp->elen) {                    /* pass errors */
01231               if (ps->hostname[0])
01232                      fprintf(stderr, "%s: ", ps->hostname);
01233               fprintf(stderr, "Error output from: %s\n", pp->com);
01234               fputs(pp->errs, stderr);
01235               fflush(stderr);
01236               if (ps->hostname[0])
01237                      status = 1;   /* because rsh doesn't return status */
01238        }
01239        lastpserver = NULL;
01240        psl = findpslot(pp->pid);   /* check for bruncom() slot */
01241        if (psl->pid) {
01242               if (status) {
01243                      if (psl->rcvf != NULL)      /* attempt recovery */
01244                             status = (*psl->rcvf)(psl->fout);
01245                      if (status) {
01246                             fprintf(stderr,
01247                                    "%s: error rendering frame %d\n",
01248                                           progname, psl->fout);
01249                             quit(1);
01250                      }
01251                      lastpserver = ps;
01252               }
01253               psl->pid = 0;               /* free process slot */
01254        } else if (status)
01255               lastpserver = ps;
01256        freestr(pp->com);           /* free command string */
01257        return(status);
01258 }
01259 
01260 
01261 static int
01262 serverdown(void)                   /* check status of last process server */
01263 {
01264        if (lastpserver == NULL || !lastpserver->hostname[0])
01265               return(0);
01266        if (pserverOK(lastpserver)) /* server still up? */
01267               return(0);
01268        delpserver(lastpserver);    /* else delete it */
01269        if (pslist == NULL) {
01270               fprintf(stderr, "%s: all process servers are down\n",
01271                             progname);
01272               quit(1);
01273        }
01274        return(1);
01275 }
01276 
01277 
01278 static RT_PID
01279 bruncom(             /* run a command in the background */
01280 char   *com,
01281 int    fout,
01282 int    (*rf)()
01283 )
01284 {
01285        RT_PID pid;
01286        register struct pslot       *psl;
01287 
01288        if (noaction) {
01289               if (!silent)
01290                      printf("\t%s\n", com);      /* echo command */
01291               return(0);
01292        }
01293        com = savestr(com);         /* else start it when we can */
01294        while ((pid = startjob(NULL, com, donecom)) == -1)
01295               bwait(1);
01296        if (!silent) {                            /* echo command */
01297               PSERVER       *ps;
01298               RT_PID psn = pid;
01299               ps = findjob(&psn);
01300               printf("\t%s\n", com);
01301               printf("\tProcess started on %s\n", phostname(ps));
01302               fflush(stdout);
01303        }
01304        psl = findpslot(pid);              /* record info. in appropriate slot */
01305        psl->pid = pid;
01306        psl->fout = fout;
01307        psl->rcvf = rf;
01308        return(pid);
01309 }
01310 
01311 
01312 static void
01313 bwait(int ncoms)                          /* wait for batch job(s) to finish */
01314 {
01315        int    status;
01316 
01317        if (noaction)
01318               return;
01319        while ((status = wait4job(NULL, -1)) != -1) {
01320               serverdown();        /* update server status */
01321               if (--ncoms == 0)
01322                      break;        /* done enough */
01323        }
01324 }
01325 
01326 
01327 static int
01328 pruncom(      /* run a command in parallel over network */
01329 char   *com,
01330 char   *ppins,
01331 int    maxcopies
01332 )
01333 {
01334        int    retstatus = 0;
01335        int    hostcopies;
01336        char   buf[10240], *com1, *s;
01337        int    status;
01338        int    pfd;
01339        register int  n;
01340        register PSERVER     *ps;
01341 
01342        if (!silent)
01343               printf("\t%s\n", com);      /* echo command */
01344        if (noaction)
01345               return(0);
01346        fflush(stdout);
01347                                    /* start jobs on each server */
01348        for (ps = pslist; ps != NULL; ps = ps->next) {
01349               hostcopies = 0;
01350               if (maxcopies > 1 && ps->nprocs > 1 && ppins != NULL) {
01351                      strcpy(com1=buf, com);      /* build -PP command */
01352                      sprintf(com1+(ppins-com), " -PP %s/%s.persist",
01353                                    vval(DIRECTORY), phostname(ps));
01354                      unlink(com1+(ppins-com)+5);
01355                      strcat(com1, ppins);
01356               } else
01357                      com1 = com;
01358               while (maxcopies > 0) {
01359                      s = savestr(com1);
01360                      if (startjob(ps, s, donecom) != -1) {
01361                             sleep(20);
01362                             hostcopies++;
01363                             maxcopies--;
01364                      } else {
01365                             freestr(s);
01366                             break;
01367                      }
01368               }
01369               if (!silent && hostcopies) {
01370                      if (hostcopies > 1)
01371                             printf("\t%d duplicate processes", hostcopies);
01372                      else
01373                             printf("\tProcess");
01374                      printf(" started on %s\n", phostname(ps));
01375                      fflush(stdout);
01376               }
01377        }
01378                                    /* wait for jobs to finish */
01379        while ((status = wait4job(NULL, -1)) != -1)
01380               retstatus += status && !serverdown();
01381                                    /* terminate parallel rpict's */
01382        for (ps = pslist; ps != NULL; ps = ps->next) {
01383               sprintf(buf, "%s/%s.persist", vval(DIRECTORY), phostname(ps));
01384               if ((pfd = open(buf, O_RDONLY)) >= 0) {
01385                      n = read(pfd, buf, sizeof(buf)-1); /* get PID */
01386                      buf[n] = '\0';
01387                      close(pfd);
01388                      for (n = 0; buf[n] && !isspace(buf[n]); n++)
01389                             ;
01390                                                         /* terminate */
01391                      sprintf(buf, "kill -ALRM %d", atoi(buf+n));
01392                      wait4job(ps, startjob(ps, buf, NULL));
01393               }
01394        }
01395        return(retstatus);
01396 }
01397 
01398 
01399 static int
01400 runcom(char *cs)                   /* run a command locally and wait for it */
01401 {
01402        if (!silent)         /* echo it */
01403               printf("\t%s\n", cs);
01404        if (noaction)
01405               return(0);
01406        fflush(stdout);             /* flush output and pass to shell */
01407        return(system(cs));
01408 }
01409 
01410 
01411 static int
01412 rmfile(char *fn)                   /* remove a file */
01413 {
01414        if (!silent)
01415 #ifdef _WIN32
01416               printf("\tdel %s\n", fn);
01417 #else
01418               printf("\trm -f %s\n", fn);
01419 #endif
01420        if (noaction)
01421               return(0);
01422        return(unlink(fn));
01423 }
01424 
01425 
01426 static void
01427 badvalue(int vc)                   /* report bad variable value and exit */
01428 {
01429        fprintf(stderr, "%s: bad value for variable '%s'\n",
01430                      progname, vnam(vc));
01431        quit(1);
01432 }
01433 
01434 
01435 static char *
01436 dirfile(             /* separate path into directory and file */
01437 char   *df,
01438 register char *path
01439 )
01440 {
01441        register int  i;
01442        int    psep;
01443 
01444        for (i = 0, psep = -1; path[i]; i++)
01445               if (path[i] == '/')
01446                      psep = i;
01447        if (df != NULL) {
01448               if (psep == 0) {
01449                      df[0] = '/';
01450                      df[1] = '\0';
01451               } else if (psep > 0) {
01452                      strncpy(df, path, psep);
01453                      df[psep] = '\0';
01454               } else
01455                      df[0] = '\0';
01456        }
01457        return(path+psep+1);
01458 }
01459 
01460 
01461 static int
01462 getblur(double *mbf, double *dbf)  /* get # blur samples (and fraction) */
01463 {
01464        double mblurf, dblurf;
01465        int    nmblur, ndblur;
01466        char   *s;
01467                                    /* get motion blur */
01468        if (!vdef(MBLUR) || (mblurf = atof(vval(MBLUR))) < 0.0)
01469               mblurf = 0.0;
01470        if (mbf != NULL)
01471               *mbf = mblurf;
01472        if (mblurf <= FTINY)
01473               nmblur = 0;
01474        else if (!*(s = sskip(vval(MBLUR))))
01475               nmblur = DEF_NBLUR;
01476        else if ((nmblur = atoi(s)) <= 0)
01477               nmblur = 1;
01478                                    /* get depth-of-field blur */
01479        if (!vdef(DBLUR) || (dblurf = atof(vval(DBLUR))) < 0.0)
01480               dblurf = 0.0;
01481        if (dbf != NULL)
01482               *dbf = dblurf;
01483        if (dblurf <= FTINY)
01484               ndblur = 0;
01485        else if (!*(s = sskip(vval(DBLUR))))
01486               ndblur = DEF_NBLUR;
01487        else if ((ndblur = atoi(s)) <= 0)
01488               ndblur = 1;
01489        if ((nmblur == 1) & (ndblur == 1))
01490               return(1);
01491                                    /* return combined samples */
01492        return(nmblur + ndblur);
01493 }