home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / GRAPHICS / mgif.lzh / GIF / flicker.c next >
Text File  |  1991-12-02  |  21KB  |  1,016 lines

  1. #undef NO_INVERT    /* def if black is 0xff */
  2. #define FLICKER        /* def to test flicker thing. else just f-s */
  3. #define NEW_RANDOM    /* def to new code to add random noise */
  4. #define SHOW_SCREENS    /* def to display each screen slowly first */
  5. #define AUTO_SHOW    /* def to automatically cycle then proceed */
  6.  
  7. /*
  8.  *    this is for screen-switching on mono to simulate grayscale. it
  9.  *    uses a combination of floyd-steinberg and simulate "planes" which
  10.  *    get displayed each vblank. the image it works from should be
  11.  *    grayscale, i.e. each pixel is represented by an 8-bit (0 to 255)
  12.  *    intensity. since GIF images come with a color table, it is first
  13.  *    required to map each GIF pixel to the color table which has been
  14.  *    first changed to grayscale, either by averaging the rgb values
  15.  *    or by using the NTSC intensity equation.
  16.  *
  17.  *    note that i think the f-s algorithm employed here sweeps each row
  18.  *    left to right rather than alternating directions. that is why there
  19.  *    is spurious info in areas otherwise supposed to be white.
  20.  *
  21.  *    also, all points where chars are used in a calculation, they MUST
  22.  *    be unsigned.
  23.  */
  24.  
  25. /* written by Klaus Pedersen (micro@imada.dk) */
  26. /* modified by Bill Rosenkranz (rosenkra@convex.com) */
  27.  
  28. static char *sccsid = "@(#) flicker.c 1.1 91/6/3 rosenkra\0\0                 ";
  29.  
  30. #include <stdio.h>
  31. /* #include <osbind.h> */
  32. #include "gpdefs.h"
  33. #include <modes.h>
  34.  
  35. #ifdef LOCAL
  36. #undef LOCAL
  37. #endif
  38. #ifdef GLOBAL
  39. #undef GLOBAL
  40. #endif
  41. #define LOCAL        /*static*/
  42. #define GLOBAL
  43. #define reg_t        register
  44.  
  45. #define LEVELS        4
  46. #define NUMERRS        1300
  47. #define SCRNSPACE    48256L
  48.  
  49. /*
  50.  *    these are the thresholds for quantizing. 0,85,170,255 seem best
  51.  */
  52. LOCAL int    _Levels[LEVELS] = {  0,  85, 170, 255};
  53.  
  54. LOCAL int    _Width;            /* image size */
  55. LOCAL int          _Hight;
  56. LOCAL int         _Beta;            /* for the Laplace filter */
  57. LOCAL int         _MaxRandom;        /* for adding random noise */
  58. LOCAL int  *_Err1,            /* the error propagation arrays */
  59.            *_Err2;
  60. LOCAL int    _Err1Array[NUMERRS],
  61.             _Err2Array[NUMERRS];
  62. LOCAL short    _ScrnBuf[SCRNSPACE],    /* enuf for 3 screens... */
  63.            *_Scrn,
  64.            *_Scrn1,
  65.            *_Scrn2,
  66.            *_Scrn3;
  67.  
  68.  
  69. /*
  70.  *    local functions
  71.  */
  72. LOCAL void    _Conv2Gray ();
  73. LOCAL void    _SimpConv2Gray ();
  74. LOCAL void    _Conv2Grayfile ();
  75. LOCAL int    _GenConvPix ();
  76. LOCAL int    _Laplace ();
  77. LOCAL void    _ClearErr ();
  78. LOCAL int    _Rand ();
  79. LOCAL int    _Delay ();
  80.  
  81.  
  82.  
  83. /*------------------------------*/
  84. /*    flicker            */
  85. /*------------------------------*/
  86. GLOBAL int flicker (pimg, width, hight, beta, maxrandom, opt)
  87. unsigned char  *pimg;        /* -> raster image of intensities */
  88. int        width;        /* width, pixels */
  89. int        hight;        /* height, pixels */
  90. int        beta;        /* for laplace filter */
  91. int        maxrandom;    /* for random noise */
  92. int        opt;        /* 0=no flicker, 1=flicker, 2=extended */
  93. {
  94.  
  95. /*
  96.  *    this is the main entry point. complete grayscale raster image
  97.  *    comes from pimg with height and width specified. if beta != 0,
  98.  *    do Laplace filter with that beta. if maxrandom != 0, add some
  99.  *    random noise with that value (see below).
  100.  */
  101.  
  102.     register long    ii;
  103.  
  104.     /*
  105.      *   set our globals
  106.      */
  107.     _Hight     = hight;    /* its height... */
  108.     _Width     = width;    /* ...and width */
  109.     _Beta      = beta;    /* Laplace filter coefficient (fixedpoint: */
  110.                 /* 1=0.25, 2=0.50, 3=0.75... (Try 4) */
  111.     _MaxRandom = maxrandom;    /* amount of random noise on threshold value */
  112.                 /* (0 - 255) for 0% to 100% noise. (Try 10) */
  113.  
  114.     for (ii = 0L; ii < SCRNSPACE; ii++)    /* clear screens! */
  115.         _ScrnBuf[ii] = 0;
  116.  
  117. #if 0
  118.     printf ("\n\nwidth,height,beta,maxrandom = %d %d %d %d\n",
  119.         _Width, _Hight, _Beta, _MaxRandom);
  120.     printf ("pimg = %ld\nany key...\n", (long) pimg);
  121.     _Delay (4000);
  122.     if (Bconstat (2))
  123.     {
  124.         while (Bconstat (2))
  125.             Bconin (2);
  126.         exit (1);
  127.     }
  128. #endif
  129.  
  130.     /*
  131.      *   do it!
  132.      */
  133.     if (opt) {
  134.         if (opt == 1)
  135.             _Conv2Gray (pimg);
  136.         else
  137.             _Conv2Grayfile (pimg);
  138.     } else
  139.         _SimpConv2Gray (pimg);
  140.  
  141.     return;
  142. }
  143.  
  144.  
  145.  
  146.  
  147. /*------------------------------*/
  148. /*    _Conv2Gray        */
  149. /*------------------------------*/
  150. LOCAL void _Conv2Gray (pic)
  151. unsigned char  *pic;
  152. {
  153.     char c;
  154.     register int   *ps;
  155.     register int   *pd;
  156.     long        ii;
  157.     int        i;
  158.     int            x,
  159.                 y;
  160.     int        w,
  161.             h;
  162.     long            yoffset;
  163.     int           *TmpErr,
  164.                 q,
  165.                 rover1,
  166.                 rover2;
  167.     unsigned short    pix, spix;
  168.     unsigned char  *p;
  169.     char           *old1;
  170.     char           *old2;
  171.  
  172.  
  173.     /*
  174.      *   first clear the error arrays
  175.      */
  176.     _ClearErr ();
  177.  
  178.  
  179.     /*
  180.      *   save old screen info, then set logbase to old physbase and
  181.      *   physbase to first screen buffer. we *should* never see logbase
  182.      *   in the displayed image since we never display logbase. make
  183.      *   sure screen is aligned on 256-byte boundary.
  184.      */
  185.     old2  = ScreenAddress(0, 0);
  186.     old1  = old2;
  187.     _Scrn = (int *) (((long) _ScrnBuf + 256L) & 0xFFFFFF00L);
  188.     for (ii = 0L; ii < 30720; ii++)
  189.     {
  190.         old1[ii] = 0;
  191.         old2[ii] = 0;
  192.     }
  193.  
  194.  
  195.     /*
  196.      *   we set physbase to our buffer already so _Scrn1 points to it.
  197.      *   set the other screen pointers. _Scrn is a buffer large enuf
  198.      *   to hold all 3 screens
  199.      */
  200.     _Scrn1 = _Scrn;
  201.     _Scrn2 = _Scrn1 + 16000L;
  202.     _Scrn3 = _Scrn2 + 16000L;
  203.  
  204.  
  205.     /*
  206.      *   initialize some things. yoffset positions us into each screen
  207.      *   which are int arrays. each scan line in the screen is thus
  208.      *   40 words long.
  209.      */
  210.     yoffset = 0L;
  211.     rover1  = 0;
  212.     rover2  = 0;
  213.     spix = 0;
  214.  
  215.     /*
  216.      *   loop over all rows in image
  217.      */
  218.     h = (_Hight > 400) ? 400 : _Hight;
  219.     for (y = 1; y < h - 1; y++)
  220.     {
  221.         /*
  222.          *   set ptr to this pixel row
  223.          */
  224.         p = pic + ((long) y * (long) _Width);
  225.  
  226.         /*
  227.          *   loop over all pixels in the row
  228.          */
  229.         w = (_Width > 640) ? 640 : _Width;
  230.         for (x = 0; x < w - 1; x++)
  231.         {
  232.             pix = (0x8000 >> (x & 0x000f));
  233.  
  234.             /*
  235.              *   get new pixel value, with f-s error. this is
  236.              *   actually an index into the _Levels array.
  237.              */
  238.             if (y & 1)
  239.                 q = _GenConvPix (p, (int) x, 0);
  240.             else
  241.                 q = _GenConvPix (p, (int) x, 1);
  242.  
  243. #ifdef 0
  244.     printf ("  y=%3d, x=%3d, p+x=%6u, q=%d, rover1,2=%d,%d\n",
  245.         (int)y, (int)x,
  246.         (unsigned int)(*(unsigned char *)(x+pic+(y*_Width))),
  247.         (int)q,
  248.         (int)rover1, (int)rover2);
  249.     fflush (stdout);
  250. #endif
  251.  
  252.             /*
  253.              *   set screen pixels based on this index
  254.              */
  255.             if (q == 1)
  256.             {
  257.                 switch (rover1)
  258.                 {
  259.                 case 0: 
  260.                     _Scrn1[yoffset + (x >> 4)] |= pix;
  261.                     rover1 = 1;
  262.                     rover2 = 1;
  263.                     break;
  264.                 case 1: 
  265.                     _Scrn2[yoffset + (x >> 4)] |= pix;
  266.                     rover1 = 2;
  267.                     rover2 = 2;
  268.                     break;
  269.                 case 2: 
  270.                     _Scrn3[yoffset + (x >> 4)] |= pix;
  271.                     rover1 = 0;
  272.                     rover2 = 0;
  273.                     break;
  274.                 }
  275.             }
  276.             else if (q == 2)
  277.             {
  278.                 switch (rover2)
  279.                 {
  280.                 case 0: 
  281.                     _Scrn1[yoffset + (x >> 4)] |= pix;
  282.                     _Scrn2[yoffset + (x >> 4)] |= pix;
  283.                     rover2 = 1;
  284.                     rover1 = 2;
  285.                     break;
  286.                 case 1: 
  287.                     _Scrn2[yoffset + (x >> 4)] |= pix;
  288.                     _Scrn3[yoffset + (x >> 4)] |= pix;
  289.                     rover2 = 2;
  290.                     rover1 = 0;
  291.                     break;
  292.                 case 2: 
  293.                     _Scrn1[yoffset + (x >> 4)] |= pix;
  294.                     _Scrn3[yoffset + (x >> 4)] |= pix;
  295.                     rover2 = 0;
  296.                     rover1 = 1;
  297.                     break;
  298.                 }
  299.             }
  300.             else if (q == 3)
  301.             {
  302.                 _Scrn1[yoffset + (x >> 4)] |= pix;
  303.                 _Scrn2[yoffset + (x >> 4)] |= pix;
  304.                 _Scrn3[yoffset + (x >> 4)] |= pix;
  305.             }
  306.             if (q > 1)
  307.                 spix |= pix;
  308.             if ((x & 15) == 15 && y < ScreenLineCount) {
  309.                 *ScreenAddress(x, y-1) = spix;
  310.                 spix = 0;
  311.             }
  312.         }
  313.  
  314.  
  315.         /*
  316.          *   get ready for next row by incrementing offset into
  317.          *   the screens (640 dots = 40 words)
  318.          */
  319.         yoffset += 40;
  320.  
  321.  
  322.         /*
  323.          *   exchange error arrays
  324.          */
  325.         TmpErr  = _Err1;
  326.         _Err1   = _Err2;
  327.         _Err2   = TmpErr;
  328.  
  329. #if 0
  330.         /*
  331.          *   check for early withdrawal...
  332.          */
  333.         if (Bconstat (2))
  334.         {
  335.             while (Bconstat (2))
  336.                 Bconin (2);
  337.  
  338.             Setscreen (old1, old2, -1);
  339.             return;
  340.         }
  341. #endif
  342.     }
  343.  
  344.  
  345.     /*
  346.      *   with that all done, now we can display the screens. only
  347.      *   phys screen is displayed (at next vblank). the Vsync waits
  348.      *   for the vblank. we display screens 1,2,3. any char stops the
  349.      *   loop. first just show the screens with delay, then do the loop
  350.      */
  351. #ifdef SHOW_SCREENS
  352.     do
  353.     {   register int i;
  354.         register long *q, *z;
  355.  
  356.         for(i=7680, q=_Scrn1, z=old2; i>0; --i) {
  357.             *z++ = *q++;
  358.         }
  359.         tsleep(20);
  360.         for(i=7680, q=_Scrn2, z=old2; i>0; --i) {
  361.             *z++ = *q++;
  362.         }
  363.         tsleep(20); 
  364.         for(i=7680, q=_Scrn3, z=old2; i>0; --i) {
  365.             *z++ = *q++;
  366.         }
  367.         tsleep(20); 
  368.     } while (_gs_rdy(0) <= 0);
  369.     /* clear any key presses */
  370.     while (_gs_rdy(0) >= 0)
  371.         read(0, &c, 1);
  372. #endif /*SHOW_SCREENS*/
  373.  
  374.     do
  375.     {   register int i;
  376.         register long *q, *z;
  377.  
  378.         for(i=7680, q=_Scrn1, z=old2; i>0; --i) {
  379.             *z++ = *q++;
  380.         }
  381.         _Delay(4);
  382.         for(i=7680, q=_Scrn2, z=old2; i>0; --i) {
  383.             *z++ = *q++;
  384.         }
  385.         _Delay(4); 
  386.         for(i=7680, q=_Scrn3, z=old2; i>0; --i) {
  387.             *z++ = *q++;
  388.         }
  389.         _Delay(4); 
  390.     } while (_gs_rdy(0) <= 0);
  391.  
  392.     /*
  393.      *   clear any waiting keys...
  394.      */
  395.  
  396.     /* clear any key presses */
  397.     while (_gs_rdy(0) > 0)
  398.         read(0, &c, 1);
  399. }
  400.  
  401. typedef unsigned short word;
  402.  
  403. typedef struct {
  404.     word version;
  405.     word header_length;
  406.     word color_planes;
  407.     word pattern_length;
  408.     word pixel_width;
  409.     word pixel_height;
  410.     word line_width;
  411.     word img_height;
  412. } GemHeader;
  413.  
  414. elemcpy(e1, e2, groesse)
  415. register char *e1;
  416. register char *e2;
  417. register int groesse;
  418. {
  419.     if ((groesse & 1) == 0) {
  420.         while ((groesse-=4) >= 0) {
  421.             *((long *) e1)++ =  *((long *) e2)++;
  422.         }
  423.         if ((groesse += 4) != 0) {
  424.             if ((groesse-=2) > 0) { 
  425.                 *((short *) e1) =  *((short *) e2);
  426.                 e1[2] =  e2[2];
  427.             } else if (groesse == 0) {
  428.                 *((short *) e1) =  *((short *) e2);            
  429.             } else {
  430.                 *e1 =  *e2;
  431.             }
  432.         }
  433.     } else {
  434.         while (--groesse >= 0) {
  435.             *e1++ =  *e2++;
  436.         }
  437.     }
  438. }
  439.  
  440. /*------------------------------*/
  441. /*    _Conv2Grayfile                 */
  442. /*------------------------------*/
  443. LOCAL void _Conv2Grayfile (pic)
  444. unsigned char  *pic;
  445. {
  446.  
  447. /*
  448.  *    I have also made a version of "Convert2Gray", that don't use
  449.  *    flicker - this allows the pictures to be saved, and used in windows,
  450.  *    and honest - the build-in test-picture looks as good, or even better, 
  451.  *    without the flicker... (this is not true for any *real* pictures 
  452.  *    that I have tested the program with). Here it is :
  453.  */
  454.  
  455.     static unsigned char sl[4*3200];
  456.     short line[255];
  457.     short line1[255];
  458.     GemHeader gh;
  459.     long        x,
  460.             y,
  461.             wordpos;
  462.     int           *TmpErr;
  463.     short i, j, w, h, linelen, schwelle;
  464.     FILE *fa;
  465.     char c;
  466.     unsigned short    pix, pix1;
  467.     unsigned char  *p, *p1, *slp;
  468.  
  469.     write(1, "\x1bY!!Schwelle (1,2,3, G)raustufen) :  ", 36);
  470.     do {
  471.         read(0, &c, 1);
  472.         c = tolower(c);
  473.     } while ((c < '1' || c > '3') && c != 'g');
  474.     if (c != 'g')
  475.         schwelle = c - '0';
  476.     else
  477.         schwelle = -1;
  478.     if ((fa = fopen("ausgabe.img", "w")) == NULL) {
  479.         printf("Cannot open 'ausgabe.img'.\n");
  480.         fflush(stdout);
  481.         while (_gs_rdy(0) > 0)
  482.             read(0, &c, 1);
  483.         while (_gs_rdy(0) <= 0)
  484.             ;
  485.         return;
  486.     }
  487.     fa->_bufsiz = 16384;
  488.     w = _Width;
  489.     h = _Hight;
  490.     /*
  491.      *   first clear the error arrays
  492.      */
  493.     _Width = 2*w;
  494.     _Hight = 2*h;
  495.     _Levels[1] = 120;
  496.     _Levels[2] = 220;
  497.     _ClearErr ();
  498.  
  499.     /*
  500.      *   loop over all rows in image
  501.      */
  502.        gh.version = 1;
  503.        gh.header_length = 8;
  504.        gh.color_planes = 1;
  505.        gh.pattern_length = 2;
  506.        gh.pixel_width = 250;
  507.        gh.pixel_height = 250;
  508.        if (schwelle > 0) {
  509.            gh.line_width = _Width;
  510.            gh.img_height = _Hight;
  511.        } else {
  512.            gh.line_width = 2*_Width;
  513.            gh.img_height = 2*_Hight;
  514.        }
  515.     fwrite(&gh, sizeof(gh), 1, fa);
  516.     for (i=sizeof(sl)-1; i >=0; --i)
  517.         sl[i] = 0;
  518.     if (schwelle > 0) {
  519.         linelen = _Width / 8;
  520.         if ((_Width & 7) != 0)
  521.             linelen++;
  522.     } else {
  523.         linelen = _Width / 4;
  524.         if ((_Width & 3) != 0)
  525.             linelen++;
  526.     }
  527.     for (y = 1; y < h - 1; y++)
  528.     {
  529.         /*
  530.          *   set ptr to this pixel row
  531.          */
  532.         p       = pic + y * w;
  533.         p1      = pic + (y+1) * w;
  534.         slp = sl+2*_Width;
  535.         for(i = 0; i <= w - 1; i++) {
  536.             slp[i*2] = p[i];
  537.         }
  538.         for(i = 0; i <= w - 2; i++) {
  539.             slp[i*2+1] = (p[i]+p[i+1])/2;
  540.         }
  541.         slp[2*w-1] = p[w-1];
  542.         slp += _Width;
  543.         for(i = 0; i < w; i++) {
  544.             slp[i*2] = (p[i]+p1[i])/2;
  545.         }
  546.         for(i = 0; i <= w - 2; i++) {
  547.             slp[i*2+1] = (p[i]+p[i+1]+p1[i]+p1[i+1])/4;
  548.         }
  549.         slp[2*w-1] = p[w-1];
  550.  
  551.         /*
  552.          *   loop over all pixels in the row _Width-1 wg. Laplace
  553.          */
  554.         
  555.         for(j = 0, slp = sl+_Width; j < 2; j++, slp += _Width) {
  556.             wordpos = 1;
  557.             pix     = 0;
  558.             pix1    = 0;
  559.  
  560.             if (schwelle > 0) {
  561.                 for (x = 0L; x < _Width-1; x++)
  562.                 {
  563.                     pix <<= 1;
  564.                     if (_GenConvPix (slp, x, 0) >= schwelle)
  565.                         pix++;
  566.                     if ((x & 0xf) == 0xf) {
  567.                         line[wordpos++] = pix;
  568.                         if (wordpos < 40) {
  569.                             *ScreenAddress((wordpos-2) * 16,
  570.                                 (2*y+j) % ScreenLineCount) = pix;
  571.                         }
  572.                     }
  573.                 }
  574.             } else {
  575.                 for (x = 0L; x < _Width-1; x++)
  576.                 {
  577.                     i = _GenConvPix (slp, x, 0);
  578.                     pix  <<= 2;
  579.                     pix1 <<= 2;
  580.                     switch (i) {
  581.                     case 1:
  582.                         pix  |= 2;
  583.                     case 0:
  584.                         break;
  585.                     case 3:
  586.                         pix  |= 1;
  587.                         pix1 |= 2;
  588.                     case 2:
  589.                         pix  |= 2; 
  590.                         pix1 |= 1;
  591.                         break;
  592.                     }
  593.                     if ((x & 7) == 7) {
  594.                         line1[wordpos] = pix1;
  595.                         line[wordpos++] = pix;
  596.                         if (wordpos < 40) {
  597.                             *ScreenAddress((wordpos-2) * 16,
  598.                                  (4*y+2*j) % ScreenLineCount) = pix;
  599.                             *ScreenAddress((wordpos-2) * 16,
  600.                                  (4*y+2*j+1) % ScreenLineCount) = pix1;
  601.                         }
  602.                     }
  603.                 }
  604.             }
  605.             line[wordpos] = pix;
  606.             line1[wordpos] = pix1;
  607.             if (linelen < 255) {
  608.                 line[0] = 0x8000+linelen;
  609.                 fwrite(line, linelen+2, 1, fa);
  610.                 if (schwelle < 0) {
  611.                     line1[0] = 0x8000+linelen;
  612.                     fwrite(line1, linelen+2, 1, fa);
  613.                 }
  614.             } else {
  615.                 line[0] = 0x8000+254;
  616.                 fwrite(line, 256, 1, fa);
  617.                 line[127] = 0x8000+linelen-254;
  618.                 fwrite(line+127, linelen+2-254, 1, fa);
  619.                 if (schwelle < 0) {
  620.                     line1[0] = 0x8000+254;
  621.                     fwrite(line1, 256, 1, fa);
  622.                     line1[127] = 0x8000+linelen-254;
  623.                     fwrite(line1+127, linelen+2-254, 1, fa);
  624.                 }
  625.             }
  626.         
  627.             /*
  628.              *   exchange error arrays
  629.              */
  630.             TmpErr  = _Err1;
  631.             _Err1   = _Err2;
  632.             _Err2   = TmpErr;
  633.         }
  634.  
  635.         elemcpy(sl, sl+2*_Width, 2*_Width);
  636.     }
  637.     fclose(fa);
  638.     _Width = w;
  639.     _Hight = h;
  640.     _Levels[0] = 0;
  641.     _Levels[1] = 85;
  642.     _Levels[2] = 170;
  643.     _Levels[3] = 255;
  644.     /* clear any key presses */
  645.     while (_gs_rdy(0) >= 0)
  646.         read(0, &c, 1);
  647. }
  648.  
  649.  
  650. /*------------------------------*/
  651. /*    _SimpConv2Gray        */
  652. /*------------------------------*/
  653. LOCAL void _SimpConv2Gray (pic)
  654. unsigned char  *pic;
  655. {
  656.  
  657. /*
  658.  *    I have also made a version of "Convert2Gray", that don't use
  659.  *    flicker - this allows the pictures to be saved, and used in windows,
  660.  *    and honest - the build-in test-picture looks as good, or even better, 
  661.  *    without the flicker... (this is not true for any *real* pictures 
  662.  *    that I have tested the program with). Here it is :
  663.  */
  664.  
  665.     long        x,
  666.             y,
  667.             yoffset,
  668.             wordpos;
  669.     int           *TmpErr;
  670.     char c;
  671.     unsigned int    pix;
  672.     unsigned char  *p;
  673.  
  674.  
  675.     /*
  676.      *   first clear the error arrays
  677.      */
  678.     _ClearErr ();
  679.  
  680.     /*
  681.      *   there is only one screen. we use existing physbase
  682.      */
  683.     _Scrn1 = ScreenAddress(0, 0);
  684.  
  685.     /*
  686.      *   yoffset positions us into the screen which is an int arrays.
  687.      *   each scan line in the screen is thus 40 words long.
  688.      */
  689.     yoffset = 0;
  690.     pix     = 0;
  691.  
  692.     /*
  693.      *   loop over all rows in image
  694.      */
  695.     for (y = 1; y < _Hight - 1; y++)
  696.     {
  697.         /*
  698.          *   set ptr to this pixel row
  699.          */
  700.         p       = pic + y * _Width;
  701.         wordpos = yoffset;
  702.  
  703.         /*
  704.          *   loop over all pixels in the row
  705.          */
  706.         for (x = 0L; x < _Width - 1; x++)
  707.         {
  708.             pix <<= 1;
  709.             if (_GenConvPix (p, x, 0))
  710.                 pix++;
  711.             if ((x & 0xf) == 0xf)
  712.                 _Scrn1[wordpos++] = pix;
  713.         }
  714.  
  715.         /*
  716.          *   get ready for next row by incrementing offset into
  717.          *   the screens (640 dots = 40 words)
  718.          */
  719.         yoffset += 40;
  720.  
  721.         /*
  722.          *   exchange error arrays
  723.          */
  724.         TmpErr  = _Err1;
  725.         _Err1   = _Err2;
  726.         _Err2   = TmpErr;
  727.  
  728.     }
  729.  
  730.  
  731.     /*
  732.      *   displaying the image consists of waiting for a char since we
  733.      *   already drew it to the screen
  734.      */
  735.     while (_gs_rdy(0) < 0)
  736.         ;
  737.     /* clear any key presses */
  738.     while (_gs_rdy(0) >= 0)
  739.         read(0, &c, 1);
  740. }
  741.  
  742.  
  743.  
  744. /*------------------------------*/
  745. /*    _GenConvPix        */
  746. /*------------------------------*/
  747.  
  748. LOCAL int _GenConvPix (pic, x, opt)
  749. unsigned char   *pic;            /* -> image pixel array */
  750. int        x;            /* the current pixel */
  751. int        opt;            /* 0=l to r, 1=r to l */
  752. {
  753.  
  754. /*
  755.  *    This rutine converts a point in the 'real' image to
  756.  *    a point in the screen image. The procedure uses error-
  757.  *    diffusion to determine the state of the new pixel.
  758.  *    The Error filter is that of Floyd & Steinberg :
  759.  *
  760.  *        / 1  5  3 \  / 
  761.  *        \ 7  X    / / 16
  762.  *
  763.  *    This rutine uses a table of levels to make the convertion.
  764.  *
  765.  *    It returns the index for the pixel from the quantizing Level
  766.  *    array, i.e. the new pixel intensity is Level[i].
  767.  */
  768.  
  769.     int     p,
  770.             e,
  771.             i,
  772.             err,
  773.             lev;
  774.  
  775. #ifdef NEW_RANDOM
  776. /*
  777.     The noise is here added to the picture, this means that the noise
  778.     isn't cancled out again, and that is NOT intended, the noise should
  779.     only act as some kind of *catalysator* (verb. is stolen from 
  780.     chemistry - something that start a reaction). The correct way to add
  781.     noise is :
  782. */
  783.  
  784.     /*
  785.      *   first do the weighted average. _Err1 is the current line,
  786.      *   _Err2 is the previous line.
  787.      */
  788.     if (x == 0)
  789.     {
  790. # ifdef NO_INVERT
  791. /*!!! next line was actually: */
  792.  
  793.         p = *pic;
  794.  
  795. /*!!! but that inverted the image. it was assumed that 0xff was black.
  796.       we insist that black is 0x00 (low intensity) */
  797. # else
  798.         p = 255 - *pic;
  799. # endif
  800.     }
  801.     else if (_Beta)
  802.     {
  803.         p = ((7*_Err1[x - 1]
  804.               + _Err2[x - 1] + 5*_Err2[x] + 3*_Err2[x + 1]) >> 4)
  805.               + _Laplace (pic + x);
  806.     }
  807.     else
  808.     {
  809.         p = ((7*_Err1[x - 1]
  810.               + _Err2[x - 1] + 5*_Err2[x] + 3*_Err2[x + 1]) >> 4)
  811. # ifdef NO_INVERT
  812.               + *(pic + x);
  813. # else
  814.               + (255 - *(pic + x));
  815. # endif
  816.     }
  817.  
  818.  
  819.     /*
  820.      *   now calculate the residual errors
  821.      */
  822.     err = NUMERRS;
  823.     for (i = 0; i < LEVELS; i++)
  824.     {
  825.         if (_MaxRandom)
  826.             e = p + _Rand (_MaxRandom) - _Levels[i];
  827.         else
  828.             e = p - _Levels[i];
  829.  
  830.         if (e < 0)
  831.             e = -e;
  832.         if (e < err)
  833.         {
  834.             err = e;
  835.             lev = i;
  836.         }
  837.     }
  838.     _Err1[x] = p - _Levels[lev];
  839.  
  840. #else /*!NEW_RANDOM*/
  841.  
  842.     if (x == 0)
  843.     {
  844. # ifdef NO_INVERT
  845.         p = *pic;
  846. # else
  847.         p = 255 - *pic;
  848. # endif
  849.     }
  850.     else if (_Beta)
  851.     {
  852.         if (_MaxRandom)
  853.             p = ((7 * _Err1[x - 1] + _Err2[x - 1]
  854.                 + 5 * _Err2[x] + 3 * _Err2[x + 1]) >> 4)
  855.                 + _Laplace (pic + x) + _Rand (_MaxRandom);
  856.         else
  857.             p = ((7 * _Err1[x - 1] + _Err2[x - 1]
  858.                 + 5 * _Err2[x] + 3 * _Err2[x + 1]) >> 4)
  859.                 + _Laplace (pic + x);
  860.     }
  861.     else
  862.     {
  863.         if (_MaxRandom)
  864.         {
  865.             p = ((7 * _Err1[x - 1] + _Err2[x - 1]
  866.                 + 5 * _Err2[x] + 3 * _Err2[x + 1]) >> 4)
  867. # ifdef NO_INVERT
  868.                 + *(pic + x) + _Rand (_MaxRandom);
  869. # else
  870.                 + (255 - *(pic + x)) + _Rand (_MaxRandom);
  871. # endif
  872.         }
  873.         else
  874.         {
  875.             p = ((7 * _Err1[x - 1] + _Err2[x - 1]
  876.                 + 5 * _Err2[x] + 3 * _Err2[x + 1]) >> 4)
  877. # ifdef NO_INVERT
  878.                 + *(pic + x);
  879. # else
  880.                 + (255 - *(pic + x));
  881. # endif
  882.         }
  883.     }
  884.     err = NUMERRS;
  885.     for (i = 0; i < LEVELS; i++)
  886.     {
  887.         e = p - _Levels[i];
  888.         if (e < 0)
  889.             e = -e;
  890.         if (e < err)
  891.         {
  892.             err = e;
  893.             lev = i;
  894.         }
  895.     }
  896.     _Err1[x] = p - _Levels[lev];
  897.  
  898. #endif /*NEW_RANDOM*/
  899.  
  900.     return (lev);
  901. }
  902.  
  903.  
  904.  
  905.  
  906. /*------------------------------*/
  907. /*    _Laplace        */
  908. /*------------------------------*/
  909. LOCAL int _Laplace (Pic)
  910. unsigned char   *Pic;
  911. {
  912.  
  913. /*
  914.  *    this is a Laplacian filter, a simple edge detector/enhancer.
  915.  *
  916.  *           -1
  917.  *        -1  4 -1
  918.  *           -1
  919.  */
  920.  
  921.     register int    lp;
  922.  
  923.  
  924.     /*
  925.      *   if _Beta 0, formula reduces to just the pixel
  926.      */
  927. #ifdef NO_INVERT
  928.     if (_Beta == 0)
  929.         return ((int) *Pic);
  930.  
  931.     lp = (*Pic << 2)            /* this pixel */
  932.        - *(Pic - 1) - *(Pic + 1)        /* left/right */
  933.        - *(Pic + _Width) - *(Pic - _Width);    /* top/bottom */
  934.     lp = ((_Beta * lp) >> 2) + *Pic;
  935. #else
  936.     if (_Beta == 0)
  937.         return ((int) (255 - *Pic));
  938.  
  939.     lp  = (255 - *Pic) << 2;            /* this pixel */
  940.     lp -= (255 - *(Pic - 1));            /* left/right */
  941.     lp -= (255 - *(Pic + 1));
  942.     lp -= (255 - *(Pic + _Width));            /* top/bottom */
  943.     lp -= (255 - *(Pic - _Width));
  944.     lp  = ((_Beta * lp) >> 2);
  945.     lp += (255 - *Pic);                /* self */
  946. #endif
  947.  
  948.     /*
  949.      *   check limits and force result to 8 bits
  950.      */
  951.     if (lp < 0)
  952.         lp = 0;
  953.     if (lp > 255)
  954.         lp = 255;
  955.  
  956.     return (lp);
  957. }
  958.  
  959.  
  960.  
  961.  
  962. /*------------------------------*/
  963. /*    _ClearErr        */
  964. /*------------------------------*/
  965. LOCAL void _ClearErr ()
  966. {
  967.     int     i;
  968.  
  969.     _Err1 = _Err1Array;
  970.     _Err2 = _Err2Array;
  971.     for (i = 0; i < _Width; i++)
  972.         _Err1Array[i] = _Err2Array[i] = 0;
  973. }
  974.  
  975.  
  976.  
  977.  
  978. /*------------------------------*/
  979. /*    _Rand            */
  980. /*------------------------------*/
  981. LOCAL int _Rand (mx)
  982. int    mx;
  983. {
  984.  
  985. /*
  986.  *    returns random number 0 <= x < mx
  987.  */
  988.  
  989.     static long     Seed = 0;
  990.  
  991.     if (mx == 0)
  992.         return (0);
  993.  
  994. /*    Seed = (5 * Seed + 37);*/
  995.     Seed += (Seed << 2) + 37;        /* same thing but faster */
  996. /*    Seed &= 0x00ffffffL;*/            /* should prevent overflow */
  997.  
  998.     return (((int) Seed) % mx);
  999. }
  1000.  
  1001.  
  1002.  
  1003.  
  1004. /*------------------------------*/
  1005. /*    _Delay            */
  1006. /*------------------------------*/
  1007. LOCAL _Delay (ms)
  1008. int    ms;
  1009. {
  1010. /*
  1011.  *    delay with 1 ms granularity on normal ST
  1012.  */
  1013.     int    i;
  1014.     for ( ; ms > 0; ms--)    for (i = 192; i > 0; i--)    ;
  1015. }
  1016.