home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 8 / CDASC08.ISO / NEWS / RADIANCE / SRC / RT / RPICT / RPICT.C
C/C++ Source or Header  |  1993-10-07  |  17KB  |  651 lines

  1. /* Copyright (c) 1992 Regents of the University of California */
  2.  
  3. #ifndef lint
  4. static char SCCSid[] = "@(#)rpict.c 2.17 10/15/92 LBL";
  5. #endif
  6.  
  7. /*
  8.  *  rpict.c - routines and variables for picture generation.
  9.  *
  10.  *     8/14/85
  11.  */
  12.  
  13. #include  "ray.h"
  14.  
  15. #ifdef BSD
  16. #include  <sys/time.h>
  17. #include  <sys/resource.h>
  18. #endif
  19.  
  20. #include  <signal.h>
  21.  
  22. #include  "view.h"
  23.  
  24. #include  "resolu.h"
  25.  
  26. #include  "random.h"
  27.  
  28. #include  "paths.h"
  29.  
  30. int  dimlist[MAXDIM];            /* sampling dimensions */
  31. int  ndims = 0;                /* number of sampling dimensions */
  32. int  samplendx;                /* sample index number */
  33.  
  34. VIEW  ourview = STDVIEW;        /* view parameters */
  35. int  hresolu = 512;            /* horizontal resolution */
  36. int  vresolu = 512;            /* vertical resolution */
  37. double    pixaspect = 1.0;        /* pixel aspect ratio */
  38.  
  39. int  psample = 4;            /* pixel sample size */
  40. double    maxdiff = .05;            /* max. difference for interpolation */
  41. double    dstrpix = 0.67;            /* square pixel distribution */
  42.  
  43. double    dstrsrc = 0.0;            /* square source distribution */
  44. double    shadthresh = .05;        /* shadow threshold */
  45. double    shadcert = .5;            /* shadow certainty */
  46. int  directrelay = 1;            /* number of source relays */
  47. int  vspretest = 512;            /* virtual source pretest density */
  48. int  directinvis = 0;            /* sources invisible? */
  49. double    srcsizerat = .25;        /* maximum ratio source size/dist. */
  50.  
  51. double    specthresh = .15;        /* specular sampling threshold */
  52. double    specjitter = 1.;        /* specular sampling jitter */
  53.  
  54. int  maxdepth = 6;            /* maximum recursion depth */
  55. double    minweight = 5e-3;        /* minimum ray weight */
  56.  
  57. COLOR  ambval = BLKCOLOR;        /* ambient value */
  58. double    ambacc = 0.2;            /* ambient accuracy */
  59. int  ambres = 32;            /* ambient resolution */
  60. int  ambdiv = 128;            /* ambient divisions */
  61. int  ambssamp = 0;            /* ambient super-samples */
  62. int  ambounce = 0;            /* ambient bounces */
  63. char  *amblist[128];            /* ambient include/exclude list */
  64. int  ambincl = -1;            /* include == 1, exclude == 0 */
  65.  
  66. #ifdef MSDOS
  67. int  ralrm = 60;            /* seconds between reports */
  68. #else
  69. int  ralrm = 0;                /* seconds between reports */
  70. #endif
  71.  
  72. double    pctdone = 0.0;            /* percentage done */
  73.  
  74. long  tlastrept = 0L;            /* time at last report */
  75.  
  76. extern long  time();
  77. extern long  tstart;            /* starting time */
  78.  
  79. extern long  nrays;            /* number of rays traced */
  80.  
  81. #define     MAXDIV        16        /* maximum sample size */
  82.  
  83. #define     pixjitter()    (.5+dstrpix*(.5-frandom()))
  84.  
  85. #define     RFTEMPLATE    "rfXXXXXX"
  86. #define     HFTEMPLATE    TEMPLATE
  87.  
  88. static char  *hfname = NULL;        /* header file name */
  89. static FILE  *hfp = NULL;        /* header file pointer */
  90.  
  91. static int  hres, vres;            /* resolution for this frame */
  92.  
  93. extern char  *mktemp();
  94.  
  95. double    pixvalue();
  96.  
  97.  
  98. quit(code)            /* quit program */
  99. int  code;
  100. {
  101.     if (code)            /* report status */
  102.         report();
  103.     if (hfname != NULL) {        /* delete header file */
  104.         if (hfp != NULL)
  105.             fclose(hfp);
  106.         unlink(hfname);
  107.     }
  108.     exit(code);
  109. }
  110.  
  111.  
  112. #ifdef BSD
  113. report()        /* report progress */
  114. {
  115.     struct rusage  rubuf;
  116.     double    t;
  117.  
  118.     getrusage(RUSAGE_SELF, &rubuf);
  119.     t = (rubuf.ru_utime.tv_usec + rubuf.ru_stime.tv_usec) / 1e6;
  120.     t += rubuf.ru_utime.tv_sec + rubuf.ru_stime.tv_sec;
  121.     getrusage(RUSAGE_CHILDREN, &rubuf);
  122.     t += (rubuf.ru_utime.tv_usec + rubuf.ru_stime.tv_usec) / 1e6;
  123.     t += rubuf.ru_utime.tv_sec + rubuf.ru_stime.tv_sec;
  124.  
  125.     sprintf(errmsg, "%ld rays, %4.2f%% done after %5.4f CPU hours\n",
  126.             nrays, pctdone, t/3600.0);
  127.     eputs(errmsg);
  128.     tlastrept = time((long *)0);
  129. }
  130. #else
  131. report()        /* report progress */
  132. {
  133.     tlastrept = time((long *)0);
  134.     sprintf(errmsg, "%ld rays, %4.2f%% done after %5.4f hours\n",
  135.             nrays, pctdone, (tlastrept-tstart)/3600.0);
  136.     eputs(errmsg);
  137.     signal(SIGALRM, report);
  138. }
  139. #endif
  140.  
  141.  
  142. openheader()            /* save standard output to header file */
  143. {
  144.     hfname = mktemp(HFTEMPLATE);
  145.     if (freopen(hfname, "w", stdout) == NULL) {
  146.         sprintf(errmsg, "cannot open header file \"%s\"", hfname);
  147.         error(SYSTEM, errmsg);
  148.     }
  149. }
  150.  
  151.  
  152. closeheader()            /* done with header output */
  153. {
  154.     if (hfname == NULL)
  155.         return;
  156.     if (fflush(stdout) == EOF || (hfp = fopen(hfname, "r")) == NULL)
  157.         error(SYSTEM, "error reopening header file");
  158. #ifdef MSDOS
  159.     setmode(fileno(hfp), O_BINARY);
  160. #endif
  161. }
  162.  
  163.  
  164. dupheader()            /* repeat header on standard output */
  165. {
  166.     register int  c;
  167.  
  168.     if (fseek(hfp, 0L, 0) < 0)
  169.         error(SYSTEM, "seek error on header file");
  170.     while ((c = getc(hfp)) != EOF)
  171.         putchar(c);
  172. }
  173.  
  174.  
  175. rpict(seq, pout, zout, prvr)            /* generate image(s) */
  176. int  seq;
  177. char  *pout, *zout, *prvr;
  178. /*
  179.  * If seq is greater than zero, then we will render a sequence of
  180.  * images based on view parameter strings read from the standard input.
  181.  * If pout is NULL, then all images will be sent to the standard ouput.
  182.  * If seq is greater than zero and prvr is an integer, then it is the
  183.  * frame number at which rendering should begin.  Preceeding view parameter
  184.  * strings will be skipped in the input.
  185.  * If pout and prvr are the same, prvr is renamed to avoid overwriting.
  186.  * Note that pout and zout should contain %d format specifications for
  187.  * sequenced file naming.
  188.  */
  189. {
  190.     extern char  *rindex(), *strncpy(), *strcat();
  191.     char  fbuf[128], fbuf2[128];
  192.     register char  *cp;
  193.     RESOLU    rs;
  194.     double    pa;
  195.                     /* finished writing header */
  196.     closeheader();
  197.                     /* check sampling */
  198.     if (psample < 1)
  199.         psample = 1;
  200.     else if (psample > MAXDIV) {
  201.         sprintf(errmsg, "pixel sampling reduced from %d to %d",
  202.                 psample, MAXDIV);
  203.         error(WARNING, errmsg);
  204.         psample = MAXDIV;
  205.     }
  206.                     /* get starting frame */
  207.     if (seq <= 0)
  208.         seq = 0;
  209.     else if (prvr != NULL && isint(prvr)) {
  210.         register int  rn;        /* skip to specified view */
  211.         if ((rn = atoi(prvr)) < seq)
  212.             error(USER, "recover frame less than start frame");
  213.         if (pout == NULL)
  214.             error(USER, "missing output file specification");
  215.         for ( ; seq < rn; seq++)
  216.             if (nextview(stdin) == EOF)
  217.                 error(USER, "unexpected EOF on view input");
  218.         prvr = fbuf;            /* mark for renaming */
  219.     }
  220.     if (pout != NULL) {
  221.         sprintf(fbuf, pout, seq);
  222.         if (prvr != NULL && !strcmp(prvr, fbuf)) {    /* rename */
  223.             fbuf2[0] = '\0';
  224.             if ((cp = rindex(fbuf, '/')) != NULL)
  225.                 strncpy(fbuf2, fbuf, cp-fbuf+1);
  226.             strcat(fbuf2, RFTEMPLATE);
  227.             prvr = mktemp(fbuf2);
  228.             if (rename(fbuf, prvr) < 0 && errno != ENOENT) {
  229.                 sprintf(errmsg,
  230.                     "cannot rename \"%s\" to \"%s\"",
  231.                         fbuf, prvr);
  232.                 error(SYSTEM, errmsg);
  233.             }
  234.         }
  235.     }
  236.                     /* render sequence */
  237.     do {
  238.         if (seq && nextview(stdin) == EOF)
  239.             break;
  240.         if (pout != NULL) {
  241.             sprintf(fbuf, pout, seq);
  242.             if (freopen(fbuf, "w", stdout) == NULL) {
  243.                 sprintf(errmsg,
  244.                     "cannot open output file \"%s\"", fbuf);
  245.                 error(SYSTEM, errmsg);
  246.             }
  247. #ifdef MSDOS
  248.             setmode(fileno(stdout), O_BINARY);
  249. #endif
  250.             dupheader();
  251.         }
  252.         hres = hresolu; vres = vresolu; pa = pixaspect;
  253.         if (prvr != NULL)
  254.             if (viewfile(prvr, &ourview, &rs) <= 0
  255.                     || rs.or != PIXSTANDARD) {
  256.                 sprintf(errmsg,
  257.             "cannot recover view parameters from \"%s\"", prvr);
  258.                 error(WARNING, errmsg);
  259.             } else {
  260.                 pa = 0.0;
  261.                 hres = scanlen(&rs);
  262.                 vres = numscans(&rs);
  263.             }
  264.         if ((cp = setview(&ourview)) != NULL)
  265.             error(USER, cp);
  266.         normaspect(viewaspect(&ourview), &pa, &hres, &vres);
  267.         if (seq) {
  268.             if (ralrm > 0) {
  269.                 fprintf(stderr, "FRAME %d:", seq);
  270.                 fprintview(&ourview, stderr);
  271.                 putc('\n', stderr);
  272.                 fflush(stderr);
  273.             }
  274.             printf("FRAME=%d\n", seq);
  275.         }
  276.         fputs(VIEWSTR, stdout);
  277.         fprintview(&ourview, stdout);
  278.         putchar('\n');
  279.         if (pa < .99 || pa > 1.01)
  280.             fputaspect(pa, stdout);
  281.         fputformat(COLRFMT, stdout);
  282.         putchar('\n');
  283.         if (zout != NULL)
  284.             sprintf(cp=fbuf, zout, seq);
  285.         else
  286.             cp = NULL;
  287.         render(cp, prvr);
  288.         prvr = NULL;
  289.     } while (seq++);
  290. }
  291.  
  292.  
  293. nextview(fp)                /* get next view from fp */
  294. FILE  *fp;
  295. {
  296.     char  linebuf[256];
  297.  
  298.     while (fgets(linebuf, sizeof(linebuf), fp) != NULL)
  299.         if (isview(linebuf) && sscanview(&ourview, linebuf) > 0)
  300.             return(0);
  301.     return(EOF);
  302. }    
  303.  
  304.  
  305. render(zfile, oldfile)                /* render the scene */
  306. char  *zfile, *oldfile;
  307. {
  308.     extern long  lseek();
  309.     COLOR  *scanbar[MAXDIV+1];    /* scanline arrays of pixel values */
  310.     float  *zbar[MAXDIV+1];        /* z values */
  311.     char  *sampdens;        /* previous sample density */
  312.     int  ypos;            /* current scanline */
  313.     int  ystep;            /* current y step size */
  314.     int  hstep;            /* h step size */
  315.     int  zfd;
  316.     COLOR  *colptr;
  317.     float  *zptr;
  318.     register int  i;
  319.                     /* allocate scanlines */
  320.     for (i = 0; i <= psample; i++) {
  321.         scanbar[i] = (COLOR *)malloc(hres*sizeof(COLOR));
  322.         if (scanbar[i] == NULL)
  323.             goto memerr;
  324.     }
  325.     hstep = (psample*140+49)/99;        /* quincunx sampling */
  326.     ystep = (psample*99+70)/140;
  327.     if (hstep > 2) {
  328.         i = hres/hstep + 2;
  329.         if ((sampdens = malloc(i)) == NULL)
  330.             goto memerr;
  331.         while (i--)
  332.             sampdens[i] = hstep;
  333.     } else
  334.         sampdens = NULL;
  335.                     /* open z file */
  336.     if (zfile != NULL) {
  337.         if ((zfd = open(zfile, O_WRONLY|O_CREAT, 0666)) == -1) {
  338.             sprintf(errmsg, "cannot open z file \"%s\"", zfile);
  339.             error(SYSTEM, errmsg);
  340.         }
  341. #ifdef MSDOS
  342.         setmode(zfd, O_BINARY);
  343. #endif
  344.         for (i = 0; i <= psample; i++) {
  345.             zbar[i] = (float *)malloc(hres*sizeof(float));
  346.             if (zbar[i] == NULL)
  347.                 goto memerr;
  348.         }
  349.     } else {
  350.         zfd = -1;
  351.         for (i = 0; i <= psample; i++)
  352.             zbar[i] = NULL;
  353.     }
  354.                     /* write out boundaries */
  355.     fprtresolu(hres, vres, stdout);
  356.                     /* recover file and compute first */
  357.     i = salvage(oldfile);
  358.     if (zfd != -1 && i > 0 &&
  359.             lseek(zfd, (long)i*hres*sizeof(float), 0) == -1)
  360.         error(SYSTEM, "z file seek error in render");
  361.     pctdone = 100.0*i/vres;
  362.     if (ralrm > 0)            /* report init stats */
  363.         report();
  364. #ifndef     BSD
  365.     else
  366. #endif
  367.     signal(SIGALRM, report);
  368.     ypos = vres-1 - i;
  369.     fillscanline(scanbar[0], zbar[0], sampdens, hres, ypos, hstep);
  370.                         /* compute scanlines */
  371.     for (ypos -= ystep; ypos > -ystep; ypos -= ystep) {
  372.                             /* bottom adjust? */
  373.         if (ypos < 0) {
  374.             ystep += ypos;
  375.             ypos = 0;
  376.         }
  377.         colptr = scanbar[ystep];        /* move base to top */
  378.         scanbar[ystep] = scanbar[0];
  379.         scanbar[0] = colptr;
  380.         zptr = zbar[ystep];
  381.         zbar[ystep] = zbar[0];
  382.         zbar[0] = zptr;
  383.                             /* fill base line */
  384.         fillscanline(scanbar[0], zbar[0], sampdens,
  385.                 hres, ypos, hstep);
  386.                             /* fill bar */
  387.         fillscanbar(scanbar, zbar, hres, ypos, ystep);
  388.                             /* write it out */
  389. #ifndef     BSD
  390.         signal(SIGALRM, SIG_IGN);    /* don't interrupt writes */
  391. #endif
  392.         for (i = ystep; i > 0; i--) {
  393.             if (zfd != -1 && write(zfd, (char *)zbar[i],
  394.                     hres*sizeof(float))
  395.                     < hres*sizeof(float))
  396.                 goto writerr;
  397.             if (fwritescan(scanbar[i], hres, stdout) < 0)
  398.                 goto writerr;
  399.         }
  400.         if (fflush(stdout) == EOF)
  401.             goto writerr;
  402.                             /* record progress */
  403.         pctdone = 100.0*(vres-1-ypos)/vres;
  404.         if (ralrm > 0 && time((long *)0) >= tlastrept+ralrm)
  405.             report();
  406. #ifndef     BSD
  407.         else
  408.             signal(SIGALRM, report);
  409. #endif
  410.     }
  411.                         /* clean up */
  412.     signal(SIGALRM, SIG_IGN);
  413.     if (zfd != -1) {
  414.         if (write(zfd, (char *)zbar[0], hres*sizeof(float))
  415.                 < hres*sizeof(float))
  416.             goto writerr;
  417.         if (close(zfd) == -1)
  418.             goto writerr;
  419.         for (i = 0; i <= psample; i++)
  420.             free((char *)zbar[i]);
  421.     }
  422.     fwritescan(scanbar[0], hres, stdout);
  423.     if (fflush(stdout) == EOF)
  424.         goto writerr;
  425.     for (i = 0; i <= psample; i++)
  426.         free((char *)scanbar[i]);
  427.     if (sampdens != NULL)
  428.         free(sampdens);
  429.     pctdone = 100.0;
  430.     if (ralrm > 0)
  431.         report();
  432.     return;
  433. writerr:
  434.     error(SYSTEM, "write error in render");
  435. memerr:
  436.     error(SYSTEM, "out of memory in render");
  437. }
  438.  
  439.  
  440. fillscanline(scanline, zline, sd, xres, y, xstep)    /* fill scan at y */
  441. register COLOR    *scanline;
  442. register float    *zline;
  443. register char  *sd;
  444. int  xres, y, xstep;
  445. {
  446.     static int  nc = 0;        /* number of calls */
  447.     int  bl = xstep, b = xstep;
  448.     double    z;
  449.     register int  i;
  450.     
  451.     z = pixvalue(scanline[0], 0, y);
  452.     if (zline) zline[0] = z;
  453.                 /* zig-zag start for quincunx pattern */
  454.     for (i = ++nc & 1 ? xstep : xstep/2; i < xres-1+xstep; i += xstep) {
  455.         if (i >= xres) {
  456.             xstep += xres-1-i;
  457.             i = xres-1;
  458.         }
  459.         z = pixvalue(scanline[i], i, y);
  460.         if (zline) zline[i] = z;
  461.         if (sd) b = sd[0] > sd[1] ? sd[0] : sd[1];
  462.         if (i <= xstep)
  463.             b = fillsample(scanline, zline, 0, y, i, 0, b/2);
  464.         else
  465.             b = fillsample(scanline+i-xstep,
  466.                     zline ? zline+i-xstep : NULL,
  467.                     i-xstep, y, xstep, 0, b/2);
  468.         if (sd) *sd++ = nc & 1 ? bl : b;
  469.         bl = b;
  470.     }
  471.     if (sd && nc & 1) *sd = bl;
  472. }
  473.  
  474.  
  475. fillscanbar(scanbar, zbar, xres, y, ysize)    /* fill interior */
  476. register COLOR    *scanbar[];
  477. register float    *zbar[];
  478. int  xres, y, ysize;
  479. {
  480.     COLOR  vline[MAXDIV+1];
  481.     float  zline[MAXDIV+1];
  482.     int  b = ysize;
  483.     register int  i, j;
  484.     
  485.     for (i = 0; i < xres; i++) {
  486.         
  487.         copycolor(vline[0], scanbar[0][i]);
  488.         copycolor(vline[ysize], scanbar[ysize][i]);
  489.         if (zbar[0]) {
  490.             zline[0] = zbar[0][i];
  491.             zline[ysize] = zbar[ysize][i];
  492.         }
  493.         
  494.         b = fillsample(vline, zbar[0] ? zline : NULL,
  495.                 i, y, 0, ysize, b/2);
  496.         
  497.         for (j = 1; j < ysize; j++)
  498.             copycolor(scanbar[j][i], vline[j]);
  499.         if (zbar[0])
  500.             for (j = 1; j < ysize; j++)
  501.                 zbar[j][i] = zline[j];
  502.     }
  503. }
  504.  
  505.  
  506. int
  507. fillsample(colline, zline, x, y, xlen, ylen, b) /* fill interior points */
  508. register COLOR    *colline;
  509. register float    *zline;
  510. int  x, y;
  511. int  xlen, ylen;
  512. int  b;
  513. {
  514.     double    ratio;
  515.     double    z;
  516.     COLOR  ctmp;
  517.     int  ncut;
  518.     register int  len;
  519.     
  520.     if (xlen > 0)            /* x or y length is zero */
  521.         len = xlen;
  522.     else
  523.         len = ylen;
  524.         
  525.     if (len <= 1)            /* limit recursion */
  526.         return(0);
  527.     
  528.     if (b > 0
  529.     || (zline && 2.*fabs(zline[0]-zline[len]) > maxdiff*(zline[0]+zline[len]))
  530.             || bigdiff(colline[0], colline[len], maxdiff)) {
  531.     
  532.         z = pixvalue(colline[len>>1], x + (xlen>>1), y + (ylen>>1));
  533.         if (zline) zline[len>>1] = z;
  534.         ncut = 1;
  535.         
  536.     } else {                    /* interpolate */
  537.     
  538.         copycolor(colline[len>>1], colline[len]);
  539.         ratio = (double)(len>>1) / len;
  540.         scalecolor(colline[len>>1], ratio);
  541.         if (zline) zline[len>>1] = zline[len] * ratio;
  542.         ratio = 1.0 - ratio;
  543.         copycolor(ctmp, colline[0]);
  544.         scalecolor(ctmp, ratio);
  545.         addcolor(colline[len>>1], ctmp);
  546.         if (zline) zline[len>>1] += zline[0] * ratio;
  547.         ncut = 0;
  548.     }
  549.                             /* recurse */
  550.     ncut += fillsample(colline, zline, x, y, xlen>>1, ylen>>1, (b-1)/2);
  551.     
  552.     ncut += fillsample(colline+(len>>1), zline ? zline+(len>>1) : NULL,
  553.             x+(xlen>>1), y+(ylen>>1),
  554.             xlen-(xlen>>1), ylen-(ylen>>1), b/2);
  555.  
  556.     return(ncut);
  557. }
  558.  
  559.  
  560. double
  561. pixvalue(col, x, y)        /* compute pixel value */
  562. COLOR  col;            /* returned color */
  563. int  x, y;            /* pixel position */
  564. {
  565.     static RAY  thisray;
  566.  
  567.     if (viewray(thisray.rorg, thisray.rdir, &ourview,
  568.             (x+pixjitter())/hres, (y+pixjitter())/vres) < 0) {
  569.         setcolor(col, 0.0, 0.0, 0.0);
  570.         return(0.0);
  571.     }
  572.  
  573.     rayorigin(&thisray, NULL, PRIMARY, 1.0);
  574.  
  575.     samplendx = pixnumber(x,y,hres,vres);    /* set pixel index */
  576.  
  577.     rayvalue(&thisray);            /* trace ray */
  578.  
  579.     copycolor(col, thisray.rcol);        /* return color */
  580.     
  581.     return(thisray.rt);            /* return distance */
  582. }
  583.  
  584.  
  585. int
  586. salvage(oldfile)        /* salvage scanlines from killed program */
  587. char  *oldfile;
  588. {
  589.     COLR  *scanline;
  590.     FILE  *fp;
  591.     int  x, y;
  592.  
  593.     if (oldfile == NULL)
  594.         return(0);
  595.     
  596.     if ((fp = fopen(oldfile, "r")) == NULL) {
  597.         sprintf(errmsg, "cannot open recover file \"%s\"", oldfile);
  598.         error(WARNING, errmsg);
  599.         return(0);
  600.     }
  601. #ifdef MSDOS
  602.     setmode(fileno(fp), O_BINARY);
  603. #endif
  604.                 /* discard header */
  605.     getheader(fp, NULL);
  606.                 /* get picture size */
  607.     if (!fscnresolu(&x, &y, fp)) {
  608.         sprintf(errmsg, "bad recover file \"%s\"", oldfile);
  609.         error(WARNING, errmsg);
  610.         fclose(fp);
  611.         return(0);
  612.     }
  613.  
  614.     if (x != hres || y != vres) {
  615.         sprintf(errmsg, "resolution mismatch in recover file \"%s\"",
  616.                 oldfile);
  617.         error(USER, errmsg);
  618.     }
  619.  
  620.     scanline = (COLR *)malloc(hres*sizeof(COLR));
  621.     if (scanline == NULL)
  622.         error(SYSTEM, "out of memory in salvage");
  623.     for (y = 0; y < vres; y++) {
  624.         if (freadcolrs(scanline, hres, fp) < 0)
  625.             break;
  626.         if (fwritecolrs(scanline, hres, stdout) < 0)
  627.             goto writerr;
  628.     }
  629.     if (fflush(stdout) == EOF)
  630.         goto writerr;
  631.     free((char *)scanline);
  632.     fclose(fp);
  633.     unlink(oldfile);
  634.     return(y);
  635. writerr:
  636.     sprintf(errmsg, "write error during recovery of \"%s\"", oldfile);
  637.     error(SYSTEM, errmsg);
  638. }
  639.  
  640.  
  641. int
  642. pixnumber(x, y, xres, yres)        /* compute pixel index (brushed) */
  643. register int  x, y;
  644. int  xres, yres;
  645. {
  646.     x -= y;
  647.     while (x < 0)
  648.         x += xres;
  649.     return((((x>>2)*yres + y) << 2) + (x & 3));
  650. }
  651.