Back to index

radiance  4R0+20100331
rpiece.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: rpiece.c,v 2.50 2009/02/07 05:40:47 greg Exp $";
00003 #endif
00004 /*
00005  * Generate sections of a picture.
00006  */
00007  
00008 
00009 #include <stdio.h>
00010 #include <signal.h>
00011 #include <sys/types.h>
00012 
00013 #include "platform.h"
00014 #ifndef NON_POSIX /* XXX need abstraction for process management */
00015  #include <sys/wait.h>
00016 #endif
00017 
00018 #include "standard.h"
00019 #include "color.h"
00020 #include "view.h"
00021 #include "rtprocess.h"
00022 
00023 #ifndef F_SETLKW
00024 
00025 int
00026 main(
00027        int argc,
00028        char *argv[]
00029 )
00030 {
00031        fprintf(stderr, "%s: no NFS lock manager on this machine\n", argv[0]);
00032        exit(1);
00033 }
00034 
00035 #else
00036 
00037 #ifndef NFS
00038 #define  NFS                1
00039 #endif
00040                             /* set the following to 0 to forgo forking */
00041 #ifndef MAXFORK
00042 #if NFS
00043 #define  MAXFORK            3      /* allotment of duped processes */
00044 #else
00045 #define  MAXFORK            0
00046 #endif
00047 #endif
00048                                    /* protection from SYSV signals(!) */
00049 #if defined(sgi)
00050 #define guard_io()   sighold(SIGALRM)
00051 #define unguard()    sigrelse(SIGALRM)
00052 #endif
00053 #ifndef guard_io
00054 #define guard_io()   
00055 #define unguard()    
00056 #endif
00057 
00058 extern char  *strerror();
00059 
00060                             /* rpict command */
00061 char  *rpargv[128] = {"rpict", "-S", "1"};
00062 int  rpargc = 3;
00063 FILE  *torp, *fromrp;
00064 COLR  *pbuf;
00065                             /* our view parameters */
00066 VIEW  ourview = STDVIEW;
00067 double  pixaspect = 1.0;
00068 int  hres = 1024, vres = 1024, hmult = 4, vmult = 4;
00069                             /* output file */
00070 char  *outfile = NULL;
00071 int  outfd;
00072 long  scanorig;
00073 FILE  *syncfp = NULL;              /* synchronization file pointer */
00074 int  synclst = F_UNLCK;            /* synchronization file lock status */
00075 int  nforked = 0;
00076 
00077 #define  sflock(t)   if ((t)!=synclst) dolock(fileno(syncfp),synclst=t)
00078 
00079 char  *progname;
00080 int  verbose = 0;
00081 unsigned  timelim = 0;
00082 int  rvrlim = -1;
00083 
00084 int  gotalrm = 0;
00085 void  onalrm(int i) { gotalrm++; }
00086 
00087 static void dolock(int  fd, int  ltyp);
00088 static void init(int  ac, char  **av);
00089 static int nextpiece(int    *xp, int      *yp);
00090 static int rvrpiece(int     *xp, int      *yp);
00091 static int cleanup(int  rstat);
00092 static void rpiece(void);
00093 static int putpiece(int     xpos, int     ypos);
00094 static void filerr(char  *t);
00095 
00096 
00097 int
00098 main(
00099        int  argc,
00100        char  *argv[]
00101 )
00102 {
00103        register int  i, rval;
00104        
00105        progname = argv[0];
00106        for (i = 1; i < argc; i++) {
00107                                           /* expand arguments */
00108               while ((rval = expandarg(&argc, &argv, i)) > 0)
00109                      ;
00110               if (rval < 0) {
00111                      fprintf(stderr, "%s: cannot expand '%s'\n",
00112                                    argv[0], argv[i]);
00113                      exit(1);
00114               }
00115               if (argv[i][0] == '-')
00116                      switch (argv[i][1]) {
00117                      case 'v':
00118                             switch (argv[i][2]) {
00119                             case '\0':    /* verbose option */
00120                                    verbose = !verbose;
00121                                    continue;
00122                             case 'f':     /* view file */
00123                                    if (viewfile(argv[++i], &ourview, NULL) <= 0) {
00124                                           fprintf(stderr,
00125                                    "%s: not a view file\n", argv[i]);
00126                                           exit(1);
00127                                    }
00128                                    continue;
00129                             default:      /* view option? */
00130                                    rval = getviewopt(&ourview, argc-i, argv+i);
00131                                    if (rval >= 0) {
00132                                           i += rval;
00133                                           continue;
00134                                    }
00135                                    break;
00136                             }
00137                             break;
00138                      case 'p':            /* pixel aspect ratio? */
00139                             if (argv[i][2] != 'a' || argv[i][3])
00140                                    break;
00141                             pixaspect = atof(argv[++i]);
00142                             continue;
00143                      case 'T':            /* time limit (hours) */
00144                             if (argv[i][2])
00145                                    break;
00146                             timelim = atof(argv[++i])*3600. + .5;
00147                             break;
00148                      case 'x':            /* overall x resolution */
00149                             if (argv[i][2])
00150                                    break;
00151                             hres = atoi(argv[++i]);
00152                             continue;
00153                      case 'y':            /* overall y resolution */
00154                             if (argv[i][2])
00155                                    break;
00156                             vres = atoi(argv[++i]);
00157                             continue;
00158                      case 'X':            /* horizontal multiplier */
00159                             if (argv[i][2])
00160                                    break;
00161                             hmult = atoi(argv[++i]);
00162                             continue;
00163                      case 'Y':            /* vertical multiplier */
00164                             if (argv[i][2])
00165                                    break;
00166                             vmult = atoi(argv[++i]);
00167                             continue;
00168                      case 'R':            /* recover */
00169                             if (argv[i][2])
00170                                    break;
00171                             rvrlim = 0;
00172                      /* fall through */
00173                      case 'F':            /* syncronization file */
00174                             if (argv[i][2])
00175                                    break;
00176                             if ((syncfp =
00177               fdopen(open(argv[++i],O_RDWR|O_CREAT,0666),"r+")) == NULL) {
00178                                    fprintf(stderr, "%s: cannot open\n",
00179                                                  argv[i]);
00180                                    exit(1);
00181                             }
00182                             continue;
00183                      case 'z':            /* z-file ist verbotten */
00184                             fprintf(stderr, "%s: -z option not allowed\n",
00185                                           argv[0]);
00186                             exit(1);
00187                      case 'o':            /* output file */
00188                             if (argv[i][2])
00189                                    break;
00190                             outfile = argv[++i];
00191                             continue;
00192                      } else if (i >= argc-1)
00193                             break;
00194               rpargv[rpargc++] = argv[i];
00195        }
00196        if (i >= argc) {
00197               fprintf(stderr, "%s: missing octree argument\n", argv[0]);
00198               exit(1);
00199        }
00200        if (outfile == NULL) {
00201               fprintf(stderr, "%s: missing output file\n", argv[0]);
00202               exit(1);
00203        }
00204        init(argc, argv);
00205        rpiece();
00206        exit(cleanup(0));
00207 }
00208 
00209 
00210 static void
00211 dolock(              /* lock or unlock a file */
00212        int  fd,
00213        int  ltyp
00214 )
00215 {
00216        static struct flock  fls;   /* static so initialized to zeroes */
00217 
00218        fls.l_type = ltyp;
00219        if (fcntl(fd, F_SETLKW, &fls) < 0) {
00220               fprintf(stderr, "%s: cannot lock/unlock file: %s\n",
00221                             progname, strerror(errno));
00222               exit(1);
00223        }
00224 }
00225 
00226 
00227 static void
00228 init(                /* set up output file and start rpict */
00229        int  ac,
00230        char  **av
00231 )
00232 {
00233        static char  hrbuf[16], vrbuf[16];
00234        extern char  VersionID[];
00235        char  *err;
00236        FILE  *fp;
00237        int  hr, vr;
00238        SUBPROC  rpd; /* since we don't close_process(), this can be local */
00239                                    /* set up view */
00240        if ((err = setview(&ourview)) != NULL) {
00241               fprintf(stderr, "%s: %s\n", progname, err);
00242               exit(1);
00243        }
00244        if (syncfp != NULL) {
00245               sflock(F_RDLCK);
00246               fscanf(syncfp, "%d %d", &hmult, &vmult);
00247               sflock(F_UNLCK);
00248        }
00249                                    /* compute piece size */
00250        hres /= hmult;
00251        vres /= vmult;
00252        if (hres <= 0 || vres <= 0) {
00253               fprintf(stderr, "%s: illegal resolution/subdivision\n", progname);
00254               exit(1);
00255        }
00256        normaspect(viewaspect(&ourview)*hmult/vmult, &pixaspect, &hres, &vres);
00257        sprintf(hrbuf, "%d", hres);
00258        rpargv[rpargc++] = "-x"; rpargv[rpargc++] = hrbuf;
00259        sprintf(vrbuf, "%d", vres);
00260        rpargv[rpargc++] = "-y"; rpargv[rpargc++] = vrbuf;
00261        rpargv[rpargc++] = "-pa"; rpargv[rpargc++] = "0";
00262        rpargv[rpargc++] = av[ac-1];
00263        rpargv[rpargc] = NULL;
00264                                    /* open output file */
00265        if ((outfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0666)) >= 0) {
00266               dolock(outfd, F_WRLCK);
00267               if ((fp = fdopen(dup(outfd), "w")) == NULL)
00268                      goto filerr;
00269               newheader("RADIANCE", fp);  /* create header */
00270               printargs(ac, av, fp);
00271               fprintf(fp, "SOFTWARE= %s\n", VersionID);
00272               fputs(VIEWSTR, fp);
00273               fprintview(&ourview, fp);
00274               putc('\n', fp);
00275               if (pixaspect < .99 || pixaspect > 1.01)
00276                      fputaspect(pixaspect, fp);
00277               fputformat(COLRFMT, fp);
00278               putc('\n', fp);
00279               fprtresolu(hres*hmult, vres*vmult, fp);
00280        } else if ((outfd = open(outfile, O_RDWR)) >= 0) {
00281               dolock(outfd, F_RDLCK);
00282               if ((fp = fdopen(dup(outfd), "r+")) == NULL)
00283                      goto filerr;
00284               getheader(fp, NULL, NULL);  /* skip header */
00285               if (!fscnresolu(&hr, &vr, fp) ||   /* check resolution */
00286                             hr != hres*hmult || vr != vres*vmult) {
00287                      fprintf(stderr, "%s: resolution mismatch on file \"%s\"\n",
00288                                    progname, outfile);
00289                      exit(1);
00290               }
00291        } else {
00292               fprintf(stderr, "%s: cannot open file \"%s\"\n",
00293                             progname, outfile);
00294               exit(1);
00295        }
00296        scanorig = ftell(fp);              /* record position of first scanline */
00297        if (fclose(fp) == -1)              /* done with stream i/o */
00298               goto filerr;
00299        dolock(outfd, F_UNLCK);
00300                                    /* start rpict process */
00301        if (open_process(&rpd, rpargv) <= 0) {
00302               fprintf(stderr, "%s: cannot start %s\n", progname, rpargv[0]);
00303               exit(1);
00304        }
00305        if ((fromrp = fdopen(rpd.r, "r")) == NULL ||
00306                      (torp = fdopen(rpd.w, "w")) == NULL) {
00307               fprintf(stderr, "%s: cannot open stream to %s\n",
00308                             progname, rpargv[0]);
00309               exit(1);
00310        }
00311        if ((pbuf = (COLR *)bmalloc(hres*vres*sizeof(COLR))) == NULL) {
00312               fprintf(stderr, "%s: out of memory\n", progname);
00313               exit(1);
00314        }
00315        signal(SIGALRM, onalrm);
00316        if (timelim)
00317               alarm(timelim);
00318        return;
00319 filerr:
00320        fprintf(stderr, "%s: i/o error on file \"%s\"\n", progname, outfile);
00321        exit(1);
00322 }
00323 
00324 
00325 static int
00326 nextpiece(           /* get next piece assignment */
00327        int    *xp,
00328        int    *yp
00329 )
00330 {
00331        if (gotalrm)                /* someone wants us to quit */
00332               return(0);
00333        if (syncfp != NULL) {              /* use sync file */
00334               /*
00335                * So we don't necessarily have to lock and unlock the file
00336                * multiple times (very slow), we establish an exclusive
00337                * lock at the beginning on our synchronization file and
00338                * maintain it in the subroutine rvrpiece().
00339                */
00340               sflock(F_WRLCK);
00341               fseek(syncfp, 0L, 0);              /* read position */
00342               if (fscanf(syncfp, "%*d %*d %d %d", xp, yp) < 2) {
00343                      *xp = hmult-1;
00344                      *yp = vmult;
00345               }
00346               if (rvrlim == 0)            /* initialize recovery limit */
00347                      rvrlim = *xp*vmult + *yp;
00348               if (rvrpiece(xp, yp)) {            /* do stragglers first */
00349                      sflock(F_UNLCK);
00350                      return(1);
00351               }
00352               if (--(*yp) < 0) {          /* decrement position */
00353                      *yp = vmult-1;
00354                      if (--(*xp) < 0) {   /* all done */
00355                             sflock(F_UNLCK);
00356                             return(0);
00357                      }
00358               }
00359               fseek(syncfp, 0L, 0);              /* write new position */
00360               fprintf(syncfp, "%4d %4d\n%4d %4d\n\n", hmult, vmult, *xp, *yp);
00361               fflush(syncfp);
00362               sflock(F_UNLCK);            /* release sync file */
00363               return(1);
00364        }
00365        return(scanf("%d %d", xp, yp) == 2);      /* use stdin */
00366 }
00367 
00368 
00369 static int
00370 rvrpiece(            /* check for recoverable pieces */
00371        register int  *xp,
00372        register int  *yp
00373 )
00374 {
00375        static char  *pdone = NULL; /* which pieces are done */
00376        static long  readpos = -1;  /* how far we've read */
00377        register int  i;
00378        /*
00379         * This routine is called by nextpiece() with an
00380         * exclusive lock on syncfp and the file pointer at the
00381         * appropriate position to read in the finished pieces.
00382         */
00383        if (rvrlim < 0)
00384               return(0);           /* only check if asked */
00385        if (pdone == NULL)          /* first call */
00386               pdone = calloc(hmult*vmult, sizeof(char));
00387        if (pdone == NULL) {
00388               fprintf(stderr, "%s: out of memory\n", progname);
00389               exit(1);
00390        }
00391        if (readpos != -1)          /* mark what's been done */
00392               fseek(syncfp, readpos, 0);
00393        while (fscanf(syncfp, "%d %d", xp, yp) == 2)
00394               pdone[*xp*vmult+*yp] = 1;
00395        if (!feof(syncfp)) {
00396               fprintf(stderr, "%s: format error in sync file\n", progname);
00397               exit(1);
00398        }
00399        readpos = ftell(syncfp);
00400        i = hmult*vmult;            /* find an unaccounted for piece */
00401        while (i-- > rvrlim)
00402               if (!pdone[i]) {
00403                      *xp = i / vmult;
00404                      *yp = i % vmult;
00405                      pdone[i] = 1; /* consider it done */
00406                      return(1);
00407               }
00408        rvrlim = -1;                /* nothing left to recover */
00409        free(pdone);
00410        pdone = NULL;
00411        return(0);
00412 }
00413 
00414 
00415 static int
00416 cleanup(                    /* close rpict process and clean up */
00417        int  rstat
00418 )
00419 {
00420        int  status;
00421 
00422        bfree((char *)pbuf, hres*vres*sizeof(COLR));
00423        fclose(torp);
00424        fclose(fromrp);
00425        while (wait(&status) != -1)
00426               if (rstat == 0)
00427                      rstat = status>>8 & 0xff;
00428        return(rstat);
00429 }
00430 
00431 
00432 static void
00433 rpiece(void)                /* render picture piece by piece */
00434 {
00435        VIEW  pview;
00436        int  xorg, yorg;
00437                                    /* compute view parameters */
00438        pview = ourview;
00439        switch (ourview.type) {
00440        case VT_PER:
00441               pview.horiz = (2.*180./PI)*atan(
00442                             tan((PI/180./2.)*ourview.horiz)/hmult );
00443               pview.vert = (2.*180./PI)*atan(
00444                             tan((PI/180./2.)*ourview.vert)/vmult );
00445               break;
00446        case VT_PAR:
00447        case VT_ANG:
00448               pview.horiz = ourview.horiz / hmult;
00449               pview.vert = ourview.vert / vmult;
00450               break;
00451        case VT_CYL:
00452               pview.horiz = ourview.horiz / hmult;
00453               pview.vert = (2.*180./PI)*atan(
00454                             tan((PI/180./2.)*ourview.vert)/vmult );
00455               break;
00456        case VT_HEM:
00457               pview.horiz = (2.*180./PI)*asin(
00458                             sin((PI/180./2.)*ourview.horiz)/hmult );
00459               pview.vert = (2.*180./PI)*asin(
00460                             sin((PI/180./2.)*ourview.vert)/vmult );
00461               break;
00462        case VT_PLS:
00463               pview.horiz = sin((PI/180./2.)*ourview.horiz) /
00464                             (1.0 + cos((PI/180./2.)*ourview.horiz)) / hmult;
00465               pview.horiz *= pview.horiz;
00466               pview.horiz = (2.*180./PI)*acos((1. - pview.horiz) /
00467                                           (1. + pview.horiz));
00468               pview.vert = sin((PI/180./2.)*ourview.vert) /
00469                             (1.0 + cos((PI/180./2.)*ourview.vert)) / vmult;
00470               pview.vert *= pview.vert;
00471               pview.vert = (2.*180./PI)*acos((1. - pview.vert) /
00472                                           (1. + pview.vert));
00473               break;
00474        default:
00475               fprintf(stderr, "%s: unknown view type '-vt%c'\n",
00476                             progname, ourview.type);
00477               exit(cleanup(1));
00478        }
00479                                    /* render each piece */
00480        while (nextpiece(&xorg, &yorg)) {
00481               pview.hoff = ourview.hoff*hmult + xorg - 0.5*(hmult-1);
00482               pview.voff = ourview.voff*vmult + yorg - 0.5*(vmult-1);
00483               fputs(VIEWSTR, torp);
00484               fprintview(&pview, torp);
00485               putc('\n', torp);
00486               fflush(torp);               /* assigns piece to rpict */
00487               putpiece(xorg, yorg);              /* place piece in output */
00488        }
00489 }
00490 
00491 
00492 static int
00493 putpiece(            /* get next piece from rpict */
00494 int    xpos,
00495 int    ypos
00496 )
00497 {
00498        struct flock  fls;
00499        int  pid, status;
00500        int  hr, vr;
00501        register int  y;
00502                             /* check bounds */
00503        if ((xpos < 0) | (ypos < 0) | (xpos >= hmult) | (ypos >= vmult)) {
00504               fprintf(stderr, "%s: requested piece (%d,%d) out of range\n",
00505                             progname, xpos, ypos);
00506               exit(cleanup(1));
00507        }
00508                             /* check header from rpict */
00509        guard_io();
00510        getheader(fromrp, NULL, NULL);
00511        if (!fscnresolu(&hr, &vr, fromrp) || (hr != hres) | (vr != vres)) {
00512               fprintf(stderr, "%s: resolution mismatch from %s\n",
00513                             progname, rpargv[0]);
00514               exit(cleanup(1));
00515        }
00516        if (verbose) {                            /* notify caller */
00517               printf("%d %d begun\n", xpos, ypos);
00518               fflush(stdout);
00519        }
00520        unguard();
00521                             /* load new piece into buffer */
00522        for (y = 0; y < vr; y++) {
00523               guard_io();
00524               if (freadcolrs(pbuf+y*hr, hr, fromrp) < 0) {
00525                      fprintf(stderr, "%s: read error from %s\n",
00526                                    progname, rpargv[0]);
00527                      exit(cleanup(1));
00528               }
00529               unguard();
00530        }
00531 #if MAXFORK
00532                             /* fork so we don't slow rpict down */
00533        if ((pid = fork()) > 0) {
00534               if (++nforked >= MAXFORK) {
00535                      wait(&status);              /* reap a child */
00536                      if (status)
00537                             exit(cleanup(status>>8 & 0xff));
00538                      nforked--;
00539               }
00540               return(pid);
00541        }
00542 #else
00543        pid = -1;            /* no forking */
00544 #endif
00545        fls.l_start = scanorig +
00546               ((long)(vmult-1-ypos)*vres*hmult+xpos)*hres*sizeof(COLR);
00547 #if NFS
00548        fls.l_len = ((long)(vres-1)*hmult+1)*hres*sizeof(COLR);
00549                             /* lock file section so NFS doesn't mess up */
00550        fls.l_whence = 0;
00551        fls.l_type = F_WRLCK;
00552        if (fcntl(outfd, F_SETLKW, &fls) < 0)
00553               filerr("lock");
00554 #endif
00555                             /* write new piece to file */
00556        if (lseek(outfd, (off_t)fls.l_start, SEEK_SET) < 0)
00557               filerr("seek");
00558        if (hmult == 1) {
00559               if (writebuf(outfd, (char *)pbuf,
00560                             vr*hr*sizeof(COLR)) != vr*hr*sizeof(COLR))
00561                      filerr("write");
00562        } else
00563               for (y = 0; y < vr; y++) {
00564                      if (writebuf(outfd, (char *)(pbuf+y*hr),
00565                                    hr*sizeof(COLR)) != hr*sizeof(COLR))
00566                             filerr("write");
00567                      if (y < vr-1 && lseek(outfd,
00568                                    (off_t)(hmult-1)*hr*sizeof(COLR),
00569                                    SEEK_CUR) < 0)
00570                             filerr("seek");
00571               }
00572 #if NFS
00573        fls.l_type = F_UNLCK;              /* release lock */
00574        if (fcntl(outfd, F_SETLKW, &fls) < 0)
00575               filerr("lock");
00576 #endif
00577        if (verbose) {                            /* notify caller */
00578               printf("%d %d done\n", xpos, ypos);
00579               fflush(stdout);
00580        }
00581        if (syncfp != NULL) {                     /* record what's been done */
00582               sflock(F_WRLCK);
00583               fseek(syncfp, 0L, 2);              /* append index */
00584               fprintf(syncfp, "%4d %4d\n", xpos, ypos);
00585               fflush(syncfp);
00586                             /*** Unlock not necessary, since
00587               sflock(F_UNLCK);     _exit() or nextpiece() is next ***/
00588        }
00589        if (pid == -1)              /* didn't fork or fork failed */
00590               return(0);
00591        _exit(0);            /* else exit child process (releasing locks) */
00592 }
00593 
00594 
00595 static void
00596 filerr(                     /* report file error and exit */
00597        char  *t
00598 )
00599 {
00600        fprintf(stderr, "%s: %s error on file \"%s\": %s\n",
00601                      progname, t, outfile, strerror(errno));
00602        _exit(1);
00603 }
00604 
00605 #endif