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