Back to index

radiance  4R0+20100331
rpict.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: rpict.c,v 2.81 2009/05/11 21:46:31 greg Exp $";
00003 #endif
00004 /*
00005  *  rpict.c - routines and variables for picture generation.
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include  <sys/types.h>
00011 
00012 #include  "platform.h"
00013 #ifdef NON_POSIX
00014  #ifdef MINGW
00015   #include  <sys/time.h>
00016  #endif
00017 #else
00018  #ifdef BSD
00019   #include  <sys/time.h>
00020   #include  <sys/resource.h>
00021  #else
00022   #include  <sys/times.h>
00023   #include  <unistd.h>
00024  #endif
00025 #endif
00026 
00027 #include  <time.h>
00028 #include  <signal.h>
00029 
00030 #include  "ray.h"
00031 #include  "paths.h"
00032 #include  "ambient.h"
00033 #include  "view.h"
00034 #include  "random.h"
00035 #include  "paths.h"
00036 #include  "rtmisc.h" /* myhostname() */
00037 
00038 
00039 #define        RFTEMPLATE   "rfXXXXXX"
00040 
00041 #ifndef SIGCONT
00042 #ifdef SIGIO     /* XXX can we live without this? */
00043 #define SIGCONT             SIGIO
00044 #endif
00045 #endif
00046 
00047 CUBE  thescene;                           /* our scene */
00048 OBJECT nsceneobjs;                 /* number of objects in our scene */
00049 
00050 int  dimlist[MAXDIM];                     /* sampling dimensions */
00051 int  ndims = 0;                           /* number of sampling dimensions */
00052 int  samplendx;                           /* sample index number */
00053 
00054 //extern void  ambnotify();
00055 void  (*addobjnotify[])() = {ambnotify, NULL};
00056 
00057 VIEW  ourview = STDVIEW;           /* view parameters */
00058 int  hresolu = 512;                /* horizontal resolution */
00059 int  vresolu = 512;                /* vertical resolution */
00060 double pixaspect = 1.0;            /* pixel aspect ratio */
00061 
00062 int  psample = 4;                  /* pixel sample size */
00063 double maxdiff = .05;                     /* max. difference for interpolation */
00064 double dstrpix = 0.67;                    /* square pixel distribution */
00065 
00066 double  mblur = 0.;                /* motion blur parameter */
00067 
00068 double  dblur = 0.;                /* depth-of-field blur parameter */
00069 
00070 void  (*trace)() = NULL;           /* trace call */
00071 
00072 int  do_irrad = 0;                 /* compute irradiance? */
00073 
00074 int  rand_samp = 0;                /* pure Monte Carlo sampling? */
00075 
00076 double dstrsrc = 0.0;                     /* square source distribution */
00077 double shadthresh = .05;           /* shadow threshold */
00078 double shadcert = .5;                     /* shadow certainty */
00079 int  directrelay = 1;                     /* number of source relays */
00080 int  vspretest = 512;                     /* virtual source pretest density */
00081 int  directvis = 1;                /* sources visible? */
00082 double srcsizerat = .25;           /* maximum ratio source size/dist. */
00083 
00084 COLOR  cextinction = BLKCOLOR;            /* global extinction coefficient */
00085 COLOR  salbedo = BLKCOLOR;         /* global scattering albedo */
00086 double  seccg = 0.;                /* global scattering eccentricity */
00087 double  ssampdist = 0.;                   /* scatter sampling distance */
00088 
00089 double specthresh = .15;           /* specular sampling threshold */
00090 double specjitter = 1.;            /* specular sampling jitter */
00091 
00092 int  backvis = 1;                  /* back face visibility */
00093 
00094 int  maxdepth = 7;                 /* maximum recursion depth */
00095 double minweight = 4e-3;           /* minimum ray weight */
00096 
00097 char  *ambfile = NULL;                    /* ambient file name */
00098 COLOR  ambval = BLKCOLOR;          /* ambient value */
00099 int  ambvwt = 0;                   /* initial weight for ambient value */
00100 double ambacc = 0.2;               /* ambient accuracy */
00101 int  ambres = 64;                  /* ambient resolution */
00102 int  ambdiv = 512;                 /* ambient divisions */
00103 int  ambssamp = 128;               /* ambient super-samples */
00104 int  ambounce = 0;                 /* ambient bounces */
00105 char  *amblist[AMBLLEN];           /* ambient include/exclude list */
00106 int  ambincl = -1;                 /* include == 1, exclude == 0 */
00107 
00108 int  ralrm = 0;                           /* seconds between reports */
00109 
00110 double pctdone = 0.0;                     /* percentage done */
00111 time_t  tlastrept = 0L;                   /* time at last report */
00112 time_t  tstart;                           /* starting time */
00113 
00114 #define        MAXDIV              16            /* maximum sample size */
00115 
00116 #define        pixjitter()  (.5+dstrpix*(.5-frandom()))
00117 
00118 int  hres, vres;                   /* resolution for this frame */
00119 
00120 static VIEW   lastview;            /* the previous view input */
00121 
00122 //extern char  *mktemp();  /* XXX should be in stdlib.h or unistd.h */
00123 
00124 //double      pixvalue();
00125 
00126 static void report(int);
00127 static int nextview(FILE *fp);
00128 static void render(char *zfile, char *oldfile);
00129 static void fillscanline(COLOR *scanline, float *zline, char *sd, int xres,
00130               int y, int xstep);
00131 static void fillscanbar(COLOR *scanbar[], float *zbar[], int xres,
00132               int y, int ysize);
00133 static int fillsample(COLOR *colline, float *zline, int x, int y,
00134               int xlen, int ylen, int b);
00135 static double pixvalue(COLOR  col, int  x, int  y);
00136 static int salvage(char  *oldfile);
00137 static int pixnumber(int  x, int  y, int  xres, int  yres);
00138 
00139 
00140 
00141 #ifdef RHAS_STAT
00142 #include  <sys/types.h>
00143 #include  <sys/stat.h>
00144 int
00145 file_exists(fname)                        /* ordinary file exists? */
00146 char  *fname;
00147 {
00148        struct stat  sbuf;
00149        if (stat(fname, &sbuf) < 0) return(0);
00150        return((sbuf.st_mode & S_IFREG) != 0);
00151 }
00152 #else
00153 #define  file_exists(f)     (access(f,F_OK)==0)
00154 #endif
00155 
00156 
00157 void
00158 quit(code)                  /* quit program */
00159 int  code;
00160 {
00161        if (code)                   /* report status */
00162               report(0);
00163 #ifndef NON_POSIX
00164        headclean();                /* delete header file */
00165        pfclean();                  /* clean up persist files */
00166 #endif
00167        exit(code);
00168 }
00169 
00170 
00171 #ifndef NON_POSIX
00172 static void
00173 report(int dummy)           /* report progress */
00174 {
00175        double  u, s;
00176 #ifdef BSD
00177        struct rusage  rubuf;
00178 #else
00179        struct tms  tbuf;
00180        double  period;
00181 #endif
00182 
00183        tlastrept = time((time_t *)NULL);
00184 #ifdef BSD
00185        getrusage(RUSAGE_SELF, &rubuf);
00186        u = rubuf.ru_utime.tv_sec + rubuf.ru_utime.tv_usec/1e6;
00187        s = rubuf.ru_stime.tv_sec + rubuf.ru_stime.tv_usec/1e6;
00188        getrusage(RUSAGE_CHILDREN, &rubuf);
00189        u += rubuf.ru_utime.tv_sec + rubuf.ru_utime.tv_usec/1e6;
00190        s += rubuf.ru_stime.tv_sec + rubuf.ru_stime.tv_usec/1e6;
00191 #else
00192        times(&tbuf);
00193 #ifdef _SC_CLK_TCK
00194        period = 1.0 / sysconf(_SC_CLK_TCK);
00195 #else
00196        period = 1.0 / 60.0;
00197 #endif
00198        u = ( tbuf.tms_utime + tbuf.tms_cutime ) * period;
00199        s = ( tbuf.tms_stime + tbuf.tms_cstime ) * period;
00200 #endif
00201 
00202        sprintf(errmsg,
00203               "%lu rays, %4.2f%% after %.3fu %.3fs %.3fr hours on %s\n",
00204                      nrays, pctdone, u/3600., s/3600.,
00205                      (tlastrept-tstart)/3600., myhostname());
00206        eputs(errmsg);
00207 #ifdef SIGCONT
00208        signal(SIGCONT, report);
00209 #endif
00210 }
00211 #else
00212 static void
00213 report(int dummy)           /* report progress */
00214 {
00215        tlastrept = time((time_t *)NULL);
00216        sprintf(errmsg, "%lu rays, %4.2f%% after %5.4f hours\n",
00217                      nrays, pctdone, (tlastrept-tstart)/3600.0);
00218        eputs(errmsg);
00219 }
00220 #endif
00221 
00222 
00223 extern void
00224 rpict(               /* generate image(s) */
00225        int  seq,
00226        char  *pout,
00227        char  *zout,
00228        char  *prvr
00229 )
00230 /*
00231  * If seq is greater than zero, then we will render a sequence of
00232  * images based on view parameter strings read from the standard input.
00233  * If pout is NULL, then all images will be sent to the standard ouput.
00234  * If seq is greater than zero and prvr is an integer, then it is the
00235  * frame number at which rendering should begin.  Preceeding view parameter
00236  * strings will be skipped in the input.
00237  * If pout and prvr are the same, prvr is renamed to avoid overwriting.
00238  * Note that pout and zout should contain %d format specifications for
00239  * sequenced file naming.
00240  */
00241 {
00242        char  fbuf[128], fbuf2[128];
00243        int  npicts;
00244        register char  *cp;
00245        RESOLU rs;
00246        double pa;
00247                                    /* check sampling */
00248        if (psample < 1)
00249               psample = 1;
00250        else if (psample > MAXDIV) {
00251               sprintf(errmsg, "pixel sampling reduced from %d to %d",
00252                             psample, MAXDIV);
00253               error(WARNING, errmsg);
00254               psample = MAXDIV;
00255        }
00256                                    /* get starting frame */
00257        if (seq <= 0)
00258               seq = 0;
00259        else if (prvr != NULL && isint(prvr)) {
00260               register int  rn;           /* skip to specified view */
00261               if ((rn = atoi(prvr)) < seq)
00262                      error(USER, "recover frame less than start frame");
00263               if (pout == NULL)
00264                      error(USER, "missing output file specification");
00265               for ( ; seq < rn; seq++)
00266                      if (nextview(stdin) == EOF)
00267                             error(USER, "unexpected EOF on view input");
00268               setview(&ourview);
00269               prvr = fbuf;                /* mark for renaming */
00270        }
00271        if ((pout != NULL) & (prvr != NULL)) {
00272               sprintf(fbuf, pout, seq);
00273               if (!strcmp(prvr, fbuf)) {  /* rename */
00274                      strcpy(fbuf2, fbuf);
00275                      for (cp = fbuf2; *cp; cp++)
00276                             ;
00277                      while (cp > fbuf2 && !ISDIRSEP(cp[-1]))
00278                             cp--;
00279                      strcpy(cp, RFTEMPLATE);
00280                      prvr = mktemp(fbuf2);
00281                      if (rename(fbuf, prvr) < 0) {
00282                             if (errno == ENOENT) {      /* ghost file */
00283                                    sprintf(errmsg,
00284                                           "new output file \"%s\"",
00285                                           fbuf);
00286                                    error(WARNING, errmsg);
00287                                    prvr = NULL;
00288                             } else {             /* serious error */
00289                                    sprintf(errmsg,
00290                                    "cannot rename \"%s\" to \"%s\"",
00291                                           fbuf, prvr);
00292                                    error(SYSTEM, errmsg);
00293                             }
00294                      }
00295               }
00296        }
00297        npicts = 0;                 /* render sequence */
00298        do {
00299               if (seq && nextview(stdin) == EOF)
00300                      break;
00301               pctdone = 0.0;
00302               if (pout != NULL) {
00303                      sprintf(fbuf, pout, seq);
00304                      if (file_exists(fbuf)) {
00305                             if (prvr != NULL || !strcmp(fbuf, pout)) {
00306                                    sprintf(errmsg,
00307                                           "output file \"%s\" exists",
00308                                           fbuf);
00309                                    error(USER, errmsg);
00310                             }
00311                             setview(&ourview);
00312                             continue;            /* don't clobber */
00313                      }
00314                      if (freopen(fbuf, "w", stdout) == NULL) {
00315                             sprintf(errmsg,
00316                                    "cannot open output file \"%s\"", fbuf);
00317                             error(SYSTEM, errmsg);
00318                      }
00319                      SET_FILE_BINARY(stdout);
00320                      dupheader();
00321               }
00322               hres = hresolu; vres = vresolu; pa = pixaspect;
00323               if (prvr != NULL) {
00324                      if (viewfile(prvr, &ourview, &rs) <= 0) {
00325                             sprintf(errmsg,
00326                      "cannot recover view parameters from \"%s\"", prvr);
00327                             error(WARNING, errmsg);
00328                      } else {
00329                             pa = 0.0;
00330                             hres = scanlen(&rs);
00331                             vres = numscans(&rs);
00332                      }
00333               }
00334               if ((cp = setview(&ourview)) != NULL)
00335                      error(USER, cp);
00336               normaspect(viewaspect(&ourview), &pa, &hres, &vres);
00337               if (seq) {
00338                      if (ralrm > 0) {
00339                             fprintf(stderr, "FRAME %d:", seq);
00340                             fprintview(&ourview, stderr);
00341                             putc('\n', stderr);
00342                             fflush(stderr);
00343                      }
00344                      printf("FRAME=%d\n", seq);
00345               }
00346               fputs(VIEWSTR, stdout);
00347               fprintview(&ourview, stdout);
00348               putchar('\n');
00349               if (pa < .99 || pa > 1.01)
00350                      fputaspect(pa, stdout);
00351               fputnow(stdout);
00352               fputformat(COLRFMT, stdout);
00353               putchar('\n');
00354               if (zout != NULL)
00355                      sprintf(cp=fbuf, zout, seq);
00356               else
00357                      cp = NULL;
00358               render(cp, prvr);
00359               prvr = NULL;
00360               npicts++;
00361        } while (seq++);
00362                                    /* check that we did something */
00363        if (npicts == 0)
00364               error(WARNING, "no output produced");
00365 }
00366 
00367 
00368 static int
00369 nextview(                          /* get next view from fp */
00370        FILE  *fp
00371 )
00372 {
00373        char  linebuf[256];
00374 
00375        lastview = ourview;
00376        while (fgets(linebuf, sizeof(linebuf), fp) != NULL)
00377               if (isview(linebuf) && sscanview(&ourview, linebuf) > 0)
00378                      return(0);
00379        return(EOF);
00380 }      
00381 
00382 
00383 static void
00384 render(                            /* render the scene */
00385        char  *zfile,
00386        char  *oldfile
00387 )
00388 {
00389        COLOR  *scanbar[MAXDIV+1];  /* scanline arrays of pixel values */
00390        float  *zbar[MAXDIV+1];            /* z values */
00391        char  *sampdens;            /* previous sample density */
00392        int  ypos;                  /* current scanline */
00393        int  ystep;                 /* current y step size */
00394        int  hstep;                 /* h step size */
00395        int  zfd;
00396        COLOR  *colptr;
00397        float  *zptr;
00398        register int  i;
00399                                    /* check for empty image */
00400        if (hres <= 0 || vres <= 0) {
00401               error(WARNING, "empty output picture");
00402               fprtresolu(0, 0, stdout);
00403               return;
00404        }
00405                                    /* allocate scanlines */
00406        for (i = 0; i <= psample; i++) {
00407               scanbar[i] = (COLOR *)malloc(hres*sizeof(COLOR));
00408               if (scanbar[i] == NULL)
00409                      goto memerr;
00410        }
00411        hstep = (psample*140+49)/99;              /* quincunx sampling */
00412        ystep = (psample*99+70)/140;
00413        if (hstep > 2) {
00414               i = hres/hstep + 2;
00415               if ((sampdens = (char *)malloc(i)) == NULL)
00416                      goto memerr;
00417               while (i--)
00418                      sampdens[i] = hstep;
00419        } else
00420               sampdens = NULL;
00421                                    /* open z-file */
00422        if (zfile != NULL) {
00423               if ((zfd = open(zfile, O_WRONLY|O_CREAT, 0666)) == -1) {
00424                      sprintf(errmsg, "cannot open z-file \"%s\"", zfile);
00425                      error(SYSTEM, errmsg);
00426               }
00427               SET_FD_BINARY(zfd);
00428               for (i = 0; i <= psample; i++) {
00429                      zbar[i] = (float *)malloc(hres*sizeof(float));
00430                      if (zbar[i] == NULL)
00431                             goto memerr;
00432               }
00433        } else {
00434               zfd = -1;
00435               for (i = 0; i <= psample; i++)
00436                      zbar[i] = NULL;
00437        }
00438                                    /* write out boundaries */
00439        fprtresolu(hres, vres, stdout);
00440                                    /* recover file and compute first */
00441        i = salvage(oldfile);
00442        if (i >= vres)
00443               goto alldone;
00444        if (zfd != -1 && i > 0 &&
00445                      lseek(zfd, (off_t)i*hres*sizeof(float), SEEK_SET) < 0)
00446               error(SYSTEM, "z-file seek error in render");
00447        pctdone = 100.0*i/vres;
00448        if (ralrm > 0)                     /* report init stats */
00449               report(0);
00450 #ifdef SIGCONT
00451        else
00452        signal(SIGCONT, report);
00453 #endif
00454        ypos = vres-1 - i;                 /* initialize sampling */
00455        if (directvis)
00456               init_drawsources(psample);
00457        fillscanline(scanbar[0], zbar[0], sampdens, hres, ypos, hstep);
00458                                           /* compute scanlines */
00459        for (ypos -= ystep; ypos > -ystep; ypos -= ystep) {
00460                                                  /* bottom adjust? */
00461               if (ypos < 0) {
00462                      ystep += ypos;
00463                      ypos = 0;
00464               }
00465               colptr = scanbar[ystep];           /* move base to top */
00466               scanbar[ystep] = scanbar[0];
00467               scanbar[0] = colptr;
00468               zptr = zbar[ystep];
00469               zbar[ystep] = zbar[0];
00470               zbar[0] = zptr;
00471                                                  /* fill base line */
00472               fillscanline(scanbar[0], zbar[0], sampdens,
00473                             hres, ypos, hstep);
00474                                                  /* fill bar */
00475               fillscanbar(scanbar, zbar, hres, ypos, ystep);
00476               if (directvis)                            /* add bitty sources */
00477                      drawsources(scanbar, zbar, 0, hres, ypos, ystep);
00478                                                  /* write it out */
00479 #ifdef SIGCONT
00480               signal(SIGCONT, SIG_IGN);   /* don't interrupt writes */
00481 #endif
00482               for (i = ystep; i > 0; i--) {
00483                      if (zfd != -1 && write(zfd, (char *)zbar[i],
00484                                    hres*sizeof(float))
00485                                    < hres*sizeof(float))
00486                             goto writerr;
00487                      if (fwritescan(scanbar[i], hres, stdout) < 0)
00488                             goto writerr;
00489               }
00490               if (fflush(stdout) == EOF)
00491                      goto writerr;
00492                                                  /* record progress */
00493               pctdone = 100.0*(vres-1-ypos)/vres;
00494               if (ralrm > 0 && time((time_t *)NULL) >= tlastrept+ralrm)
00495                      report(0);
00496 #ifdef SIGCONT
00497               else
00498                      signal(SIGCONT, report);
00499 #endif
00500        }
00501                                           /* clean up */
00502 #ifdef SIGCONT
00503        signal(SIGCONT, SIG_IGN);
00504 #endif
00505        if (zfd != -1 && write(zfd, (char *)zbar[0], hres*sizeof(float))
00506                             < hres*sizeof(float))
00507               goto writerr;
00508        fwritescan(scanbar[0], hres, stdout);
00509        if (fflush(stdout) == EOF)
00510               goto writerr;
00511 alldone:
00512        if (zfd != -1) {
00513               if (close(zfd) == -1)
00514                      goto writerr;
00515               for (i = 0; i <= psample; i++)
00516                      free((void *)zbar[i]);
00517        }
00518        for (i = 0; i <= psample; i++)
00519               free((void *)scanbar[i]);
00520        if (sampdens != NULL)
00521               free(sampdens);
00522        pctdone = 100.0;
00523        if (ralrm > 0)
00524               report(0);
00525 #ifdef SIGCONT
00526        signal(SIGCONT, SIG_DFL);
00527 #endif
00528        return;
00529 writerr:
00530        error(SYSTEM, "write error in render");
00531 memerr:
00532        error(SYSTEM, "out of memory in render");
00533 }
00534 
00535 
00536 static void
00537 fillscanline( /* fill scan at y */
00538        register COLOR       *scanline,
00539        register float       *zline,
00540        register char  *sd,
00541        int  xres,
00542        int  y,
00543        int  xstep
00544 )
00545 {
00546        static int  nc = 0;         /* number of calls */
00547        int  bl = xstep, b = xstep;
00548        double z;
00549        register int  i;
00550 
00551        z = pixvalue(scanline[0], 0, y);
00552        if (zline) zline[0] = z;
00553                             /* zig-zag start for quincunx pattern */
00554        for (i = ++nc & 1 ? xstep : xstep/2; i < xres-1+xstep; i += xstep) {
00555               if (i >= xres) {
00556                      xstep += xres-1-i;
00557                      i = xres-1;
00558               }
00559               z = pixvalue(scanline[i], i, y);
00560               if (zline) zline[i] = z;
00561               if (sd) b = sd[0] > sd[1] ? sd[0] : sd[1];
00562               if (i <= xstep)
00563                      b = fillsample(scanline, zline, 0, y, i, 0, b/2);
00564               else
00565                      b = fillsample(scanline+i-xstep,
00566                                    zline ? zline+i-xstep : (float *)NULL,
00567                                    i-xstep, y, xstep, 0, b/2);
00568               if (sd) *sd++ = nc & 1 ? bl : b;
00569               bl = b;
00570        }
00571        if (sd && nc & 1) *sd = bl;
00572 }
00573 
00574 
00575 static void
00576 fillscanbar(  /* fill interior */
00577        register COLOR       *scanbar[],
00578        register float       *zbar[],
00579        int  xres,
00580        int  y,
00581        int  ysize
00582 )
00583 {
00584        COLOR  vline[MAXDIV+1];
00585        float  zline[MAXDIV+1];
00586        int  b = ysize;
00587        register int  i, j;
00588 
00589        for (i = 0; i < xres; i++) {
00590               copycolor(vline[0], scanbar[0][i]);
00591               copycolor(vline[ysize], scanbar[ysize][i]);
00592               if (zbar[0]) {
00593                      zline[0] = zbar[0][i];
00594                      zline[ysize] = zbar[ysize][i];
00595               }
00596               b = fillsample(vline, zbar[0] ? zline : (float *)NULL,
00597                             i, y, 0, ysize, b/2);
00598 
00599               for (j = 1; j < ysize; j++)
00600                      copycolor(scanbar[j][i], vline[j]);
00601               if (zbar[0])
00602                      for (j = 1; j < ysize; j++)
00603                             zbar[j][i] = zline[j];
00604        }
00605 }
00606 
00607 
00608 static int
00609 fillsample( /* fill interior points */
00610        register COLOR       *colline,
00611        register float       *zline,
00612        int  x,
00613        int  y,
00614        int  xlen,
00615        int  ylen,
00616        int  b
00617 )
00618 {
00619        double ratio;
00620        double z;
00621        COLOR  ctmp;
00622        int  ncut;
00623        register int  len;
00624 
00625        if (xlen > 0)               /* x or y length is zero */
00626               len = xlen;
00627        else
00628               len = ylen;
00629 
00630        if (len <= 1)               /* limit recursion */
00631               return(0);
00632 
00633        if (b > 0 ||
00634        (zline && 2.*fabs(zline[0]-zline[len]) > maxdiff*(zline[0]+zline[len]))
00635                      || bigdiff(colline[0], colline[len], maxdiff)) {
00636 
00637               z = pixvalue(colline[len>>1], x + (xlen>>1), y + (ylen>>1));
00638               if (zline) zline[len>>1] = z;
00639               ncut = 1;
00640        } else {                                  /* interpolate */
00641               copycolor(colline[len>>1], colline[len]);
00642               ratio = (double)(len>>1) / len;
00643               scalecolor(colline[len>>1], ratio);
00644               if (zline) zline[len>>1] = zline[len] * ratio;
00645               ratio = 1.0 - ratio;
00646               copycolor(ctmp, colline[0]);
00647               scalecolor(ctmp, ratio);
00648               addcolor(colline[len>>1], ctmp);
00649               if (zline) zline[len>>1] += zline[0] * ratio;
00650               ncut = 0;
00651        }
00652                                                  /* recurse */
00653        ncut += fillsample(colline, zline, x, y, xlen>>1, ylen>>1, (b-1)/2);
00654 
00655        ncut += fillsample(colline+(len>>1),
00656                      zline ? zline+(len>>1) : (float *)NULL,
00657                      x+(xlen>>1), y+(ylen>>1),
00658                      xlen-(xlen>>1), ylen-(ylen>>1), b/2);
00659 
00660        return(ncut);
00661 }
00662 
00663 
00664 static double
00665 pixvalue(            /* compute pixel value */
00666        COLOR  col,                 /* returned color */
00667        int  x,                     /* pixel position */
00668        int  y
00669 )
00670 {
00671        RAY  thisray;
00672        FVECT  lorg, ldir;
00673        double hpos, vpos, vdist, lmax;
00674        register int  i;
00675                                           /* compute view ray */
00676        hpos = (x+pixjitter())/hres;
00677        vpos = (y+pixjitter())/vres;
00678        if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir,
00679                                    &ourview, hpos, vpos)) < -FTINY) {
00680               setcolor(col, 0.0, 0.0, 0.0);
00681               return(0.0);
00682        }
00683        vdist = ourview.vdist;
00684                                           /* set pixel index */
00685        samplendx = pixnumber(x,y,hres,vres);
00686                                           /* optional motion blur */
00687        if (lastview.type && mblur > FTINY && (lmax = viewray(lorg, ldir,
00688                                    &lastview, hpos, vpos)) >= -FTINY) {
00689               register double  d = mblur*(.5-urand(281+samplendx));
00690 
00691               thisray.rmax = (1.-d)*thisray.rmax + d*lmax;
00692               for (i = 3; i--; ) {
00693                      thisray.rorg[i] = (1.-d)*thisray.rorg[i] + d*lorg[i];
00694                      thisray.rdir[i] = (1.-d)*thisray.rdir[i] + d*ldir[i];
00695               }
00696               if (normalize(thisray.rdir) == 0.0)
00697                      return(0.0);
00698               vdist = (1.-d)*vdist + d*lastview.vdist;
00699        }
00700                                           /* optional depth-of-field */
00701        if (dblur > FTINY && vdist > FTINY) {
00702               double  vc, dfh, dfv;
00703                                           /* square/circle conv. */
00704               dfh = vc = frandom();
00705               dfv = frandom();
00706               dfh *= .5*dblur*sqrt(1. - .5*dfv*dfv);
00707               dfv *= .5*dblur*sqrt(1. - .5*vc*vc);
00708               if (ourview.type == VT_PER || ourview.type == VT_PAR) {
00709                      dfh /= sqrt(ourview.hn2);
00710                      dfv /= sqrt(ourview.vn2);
00711                      for (i = 3; i--; ) {
00712                             vc = thisray.rorg[i] + vdist*thisray.rdir[i];
00713                             thisray.rorg[i] += dfh*ourview.hvec[i] +
00714                                                  dfv*ourview.vvec[i] ;
00715                             thisray.rdir[i] = vc - thisray.rorg[i];
00716                      }
00717               } else {                    /* non-standard view case */
00718                      double dfd = PI/4.*dblur*(.5 - frandom());
00719                      if (ourview.type != VT_ANG && ourview.type != VT_PLS) {
00720                             if (ourview.type != VT_CYL)
00721                                    dfh /= sqrt(ourview.hn2);
00722                             dfv /= sqrt(ourview.vn2);
00723                      }
00724                      for (i = 3; i--; ) {
00725                             vc = thisray.rorg[i] + vdist*thisray.rdir[i];
00726                             thisray.rorg[i] += dfh*ourview.hvec[i] +
00727                                                  dfv*ourview.vvec[i] +
00728                                                  dfd*ourview.vdir[i] ;
00729                             thisray.rdir[i] = vc - thisray.rorg[i];
00730                      }
00731               }
00732               if (normalize(thisray.rdir) == 0.0)
00733                      return(0.0);
00734        }
00735 
00736        rayorigin(&thisray, PRIMARY, NULL, NULL);
00737 
00738        rayvalue(&thisray);                /* trace ray */
00739 
00740        copycolor(col, thisray.rcol);             /* return color */
00741 
00742        return(thisray.rt);                /* return distance */
00743 }
00744 
00745 
00746 static int
00747 salvage(             /* salvage scanlines from killed program */
00748        char  *oldfile
00749 )
00750 {
00751        COLR  *scanline;
00752        FILE  *fp;
00753        int  x, y;
00754 
00755        if (oldfile == NULL)
00756               goto gotzip;
00757 
00758        if ((fp = fopen(oldfile, "r")) == NULL) {
00759               sprintf(errmsg, "cannot open recover file \"%s\"", oldfile);
00760               error(WARNING, errmsg);
00761               goto gotzip;
00762        }
00763        SET_FILE_BINARY(fp);
00764                             /* discard header */
00765        getheader(fp, NULL, NULL);
00766                             /* get picture size */
00767        if (!fscnresolu(&x, &y, fp)) {
00768               sprintf(errmsg, "bad recover file \"%s\" - not removed",
00769                             oldfile);
00770               error(WARNING, errmsg);
00771               fclose(fp);
00772               goto gotzip;
00773        }
00774 
00775        if (x != hres || y != vres) {
00776               sprintf(errmsg, "resolution mismatch in recover file \"%s\"",
00777                             oldfile);
00778               error(USER, errmsg);
00779        }
00780 
00781        scanline = (COLR *)malloc(hres*sizeof(COLR));
00782        if (scanline == NULL)
00783               error(SYSTEM, "out of memory in salvage");
00784        for (y = 0; y < vres; y++) {
00785               if (freadcolrs(scanline, hres, fp) < 0)
00786                      break;
00787               if (fwritecolrs(scanline, hres, stdout) < 0)
00788                      goto writerr;
00789        }
00790        if (fflush(stdout) == EOF)
00791               goto writerr;
00792        free((void *)scanline);
00793        fclose(fp);
00794        unlink(oldfile);
00795        return(y);
00796 gotzip:
00797        if (fflush(stdout) == EOF)
00798               error(SYSTEM, "error writing picture header");
00799        return(0);
00800 writerr:
00801        sprintf(errmsg, "write error during recovery of \"%s\"", oldfile);
00802        error(SYSTEM, errmsg);
00803        return -1; /* pro forma return */
00804 }
00805 
00806 static int
00807 pixnumber(           /* compute pixel index (brushed) */
00808        register int  x,
00809        register int  y,
00810        int  xres,
00811        int  yres
00812 )
00813 {
00814        x -= y;
00815        while (x < 0)
00816               x += xres;
00817        return((((x>>2)*yres + y) << 2) + (x & 3));
00818 }