home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / graphics / utility / mgif35s / flicker.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-13  |  21.8 KB  |  1,099 lines

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