Back to index

radiance  4R0+20100331
rad.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: rad.c,v 2.92 2009/02/09 16:41:29 greg Exp $";
00003 #endif
00004 /*
00005  * Executive program for oconv, rpict and pfilt
00006  */
00007 
00008 #include "standard.h"
00009 
00010 #include <ctype.h>
00011 #include <time.h>
00012 
00013 #include "platform.h"
00014 #include "rtprocess.h"
00015 #include "view.h"
00016 #include "paths.h"
00017 #include "vars.h"
00018 
00019 #ifdef _WIN32
00020   #define DELCMD "del"
00021   #define RENAMECMD "rename"
00022 #else
00023   #define DELCMD "rm -f"
00024   #define RENAMECMD "mv"
00025   #include <sys/types.h>
00026   #include <sys/wait.h>
00027 #endif
00028 
00029                             /* variables (alphabetical by name) */
00030 #define AMBFILE             0             /* ambient file name */
00031 #define DETAIL              1             /* level of scene detail */
00032 #define EXPOSURE     2             /* picture exposure setting */
00033 #define EYESEP              3             /* interocular distance */
00034 #define ILLUM        4             /* mkillum input files */
00035 #define INDIRECT     5             /* indirection in lighting */
00036 #define MATERIAL     6             /* material files */
00037 #define MKILLUM             7             /* mkillum options */
00038 #define OBJECT              8             /* object files */
00039 #define OCONV        9             /* oconv options */
00040 #define OCTREE              10            /* octree file name */
00041 #define OPTFILE             11            /* rendering options file */
00042 #define PENUMBRAS    12            /* shadow penumbras are desired */
00043 #define PFILT        13            /* pfilt options */
00044 #define PICTURE             14            /* picture file root name */
00045 #define QUALITY             15            /* desired rendering quality */
00046 #define RAWFILE             16            /* raw picture file root name */
00047 #define RENDER              17            /* rendering options */
00048 #define REPORT              18            /* report frequency and errfile */
00049 #define RESOLUTION   19            /* maximum picture resolution */
00050 #define RPICT        20            /* rpict parameters */
00051 #define RVU          21            /* rvu parameters */
00052 #define SCENE        22            /* scene files */
00053 #define UP           23            /* view up (X, Y or Z) */
00054 #define VARIABILITY  24            /* level of light variability */
00055 #define VIEWS        25            /* view(s) for picture(s) */
00056 #define ZFILE        26            /* distance file root name */
00057 #define ZONE         27            /* simulation zone */
00058                             /* total number of variables */
00059 int NVARS = 28;
00060 
00061 VARIABLE      vv[] = {             /* variable-value pairs */
00062        {"AMBFILE",   3,     0,     NULL,  onevalue},
00063        {"DETAIL",    3,     0,     NULL,  qualvalue},
00064        {"EXPOSURE",  3,     0,     NULL,  fltvalue},
00065        {"EYESEP",    3,     0,     NULL,  fltvalue},
00066        {"illum",     3,     0,     NULL,  catvalues},
00067        {"INDIRECT",  3,     0,     NULL,  intvalue},
00068        {"materials", 3,     0,     NULL,  catvalues},
00069        {"mkillum",   3,     0,     NULL,  catvalues},
00070        {"objects",   3,     0,     NULL,  catvalues},
00071        {"oconv",     3,     0,     NULL,  catvalues},
00072        {"OCTREE",    3,     0,     NULL,  onevalue},
00073        {"OPTFILE",   3,     0,     NULL,  onevalue},
00074        {"PENUMBRAS", 3,     0,     NULL,  boolvalue},
00075        {"pfilt",     2,     0,     NULL,  catvalues},
00076        {"PICTURE",   3,     0,     NULL,  onevalue},
00077        {"QUALITY",   3,     0,     NULL,  qualvalue},
00078        {"RAWFILE",   3,     0,     NULL,  onevalue},
00079        {"render",    3,     0,     NULL,  catvalues},
00080        {"REPORT",    3,     0,     NULL,  onevalue},
00081        {"RESOLUTION",       3,     0,     NULL,  onevalue},
00082        {"rpict",     3,     0,     NULL,  catvalues},
00083        {"rvu",              3,     0,     NULL,  catvalues},
00084        {"scene",     3,     0,     NULL,  catvalues},
00085        {"UP",        2,     0,     NULL,  onevalue},
00086        {"VARIABILITY",      3,     0,     NULL,  qualvalue},
00087        {"view",      2,     0,     NULL,  NULL},
00088        {"ZFILE",     2,     0,     NULL,  onevalue},
00089        {"ZONE",      2,     0,     NULL,  onevalue},
00090 };
00091 
00092                             /* overture calculation file */
00093 #ifdef NULL_DEVICE
00094 char   overfile[] = NULL_DEVICE;
00095 #else
00096 char   overfile[] = "overture.unf";
00097 #endif
00098 
00099 
00100 time_t scenedate;           /* date of latest scene or object file */
00101 time_t octreedate;          /* date of octree */
00102 time_t matdate;             /* date of latest material file */
00103 time_t illumdate;           /* date of last illum file */
00104 
00105 char   *oct0name;           /* name of pre-mkillum octree */
00106 time_t oct0date;            /* date of pre-mkillum octree */
00107 char   *oct1name;           /* name of post-mkillum octree */
00108 time_t oct1date;            /* date of post-mkillum octree (>= matdate) */
00109 
00110 int    nowarn = 0;          /* no warnings */
00111 int    explicate = 0;              /* explicate variables */
00112 int    silent = 0;          /* do work silently */
00113 int    touchonly = 0;              /* touch files only */
00114 int    nprocs = 1;          /* maximum executing processes */
00115 int    sayview = 0;         /* print view out */
00116 char   *rvdevice = NULL;    /* rvu output device */
00117 char   *viewselect = NULL;  /* specific view only */
00118 
00119                             /* command paths */
00120 char   c_oconv[256] = "oconv";
00121 char   c_mkillum[256] = "mkillum";
00122 char   c_rvu[256] = "rvu";
00123 char   c_rpict[256] = "rpict";
00124 char   c_pfilt[256] = "pfilt";
00125 
00126 int    overture = 0;        /* overture calculation needed */
00127 
00128 int    children_running = 0;       /* set negative in children */
00129 
00130 char   *progname;           /* global argv[0] */
00131 char   *rifname;            /* global rad input file name */
00132 
00133 char   radname[PATH_MAX];   /* root Radiance file name */
00134 
00135 #define       inchild()     (children_running < 0)
00136 
00137 static void rootname(char   *rn, char     *fn);
00138 static time_t checklast(char       *fnames);
00139 static char * newfname(char *orig, int    pred);
00140 static void checkfiles(void);
00141 static void getoctcube(double      org[3], double       *sizp);
00142 static void setdefaults(void);
00143 static void oconv(void);
00144 static char * addarg(char   *op, char     *arg);
00145 static void oconvopts(char  *oo);
00146 static void mkillumopts(char       *mo);
00147 static void checkambfile(void);
00148 static double ambval(void);
00149 static void renderopts(char *op, char     *po);
00150 static void lowqopts(char   *op, char     *po);
00151 static void medqopts(char   *op, char     *po);
00152 static void hiqopts(char    *op, char     *po);
00153 static void xferopts(char   *ro);
00154 static void pfiltopts(char  *po);
00155 static int matchword(char   *s1, char     *s2);
00156 static char * specview(char *vs);
00157 static char * getview(int   n, char       *vn);
00158 static int myprintview(char *vopts, FILE  *fp);
00159 static void rvu(char *opts, char   *po);
00160 static void rpict(char      *opts, char   *po);
00161 static int touch(char       *fn);
00162 static int runcom(char      *cs);
00163 static int rmfile(char      *fn);
00164 static int mvfile(char      *fold, char   *fnew);
00165 static int next_process(void);
00166 static void wait_process(int       all);
00167 static void finish_process(void);
00168 static void badvalue(int    vc);
00169 static void syserr(char     *s);
00170 
00171 
00172 int
00173 main(
00174        int    argc,
00175        char   *argv[]
00176 )
00177 {
00178        char   ropts[512];
00179        char   popts[64];
00180        int    i;
00181 
00182        progname = argv[0];
00183                             /* get options */
00184        for (i = 1; i < argc && argv[i][0] == '-'; i++)
00185               switch (argv[i][1]) {
00186               case 's':
00187                      silent++;
00188                      break;
00189               case 'n':
00190                      nprocs = 0;
00191                      break;
00192               case 'N':
00193                      nprocs = atoi(argv[++i]);
00194                      if (nprocs < 0)
00195                             nprocs = 0;
00196                      break;
00197               case 't':
00198                      touchonly++;
00199                      break;
00200               case 'e':
00201                      explicate++;
00202                      break;
00203               case 'o':
00204                      rvdevice = argv[++i];
00205                      break;
00206               case 'V':
00207                      sayview++;
00208                      break;
00209               case 'v':
00210                      viewselect = argv[++i];
00211                      break;
00212               case 'w':
00213                      nowarn++;
00214                      break;
00215               default:
00216                      goto userr;
00217               }
00218        if (i >= argc)
00219               goto userr;
00220        rifname = argv[i];
00221                             /* check command-line options */
00222        if ((nprocs > 1) & (viewselect != NULL) & (rvdevice == NULL))
00223               nprocs = 1;
00224                             /* assign Radiance root file name */
00225        rootname(radname, rifname);
00226                             /* load variable values */
00227        loadvars(rifname);
00228                             /* get any additional assignments */
00229        for (i++; i < argc; i++)
00230               if (setvariable(argv[i], matchvar) < 0) {
00231                      fprintf(stderr, "%s: unknown variable: %s\n",
00232                                    progname, argv[i]);
00233                      quit(1);
00234               }
00235                             /* check assignments */
00236        checkvalues();
00237                             /* check files and dates */
00238        checkfiles();
00239                             /* set default values as necessary */
00240        setdefaults();
00241                             /* print all values if requested */
00242        if (explicate)
00243               printvars(stdout);
00244                             /* build octree (and run mkillum) */
00245        oconv();
00246                             /* check date on ambient file */
00247        checkambfile();
00248                             /* run simulation */
00249        renderopts(ropts, popts);
00250        xferopts(ropts);
00251        if (rvdevice != NULL)
00252               rvu(ropts, popts);
00253        else
00254               rpict(ropts, popts);
00255        quit(0);
00256 userr:
00257        fprintf(stderr,
00258 "Usage: %s [-w][-s][-n|-N npr][-t][-e][-V][-v view][-o dev] rfile [VAR=value ..]\n",
00259                      progname);
00260        quit(1);
00261        return 1; /* pro forma return */
00262 }
00263 
00264 
00265 static void
00266 rootname(            /* remove tail from end of fn */
00267        register char *rn,
00268        register char *fn
00269 )
00270 {
00271        char   *tp, *dp;
00272 
00273        for (tp = NULL, dp = rn; (*rn = *fn++); rn++)
00274               if (ISDIRSEP(*rn))
00275                      dp = rn;
00276               else if (*rn == '.')
00277                      tp = rn;
00278        if (tp != NULL && tp > dp)
00279               *tp = '\0';
00280 }
00281 
00282 
00283 static time_t
00284 checklast(                  /* check files and find most recent */
00285        register char *fnames
00286 )
00287 {
00288        char   thisfile[PATH_MAX];
00289        time_t thisdate, lastdate = 0;
00290 
00291        if (fnames == NULL)
00292               return(0);
00293        while ((fnames = nextword(thisfile, PATH_MAX, fnames)) != NULL) {
00294               if (thisfile[0] == '!' ||
00295                             (thisfile[0] == '\\' && thisfile[1] == '!')) {
00296                      if (!lastdate)
00297                             lastdate = 1;
00298                      continue;
00299               }
00300               if (!(thisdate = fdate(thisfile)))
00301                      syserr(thisfile);
00302               if (thisdate > lastdate)
00303                      lastdate = thisdate;
00304        }
00305        return(lastdate);
00306 }
00307 
00308 
00309 static char *
00310 newfname(            /* create modified file name */
00311        char   *orig,
00312        int    pred
00313 )
00314 {
00315        register char *cp;
00316        register int  n;
00317        int    suffix;
00318 
00319        n = 0; cp = orig; suffix = -1;            /* suffix position, length */
00320        while (*cp) {
00321               if (*cp == '.') suffix = n;
00322               else if (ISDIRSEP(*cp)) suffix = -1;
00323               cp++; n++;
00324        }
00325        if (suffix == -1) suffix = n;
00326        if ((cp = bmalloc(n+2)) == NULL)
00327               syserr(progname);
00328        strncpy(cp, orig, suffix);
00329        cp[suffix] = pred;                 /* root name + pred + suffix */
00330        strcpy(cp+suffix+1, orig+suffix);
00331        return(cp);
00332 }
00333 
00334 
00335 static void
00336 checkfiles(void)                   /* check for existence and modified times */
00337 {
00338        time_t objdate;
00339 
00340        if (!vdef(OCTREE)) {
00341               if ((vval(OCTREE) = bmalloc(strlen(radname)+5)) == NULL)
00342                      syserr(progname);
00343               sprintf(vval(OCTREE), "%s.oct", radname);
00344               vdef(OCTREE)++;
00345        } else if (vval(OCTREE)[0] == '!') {
00346               fprintf(stderr, "%s: illegal '%s' specification\n",
00347                             progname, vnam(OCTREE));
00348               quit(1);
00349        }
00350        octreedate = fdate(vval(OCTREE));
00351        if (vdef(ILLUM)) {          /* illum requires secondary octrees */
00352               oct0name = newfname(vval(OCTREE), '0');
00353               oct1name = newfname(vval(OCTREE), '1');
00354               oct0date = fdate(oct0name);
00355               oct1date = fdate(oct1name);
00356        } else
00357               oct0name = oct1name = vval(OCTREE);
00358        if ((scenedate = checklast(vval(SCENE))) &&
00359                      (objdate = checklast(vval(OBJECT))) > scenedate)
00360               scenedate = objdate;
00361        illumdate = checklast(vval(ILLUM));
00362        if (!octreedate & !scenedate & !illumdate) {
00363               fprintf(stderr, "%s: need '%s' or '%s' or '%s'\n", progname,
00364                             vnam(OCTREE), vnam(SCENE), vnam(ILLUM));
00365               quit(1);
00366        }
00367        matdate = checklast(vval(MATERIAL));
00368 }      
00369 
00370 
00371 static void
00372 getoctcube(          /* get octree bounding cube */
00373        double org[3],
00374        double *sizp
00375 )
00376 {
00377        static double oorg[3], osiz = 0.;
00378        double min[3], max[3];
00379        char   buf[1024];
00380        FILE   *fp;
00381        register int  i;
00382 
00383        if (osiz <= FTINY) {
00384               if (!nprocs && fdate(oct1name) <
00385                             (scenedate>illumdate?scenedate:illumdate)) {
00386                                                  /* run getbbox */
00387                      sprintf(buf, "getbbox -w -h %s",
00388                             vdef(SCENE) ? vval(SCENE) : vval(ILLUM));
00389                      if ((fp = popen(buf, "r")) == NULL)
00390                             syserr("getbbox");
00391                      if (fscanf(fp, "%lf %lf %lf %lf %lf %lf",
00392                                    &min[0], &max[0], &min[1], &max[1],
00393                                    &min[2], &max[2]) != 6) {
00394                             fprintf(stderr,
00395                      "%s: error reading bounding box from getbbox\n",
00396                                           progname);
00397                             quit(1);
00398                      }
00399                      for (i = 0; i < 3; i++)
00400                             if (max[i] - min[i] > osiz)
00401                                    osiz = max[i] - min[i];
00402                      for (i = 0; i < 3; i++)
00403                             oorg[i] = (max[i]+min[i]-osiz)*.5;
00404                      pclose(fp);
00405               } else {                           /* from octree */
00406                      oconv();      /* does nothing if done already */
00407                      sprintf(buf, "getinfo -d < %s", oct1name);
00408                      if ((fp = popen(buf, "r")) == NULL)
00409                             syserr("getinfo");
00410                      if (fscanf(fp, "%lf %lf %lf %lf", &oorg[0], &oorg[1],
00411                                    &oorg[2], &osiz) != 4) {
00412                             fprintf(stderr,
00413                      "%s: error reading bounding cube from getinfo\n",
00414                                           progname);
00415                             quit(1);
00416                      }
00417                      pclose(fp);
00418               }
00419        }
00420        org[0] = oorg[0]; org[1] = oorg[1]; org[2] = oorg[2]; *sizp = osiz;
00421 }
00422 
00423 
00424 static void
00425 setdefaults(void)                  /* set default values for unassigned var's */
00426 {
00427        double org[3], lim[3], size;
00428        char   buf[128];
00429 
00430        if (!vdef(ZONE)) {
00431               getoctcube(org, &size);
00432               sprintf(buf, "E %g %g %g %g %g %g", org[0], org[0]+size,
00433                             org[1], org[1]+size, org[2], org[2]+size);
00434               vval(ZONE) = savqstr(buf);
00435               vdef(ZONE)++;
00436        }
00437        if (!vdef(EYESEP)) {
00438               if (sscanf(vval(ZONE), "%*s %lf %lf %lf %lf %lf %lf",
00439                             &org[0], &lim[0], &org[1], &lim[1],
00440                             &org[2], &lim[2]) != 6)
00441                      badvalue(ZONE);
00442               sprintf(buf, "%f",
00443                      0.01*(lim[0]-org[0]+lim[1]-org[1]+lim[2]-org[2]));
00444               vval(EYESEP) = savqstr(buf);
00445               vdef(EYESEP)++;
00446        }
00447        if (!vdef(INDIRECT)) {
00448               vval(INDIRECT) = "0";
00449               vdef(INDIRECT)++;
00450        }
00451        if (!vdef(QUALITY)) {
00452               vval(QUALITY) = "L";
00453               vdef(QUALITY)++;
00454        }
00455        if (!vdef(RESOLUTION)) {
00456               vval(RESOLUTION) = "512";
00457               vdef(RESOLUTION)++;
00458        }
00459        if (!vdef(PICTURE)) {
00460               vval(PICTURE) = radname;
00461               vdef(PICTURE)++;
00462        }
00463        if (!vdef(VIEWS)) {
00464               vval(VIEWS) = "X";
00465               vdef(VIEWS)++;
00466        }
00467        if (!vdef(DETAIL)) {
00468               vval(DETAIL) = "M";
00469               vdef(DETAIL)++;
00470        }
00471        if (!vdef(PENUMBRAS)) {
00472               vval(PENUMBRAS) = "F";
00473               vdef(PENUMBRAS)++;
00474        }
00475        if (!vdef(VARIABILITY)) {
00476               vval(VARIABILITY) = "L";
00477               vdef(VARIABILITY)++;
00478        }
00479 }
00480 
00481 
00482 static void
00483 oconv(void)                        /* run oconv and mkillum if necessary */
00484 {
00485        static char   illumtmp[] = "ilXXXXXX";
00486        char   combuf[PATH_MAX], ocopts[64], mkopts[1024];
00487 
00488        oconvopts(ocopts);          /* get options */
00489        if (octreedate < scenedate) {      /* check date on original octree */
00490               if (touchonly && octreedate)
00491                      touch(vval(OCTREE));
00492               else {                      /* build command */
00493                      if (vdef(MATERIAL))
00494                             sprintf(combuf, "%s%s %s %s > %s", c_oconv,
00495                                           ocopts, vval(MATERIAL),
00496                                           vval(SCENE), vval(OCTREE));
00497                      else
00498                             sprintf(combuf, "%s%s %s > %s", c_oconv, ocopts,
00499                                           vval(SCENE), vval(OCTREE));
00500                      
00501                      if (runcom(combuf)) {              /* run it */
00502                             fprintf(stderr,
00503                             "%s: error generating octree\n\t%s removed\n",
00504                                           progname, vval(OCTREE));
00505                             unlink(vval(OCTREE));
00506                             quit(1);
00507                      }
00508               }
00509               octreedate = time((time_t *)NULL);
00510               if (octreedate < scenedate) /* in case clock is off */
00511                      octreedate = scenedate;
00512        }
00513        if (oct1name == vval(OCTREE))             /* no mkillum? */
00514               oct1date = octreedate > matdate ? octreedate : matdate;
00515        if ((oct1date >= octreedate) & (oct1date >= matdate)
00516                      & (oct1date >= illumdate))  /* all done */
00517               return;
00518                                           /* make octree0 */
00519        if ((oct0date < scenedate) | (oct0date < illumdate)) {
00520               if (touchonly && oct0date)
00521                      touch(oct0name);
00522               else {                      /* build command */
00523                      if (octreedate)
00524                             sprintf(combuf, "%s%s -i %s %s > %s", c_oconv,
00525                                    ocopts, vval(OCTREE),
00526                                    vval(ILLUM), oct0name);
00527                      else if (vdef(MATERIAL))
00528                             sprintf(combuf, "%s%s %s %s > %s", c_oconv,
00529                                    ocopts, vval(MATERIAL),
00530                                    vval(ILLUM), oct0name);
00531                      else
00532                             sprintf(combuf, "%s%s %s > %s", c_oconv,
00533                                    ocopts, vval(ILLUM), oct0name);
00534                      if (runcom(combuf)) {              /* run it */
00535                             fprintf(stderr,
00536                             "%s: error generating octree\n\t%s removed\n",
00537                                           progname, oct0name);
00538                             unlink(oct0name);
00539                             quit(1);
00540                      }
00541               }
00542               oct0date = time((time_t *)NULL);
00543               if (oct0date < octreedate)  /* in case clock is off */
00544                      oct0date = octreedate;
00545               if (oct0date < illumdate)   /* ditto */
00546                      oct0date = illumdate;
00547               }
00548        if (touchonly && oct1date)
00549               touch(oct1name);
00550        else {
00551               mkillumopts(mkopts);        /* build mkillum command */
00552               mktemp(illumtmp);
00553               sprintf(combuf, "%s%s %s \"<\" %s > %s", c_mkillum, mkopts,
00554                             oct0name, vval(ILLUM), illumtmp);
00555               if (runcom(combuf)) {                     /* run it */
00556                      fprintf(stderr, "%s: error running %s\n",
00557                                    progname, c_mkillum);
00558                      unlink(illumtmp);
00559                      quit(1);
00560               }
00561                                           /* make octree1 (frozen) */
00562               if (octreedate)
00563                      sprintf(combuf, "%s%s -f -i %s %s > %s", c_oconv,
00564                             ocopts, vval(OCTREE), illumtmp, oct1name);
00565               else if (vdef(MATERIAL))
00566                      sprintf(combuf, "%s%s -f %s %s > %s", c_oconv,
00567                             ocopts, vval(MATERIAL), illumtmp, oct1name);
00568               else
00569                      sprintf(combuf, "%s%s -f %s > %s", c_oconv, ocopts,
00570                             illumtmp, oct1name);
00571               if (runcom(combuf)) {              /* run it */
00572                      fprintf(stderr,
00573                             "%s: error generating octree\n\t%s removed\n",
00574                                    progname, oct1name);
00575                      unlink(oct1name);
00576                      unlink(illumtmp);
00577                      quit(1);
00578               }
00579               rmfile(illumtmp);
00580        }
00581        oct1date = time((time_t *)NULL);
00582        if (oct1date < oct0date)    /* in case clock is off */
00583               oct1date = oct0date;
00584 }
00585 
00586 
00587 static char *
00588 addarg(                            /* append argument and advance pointer */
00589 register char *op,
00590 register char *arg
00591 )
00592 {
00593        while (*op)
00594               op++;
00595        *op = ' ';
00596        while ( (*++op = *arg++) )
00597               ;
00598        return(op);
00599 }
00600 
00601 
00602 static void
00603 oconvopts(                         /* get oconv options */
00604        register char *oo
00605 )
00606 {
00607        /* BEWARE:  This may be called via setdefaults(), so no assumptions */
00608 
00609        *oo = '\0';
00610        if (vdef(OCONV))
00611               if (vval(OCONV)[0] != '-') {
00612                      atos(c_oconv, sizeof(c_oconv), vval(OCONV));
00613                      oo = addarg(oo, sskip2(vval(OCONV), 1));
00614               } else
00615                      oo = addarg(oo, vval(OCONV));
00616 }
00617 
00618 
00619 static void
00620 mkillumopts(                       /* get mkillum options */
00621        char   *mo
00622 )
00623 {
00624        /* BEWARE:  This may be called via setdefaults(), so no assumptions */
00625 
00626        if (nprocs > 1)
00627               sprintf(mo, " -n %d", nprocs);
00628        else
00629               *mo = '\0';
00630        if (vdef(MKILLUM))
00631               if (vval(MKILLUM)[0] != '-') {
00632                      atos(c_mkillum, sizeof(c_mkillum), vval(MKILLUM));
00633                      mo = addarg(mo, sskip2(vval(MKILLUM), 1));
00634               } else
00635                      mo = addarg(mo, vval(MKILLUM));
00636 }
00637 
00638 
00639 static void
00640 checkambfile(void)                 /* check date on ambient file */
00641 {
00642        time_t afdate;
00643 
00644        if (!vdef(AMBFILE))
00645               return;
00646        if (!(afdate = fdate(vval(AMBFILE))))
00647               return;
00648        if (oct1date > afdate) {
00649               if (touchonly)
00650                      touch(vval(AMBFILE));
00651               else
00652                      rmfile(vval(AMBFILE));
00653        }
00654 }
00655 
00656 
00657 static double
00658 ambval(void)                       /* compute ambient value */
00659 {
00660        if (vdef(EXPOSURE)) {
00661               if (vval(EXPOSURE)[0] == '+' || vval(EXPOSURE)[0] == '-')
00662                      return(.5/pow(2.,vflt(EXPOSURE)));
00663               return(.5/vflt(EXPOSURE));
00664        }
00665        if (vlet(ZONE) == 'E')
00666               return(10.);
00667        if (vlet(ZONE) == 'I')
00668               return(.01);
00669        badvalue(ZONE);
00670        return 0; /* pro forma return */
00671 }
00672 
00673 
00674 static void
00675 renderopts(                 /* set rendering options */
00676        char   *op,
00677        char   *po
00678 )
00679 {
00680        switch(vscale(QUALITY)) {
00681        case LOW:
00682               lowqopts(op, po);
00683               break;
00684        case MEDIUM:
00685               medqopts(op, po);
00686               break;
00687        case HIGH:
00688               hiqopts(op, po);
00689               break;
00690        }
00691        if (vdef(RENDER))
00692               op = addarg(op, vval(RENDER));
00693        if (rvdevice != NULL) {
00694               if (vdef(RVU))
00695                      if (vval(RVU)[0] != '-') {
00696                             atos(c_rvu, sizeof(c_rvu), vval(RVU));
00697                             po = addarg(po, sskip2(vval(RVU), 1));
00698                      } else
00699                             po = addarg(po, vval(RVU));
00700        } else {
00701               if (vdef(RPICT))
00702                      if (vval(RPICT)[0] != '-') {
00703                             atos(c_rpict, sizeof(c_rpict), vval(RPICT));
00704                             po = addarg(po, sskip2(vval(RPICT), 1));
00705                      } else
00706                             po = addarg(po, vval(RPICT));
00707        }
00708 }
00709 
00710 
00711 static void
00712 lowqopts(                   /* low quality rendering options */
00713        register char *op,
00714        char   *po
00715 )
00716 {
00717        double d, org[3], siz[3];
00718 
00719        *op = '\0';
00720        *po = '\0';
00721        if (sscanf(vval(ZONE), "%*s %lf %lf %lf %lf %lf %lf", &org[0],
00722                      &siz[0], &org[1], &siz[1], &org[2], &siz[2]) != 6)
00723               badvalue(ZONE);
00724        siz[0] -= org[0]; siz[1] -= org[1]; siz[2] -= org[2];
00725        if ((siz[0] <= FTINY) | (siz[1] <= FTINY) | (siz[2] <= FTINY))
00726               badvalue(ZONE);
00727        getoctcube(org, &d);
00728        d *= 3./(siz[0]+siz[1]+siz[2]);
00729        switch (vscale(DETAIL)) {
00730        case LOW:
00731               po = addarg(po, "-ps 16");
00732               op = addarg(op, "-dp 64");
00733               sprintf(op, " -ar %d", (int)(8*d));
00734               op += strlen(op);
00735               break;
00736        case MEDIUM:
00737               po = addarg(po, "-ps 8");
00738               op = addarg(op, "-dp 128");
00739               sprintf(op, " -ar %d", (int)(16*d));
00740               op += strlen(op);
00741               break;
00742        case HIGH:
00743               po = addarg(po, "-ps 4");
00744               op = addarg(op, "-dp 256");
00745               sprintf(op, " -ar %d", (int)(32*d));
00746               op += strlen(op);
00747               break;
00748        }
00749        po = addarg(po, "-pt .16");
00750        if (vbool(PENUMBRAS))
00751               op = addarg(op, "-ds .4");
00752        else
00753               op = addarg(op, "-ds 0");
00754        op = addarg(op, "-dt .2 -dc .25 -dr 0 -sj 0 -st .5");
00755        if (vdef(AMBFILE)) {
00756               sprintf(op, " -af %s", vval(AMBFILE));
00757               op += strlen(op);
00758        } else
00759               overture = 0;
00760        switch (vscale(VARIABILITY)) {
00761        case LOW:
00762               op = addarg(op, "-aa .3 -ad 256");
00763               break;
00764        case MEDIUM:
00765               op = addarg(op, "-aa .25 -ad 512");
00766               break;
00767        case HIGH:
00768               op = addarg(op, "-aa .2 -ad 1024");
00769               break;
00770        }
00771        op = addarg(op, "-as 0");
00772        d = ambval();
00773        sprintf(op, " -av %.2g %.2g %.2g", d, d, d);
00774        op += strlen(op);
00775        op = addarg(op, "-lr 6 -lw .01");
00776 }
00777 
00778 
00779 static void
00780 medqopts(                   /* medium quality rendering options */
00781        register char *op,
00782        char   *po
00783 )
00784 {
00785        double d, org[3], siz[3], asz;
00786 
00787        *op = '\0';
00788        *po = '\0';
00789        if (sscanf(vval(ZONE), "%*s %lf %lf %lf %lf %lf %lf", &org[0],
00790                      &siz[0], &org[1], &siz[1], &org[2], &siz[2]) != 6)
00791               badvalue(ZONE);
00792        siz[0] -= org[0]; siz[1] -= org[1]; siz[2] -= org[2];
00793        if ((siz[0] <= FTINY) | (siz[1] <= FTINY) | (siz[2] <= FTINY))
00794               badvalue(ZONE);
00795        getoctcube(org, &d);
00796        asz = (siz[0]+siz[1]+siz[2])/3.;
00797        d /= asz;
00798        switch (vscale(DETAIL)) {
00799        case LOW:
00800               po = addarg(po, vbool(PENUMBRAS) ? "-ps 4" : "-ps 8");
00801               op = addarg(op, "-dp 256");
00802               sprintf(op, " -ar %d", (int)(16*d));
00803               op += strlen(op);
00804               sprintf(op, " -ms %.2g", asz/20.);
00805               op += strlen(op);
00806               break;
00807        case MEDIUM:
00808               po = addarg(po, vbool(PENUMBRAS) ? "-ps 3" : "-ps 6");
00809               op = addarg(op, "-dp 512");
00810               sprintf(op, " -ar %d", (int)(32*d));
00811               op += strlen(op);
00812               sprintf(op, " -ms %.2g", asz/40.);
00813               op += strlen(op);
00814               break;
00815        case HIGH:
00816               po = addarg(po, vbool(PENUMBRAS) ? "-ps 2" : "-ps 4");
00817               op = addarg(op, "-dp 1024");
00818               sprintf(op, " -ar %d", (int)(64*d));
00819               op += strlen(op);
00820               sprintf(op, " -ms %.2g", asz/80.);
00821               op += strlen(op);
00822               break;
00823        }
00824        po = addarg(po, "-pt .08");
00825        if (vbool(PENUMBRAS))
00826               op = addarg(op, "-ds .2 -dj .9");
00827        else
00828               op = addarg(op, "-ds .3");
00829        op = addarg(op, "-dt .1 -dc .5 -dr 1 -sj .7 -st .1");
00830        if ( (overture = vint(INDIRECT)) ) {
00831               sprintf(op, " -ab %d", overture);
00832               op += strlen(op);
00833        }
00834        if (vdef(AMBFILE)) {
00835               sprintf(op, " -af %s", vval(AMBFILE));
00836               op += strlen(op);
00837        } else
00838               overture = 0;
00839        switch (vscale(VARIABILITY)) {
00840        case LOW:
00841               op = addarg(op, "-aa .2 -ad 329 -as 42");
00842               break;
00843        case MEDIUM:
00844               op = addarg(op, "-aa .15 -ad 800 -as 128");
00845               break;
00846        case HIGH:
00847               op = addarg(op, "-aa .1 -ad 1536 -as 392");
00848               break;
00849        }
00850        d = ambval();
00851        sprintf(op, " -av %.2g %.2g %.2g", d, d, d);
00852        op += strlen(op);
00853        op = addarg(op, "-lr 8 -lw .002");
00854 }
00855 
00856 
00857 static void
00858 hiqopts(                           /* high quality rendering options */
00859        register char *op,
00860        char   *po
00861 )
00862 {
00863        double d, org[3], siz[3], asz;
00864 
00865        *op = '\0';
00866        *po = '\0';
00867        if (sscanf(vval(ZONE), "%*s %lf %lf %lf %lf %lf %lf", &org[0],
00868                      &siz[0], &org[1], &siz[1], &org[2], &siz[2]) != 6)
00869               badvalue(ZONE);
00870        siz[0] -= org[0]; siz[1] -= org[1]; siz[2] -= org[2];
00871        if ((siz[0] <= FTINY) | (siz[1] <= FTINY) | (siz[2] <= FTINY))
00872               badvalue(ZONE);
00873        getoctcube(org, &d);
00874        asz = (siz[0]+siz[1]+siz[2])/3.;
00875        d /= asz;
00876        switch (vscale(DETAIL)) {
00877        case LOW:
00878               po = addarg(po, vbool(PENUMBRAS) ? "-ps 1" : "-ps 8");
00879               op = addarg(op, "-dp 1024");
00880               sprintf(op, " -ar %d", (int)(32*d));
00881               op += strlen(op);
00882               sprintf(op, " -ms %.2g", asz/40.);
00883               op += strlen(op);
00884               break;
00885        case MEDIUM:
00886               po = addarg(po, vbool(PENUMBRAS) ? "-ps 1" : "-ps 5");
00887               op = addarg(op, "-dp 2048");
00888               sprintf(op, " -ar %d", (int)(64*d));
00889               op += strlen(op);
00890               sprintf(op, " -ms %.2g", asz/80.);
00891               op += strlen(op);
00892               break;
00893        case HIGH:
00894               po = addarg(po, vbool(PENUMBRAS) ? "-ps 1" : "-ps 3");
00895               op = addarg(op, "-dp 4096");
00896               sprintf(op, " -ar %d", (int)(128*d));
00897               op += strlen(op);
00898               sprintf(op, " -ms %.2g", asz/160.);
00899               op += strlen(op);
00900               break;
00901        }
00902        po = addarg(po, "-pt .04");
00903        if (vbool(PENUMBRAS))
00904               op = addarg(op, "-ds .1 -dj .9");
00905        else
00906               op = addarg(op, "-ds .2");
00907        op = addarg(op, "-dt .05 -dc .75 -dr 3 -sj 1 -st .01");
00908        sprintf(op, " -ab %d", overture=vint(INDIRECT)+1);
00909        op += strlen(op);
00910        if (vdef(AMBFILE)) {
00911               sprintf(op, " -af %s", vval(AMBFILE));
00912               op += strlen(op);
00913        } else
00914               overture = 0;
00915        switch (vscale(VARIABILITY)) {
00916        case LOW:
00917               op = addarg(op, "-aa .125 -ad 512 -as 64");
00918               break;
00919        case MEDIUM:
00920               op = addarg(op, "-aa .1 -ad 1536 -as 768");
00921               break;
00922        case HIGH:
00923               op = addarg(op, "-aa .075 -ad 4096 -as 2048");
00924               break;
00925        }
00926        d = ambval();
00927        sprintf(op, " -av %.2g %.2g %.2g", d, d, d);
00928        op += strlen(op);
00929        op = addarg(op, "-lr 12 -lw .0005");
00930 }
00931 
00932 
00933 static void
00934 xferopts(                          /* transfer options if indicated */
00935        char   *ro
00936 )
00937 {
00938        int    fd, n;
00939        register char *cp;
00940        
00941        n = strlen(ro);
00942        if (n < 2)
00943               return;
00944        if (vdef(OPTFILE)) {
00945               for (cp = ro; cp[1]; cp++)
00946                      if (isspace(cp[1]) && (cp[2] == '@' ||
00947                                    (cp[2] == '-' && isalpha(cp[3]))))
00948                             *cp = '\n';
00949                      else
00950                             *cp = cp[1];
00951               *cp = '\n';
00952               fd = open(vval(OPTFILE), O_WRONLY|O_CREAT|O_TRUNC, 0666);
00953               if (fd < 0 || write(fd, ro, n) != n || close(fd) < 0)
00954                      syserr(vval(OPTFILE));
00955               sprintf(ro, " @%s", vval(OPTFILE));
00956        }
00957 #ifdef _WIN32
00958        else if (n > 50) {
00959               setenv("ROPT", ro+1);
00960               strcpy(ro, " $ROPT");
00961        }
00962 #endif
00963 }
00964 
00965 
00966 static void
00967 pfiltopts(                         /* get pfilt options */
00968        register char *po
00969 )
00970 {
00971        *po = '\0';
00972        if (vdef(EXPOSURE)) {
00973               po = addarg(po, "-1 -e");
00974               po = addarg(po, vval(EXPOSURE));
00975        }
00976        switch (vscale(QUALITY)) {
00977        case MEDIUM:
00978               po = addarg(po, "-r .6");
00979               break;
00980        case HIGH:
00981               po = addarg(po, "-m .25");
00982               break;
00983        }
00984        if (vdef(PFILT))
00985               if (vval(PFILT)[0] != '-') {
00986                      atos(c_pfilt, sizeof(c_pfilt), vval(PFILT));
00987                      po = addarg(po, sskip2(vval(PFILT), 1));
00988               } else
00989                      po = addarg(po, vval(PFILT));
00990 }
00991 
00992 
00993 static int
00994 matchword(                  /* match white-delimited words */
00995        register char *s1,
00996        register char *s2
00997 )
00998 {
00999        while (isspace(*s1)) s1++;
01000        while (isspace(*s2)) s2++;
01001        while (*s1 && !isspace(*s1))
01002               if (*s1++ != *s2++)
01003                      return(0);
01004        return(!*s2 || isspace(*s2));
01005 }
01006 
01007 
01008 static char *
01009 specview(                          /* get proper view spec from vs */
01010        register char *vs
01011 )
01012 {
01013        static char   vup[7][12] = {"-vu 0 0 -1","-vu 0 -1 0","-vu -1 0 0",
01014                      "-vu 0 0 1", "-vu 1 0 0","-vu 0 1 0","-vu 0 0 1"};
01015        static char   viewopts[128];
01016        register char *cp;
01017        int    xpos, ypos, zpos, viewtype, upax;
01018        register int  i;
01019        double cent[3], dim[3], mult, d;
01020 
01021        if (vs == NULL || *vs == '-')
01022               return(vs);
01023        upax = 0;                   /* get the up vector */
01024        if (vdef(UP)) {
01025               if (vval(UP)[0] == '-' || vval(UP)[0] == '+')
01026                      upax = 1-'X'+UPPER(vval(UP)[1]);
01027               else
01028                      upax = 1-'X'+vlet(UP);
01029               if ((upax < 1) | (upax > 3))
01030                      badvalue(UP);
01031               if (vval(UP)[0] == '-')
01032                      upax = -upax;
01033        }
01034                                    /* check standard view names */
01035        xpos = ypos = zpos = 0;
01036        if (*vs == 'X') {
01037               xpos = 1; vs++;
01038        } else if (*vs == 'x') {
01039               xpos = -1; vs++;
01040        }
01041        if (*vs == 'Y') {
01042               ypos = 1; vs++;
01043        } else if (*vs == 'y') {
01044               ypos = -1; vs++;
01045        }
01046        if (*vs == 'Z') {
01047               zpos = 1; vs++;
01048        } else if (*vs == 'z') {
01049               zpos = -1; vs++;
01050        }
01051        switch (*vs) {
01052        case VT_PER:
01053        case VT_PAR:
01054        case VT_ANG:
01055        case VT_HEM:
01056        case VT_PLS:
01057        case VT_CYL:
01058               viewtype = *vs++;
01059               break;
01060        default:
01061               viewtype = VT_PER;
01062               break;
01063        }
01064        cp = viewopts;
01065        if ((!*vs || isspace(*vs)) && (xpos|ypos|zpos)) {       /* got one! */
01066               *cp++ = '-'; *cp++ = 'v'; *cp++ = 't'; *cp++ = viewtype;
01067               if (sscanf(vval(ZONE), "%*s %lf %lf %lf %lf %lf %lf",
01068                             &cent[0], &dim[0], &cent[1], &dim[1],
01069                             &cent[2], &dim[2]) != 6)
01070                      badvalue(ZONE);
01071               for (i = 0; i < 3; i++) {
01072                      dim[i] -= cent[i];
01073                      if (dim[i] <= FTINY)
01074                             badvalue(ZONE);
01075                      cent[i] += .5*dim[i];
01076               }
01077               mult = vlet(ZONE)=='E' ? 2. : .45 ;
01078               sprintf(cp, " -vp %.2g %.2g %.2g -vd %.2g %.2g %.2g",
01079                             cent[0]+xpos*mult*dim[0],
01080                             cent[1]+ypos*mult*dim[1],
01081                             cent[2]+zpos*mult*dim[2],
01082                             -xpos*dim[0], -ypos*dim[1], -zpos*dim[2]);
01083               cp += strlen(cp);
01084                                    /* redirect up axis if necessary */
01085               switch (upax) {
01086               case 3:                     /* plus or minus Z axis */
01087               case -3:
01088               case 0:
01089                      if (!(xpos|ypos))
01090                             upax = 2;
01091                      break;
01092               case 2:                     /* plus or minus Y axis */
01093               case -2:
01094                      if (!(xpos|zpos))
01095                             upax = 1;
01096                      break;
01097               case 1:                     /* plus or minus X axis */
01098               case -1:
01099                      if (!(ypos|zpos))
01100                             upax = 3;
01101                      break;
01102               }
01103               cp = addarg(cp, vup[upax+3]);
01104               switch (viewtype) {
01105               case VT_PER:
01106                      cp = addarg(cp, "-vh 45 -vv 45");
01107                      break;
01108               case VT_PAR:
01109                      d = sqrt(dim[0]*dim[0]+dim[1]*dim[1]+dim[2]*dim[2]);
01110                      sprintf(cp, " -vh %.2g -vv %.2g", d, d);
01111                      cp += strlen(cp);
01112                      break;
01113               case VT_ANG:
01114               case VT_HEM:
01115               case VT_PLS:
01116                      cp = addarg(cp, "-vh 180 -vv 180");
01117                      break;
01118               case VT_CYL:
01119                      cp = addarg(cp, "-vh 180 -vv 90");
01120                      break;
01121               }
01122        } else {
01123               while (!isspace(*vs))              /* else skip id */
01124                      if (!*vs++)
01125                             return(NULL);
01126               if (upax) {                 /* prepend up vector */
01127                      strcpy(cp, vup[upax+3]);
01128                      cp += strlen(cp);
01129               }
01130        }
01131        if (cp == viewopts)         /* append any additional options */
01132               vs++;         /* skip prefixed space if unneeded */
01133        strcpy(cp, vs);
01134 #ifdef _WIN32
01135        if (strlen(viewopts) > 40) {
01136               setenv("VIEW", viewopts);
01137               return("$VIEW");
01138        }
01139 #endif
01140        return(viewopts);
01141 }
01142 
01143 
01144 static char *
01145 getview(                           /* get view n, or NULL if none */
01146        int    n,
01147        char   *vn           /* returned view name */
01148 )
01149 {
01150        register char *mv;
01151 
01152        if (viewselect != NULL) {          /* command-line selected */
01153               if (n)                      /* only do one */
01154                      return(NULL);
01155                                    
01156               if (isint(viewselect)) {    /* view number? */
01157                      n = atoi(viewselect)-1;
01158                      goto numview;
01159               }
01160               if (viewselect[0] == '-') { /* already specified */
01161                      if (vn != NULL) *vn = '\0';
01162                      return(viewselect);
01163               }
01164               if (vn != NULL) {
01165                      for (mv = viewselect; *mv && !isspace(*mv);
01166                                    *vn++ = *mv++)
01167                             ;
01168                      *vn = '\0';
01169               }
01170                                           /* check list */
01171               while ((mv = nvalue(VIEWS, n++)) != NULL)
01172                      if (matchword(viewselect, mv))
01173                             return(specview(mv));
01174 
01175               return(specview(viewselect));      /* standard view? */
01176        }
01177 numview:
01178        mv = nvalue(VIEWS, n);             /* use view n */
01179        if ((vn != NULL) & (mv != NULL))
01180               if (*mv != '-') {
01181                      register char *mv2 = mv;
01182                      while (*mv2 && !isspace(*mv2))
01183                             *vn++ = *mv2++;
01184                      *vn = '\0';
01185               } else
01186                      sprintf(vn, "%d", n+1);
01187 
01188        return(specview(mv));
01189 }
01190 
01191 
01192 static int
01193 myprintview(                /* print out selected view */
01194        register char *vopts,
01195        FILE   *fp
01196 )
01197 {
01198        VIEW   vwr;
01199        char   buf[128];
01200        register char *cp;
01201 #ifdef _WIN32
01202 /* XXX Should we allow something like this for all platforms? */
01203 /* XXX Or is it still required at all? */
01204 again:
01205 #endif
01206        if (vopts == NULL)
01207               return(-1);
01208 #ifdef _WIN32
01209        if (vopts[0] == '$') {
01210               vopts = getenv(vopts+1);
01211               goto again;
01212        }
01213 #endif
01214        vwr = stdview;
01215        sscanview(&vwr, cp=vopts);         /* set initial options */
01216        while ((cp = strstr(cp, "-vf ")) != NULL &&
01217                      *atos(buf, sizeof(buf), cp += 4)) {
01218               viewfile(buf, &vwr, NULL);  /* load -vf file */
01219               sscanview(&vwr, cp);        /* reset tail */
01220        }
01221        fputs(VIEWSTR, fp);
01222        fprintview(&vwr, fp);                     /* print full spec. */
01223        fputc('\n', fp);
01224        return(0);
01225 }
01226 
01227 
01228 static void
01229 rvu(                        /* run rvu with first view */
01230        char   *opts,
01231        char   *po
01232 )
01233 {
01234        char   *vw;
01235        char   combuf[PATH_MAX];
01236                                    /* build command */
01237        if (touchonly || (vw = getview(0, NULL)) == NULL)
01238               return;
01239        if (sayview)
01240               myprintview(vw, stdout);
01241        sprintf(combuf, "%s %s%s%s -R %s ", c_rvu, vw, opts, po, rifname);
01242        if (nprocs > 1)
01243               sprintf(combuf+strlen(combuf), "-n %d ", nprocs);
01244        if (rvdevice != NULL)
01245               sprintf(combuf+strlen(combuf), "-o %s ", rvdevice);
01246        if (vdef(EXPOSURE))
01247               sprintf(combuf+strlen(combuf), "-pe %s ", vval(EXPOSURE));
01248        strcat(combuf, oct1name);
01249        if (runcom(combuf)) {              /* run it */
01250               fprintf(stderr, "%s: error running %s\n", progname, c_rvu);
01251               quit(1);
01252        }
01253 }
01254 
01255 
01256 static void
01257 rpict(                      /* run rpict and pfilt for each view */
01258        char   *opts,
01259        char   *po
01260 )
01261 {
01262        char   combuf[PATH_MAX];
01263        char   rawfile[PATH_MAX], picfile[PATH_MAX];
01264        char   zopt[PATH_MAX+4], rep[PATH_MAX+16], res[32];
01265        char   rppopt[128], *pfile = NULL;
01266        char   pfopts[128];
01267        char   vs[32], *vw;
01268        int    vn, mult;
01269        FILE   *fp;
01270        time_t rfdt, pfdt;
01271                                    /* get pfilt options */
01272        pfiltopts(pfopts);
01273                                    /* get resolution, reporting */
01274        switch (vscale(QUALITY)) {
01275        case LOW:
01276               mult = 1;
01277               break;
01278        case MEDIUM:
01279               mult = 2;
01280               break;
01281        case HIGH:
01282               mult = 3;
01283               break;
01284        }
01285        {
01286               int    xres, yres;
01287               double aspect;
01288               int    n;
01289               n = sscanf(vval(RESOLUTION), "%d %d %lf", &xres, &yres, &aspect);
01290               if (n == 3)
01291                      sprintf(res, "-x %d -y %d -pa %.3f",
01292                                    mult*xres, mult*yres, aspect);
01293               else if (n) {
01294                      if (n == 1) yres = xres;
01295                      sprintf(res, "-x %d -y %d", mult*xres, mult*yres);
01296               } else
01297                      badvalue(RESOLUTION);
01298        }
01299        rep[0] = '\0';
01300        if (vdef(REPORT)) {
01301               double minutes;
01302               int    n;
01303               n = sscanf(vval(REPORT), "%lf %s", &minutes, rawfile);
01304               if (n == 2)
01305                      sprintf(rep, " -t %d -e %s", (int)(minutes*60), rawfile);
01306               else if (n == 1)
01307                      sprintf(rep, " -t %d", (int)(minutes*60));
01308               else
01309                      badvalue(REPORT);
01310        }
01311                                    /* set up parallel rendering */
01312        if ((nprocs > 1) & (!vdef(ZFILE))) {
01313               strcpy(rppopt, "-S 1 -PP pfXXXXXX");
01314               pfile = rppopt+9;
01315               if (mktemp(pfile) == NULL)
01316                      pfile = NULL;
01317        }
01318        vn = 0;                                   /* do each view */
01319        while ((vw = getview(vn++, vs)) != NULL) {
01320               if (sayview)
01321                      myprintview(vw, stdout);
01322               if (!vs[0])
01323                      sprintf(vs, "%d", vn);
01324               sprintf(picfile, "%s_%s.hdr", vval(PICTURE), vs);
01325               if (vdef(ZFILE))
01326                      sprintf(zopt, " -z %s_%s.zbf", vval(ZFILE), vs);
01327               else
01328                      zopt[0] = '\0';
01329                                           /* check date on picture */
01330               pfdt = fdate(picfile);
01331               if (pfdt >= oct1date)
01332                      continue;
01333                                           /* get raw file name */
01334               sprintf(rawfile, "%s_%s.unf",
01335                      vdef(RAWFILE) ? vval(RAWFILE) : vval(PICTURE), vs);
01336               rfdt = fdate(rawfile);
01337               if (touchonly) {            /* update times only */
01338                      if (rfdt) {
01339                             if (rfdt < oct1date)
01340                                    touch(rawfile);
01341                      } else if (pfdt && pfdt < oct1date)
01342                             touch(picfile);
01343                      continue;
01344               }
01345               if (next_process()) {              /* parallel running? */
01346                      if (pfile != NULL)
01347                             sleep(20);
01348                      continue;
01349               }
01350               /* XXX Remember to call finish_process() */
01351                                           /* build rpict command */
01352               if (rfdt >= oct1date) {            /* recover */
01353                      sprintf(combuf, "%s%s%s%s%s -ro %s %s", c_rpict,
01354                             rep, opts, po, zopt, rawfile, oct1name);
01355                      if (runcom(combuf))  /* run rpict */
01356                             goto rperror;
01357               } else {
01358                      if (overture) {             /* run overture calculation */
01359                             sprintf(combuf,
01360                             "%s%s %s%s -x 64 -y 64 -ps 1 %s > %s",
01361                                           c_rpict, rep, vw, opts,
01362                                           oct1name, overfile);
01363                             if (runcom(combuf)) {
01364                                    fprintf(stderr,
01365                                    "%s: error in overture for view %s\n",
01366                                           progname, vs);
01367                                    quit(1);
01368                             }
01369 #ifndef NULL_DEVICE
01370                             rmfile(overfile);
01371 #endif
01372                      }
01373                      sprintf(combuf, "%s%s %s %s%s%s%s %s > %s",
01374                                    c_rpict, rep, vw, res, opts, po,
01375                                    zopt, oct1name, rawfile);
01376                      if (pfile != NULL && inchild()) {
01377                                           /* rpict persistent mode */
01378                             if (!silent)
01379                                    printf("\t%s\n", combuf);
01380                             fflush(stdout);
01381                             sprintf(combuf, "%s%s %s %s%s%s %s > %s",
01382                                           c_rpict, rep, rppopt, res, opts,
01383                                           po, oct1name, rawfile);
01384                             fp = popen(combuf, "w");
01385                             if (fp == NULL)
01386                                    goto rperror;
01387                             myprintview(vw, fp);
01388                             if (pclose(fp))
01389                                    goto rperror;
01390                      } else {             /* rpict normal mode */
01391                             if (runcom(combuf))
01392                                    goto rperror;
01393                      }
01394               }
01395               if (!vdef(RAWFILE) || strcmp(vval(RAWFILE),vval(PICTURE))) {
01396                                           /* build pfilt command */
01397                      if (mult > 1)
01398                             sprintf(combuf, "%s%s -x /%d -y /%d %s > %s",
01399                                    c_pfilt, pfopts, mult, mult,
01400                                    rawfile, picfile);
01401                      else
01402                             sprintf(combuf, "%s%s %s > %s", c_pfilt,
01403                                    pfopts, rawfile, picfile);
01404                      if (runcom(combuf)) {       /* run pfilt */
01405                             fprintf(stderr,
01406                             "%s: error filtering view %s\n\t%s removed\n",
01407                                           progname, vs, picfile);
01408                             unlink(picfile);
01409                             quit(1);
01410                      }
01411               }
01412                                           /* remove/rename raw file */
01413               if (vdef(RAWFILE)) {
01414                      sprintf(combuf, "%s_%s.hdr", vval(RAWFILE), vs);
01415                      mvfile(rawfile, combuf);
01416               } else
01417                      rmfile(rawfile);
01418               finish_process();           /* exit if child */
01419        }
01420        wait_process(1);            /* wait for children to finish */
01421        if (pfile != NULL) {        /* clean up rpict persistent mode */
01422               RT_PID pid;
01423               fp = fopen(pfile, "r");
01424               if (fp != NULL) {
01425                      if (fscanf(fp, "%*s %d", &pid) != 1 ||
01426                                    kill(pid, 1) < 0)
01427                             unlink(pfile);
01428                      fclose(fp);
01429               }
01430        }
01431        return;
01432 rperror:
01433        fprintf(stderr, "%s: error rendering view %s\n", progname, vs);
01434        quit(1);
01435 }
01436 
01437 
01438 static int
01439 touch(               /* update a file */
01440        char   *fn
01441 )
01442 {
01443        if (!silent)
01444               printf("\ttouch %s\n", fn);
01445        if (!nprocs)
01446               return(0);
01447 #ifdef notused
01448        if (access(fn, F_OK) == -1)        /* create it */
01449               if (close(open(fn, O_WRONLY|O_CREAT, 0666)) == -1)
01450                      return(-1);
01451 #endif
01452        return(setfdate(fn, time((time_t *)NULL)));
01453 }
01454 
01455 
01456 static int
01457 runcom(                     /* run command */
01458        char   *cs
01459 )
01460 {
01461        if (!silent)         /* echo it */
01462               printf("\t%s\n", cs);
01463        if (!nprocs)
01464               return(0);
01465        fflush(NULL);        /* flush output and pass to shell */
01466        return(system(cs));
01467 }
01468 
01469 
01470 static int
01471 rmfile(                     /* remove a file */
01472        char   *fn
01473 )
01474 {
01475        if (!silent)
01476               printf("\t%s %s\n", DELCMD, fn);
01477        if (!nprocs)
01478               return(0);
01479        return(unlink(fn));
01480 }
01481 
01482 
01483 static int
01484 mvfile(              /* move a file */
01485        char   *fold,
01486        char   *fnew
01487 )
01488 {
01489        if (!silent)
01490               printf("\t%s %s %s\n", RENAMECMD, fold, fnew);
01491        if (!nprocs)
01492               return(0);
01493        return(rename(fold, fnew));
01494 }
01495 
01496 
01497 #ifdef RHAS_FORK_EXEC
01498 static int
01499 next_process(void)                 /* fork the next process (max. nprocs) */
01500 {
01501        RT_PID child_pid;
01502 
01503        if (nprocs <= 1)
01504               return(0);           /* it's us or no one */
01505        if (inchild()) {
01506               fprintf(stderr, "%s: internal error 1 in next_process()\n",
01507                             progname);
01508               quit(1);
01509        }
01510        if (children_running >= nprocs)
01511               wait_process(0);     /* wait for someone to finish */
01512        fflush(NULL);               /* flush output */
01513        child_pid = fork();         /* split process */
01514        if (child_pid == 0) {              /* we're the child */
01515               children_running = -1;
01516               return(0);
01517        }
01518        if (child_pid > 0) {        /* we're the parent */
01519               ++children_running;
01520               return(1);
01521        }
01522        fprintf(stderr, "%s: warning -- fork() failed\n", progname);
01523        return(0);
01524 }
01525 
01526 static void
01527 wait_process(               /* wait for process(es) to finish */
01528        int    all
01529 )
01530 {
01531        int    ourstatus = 0, status;
01532        RT_PID pid;
01533 
01534        if (all)
01535               all = children_running;
01536        else if (children_running > 0)
01537               all = 1;
01538        while (all-- > 0) {
01539               pid = wait(&status);
01540               if (pid < 0)
01541                      syserr(progname);
01542               status = status>>8 & 0xff;
01543               --children_running;
01544               if (status != 0) {   /* child's problem is our problem */
01545                      if ((ourstatus == 0) & (children_running > 0))
01546                             fprintf(stderr, "%s: waiting for remaining processes\n",
01547                                           progname);
01548                      ourstatus = status;
01549                      all = children_running;
01550               }
01551        }
01552        if (ourstatus != 0)
01553               quit(ourstatus);     /* bad status from child */
01554 }
01555 #else  /* ! RHAS_FORK_EXEC */
01556 static int
01557 next_process(void)
01558 {
01559        return(0);                  /* cannot start new process */
01560 }
01561 static void
01562 wait_process(all)
01563 int    all;
01564 {
01565        (void)all;                  /* no one to wait for */
01566 }
01567 int
01568 kill(pid, sig) /* win|unix_process.c should also wait and kill */
01569 RT_PID pid;
01570 int sig;
01571 {
01572        return 0;
01573 }
01574 #endif /* ! RHAS_FORK_EXEC */
01575 
01576 static void
01577 finish_process(void)               /* exit a child process */
01578 {
01579        if (!inchild())
01580               return;                     /* in parent -- noop */
01581        exit(0);
01582 }
01583 
01584 #ifdef _WIN32
01585 setenv(vname, value)        /* set an environment variable */
01586 char   *vname, *value;
01587 {
01588        register char *evp;
01589 
01590        evp = bmalloc(strlen(vname)+strlen(value)+2);
01591        if (evp == NULL)
01592               syserr(progname);
01593        sprintf(evp, "%s=%s", vname, value);
01594        if (putenv(evp) != 0) {
01595               fprintf(stderr, "%s: out of environment space\n", progname);
01596               quit(1);
01597        }
01598        if (!silent)
01599               printf("set %s\n", evp);
01600 }
01601 #endif
01602 
01603 
01604 static void
01605 badvalue(                   /* report bad variable value and exit */
01606        int    vc
01607 )
01608 {
01609        fprintf(stderr, "%s: bad value for variable '%s'\n",
01610                      progname, vnam(vc));
01611        quit(1);
01612 }
01613 
01614 
01615 static void
01616 syserr(                     /* report a system error and exit */
01617        char   *s
01618 )
01619 {
01620        perror(s);
01621        quit(1);
01622 }
01623 
01624 
01625 void
01626 quit(ec)                    /* exit program */
01627 int    ec;
01628 {
01629        exit(ec);
01630 }