Back to index

radiance  4R0+20100331
rtmain.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: rtmain.c,v 2.20 2009/12/13 19:39:51 greg Exp $";
00003 #endif
00004 /*
00005  *  rtmain.c - main for rtrace per-ray calculation program
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include  <signal.h>
00011 
00012 #include  "platform.h"
00013 #include  "rtprocess.h" /* getpid() */
00014 #include  "resolu.h"
00015 #include  "ray.h"
00016 #include  "source.h"
00017 #include  "ambient.h"
00018 #include  "random.h"
00019 #include  "paths.h"
00020 
00021 extern char   *progname;           /* global argv[0] */
00022 
00023 extern char   *shm_boundary;              /* boundary of shared memory */
00024 
00025                                    /* persistent processes define */
00026 #ifdef  F_SETLKW
00027 #define  PERSIST     1             /* normal persist */
00028 #define  PARALLEL    2             /* parallel persist */
00029 #define  PCHILD             3             /* child of normal persist */
00030 #endif
00031 
00032 char  *sigerr[NSIG];               /* signal error messages */
00033 char  *errfile = NULL;                    /* error output file */
00034 
00035 int  nproc = 1;                           /* number of processes */
00036 
00037 extern char  *formstr();           /* string from format */
00038 int  inform = 'a';                 /* input format */
00039 int  outform = 'a';                /* output format */
00040 char  *outvals = "v";                     /* output specification */
00041 
00042 int  hresolu = 0;                  /* horizontal (scan) size */
00043 int  vresolu = 0;                  /* vertical resolution */
00044 
00045 int  imm_irrad = 0;                /* compute immediate irradiance? */
00046 int  lim_dist = 0;                 /* limit distance? */
00047 
00048 #ifndef       MAXMODLIST
00049 #define       MAXMODLIST    1024          /* maximum modifiers we'll track */
00050 #endif
00051 
00052 extern void  (*addobjnotify[])();  /* object notification calls */
00053 extern void  tranotify(OBJECT obj);
00054 
00055 char  *tralist[MAXMODLIST];        /* list of modifers to trace (or no) */
00056 int  traincl = -1;                 /* include == 1, exclude == 0 */
00057 
00058 static int  loadflags = ~IO_FILES; /* what to load from octree */
00059 
00060 static void onsig(int  signo);
00061 static void sigdie(int  signo, char  *msg);
00062 static void printdefaults(void);
00063 
00064 
00065 int
00066 main(int  argc, char  *argv[])
00067 {
00068 #define        check(ol,al)        if (argv[i][ol] || \
00069                             badarg(argc-i-1,argv+i+1,al)) \
00070                             goto badopt
00071 #define        bool(olen,var)             switch (argv[i][olen]) { \
00072                             case '\0': var = !var; break; \
00073                             case 'y': case 'Y': case 't': case 'T': \
00074                             case '+': case '1': var = 1; break; \
00075                             case 'n': case 'N': case 'f': case 'F': \
00076                             case '-': case '0': var = 0; break; \
00077                             default: goto badopt; }
00078        int  persist = 0;
00079        char  *octnm = NULL;
00080        char  **tralp;
00081        int  duped1;
00082        int  rval;
00083        int  i;
00084                                    /* global program name */
00085        progname = argv[0] = fixargv0(argv[0]);
00086                                    /* add trace notify function */
00087        for (i = 0; addobjnotify[i] != NULL; i++)
00088               ;
00089        addobjnotify[i] = tranotify;
00090                                    /* set our defaults */
00091        rand_samp = 1;
00092        maxdepth = -10;
00093        minweight = 2e-3;
00094                                    /* option city */
00095        for (i = 1; i < argc; i++) {
00096                                           /* expand arguments */
00097               while ((rval = expandarg(&argc, &argv, i)) > 0)
00098                      ;
00099               if (rval < 0) {
00100                      sprintf(errmsg, "cannot expand '%s'", argv[i]);
00101                      error(SYSTEM, errmsg);
00102               }
00103               if (argv[i] == NULL || argv[i][0] != '-')
00104                      break;               /* break from options */
00105               if (!strcmp(argv[i], "-version")) {
00106                      puts(VersionID);
00107                      quit(0);
00108               }
00109               if (!strcmp(argv[i], "-defaults") ||
00110                             !strcmp(argv[i], "-help")) {
00111                      printdefaults();
00112                      quit(0);
00113               }
00114               rval = getrenderopt(argc-i, argv+i);
00115               if (rval >= 0) {
00116                      i += rval;
00117                      continue;
00118               }
00119               switch (argv[i][1]) {
00120               case 'n':                          /* number of cores */
00121                      check(2,"i");
00122                      nproc = atoi(argv[++i]);
00123                      if (nproc <= 0)
00124                             error(USER, "bad number of processes");
00125                      break;
00126               case 'x':                          /* x resolution */
00127                      check(2,"i");
00128                      hresolu = atoi(argv[++i]);
00129                      break;
00130               case 'y':                          /* y resolution */
00131                      check(2,"i");
00132                      vresolu = atoi(argv[++i]);
00133                      break;
00134               case 'w':                          /* warnings */
00135                      rval = erract[WARNING].pf != NULL;
00136                      bool(2,rval);
00137                      if (rval) erract[WARNING].pf = wputs;
00138                      else erract[WARNING].pf = NULL;
00139                      break;
00140               case 'e':                          /* error file */
00141                      check(2,"s");
00142                      errfile = argv[++i];
00143                      break;
00144               case 'l':                          /* limit distance */
00145                      if (argv[i][2] != 'd')
00146                             goto badopt;
00147                      bool(3,lim_dist);
00148                      break;
00149               case 'I':                          /* immed. irradiance */
00150                      bool(2,imm_irrad);
00151                      break;
00152               case 'f':                          /* format i/o */
00153                      switch (argv[i][2]) {
00154                      case 'a':                          /* ascii */
00155                      case 'f':                          /* float */
00156                      case 'd':                          /* double */
00157                             inform = argv[i][2];
00158                             break;
00159                      default:
00160                             goto badopt;
00161                      }
00162                      switch (argv[i][3]) {
00163                      case '\0':
00164                             outform = inform;
00165                             break;
00166                      case 'a':                          /* ascii */
00167                      case 'f':                          /* float */
00168                      case 'd':                          /* double */
00169                      case 'c':                          /* color */
00170                             check(4,"");
00171                             outform = argv[i][3];
00172                             break;
00173                      default:
00174                             goto badopt;
00175                      }
00176                      break;
00177               case 'o':                          /* output */
00178                      outvals = argv[i]+2;
00179                      break;
00180               case 'h':                          /* header output */
00181                      rval = loadflags & IO_INFO;
00182                      bool(2,rval);
00183                      loadflags = rval ? loadflags | IO_INFO :
00184                                    loadflags & ~IO_INFO;
00185                      break;
00186               case 't':                          /* trace */
00187                      switch (argv[i][2]) {
00188                      case 'i':                          /* include */
00189                      case 'I':
00190                             check(3,"s");
00191                             if (traincl != 1) {
00192                                    traincl = 1;
00193                                    tralp = tralist;
00194                             }
00195                             if (argv[i][2] == 'I') {    /* file */
00196                                    rval = wordfile(tralp,
00197                                    getpath(argv[++i],getrlibpath(),R_OK));
00198                                    if (rval < 0) {
00199                                           sprintf(errmsg,
00200                             "cannot open trace include file \"%s\"",
00201                                                         argv[i]);
00202                                           error(SYSTEM, errmsg);
00203                                    }
00204                                    tralp += rval;
00205                             } else {
00206                                    *tralp++ = argv[++i];
00207                                    *tralp = NULL;
00208                             }
00209                             break;
00210                      case 'e':                          /* exclude */
00211                      case 'E':
00212                             check(3,"s");
00213                             if (traincl != 0) {
00214                                    traincl = 0;
00215                                    tralp = tralist;
00216                             }
00217                             if (argv[i][2] == 'E') {    /* file */
00218                                    rval = wordfile(tralp,
00219                                    getpath(argv[++i],getrlibpath(),R_OK));
00220                                    if (rval < 0) {
00221                                           sprintf(errmsg,
00222                             "cannot open trace exclude file \"%s\"",
00223                                                         argv[i]);
00224                                           error(SYSTEM, errmsg);
00225                                    }
00226                                    tralp += rval;
00227                             } else {
00228                                    *tralp++ = argv[++i];
00229                                    *tralp = NULL;
00230                             }
00231                             break;
00232                      default:
00233                             goto badopt;
00234                      }
00235                      break;
00236 #ifdef  PERSIST
00237               case 'P':                          /* persist file */
00238                      if (argv[i][2] == 'P') {
00239                             check(3,"s");
00240                             persist = PARALLEL;
00241                      } else {
00242                             check(2,"s");
00243                             persist = PERSIST;
00244                      }
00245                      persistfile(argv[++i]);
00246                      break;
00247 #endif
00248               default:
00249                      goto badopt;
00250               }
00251        }
00252        if (nproc > 1) {
00253               if (persist)
00254                      error(USER, "multiprocessing incompatible with persist file");
00255               if (hresolu > 0 && hresolu < nproc)
00256                      error(WARNING, "number of cores should not exceed horizontal resolution");
00257               if (trace != NULL)
00258                      error(WARNING, "multiprocessing does not work properly with trace mode");
00259        }
00260                                    /* initialize object types */
00261        initotypes();
00262                                    /* initialize urand */
00263        if (rand_samp) {
00264               srandom((long)time(0));
00265               initurand(0);
00266        } else {
00267               srandom(0L);
00268               initurand(2048);
00269        }
00270                                    /* set up signal handling */
00271        sigdie(SIGINT, "Interrupt");
00272 #ifdef SIGHUP
00273        sigdie(SIGHUP, "Hangup");
00274 #endif
00275        sigdie(SIGTERM, "Terminate");
00276 #ifdef SIGPIPE
00277        sigdie(SIGPIPE, "Broken pipe");
00278 #endif
00279 #ifdef SIGALRM
00280        sigdie(SIGALRM, "Alarm clock");
00281 #endif
00282 #ifdef SIGXCPU
00283        sigdie(SIGXCPU, "CPU limit exceeded");
00284        sigdie(SIGXFSZ, "File size exceeded");
00285 #endif
00286                                    /* open error file */
00287        if (errfile != NULL) {
00288               if (freopen(errfile, "a", stderr) == NULL)
00289                      quit(2);
00290               fprintf(stderr, "**************\n*** PID %5d: ",
00291                             getpid());
00292               printargs(argc, argv, stderr);
00293               putc('\n', stderr);
00294               fflush(stderr);
00295        }
00296 #ifdef NICE
00297        nice(NICE);                 /* lower priority */
00298 #endif
00299                                    /* get octree */
00300        if (i == argc)
00301               octnm = NULL;
00302        else if (i == argc-1)
00303               octnm = argv[i];
00304        else
00305               goto badopt;
00306        if (octnm == NULL)
00307               error(USER, "missing octree argument");
00308                                    /* set up output */
00309 #ifdef  PERSIST
00310        if (persist) {
00311               duped1 = dup(fileno(stdout));      /* don't lose our output */
00312               openheader();
00313        }
00314 #endif
00315        if (outform != 'a')
00316               SET_FILE_BINARY(stdout);
00317        readoct(octnm, loadflags, &thescene, NULL);
00318        nsceneobjs = nobjects;
00319 
00320        if (loadflags & IO_INFO) {  /* print header */
00321               printargs(i, argv, stdout);
00322               printf("SOFTWARE= %s\n", VersionID);
00323               fputnow(stdout);
00324               fputformat(formstr(outform), stdout);
00325               putchar('\n');
00326        }
00327 
00328        marksources();                     /* find and mark sources */
00329 
00330        setambient();               /* initialize ambient calculation */
00331 
00332 #ifdef  PERSIST
00333        if (persist) {
00334               fflush(stdout);
00335                                           /* reconnect stdout */
00336               dup2(duped1, fileno(stdout));
00337               close(duped1);
00338               if (persist == PARALLEL) {  /* multiprocessing */
00339                      preload_objs();             /* preload scene */
00340                      shm_boundary = (char *)malloc(16);
00341                      strcpy(shm_boundary, "SHM_BOUNDARY");
00342                      while ((rval=fork()) == 0) {       /* keep on forkin' */
00343                             pflock(1);
00344                             pfhold();
00345                             ambsync();           /* load new values */
00346                      }
00347                      if (rval < 0)
00348                             error(SYSTEM, "cannot fork child for persist function");
00349                      pfdetach();          /* parent will run then exit */
00350               }
00351        }
00352 runagain:
00353        if (persist)
00354               dupheader();                /* send header to stdout */
00355 #endif
00356                                    /* trace rays */
00357        rtrace(NULL, nproc);
00358                                    /* flush ambient file */
00359        ambsync();
00360 #ifdef  PERSIST
00361        if (persist == PERSIST) {   /* first run-through */
00362               if ((rval=fork()) == 0) {   /* child loops until killed */
00363                      pflock(1);
00364                      persist = PCHILD;
00365               } else {                    /* original process exits */
00366                      if (rval < 0)
00367                             error(SYSTEM, "cannot fork child for persist function");
00368                      pfdetach();          /* parent exits */
00369               }
00370        }
00371        if (persist == PCHILD) {    /* wait for a signal then go again */
00372               pfhold();
00373               raynum = nrays = 0;         /* reinitialize */
00374               goto runagain;
00375        }
00376 #endif
00377        quit(0);
00378 
00379 badopt:
00380        sprintf(errmsg, "command line error at '%s'", argv[i]);
00381        error(USER, errmsg);
00382        return 1; /* pro forma return */
00383 
00384 #undef check
00385 #undef bool
00386 }
00387 
00388 
00389 void
00390 wputs(                      /* warning output function */
00391        char   *s
00392 )
00393 {
00394        int  lasterrno = errno;
00395        eputs(s);
00396        errno = lasterrno;
00397 }
00398 
00399 
00400 void
00401 eputs(                      /* put string to stderr */
00402        register char  *s
00403 )
00404 {
00405        static int  midline = 0;
00406 
00407        if (!*s)
00408               return;
00409        if (!midline++) {
00410               fputs(progname, stderr);
00411               fputs(": ", stderr);
00412        }
00413        fputs(s, stderr);
00414        if (s[strlen(s)-1] == '\n') {
00415               fflush(stderr);
00416               midline = 0;
00417        }
00418 }
00419 
00420 
00421 static void
00422 onsig(                      /* fatal signal */
00423        int  signo
00424 )
00425 {
00426        static int  gotsig = 0;
00427 
00428        if (gotsig++)               /* two signals and we're gone! */
00429               _exit(signo);
00430 
00431 #ifdef SIGALRM
00432        alarm(15);                  /* allow 15 seconds to clean up */
00433        signal(SIGALRM, SIG_DFL);   /* make certain we do die */
00434 #endif
00435        eputs("signal - ");
00436        eputs(sigerr[signo]);
00437        eputs("\n");
00438        quit(3);
00439 }
00440 
00441 
00442 static void
00443 sigdie(                     /* set fatal signal */
00444        int  signo,
00445        char  *msg
00446 )
00447 {
00448        if (signal(signo, onsig) == SIG_IGN)
00449               signal(signo, SIG_IGN);
00450        sigerr[signo] = msg;
00451 }
00452 
00453 
00454 static void
00455 printdefaults(void)                /* print default values to stdout */
00456 {
00457        register char  *cp;
00458 
00459        if (imm_irrad)
00460               printf("-I+\t\t\t\t# immediate irradiance on\n");
00461        printf("-n %-2d\t\t\t\t# number of rendering processes\n", nproc);
00462        printf("-x %-9d\t\t\t# x resolution (flush interval)\n", hresolu);
00463        printf("-y %-9d\t\t\t# y resolution\n", vresolu);
00464        printf(lim_dist ? "-ld+\t\t\t\t# limit distance on\n" :
00465                      "-ld-\t\t\t\t# limit distance off\n");
00466        printf("-h%c\t\t\t\t# %s header\n", loadflags & IO_INFO ? '+' : '-',
00467                      loadflags & IO_INFO ? "output" : "no");
00468        printf("-f%c%c\t\t\t\t# format input/output = %s/%s\n",
00469                      inform, outform, formstr(inform), formstr(outform));
00470        printf("-o%-9s\t\t\t# output", outvals);
00471        for (cp = outvals; *cp; cp++)
00472               switch (*cp) {
00473               case 't': case 'T': printf(" trace"); break;
00474               case 'o': printf(" origin"); break;
00475               case 'd': printf(" direction"); break;
00476               case 'v': printf(" value"); break;
00477               case 'V': printf(" contribution"); break;
00478               case 'l': printf(" length"); break;
00479               case 'L': printf(" first_length"); break;
00480               case 'p': printf(" point"); break;
00481               case 'n': printf(" normal"); break;
00482               case 'N': printf(" unperturbed_normal"); break;
00483               case 's': printf(" surface"); break;
00484               case 'w': printf(" weight"); break;
00485               case 'W': printf(" coefficient"); break;
00486               case 'm': printf(" modifier"); break;
00487               case 'M': printf(" material"); break;
00488               case '-': printf(" stroke"); break;
00489               }
00490        putchar('\n');
00491        printf(erract[WARNING].pf != NULL ?
00492                      "-w+\t\t\t\t# warning messages on\n" :
00493                      "-w-\t\t\t\t# warning messages off\n");
00494        print_rdefaults();
00495 }