/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Lexmark Corporation, 1989                                   */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = PRDBEXIN
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION   Printer Bitmap external to internal conversion routines
 *
 * FUNCTIONS  prdb_ConvertExttoInt
 *            prdb_TableExttoInt
 *            prdb_TransferExttoInt
 *            convert_ext1_to_int1
 *            convert_ext4_to_int1
 *            convert_ext8_to_int1
 *            convert_ext24_to_int1
 *            convert_ext1_to_int4
 *            convert_ext4_to_int4
 *            convert_ext8_to_int4
 *            convert_ext24_to_int4
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/
#define INCL_32                         /* Convert to C/SET2    CON3201       */
#define INCL_DOSPROCESS                 /* Convert to C/SET2    CON3201       */
#define INCL_DOSSEMAPHORES
#define INCL_GPIERRORS
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#define INCL_DOSMEMMGR
#include <os2.h>
#undef INCL_DOSPROCESS                  /* Convert to C/SET2    CON3201       */
#undef INCL_DOSSEMAPHORES
#undef INCL_GPIERRORS
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_DOSMEMMGR

#define INCL_DDIMISC
#define INCL_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#define INCL_DDICOMFLAGS
#include <pmddi.h>
#undef INCL_DDIMISC
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS
#undef INCL_DDICOMFLAGS

#define INCL_WINP_SELECTIVE
#define INCL_WINP_SEI
#include <pmwinx.h>
#undef INCL_WINP_SELECTIVE
#undef INCL_WINP_SEI
#undef INCL_32                          /* Convert to C/SET2    CON3201       */

#include <prdbcone.h>

#define NO_SYS
#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL
#undef NO_SYS

#include <prdbtyp1.h>
#include <prdbextf.h>
#include <prdgextf.h>
#include <prdcextf.h>
#include <prdyextf.h>
#include <prdbsize.h>
#include <prduextf.h>

/******************************************************************************/
/*  External declarations...                                                  */
/******************************************************************************/
extern USHORT prdd_HugeInc;

/******************************************************************************/
/*  FUNCTION: prdb_ConvertExttoInt                                            */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  pBMListEntry  InfoList    Pointer to bitmap list entry                    */
/*  PBYTE         SrcAddress  Pointer to external bitmap                      */
/*  PBITMAPINFO   ArgInfo     Pointer to external bitmap info                 */
/*  ULONG         StartLine   First line to convert                           */
/*  USHORT        ScanLines   Number of lines to convert                      */
/*  lpDCI         DCIData     DCIData            PD00400...                   */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  Convert an external to an internal bitmap.  This routine does the main    */
/*  work.  It assumes that all the parameters of the bitmaps have already been*/
/*  verified.                                                                 */
/******************************************************************************/
VOID prdb_ConvertExttoInt(pBMListEntry InfoList,
                          PBYTE        SrcAddress,
/* CON3201 - GRE CHANGE*/ PBITMAPINFO2 ArgInfo,
                          ULONG        StartLine,
                          USHORT       ScanLines,
                          lpDCI        DCIData)

{

#define TFUNC "prdb_ConvertExttoInt"

    /**************************************************************************/
    /*  Local variables                                                       */
    /**************************************************************************/
    ULONG     MoveAlong;
    lpBMSPad  SPad;                    /* PD00400 : Pointer to bitmap scratch */
                                       /* pad.  lpBMSPad is a typedef pointer */
                                       /* to the structure BMConvertScratch   */
                                       /* (see PRDBTYPT.H)...                 */
    RGB2     *ColorTable;              /* CON3201 */

    /**************************************************************************/
    /*  PD00400 : Allocate the memory used for the BM scratch pad             */
    /**************************************************************************/
    if (prdg_AllocHeapItem(DCIData, sizeof(BMConvertScratch),
                           (PUSHORT *)&SPad) != OK)
    {
        return;
    }

    /**************************************************************************/
    /*  PD00400 : GWD.  Set the allocated heap space to all zero's            */
    /**************************************************************************/
    prdu_memset((PBYTE)SPad, 0, sizeof(BMConvertScratch));

    /**************************************************************************/
    /*  Set up a scratchpad to reduce parameter passing Note that we update   */
    /*  DestPtr to move to the first line to which conversion is requested.   */
    /**************************************************************************/
    SPad->SrcPtr               = SrcAddress;
 /* SPad->DestPtr              = InfoList->Bitmap; */
    MoveAlong                  = StartLine * InfoList->Parms.BytesPerRow;
 /* OFFSETOF(SPad->DestPtr)   += (USHORT)(MoveAlong&0x0000FFFFL);          */
 /* SELECTOROF(SPad->DestPtr) += ((USHORT)(MoveAlong>>16)) * prdd_HugeInc; */
    SPad->DestPtr              = (InfoList->Bitmap) + MoveAlong;   /* CON3201 */
    SPad->IntBpp               = (USHORT)InfoList->Parms.Bitcount;
    SPad->ExtBpp               = ArgInfo->cBitCount;
    SPad->PelsPerLine          = (USHORT)InfoList->Parms.Width;
    SPad->LinesToConvert       = ScanLines;
    ColorTable                 = (RGB2*)((PBYTE)ArgInfo + ArgInfo->cbFix);/* CON3201 */

    /**************************************************************************/
    /*  Set up a color conversion table                                       */
    /**************************************************************************/
    prdb_TableExttoInt(ColorTable, SPad);    /* CON3201 */

    /**************************************************************************/
    /*  Do the actual transferral.                                            */
    /**************************************************************************/
    prdb_TransferExttoInt(SPad);

    /**************************************************************************/
    /*  PD00400 : Free the memory used for the BM scratch pad                 */
    /**************************************************************************/
    (VOID)prdg_FreeHeapItem(DCIData, sizeof(BMConvertScratch), (PUSHORT)SPad);
}
#undef TFUNC

/******************************************************************************/
/*  FUNCTION: prdb_TableExttoInt                                              */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  RGB far *  RGBTable  Pointer to external color table                      */
/*  lpBMSPad   SPad      PD00400 :Pointer to bitmap scratch                   */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  Create a color conversion table mapping colors in the external bitmap to  */
/*  colors in the internal bitmap.  Note that the conversion table for        */
/*  External 1bpp to Internal 4bpp is for four pels at a time, and that the   */
/*  conversion table for External 4bpp to Internal 4bpp is for 2 pels at a    */
/*  time.  We do not have a color conversion table when the external bitmap is*/
/*  24bpp.                                                                    */
/******************************************************************************/
VOID prdb_TableExttoInt( RGB2    *  RGBTable,    /* CON3201 - Now use RGB2    */
                         lpBMSPad   SPad )
#if 0
RGB     *  RGBTable;
lpBMSPad   SPad;                       /* PD00400 : Pointer to bitmap scratch */
                                       /* pad                                 */
#endif
{

#define TFUNC "prdb_TableExttoInt"

    /**************************************************************************/
    /*  Local variables...                                                    */
    /**************************************************************************/
    int ii, jj, kk, ll;
    int NumberOfcolors;
    int ScratchTable[16];

    if (SPad->IntBpp == 1)
    {
        if (SPad->ExtBpp == 1)
        {
            /******************************************************************/
            /*  Both bitmaps are 1bpp.  We check each of the colors in the    */
            /*  source bitmap for whether they are nearest to white or to     */
            /*  black.  This may result in us either filling the internal     */
            /*  bitmap with zeroes or with ones, copying the external bitmap, */
            /*  or copying the external data and inverting all the bytes.     */
            /*                                                                */
            /*  The method used to determine whether an RGB value is black or */
            /*  white is to compare R+G+B with a threshold value of 384 (384 =*/
            /*  0x80 + 0x80 + 0x80).  This threshold ensures that 0x808080    */
            /*  maps to black.                                                */
            /******************************************************************/

            if ((USHORT)(RGBTable[0].bRed + RGBTable[0].bGreen +
                RGBTable[0].bBlue) <= 384) /* color 0 nearest to black        */
            {
                if ((USHORT)(RGBTable[1].bRed + RGBTable[1].bGreen +
                    RGBTable[1].bBlue) > 384) /* col. 1 nearest to white      */
                {

                    /**********************************************************/
                    /*  External colors are the same as internal colors - we  */
                    /*  just need to copy bytes from one bitmap to the other. */
                    /**********************************************************/
                    SPad->FillFlag = SRC_COPY_BITS;
                }
                else                   /* color 1 closest to black            */
                {

                    /**********************************************************/
                    /*  Both external colors map to black - fill the internal */
                    /*  (destination) bitmap with zeroes.                     */
                    /**********************************************************/
                    SPad->FillFlag = SRC_ZEROS;
                }
            }
            else                       /* color 0 closest to white            */
            {
                if ((USHORT) (RGBTable[1].bRed + RGBTable[1].bGreen +
                    RGBTable[1].bBlue) > 384) /* col. 1 nearest to white      */
                {

                    /**********************************************************/
                    /*  Both external colors map to white - fill the internal */
                    /*  (destination) bitmap with ones.                       */
                    /**********************************************************/
                    SPad->FillFlag = SRC_ONES;
                }
                else                   /* color 1 closest to black            */
                {

                    /**********************************************************/
                    /*  External color 1 maps to internal color 0, and        */
                    /*  external color 0 maps to internal color 1 - we need to*/
                    /*  invert every pel.                                     */
                    /**********************************************************/
                    SPad->FillFlag = SRC_INVERT_BITS;
                }
            }
        }
        else if (SPad->ExtBpp == 4 || SPad->ExtBpp == 8)
        {

            /******************************************************************/
            /*  External 4 or 8bpp to Internal 1bpp.                          */
            /*                                                                */
            /*  We set up a conversion table which for each color in the      */
            /*  external color table indicates whether it maps to black or    */
            /*  white.  We also maintain a flag which indicates whether any   */
            /*  color in the external CT has mapped to black, and whether any */
            /*  color has mapped to white.  Thus if all the colors in the CT  */
            /*  all map to only one of white or black, when we come to fill in*/
            /*  the internal bitmap, we can do it very quickly.               */
            /*                                                                */
            /*  Note that we compare R+G+B with 384 not 382.5.  This will be  */
            /*  completely invisible to the eye for a random color.  The      */
            /*  reason we do this is because the color 80 80 80 often occurs, */
            /*  and it is often in a bitmap with (e.g.) the colors CC CC CC   */
            /*  and FF FF FF (as these are in the VGA default palette).  If we*/
            /*  used 382.5 as our threshold value, all three of these colors  */
            /*  would map to white, and thus we would not get any contrast    */
            /*  between them.  Thus we move the threshold very slightly so    */
            /*  that 80 80 80 maps to black not white to get some contrast.   */
            /*                                                                */
            /*  [ 384 = 3 * 0x80 and 382.5 = (3 * 0xFF) / 2 ]                 */
            /******************************************************************/
            SPad->ColoursHad = 0;
            NumberOfcolors = 1 << SPad->ExtBpp; /* = 2**SPad->ExtBpp          */
            for (ii=0 ; ii < NumberOfcolors; ii++)
            {
                if ((USHORT) (RGBTable[ii].bRed + RGBTable[ii].bGreen +
                    RGBTable[ii].bBlue) > 384)/* col ii nearest to white      */
                {
                    SPad->ColoursHad |= HAD_WHITE;
                    SPad->Col.ConvertTable[ii] = MONO_WHITE;
                }
                else                   /* color ii nearest to black           */
                {
                    SPad->ColoursHad |= HAD_BLACK;
                    SPad->Col.ConvertTable[ii] = MONO_BLACK;
                }
            }
        }
    }
    else
    {
        if (SPad->ExtBpp == 1)
        {

            /******************************************************************/
            /*  External 1bpp to Internal 4bpp                                */
            /*                                                                */
            /*  First we find which colors in the palette the two colors in   */
            /*  the external color table are nearest to.  Then set up a       */
            /*  conversion table where the routine convert_ext1_to_int4 can   */
            /*  look up four source pels at once, ie a nibble lookup table.   */
            /*  Note that this nibble table has the bytes flipped, i.e the    */
            /*  destination pels are stored as nibbles in order 3412          */
            /******************************************************************/
            SPad->Col.Bpp1.OneBppColour[0] = prdc_RGBToColIndex(&RGBTable[0]);
            SPad->Col.Bpp1.OneBppColour[1] = prdc_RGBToColIndex(&RGBTable[1]);
            for (ll=0; ll < 2 ; ll++)  /* bit 3                               */
            {
                for (kk=0; kk < 2 ; kk++) /* bit 2                            */
                {
                    for (jj=0; jj < 2 ; jj++) /* bit 1                        */
                    {
                        for (ii=0; ii < 2 ; ii++) /* bit 0                    */
                        {
          SPad->Col.Bpp1.ConvertTable[(ll << 3) + (kk << 2) + (jj << 1) + ii] =
                            (SPad->Col.Bpp1.OneBppColour[ll] << 4) +
                            (SPad->Col.Bpp1.OneBppColour[kk] << 0) +
                            (SPad->Col.Bpp1.OneBppColour[jj] << 12) +
                            (SPad->Col.Bpp1.OneBppColour[ii] << 8);
                        }
                    }
                }
            }
        }
        else if (SPad->ExtBpp == 4)
        {

            /******************************************************************/
            /*  External 4bpp to Internal 4bpp                                */
            /*                                                                */
            /*  Loop through all the colors in the external color table       */
            /*  finding which color in the internal palette is nearest to it. */
            /*                                                                */
            /*  We set up a conversion table which converts 2 pels (i.e one   */
            /*  byte) at a time.  We already have the space available for a   */
            /*  256 byte conversion table, and this should speed things up in */
            /*  convert_ext4_to_int4.                                         */
            /******************************************************************/
            for (ii=0; ii < 16 ; ii++)
            {
                ScratchTable[ii] = prdc_RGBToColIndex(&RGBTable[ii]);
            }
            for (jj=0; jj < 16 ; jj++) /* high nibble/pel                     */
            {
                for (ii=0; ii < 16 ; ii++) /* low nibble/pel                  */
                {
                    SPad->Col.ConvertTable[(jj << 4) | ii] =
                                 (BYTE)((ScratchTable[jj] << 4) |
                                         ScratchTable[ii]);
                }
            }
        }
        else if (SPad->ExtBpp == 8)
        {

            /******************************************************************/
            /*  External 8bpp to Internal 4bpp                                */
            /*                                                                */
            /*  Loop through all the colors in the external color table       */
            /*  finding which color in the internal palette is nearest to it. */
            /******************************************************************/
            for (ii=0; ii < 256 ; ii++)
            {
                SPad->Col.ConvertTable[ii] = prdc_RGBToColIndex(&RGBTable[ii]);
            }
        }
    }
}
#undef TFUNC

/******************************************************************************/
/*   FUNCTION: prdb_TransferExttoInt                                          */
/*                                                                            */
/*   PARAMETERS:                                                              */
/*   lpBMSPad  SPad  PD00400 : Pointer to bitmap scratch                      */
/*                                                                            */
/*   DESCRIPTION:                                                             */
/*                                                                            */
/*  This function transfers data from an external to an internal bitmap.  We  */
/*  do the transfers line by line, and for each line we calculate in advance  */
/*  whether we will hit a segment boundary.  Each of the routines             */
/*  convert_extX_to_intY which convert a line have two arms depending on      */
/*  whether the segment boundary flag is set.  If there is a segment boundary */
/*  somewhere in the line, the code uses the POSTINC macro for each increment */
/*  of the pointers; otherwise it uses a plain ++ operation.  This is a       */
/*  tradeoff which gives a large increase in speed for an increase in         */
/*  occupancy.                                                                */
/******************************************************************************/
VOID prdb_TransferExttoInt(lpBMSPad SPad)

#if 0
lpBMSPad  SPad;                        /* PD00400 : Pointer to bitmap scratch */
                                       /* pad                                 */
#endif
{

#define TFUNC "prdb_TransferExttoInt"

    /**************************************************************************/
    /*  Local variables...                                                    */
    /**************************************************************************/
    ULONG   BytesPerLine;
/*  ULONG   BytesLeftInSrcSeg, BytesLeftInDestSeg;  CON3201 : don't need      */
    ULONG   TotalSrcBytesPerLine;
    USHORT  SrcPadLength, DestPadLength;
/*  VOID    (pascal near *inner_convert)(); */
    VOID    (*inner_convert)();                                    /* CON3201 */

    /**************************************************************************/
    /*  Work out which routine will do the copying                            */
    /**************************************************************************/
    if (SPad->IntBpp==1)
    {
        switch (SPad->ExtBpp)
        {
            case  1 :
                inner_convert = convert_ext1_to_int1;
                break;
            case  4 :
                inner_convert = convert_ext4_to_int1;
                break;
            case  8 :
                inner_convert = convert_ext8_to_int1;
                break;
            case 24 :
                inner_convert = convert_ext24_to_int1;
                break;
            default : ;
        }
    }
    else
    {
        switch (SPad->ExtBpp)
        {
            case  1 :
                inner_convert = convert_ext1_to_int4;
                break;
            case  4 :
                inner_convert = convert_ext4_to_int4;
                break;
            case  8 :
                inner_convert = convert_ext8_to_int4;
                break;
            case 24 :
                inner_convert = convert_ext24_to_int4;
                break;
            default : ;
        }
    }

    /**************************************************************************/
    /*  We now set up variables concerning line lengths.  We require this     */
    /*  information in several different forms, so we do all calculations     */
    /*  outside the main copying loop.  The usage of the various local        */
    /*  variables is exemplified below.                                       */
    /*                                                                        */
    /*  For example, if we are converting from 4bpp to 1bpp and we have a line*/
    /*  length of 25 pels we would have:                                      */
    /*                                                                        */
    /*    BytesPerLine           = 12    (12 full bytes)                      */
    /*    SPad->PelsLeftOver     = 1     (plus one pel=a nibble)              */
    /*    TotalSrcBytesPerLine   = 13    (makes a total 13 bytes)             */
    /*    SrcPadLength           = 3     (+3bytes to be DWORD aligned)        */
    /*    SPad->DestBytesPerLine = 4     (3 full bytes+1 bit)                 */
    /*    DestPadLength          = 0                                          */
    /*                                                                        */
    /*  Or if we are converting from 24bpp to 4bpp and we have a line length  */
    /*  of 85 pels we would have:                                             */
    /*                                                                        */
    /*    BytesPerLine           = 255   (255 full bytes)                     */
    /*    SPad->PelsLeftOver     = 0     (plus 0pels)                         */
    /*    TotalSrcBytesPerLine   = 255   (makes a total 255 bytes)            */
    /*    SrcPadLength           = 1     (+1byte to be DWORD aligned)         */
    /*    SPad->DestBytesPerLine = 42    (42 full bytes + 1 nibble)           */
    /*    DestPadLength          = 2                                          */
    /*                                                                        */
    /**************************************************************************/

    /**************************************************************************/
    /*  Set up total number of bytes per line variables.  These include any   */
    /*  incomplete extra bytes at the end of the line.  Note that             */
    /*  SPad->DestBytesPerLine is used by several of the convert_extX_to_intY */
    /*  routines to save redoing this calculation.                            */
    /**************************************************************************/
    /**************************************************************************/
    /* PD00708 : Added ULONG cast to prevent overflow for 24:1 bitmap         */
    /**************************************************************************/
    TotalSrcBytesPerLine = ((ULONG)SPad->PelsPerLine *
                                                  (ULONG)SPad->ExtBpp + 7) / 8;
    SPad->DestBytesPerLine = (SPad->PelsPerLine * SPad->IntBpp + 7) / 8;

    /**************************************************************************/
    /*  Set up pads to DWORD boundaries at ends of lines                      */
    /**************************************************************************/
    if (SrcPadLength = (USHORT)(TotalSrcBytesPerLine % 4))
    {
        SrcPadLength  = 4 - SrcPadLength;
    }
    if (DestPadLength = (USHORT)(SPad->DestBytesPerLine % 4))
    {
        DestPadLength = 4 - DestPadLength;
    }

    /**************************************************************************/
    /*  Set up line length in terms of whole source bytes (BytesPerLine) and  */
    /*  extra pels (PelsLeftOver).                                            */
    /**************************************************************************/
    BytesPerLine       = (SPad->PelsPerLine * SPad->ExtBpp) / 8;
    SPad->PelsLeftOver = (SPad->PelsPerLine * SPad->ExtBpp) % 8;

    /**************************************************************************/
    /*  Main Loop: Loop through all of the lines to be converted.             */
    /**************************************************************************/
    while (SPad->LinesToConvert--)
    {

        /**********************************************************************/
        /*  CON3201 : don't need the following for 32-bit code                */
        /**********************************************************************/
#if 0
        /**********************************************************************/
        /*  Check if it is possible that this line can overrun a segment      */
        /*  boundary.                                                         */
        /**********************************************************************/
        BytesLeftInSrcSeg  = 65536L - (ULONG)OFFSETOF(SPad->SrcPtr);
        BytesLeftInDestSeg = 65536L - (ULONG)OFFSETOF(SPad->DestPtr);
        SPad->Safe = ((SPad->DestBytesPerLine < BytesLeftInDestSeg) &&
                      (TotalSrcBytesPerLine < BytesLeftInSrcSeg));
#endif
        SPad->Safe = TRUE;                                         /* CON3201 */

        /**********************************************************************/
        /*  Call a routine to convert one line.  This routine will update     */
        /*  SPad->SrcPtr and SPad->DestPtr to point just past the end of the  */
        /*  line.                                                             */
        /**********************************************************************/
        SPad->ChunkLength = BytesPerLine;
        inner_convert( SPad );

        /**********************************************************************/
        /*  Now move to DWORD boundaries, as each line must start on a DWORD  */
        /*  boundary.                                                         */
        /**********************************************************************/
        SPad->SrcPtr         += SrcPadLength;
     /* (PBYTE)SPad->DestPtr += DestPadLength; */
        SPad->DestPtr      = ((PBYTE)SPad->DestPtr) + DestPadLength; /*CON3201*/

        /**********************************************************************/
        /*  CON3201 : don't need the following for 32-bit code                */
        /**********************************************************************/
#if 0
        /**********************************************************************/
        /*  Check whether this last action has brought us to the start of a   */
        /*  new segment, and if so adjust accordingly.                        */
        /**********************************************************************/
        if (SrcPadLength && !OFFSETOF(SPad->SrcPtr))
        {
            SELECTOROF(SPad->SrcPtr) += prdd_HugeInc;
        }
        if (DestPadLength && !OFFSETOF(SPad->DestPtr))
        {
            SELECTOROF(SPad->DestPtr) += prdd_HugeInc;
        }
#endif
    }
}

PBYTE pTemp;    /* CON3201 : define temporary byte pointer */

/******************************************************************************/
/*  FUNCTION: convert_ext1_to_int1                                            */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*  lpBMSPad  SPad;  PD00400 : Pointer to bitmap scratch                      */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  These functions all transfer one whole line from the external bitmap to   */
/*  the internal bitmap, performing any necessary color conversions.  They    */
/*  take their parameters from the scratchpad area SPad, mainly using the     */
/*  fields:                                                                   */
/*                                                                            */
/*    SPad->ChunkLength       Number of whole bytes to convert                */
/*    SPad->PelsLeftOver      Number of pels in incomplete last byte          */
/*    SPad->Col.ConvertTable  color conversion table (array of bytes)         */
/*    SPad->Safe              Indicates whether to check for segment          */
/*                            boundaries or not.                              */
/*    SPad->SrcPtr            Pointer to current position in external bitmap  */
/*    SPad->DestPtr           Pointer to current position in internal bitmap  */
/*                                                                            */
/*  Each routine contains two arms, depending on the value of SPad->Safe.  If */
/*  it is TRUE, this means that there are no segment boundaries contained in  */
/*  this line, and thus we can use the increment (++) operator on pointers to */
/*  increase speed.  The second arm is the same as the first, but with        */
/*  increments replaced with the POSTINC macro, which checks for segment      */
/*  boundaries.  It is VERY IMPORTANT that if you change any of these routines*/
/*  that you make sure to change BOTH arms in the same way.                   */
/*                                                                            */
/*  Also note that, since each line in the bitmap will always start on a DWORD*/
/*  (4 byte) boundary, in some cases we can use the increment (++) operator in*/
/*  the segment boundary checking arm.                                        */
/******************************************************************************/
VOID convert_ext1_to_int1(lpBMSPad SPad)

#if 0
lpBMSPad  SPad;                        /* PD00400 : Pointer to bitmap scratch */
                                       /* pad                                 */
#endif
{

    /**************************************************************************/
    /*  Local variables...                                                    */
    /**************************************************************************/
    ULONG  TotalLength;

    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    /**************************************************************************/
    /*  See if we need to worry about segment boundaries.                     */
    /**************************************************************************/
    if (SPad->Safe)
    {
#endif
        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We know that we    */
        /*  don't need to worry about segment boundaries.  We use the flag    */
        /*  SPad->FillFlag, set up in TableExttoInt, which tells us what to do*/
        /*  with the target bitmap.                                           */
        /**********************************************************************/
        switch (SPad->FillFlag)
        {
            case SRC_ZEROS :

                /**************************************************************/
                /*  Fill the destination bitmap with zeroes.  Do the whole    */
                /*  line and zero the byte containing leftover pels.  We don't*/
                /*  bother updating SPad->SrcPtr since we don't need any of   */
                /*  the source data.  The routine TransferExttoInt, which     */
                /*  calls this routine, may change the pointer (by moving it  */
                /*  to what it thinks is a DWORD boundary at ends of lines)   */
                /*  but this will not matter as the scratchpad is not accessed*/
                /*  elsewhere.                                                */
                /**************************************************************/
                prdu_memset((PBYTE)SPad->DestPtr, (BYTE)'\0',
             /*             (SHORT)SPad->DestBytesPerLine);    */
                            (ULONG)SPad->DestBytesPerLine);        /* CON3201 */
             /* (PBYTE)SPad->DestPtr += SPad->DestBytesPerLine; */
                SPad->DestPtr = ((PBYTE)SPad->DestPtr) +           /* CON3201 */
                                (SPad->DestBytesPerLine);          /* CON3201 */
                break;
            case SRC_ONES   :

                /**************************************************************/
                /*  Fill the destination bitmap with ones.  We do not worry   */
                /*  about filling a few extra bits after the end of the line  */
                /*  with ones.  We don't bother updating SPad->SrcPtr since we*/
                /*  don't need any of the source data.  The routine           */
                /*  TransferExttoInt, which calls this routine, may change the*/
                /*  pointer (by moving it to what it thinks is a DWORD        */
                /*  boundary at ends of lines) but this will not matter as the*/
                /*  scratchpad is not accessed elsewhere.                     */
                /**************************************************************/
                prdu_memset((PBYTE)SPad->DestPtr, '\xff',
             /*             (SHORT)SPad->DestBytesPerLine);    */
                            (ULONG)SPad->DestBytesPerLine);        /* CON3201 */
             /* (PBYTE)SPad->DestPtr += SPad->DestBytesPerLine; */
                SPad->DestPtr = ((PBYTE)SPad->DestPtr) +           /* CON3201 */
                                (SPad->DestBytesPerLine);          /* CON3201 */
                break;
            case SRC_COPY_BITS  :

                /**************************************************************/
                /*  Copy the source (external) bitmap as it is.  We do the    */
                /*  whole line and include the final byte containing leftover */
                /*  pels if it exists.                                        */
                /**************************************************************/
                prdu_memcpy((PBYTE)SPad->DestPtr, (PBYTE)SPad->SrcPtr,
             /*             (SHORT)SPad->DestBytesPerLine);     */
                            (ULONG)SPad->DestBytesPerLine);        /* CON3201 */
             /* (PBYTE) SPad->DestPtr += SPad->DestBytesPerLine; */
                SPad->DestPtr = ((PBYTE)SPad->DestPtr) +           /* CON3201 */
                                (SPad->DestBytesPerLine);          /* CON3201 */
                SPad->SrcPtr          += SPad->DestBytesPerLine;
                break;
            case SRC_INVERT_BITS:

                /**************************************************************/
                /*  Copy the external bitmap, doing a bitwise NOT on each     */
                /*  byte.  For the final byte, we don't worry about those bits*/
                /*  which are not part of the line.                           */
                /**************************************************************/
                TotalLength = SPad->DestBytesPerLine;
                while (TotalLength--)
                {
                 /* *((PBYTE) SPad->DestPtr)++ = ~*SPad->SrcPtr++; */
                    pTemp         = SPad->DestPtr;                 /* CON3201 */
                    *pTemp++      = ~*SPad->SrcPtr++;              /* CON3201 */
                    SPad->DestPtr = pTemp;                         /* CON3201 */
                }
                break;
        }

    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    }
    else
    {

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We use the POSTINC */
        /*  macro to cope with segment boundaries.  This arm will be much     */
        /*  slower than the arm above.  We use the flag SPad->FillFlag, set up*/
        /*  in TableExttoInt, which tells us what to do with the target       */
        /*  bitmap.                                                           */
        /**********************************************************************/
        TotalLength = SPad->DestBytesPerLine;
        switch (SPad->FillFlag)
        {
            case SRC_ZEROS :

                /**************************************************************/
                /*  Fill the destination bitmap with zeroes.  Do the whole    */
                /*  line and zero the byte containing leftover pels.  We don't*/
                /*  bother updating SPad->SrcPtr since we don't need any of   */
                /*  the source data.  The routine TransferExttoInt, which     */
                /*  calls this routine, may change the pointer (by moving it  */
                /*  to what it thinks is a DWORD boundary at ends of lines)   */
                /*  but this will not matter as the scratchpad is not accessed*/
                /*  elsewhere.                                                */
                /**************************************************************/
                while (TotalLength--)
                {
                    *((PBYTE) SPad->DestPtr) = '\0';
                    POSTINC(SPad->DestPtr);
                }
                break;
            case SRC_ONES   :

                /**************************************************************/
                /*  Fill the destination bitmap with ones.  We do not worry   */
                /*  about filling a few extra bits after the end of the line  */
                /*  with ones.  We don't bother updating SPad->SrcPtr since we*/
                /*  don't need any of the source data.  The routine           */
                /*  TransferExttoInt, which calls this routine, may change the*/
                /*  pointer (by moving it to what it thinks is a DWORD        */
                /*  boundary at ends of lines) but this will not matter as the*/
                /*  scratchpad is not accessed elsewhere.                     */
                /**************************************************************/
                while (TotalLength--)
                {
                    *((PBYTE) SPad->DestPtr) = '\xff';
                    POSTINC(SPad->DestPtr);
                }
                break;
            case SRC_COPY_BITS  :

                /**************************************************************/
                /*  Copy the source (external) bitmap as it is.  We do the    */
                /*  whole line and include the final byte containing leftover */
                /*  pels if it exists.                                        */
                /**************************************************************/
                while (TotalLength--)
                {
                    *((PBYTE) SPad->DestPtr) = *SPad->SrcPtr;
                    POSTINC(SPad->SrcPtr);
                    POSTINC(SPad->DestPtr);
                }
                break;
            case SRC_INVERT_BITS:

                /**************************************************************/
                /*  Copy the external bitmap, doing a bitwise NOT on each     */
                /*  byte.  For the final byte, we don't worry about those bits*/
                /*  which are not part of the line.                           */
                /**************************************************************/
                while (TotalLength--)
                {
                    *((PBYTE) SPad->DestPtr) = ~*SPad->SrcPtr;
                    POSTINC(SPad->SrcPtr);
                    POSTINC(SPad->DestPtr);
                }
                break;
        }
    }
#endif
}

/******************************************************************************/
/*  FUNCTION: convert_ext4_to_int1                                            */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*  lpBMSPad  SPad;  PD00400 : Pointer to bitmap scratch                      */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  These functions all transfer one whole line from the external bitmap to   */
/*  the internal bitmap, performing any necessary color conversions.  They    */
/*  take their parameters from the scratchpad area SPad, mainly using the     */
/*  fields:                                                                   */
/*                                                                            */
/*    SPad->ChunkLength       Number of whole bytes to convert                */
/*    SPad->PelsLeftOver      Number of pels in incomplete last byte          */
/*    SPad->Col.ConvertTable  color conversion table (array of bytes)         */
/*    SPad->Safe              Indicates whether to check for segment          */
/*                            boundaries or not.                              */
/*    SPad->SrcPtr            Pointer to current position in external bitmap  */
/*    SPad->DestPtr           Pointer to current position in internal bitmap  */
/*                                                                            */
/*  Each routine contains two arms, depending on the value of SPad->Safe.  If */
/*  it is TRUE, this means that there are no segment boundaries contained in  */
/*  this line, and thus we can use the increment (++) operator on pointers to */
/*  increase speed.  The second arm is the same as the first, but with        */
/*  increments replaced with the POSTINC macro, which checks for segment      */
/*  boundaries.  It is VERY IMPORTANT that if you change any of these routines*/
/*  that you make sure to change BOTH arms in the same way.                   */
/*                                                                            */
/*  Also note that, since each line in the bitmap will always start on a DWORD*/
/*  (4 byte) boundary, in some cases we can use the increment (++) operator in*/
/*  the segment boundary checking arm.                                        */
/******************************************************************************/
VOID convert_ext4_to_int1(lpBMSPad SPad)

#if 0
lpBMSPad  SPad;                        /* PD00400 : Pointer to bitmap scratch */
                                       /* pad                                 */
#endif
{

    /**************************************************************************/
    /*  Local variables...                                                    */
    /**************************************************************************/
    BYTE    SrcByte, DestByte;
    USHORT  BytesToConvert;
    int     Bit = 7;

    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    /**************************************************************************/
    /*  See if we need to worry about segment boundaries.                     */
    /**************************************************************************/
    if (SPad->Safe)
    {
#endif

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We know that we    */
        /*  don't need to worry about segment boundaries.  We also check for  */
        /*  the special case when all of the source colors all mapped to the  */
        /*  same destination color - this is marked by TableExttoInt in the   */
        /*  field SPad->ColoursHad We use the field SPad->DestBytesPerLine,    */
        /*  which is set up in TransferExttoInt, to tell us how big the       */
        /*  destination line is, when we are just filling it with one color.  */
        /**********************************************************************/
        if (SPad->ColoursHad != (HAD_WHITE | HAD_BLACK))
        {

            /******************************************************************/
            /*  We fill the entire line with either black or white.  We don't */
            /*  worry about filling the last byte (which may only be partially*/
            /*  in the line).  We don't bother updating SPad->SrcPtr as we    */
            /*  will never use it.                                            */
            /******************************************************************/
            DestByte = (BYTE)(0xFF * SPad->Col.ConvertTable[0]);
            prdu_memset((PBYTE) SPad->DestPtr, DestByte,
         /*             (USHORT)SPad->DestBytesPerLine);    */
                        (ULONG)SPad->DestBytesPerLine);            /* CON3201 */
         /* (PBYTE)SPad->DestPtr += SPad->DestBytesPerLine; */
            SPad->DestPtr = ((PBYTE)SPad->DestPtr) +               /* CON3201 */
                            (SPad->DestBytesPerLine);              /* CON3201 */
        }
        else
        {

            /******************************************************************/
            /*  Loop through converting four source bytes to one target byte. */
            /******************************************************************/
            BytesToConvert = (USHORT)(SPad->ChunkLength / 4);
            while (BytesToConvert--)
            {
                SrcByte   = *SPad->SrcPtr++;
                DestByte  = SPad->Col.ConvertTable[SrcByte >> 4] << 7 |
                            SPad->Col.ConvertTable[SrcByte & 0x0f] << 6;
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte >> 4] << 5 |
                            SPad->Col.ConvertTable[SrcByte & 0x0f] << 4;
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte >> 4] << 3 |
                            SPad->Col.ConvertTable[SrcByte & 0x0f] << 2;
                SrcByte   = *SPad->SrcPtr++;
             /* *((PBYTE)SPad->DestPtr)++ = DestByte | */
                pTemp     = SPad->DestPtr;                         /* CON3201 */
                *pTemp++  = DestByte |                             /* CON3201 */
                            SPad->Col.ConvertTable[SrcByte >> 4] << 1 |
                            SPad->Col.ConvertTable[SrcByte & 0x0f];
                SPad->DestPtr = pTemp;                             /* CON3201 */
            }
            DestByte = 0;

            /******************************************************************/
            /*  We may have up to three source bytes still to convert.        */
            /******************************************************************/
            for (BytesToConvert = 0;
                 BytesToConvert < (USHORT) (SPad->ChunkLength % 4);
                 BytesToConvert++)
            {
                SrcByte = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte >> 4] << Bit |
                            SPad->Col.ConvertTable[SrcByte & 0x0f] << (Bit - 1);
                Bit -= 2;
            }

            /******************************************************************/
            /*  We may have one pel left over still to convert.               */
            /******************************************************************/
            if (SPad->PelsLeftOver)
            {
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte >> 4] << Bit--;
            }
            if (Bit < 7)               /* need to write this last byte        */
            {
             /* *((PBYTE)SPad->DestPtr)++ = DestByte; */
                pTemp         = SPad->DestPtr;                     /* CON3201 */
                *pTemp++      = DestByte;                          /* CON3201 */
                SPad->DestPtr = pTemp;                             /* CON3201 */
            }

        }
    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    }
    else
    {

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We use the POSTINC */
        /*  macro to check for segment boundaries.  We also check for the     */
        /*  special case when all of the source colors all mapped to the same */
        /*  destination color - this is marked by TableExttoInt in the field  */
        /*  SPad->ColoursHad We use the field SPad->DestBytesPerLine, which is */
        /*  set up in TransferExttoInt, to tell us how big the destination    */
        /*  line is, when we are just filling it with one color.              */
        /**********************************************************************/
        if (SPad->ColoursHad != (HAD_WHITE | HAD_BLACK))
        {

            /******************************************************************/
            /*  We fill the entire line with either black or white.  We don't */
            /*  worry about filling the last byte (which may only be partially*/
            /*  in the line).  We don't bother updating SPad->SrcPtr as we    */
            /*  will never use it.                                            */
            /******************************************************************/
            BytesToConvert = (USHORT) SPad->DestBytesPerLine;
            DestByte = (BYTE)(0xFF * SPad->Col.ConvertTable[0]);
            while (BytesToConvert--)
            {
                *((PBYTE) SPad->DestPtr) = DestByte;
                POSTINC(SPad->DestPtr);
            }
        }
        else
        {

            /******************************************************************/
            /*  Loop through converting four source bytes to one target byte. */
            /*  Although we need to check for segment boundaries, as we know  */
            /*  that both lines and segments start on DWORD boundaries, in the*/
            /*  following code, we only check for segment boundaries every    */
            /*  fourth source byte.                                           */
            /*    Now very second source byte (PD00680).                      */
            /******************************************************************/
            BytesToConvert = (USHORT) (SPad->ChunkLength / 4);
            while (BytesToConvert--)
            {
                SrcByte   = *SPad->SrcPtr++;
                DestByte  = SPad->Col.ConvertTable[SrcByte >> 4] << 7 |
                            SPad->Col.ConvertTable[SrcByte & 0x0f] << 6;
                SrcByte   = *SPad->SrcPtr;                        /* PD00680 */
                POSTINC(SPad->SrcPtr); /* check every 2nd byte */ /* PD00680 */
                DestByte |= SPad->Col.ConvertTable[SrcByte >> 4] << 5 |
                            SPad->Col.ConvertTable[SrcByte & 0x0f] << 4;
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte >> 4] << 3 |
                            SPad->Col.ConvertTable[SrcByte & 0x0f] << 2;
                SrcByte   = *SPad->SrcPtr;
                POSTINC(SPad->SrcPtr); /* we can get four bytes at once */
                *((PBYTE)SPad->DestPtr) = DestByte |
                            SPad->Col.ConvertTable[SrcByte >> 4] << 1 |
                            SPad->Col.ConvertTable[SrcByte & 0x0f];
                POSTINC(SPad->DestPtr);
            }
            DestByte = 0;

            /******************************************************************/
            /*  We may have up to three source bytes still to convert.  The   */
            /*  first of these must start on a DWORD boundary, and thus as we */
            /*  are examining at most three souce bytes, we don't need to     */
            /*  check for source segment boundaries in this loop.             */
            /*    NOW every second byte (PD00680).                            */
            /******************************************************************/
            for (BytesToConvert = 0;
                 BytesToConvert < (USHORT) (SPad->ChunkLength % 4);
                 BytesToConvert++)
            {
                SrcByte   = *SPad->SrcPtr;                        /* PD00680 */
                POSTINC(SPad->SrcPtr); /* check every 2nd byte */ /* PD00680 */
                DestByte |= SPad->Col.ConvertTable[SrcByte >> 4] << Bit |
                            SPad->Col.ConvertTable[SrcByte & 0x0f] << (Bit - 1);
                Bit -= 2;
            }

            /******************************************************************/
            /*  We may have one pel left over still to convert.               */
            /******************************************************************/
            if (SPad->PelsLeftOver)
            {
                SrcByte = *SPad->SrcPtr;
                POSTINC(SPad->SrcPtr);
                DestByte |= SPad->Col.ConvertTable[SrcByte >> 4] << Bit--;
            }
            if (Bit < 7)               /* need to write this last byte        */
            {
                *((PBYTE)SPad->DestPtr) = DestByte;
                POSTINC(SPad->DestPtr);
            }
        }
    }
#endif
}

/******************************************************************************/
/*  FUNCTION: convert_ext8_to_int1                                            */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*  lpBMSPad  SPad;  PD00400 : Pointer to bitmap scratch                      */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  These functions all transfer one whole line from the external bitmap to   */
/*  the internal bitmap, performing any necessary color conversions.  They    */
/*  take their parameters from the scratchpad area SPad, mainly using the     */
/*  fields:                                                                   */
/*                                                                            */
/*    SPad->ChunkLength       Number of whole bytes to convert                */
/*    SPad->PelsLeftOver      Number of pels in incomplete last byte          */
/*    SPad->Col.ConvertTable  color conversion table (array of bytes)         */
/*    SPad->Safe              Indicates whether to check for segment          */
/*                            boundaries or not.                              */
/*    SPad->SrcPtr            Pointer to current position in external bitmap  */
/*    SPad->DestPtr           Pointer to current position in internal bitmap  */
/*                                                                            */
/*  Each routine contains two arms, depending on the value of SPad->Safe.  If */
/*  it is TRUE, this means that there are no segment boundaries contained in  */
/*  this line, and thus we can use the increment (++) operator on pointers to */
/*  increase speed.  The second arm is the same as the first, but with        */
/*  increments replaced with the POSTINC macro, which checks for segment      */
/*  boundaries.  It is VERY IMPORTANT that if you change any of these routines*/
/*  that you make sure to change BOTH arms in the same way.                   */
/*                                                                            */
/*  Also note that, since each line in the bitmap will always start on a DWORD*/
/*  (4 byte) boundary, in some cases we can use the increment (++) operator in*/
/*  the segment boundary checking arm.                                        */
/******************************************************************************/
VOID convert_ext8_to_int1(lpBMSPad SPad)

#if 0
lpBMSPad  SPad;                        /* PD00400 : Pointer to bitmap scratch */
                                       /* pad                                 */
#endif
{

    /**************************************************************************/
    /*  Local variables...                                                    */
    /**************************************************************************/
    BYTE    SrcByte, DestByte;
    USHORT  BytesToConvert;
    USHORT  Bit = 7;

    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    /**************************************************************************/
    /*  See if we need to worry about segment boundaries.                     */
    /**************************************************************************/
    if (SPad->Safe)
    {
#endif

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We know that we    */
        /*  don't need to worry about segment boundaries.  We also check for  */
        /*  the special case when all of the source colors all mapped to the  */
        /*  same destination color - this is marked by TableExttoInt in the   */
        /*  field SPad->ColoursHad We use the field SPad->DestBytesPerLine,    */
        /*  which is set up in TransferExttoInt, to tell us how big the       */
        /*  destination line is, when we are just filling it with one color.  */
        /**********************************************************************/
        if (SPad->ColoursHad != (HAD_WHITE | HAD_BLACK))
        {

            /******************************************************************/
            /*  We fill the entire line with either black or white.  We don't */
            /*  worry about filling the last byte (which may only be partially*/
            /*  in the line).  We don't bother updating SPad->SrcPtr as we    */
            /*  will never use it.                                            */
            /******************************************************************/
            DestByte = (BYTE)(0xFF * SPad->Col.ConvertTable[0]);
            prdu_memset((PBYTE)SPad->DestPtr, DestByte,
         /*             (USHORT)SPad->DestBytesPerLine);       */
                        (ULONG)SPad->DestBytesPerLine);            /* CON3201 */
         /* ((BYTE *)SPad->DestPtr) += SPad->DestBytesPerLine; */
            SPad->DestPtr = ((PBYTE)SPad->DestPtr) +               /* CON3201 */
                            (SPad->DestBytesPerLine);              /* CON3201 */
        }
        else
        {

            /******************************************************************/
            /*  Loop through converting eight source bytes to one target byte.*/
            /*                                                                */
            /******************************************************************/
            BytesToConvert = (USHORT)(SPad->ChunkLength / 8);
            while (BytesToConvert--)
            {
                SrcByte   = *SPad->SrcPtr++;
                DestByte  = SPad->Col.ConvertTable[SrcByte] << 7;
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte] << 6;
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte] << 5;
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte] << 4;
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte] << 3;
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte] << 2;
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte] << 1;
                SrcByte   = *SPad->SrcPtr++;
             /* *((PBYTE)SPad->DestPtr)++ = DestByte | */
                pTemp     = SPad->DestPtr;                         /* CON3201 */
                *pTemp++  = DestByte |                             /* CON3201 */
                            SPad->Col.ConvertTable[SrcByte];
                SPad->DestPtr = pTemp;                             /* CON3201 */
            }
            DestByte = 0;

            /******************************************************************/
            /*  We may have up to seven source bytes still to convert.        */
            /******************************************************************/
            for (BytesToConvert = 0;
                 BytesToConvert < (USHORT) (SPad->ChunkLength % 8);
                 BytesToConvert++)
            {
                SrcByte = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte] << Bit--;
            }
            if (Bit < 7)               /* need to write this last byte        */
            {
             /* *((PBYTE)SPad->DestPtr)++ = DestByte; */
                pTemp         = SPad->DestPtr;                     /* CON3201 */
                *pTemp++      = DestByte;                          /* CON3201 */
                SPad->DestPtr = pTemp;                             /* CON3201 */
            }
        }
    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    }
    else
    {

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We use the POSTINC */
        /*  macro to check for segment boundaries.  We also check for the     */
        /*  special case when all of the source colors all mapped to the same */
        /*  destination color - this is marked by TableExttoInt in the field  */
        /*  SPad->ColoursHad We use the field SPad->DestBytesPerLine, which is */
        /*  set up in TransferExttoInt, to tell us how big the destination    */
        /*  line is, when we are just filling it with one color.              */
        /**********************************************************************/
        if (SPad->ColoursHad != (HAD_WHITE | HAD_BLACK))
        {
            BytesToConvert = (USHORT)SPad->DestBytesPerLine;
            DestByte       = (BYTE)(0xFF * SPad->Col.ConvertTable[0]);
            while (BytesToConvert--)
            {
              *((PBYTE) SPad->DestPtr) = DestByte;
              POSTINC(SPad->DestPtr);
            }
        }
        else
        {

            /******************************************************************/
            /*  Loop through converting eight source bytes to one target byte.*/
            /*  Although we need to check for segment boundaries, as we know  */
            /*  that both lines and segments start on DWORD boundaries, in the*/
            /*  following code, we only check for segment boundaries every    */
            /*  fourth source byte.                                           */
            /*    NOW every second source byte (PD00680).                     */
            /******************************************************************/
            BytesToConvert = (USHORT) (SPad->ChunkLength / 8);
            while (BytesToConvert--)
            {
                SrcByte   = *SPad->SrcPtr++;
                DestByte  = SPad->Col.ConvertTable[SrcByte] << 7;
                SrcByte   = *SPad->SrcPtr;                        /* PD00680 */
                POSTINC(SPad->SrcPtr); /* check every 2nd byte */ /* PD00680 */
                DestByte |= SPad->Col.ConvertTable[SrcByte] << 6;
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte] << 5;
                SrcByte   = *SPad->SrcPtr;
                POSTINC(SPad->SrcPtr); /* check every 2nd byte */
                DestByte |= SPad->Col.ConvertTable[SrcByte] << 4;
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte] << 3;
                SrcByte   = *SPad->SrcPtr;                        /* PD00680 */
                POSTINC(SPad->SrcPtr); /* check every 2nd byte */ /* PD00680 */
                DestByte |= SPad->Col.ConvertTable[SrcByte] << 2;
                SrcByte   = *SPad->SrcPtr++;
                DestByte |= SPad->Col.ConvertTable[SrcByte] << 1;
                SrcByte   = *SPad->SrcPtr;
                POSTINC(SPad->SrcPtr); /* check every 2nd byte */
                *((PBYTE)SPad->DestPtr) = DestByte |
                                          SPad->Col.ConvertTable[SrcByte];
                POSTINC(SPad->DestPtr);
            }
            DestByte = 0;

            /******************************************************************/
            /*  We may have up to seven source bytes still to convert.        */
            /******************************************************************/
            for (BytesToConvert=0;
                 BytesToConvert < (USHORT) (SPad->ChunkLength % 8);
                 BytesToConvert++)
            {
                SrcByte = *SPad->SrcPtr;
                POSTINC(SPad->SrcPtr);
                DestByte |= SPad->Col.ConvertTable[SrcByte] << Bit--;
            }
            if (Bit < 7)               /* need to write this last byte        */
            {
                *((PBYTE)SPad->DestPtr) = DestByte;
                POSTINC(SPad->DestPtr);
            }
        }
    }
#endif
}

/******************************************************************************/
/*  FUNCTION: convert_ext24_to_int1                                           */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*  lpBMSPad  SPad;  PD00400 : Pointer to bitmap scratch                      */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  These functions all transfer one whole line from the external bitmap to   */
/*  the internal bitmap, performing any necessary color conversions.  They    */
/*  take their parameters from the scratchpad area SPad, mainly using the     */
/*  fields:                                                                   */
/*                                                                            */
/*    SPad->ChunkLength       Number of whole bytes to convert                */
/*    SPad->PelsLeftOver      Number of pels in incomplete last byte          */
/*    SPad->Col.ConvertTable  color conversion table (array of bytes)         */
/*    SPad->Safe              Indicates whether to check for segment          */
/*                            boundaries or not.                              */
/*    SPad->SrcPtr            Pointer to current position in external bitmap  */
/*    SPad->DestPtr           Pointer to current position in internal bitmap  */
/*                                                                            */
/*  Each routine contains two arms, depending on the value of SPad->Safe.  If */
/*  it is TRUE, this means that there are no segment boundaries contained in  */
/*  this line, and thus we can use the increment (++) operator on pointers to */
/*  increase speed.  The second arm is the same as the first, but with        */
/*  increments replaced with the POSTINC macro, which checks for segment      */
/*  boundaries.  It is VERY IMPORTANT that if you change any of these routines*/
/*  that you make sure to change BOTH arms in the same way.                   */
/*                                                                            */
/*  Also note that, since each line in the bitmap will always start on a DWORD*/
/*  (4 byte) boundary, in some cases we can use the increment (++) operator in*/
/*  the segment boundary checking arm.                                        */
/******************************************************************************/
VOID convert_ext24_to_int1(lpBMSPad SPad)

#if 0
lpBMSPad  SPad;                        /* PD00400 : Pointer to bitmap scratch */
                                       /* pad                                 */
#endif
{

    /**************************************************************************/
    /*  Local variables...                                                    */
    /**************************************************************************/
    RGB2    ThisPel;                                /* CON3201 - Now use RGB2 */
    RGB2    *prgbTemp;                                             /* CON3201 */
    USHORT  Bit = 8;
    BYTE    DestByte = 0;

    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    /**************************************************************************/
    /*  See if we need to worry about segment boundaries.                     */
    /**************************************************************************/
    if (SPad->Safe)
    {
#endif

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We know that we    */
        /*  don't need to worry about segment boundaries.  If MONO_BLACK is 1 */
        /*  then we need to invert each pel.                                  */
        /**********************************************************************/
        do
        {
         /* ThisPel = *((RGB far *) SPad->SrcPtr)++; */
            prgbTemp = ((RGB2 *) SPad->SrcPtr);                    /* CON3201 */
            ThisPel  = *prgbTemp++;                                /* CON3201 */
            SPad->SrcPtr = (PBYTE)prgbTemp;                        /* CON3201 */
            DestByte |= (

#if MONO_BLACK==1

                        MONO_BLACK -

#endif

                        ((ThisPel.bRed + ThisPel.bGreen + ThisPel.bBlue) / 385))
                        << --Bit;

            /******************************************************************/
            /*  If we are on bit zero, we are finished with this destination  */
            /*  byte.  Write it, then reset DestByte and Bit.                 */
            /******************************************************************/
            if (!Bit)
            {
             /* *((PBYTE) SPad->DestPtr)++ = DestByte; */
                pTemp         = SPad->DestPtr;                     /* CON3201 */
                *pTemp++      = DestByte;                          /* CON3201 */
                SPad->DestPtr = pTemp;                             /* CON3201 */
                DestByte = 0;
                Bit = 8;
            }
        } while (SPad->ChunkLength-=3);

        /**********************************************************************/
        /*  We have finished all the source bytes.  We may be partially       */
        /*  through a destination byte.                                       */
        /**********************************************************************/
        if (Bit < 8)
        {
         /* *((PBYTE) SPad->DestPtr)++ = DestByte; */
            pTemp         = SPad->DestPtr;                         /* CON3201 */
            *pTemp++      = DestByte;                              /* CON3201 */
            SPad->DestPtr = pTemp;                                 /* CON3201 */
        }
    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    }
    else
    {

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We use the POSTINC */
        /*  macro to check for segment boundaries.  We keep the last RGB value*/
        /*  and whether it mapped to black or white, and check against this   */
        /*  before calculating whether a pel is white or black.  If MONO_BLACK*/
        /*  is 1 then we need to invert each pel.  Note that bits in the      */
        /*  external bitmap are stored in order blue, green, red.             */
        /**********************************************************************/
        do
        {
            ThisPel.bBlue  = *SPad->SrcPtr;
            POSTINC(SPad->SrcPtr);
            ThisPel.bGreen = *SPad->SrcPtr;
            POSTINC(SPad->SrcPtr);
            ThisPel.bRed   = *SPad->SrcPtr;
            POSTINC(SPad->SrcPtr);
            DestByte |= (

*if MONO_BLACK==1   /* CON3201 : changed # to * so compiler will ignore       */

                        MONO_BLACK -

*endif              /* CON3201 : changed # to * so compiler will ignore       */

                        ((ThisPel.bRed + ThisPel.bGreen + ThisPel.bBlue) / 385))
                        << --Bit;

            /******************************************************************/
            /*  If we are on bit zero, we are finished with this destination  */
            /*  byte.  Write it, then reset DestByte and Bit.                 */
            /******************************************************************/
            if (!Bit)
            {
                *((PBYTE) SPad->DestPtr) = DestByte;
                POSTINC(SPad->DestPtr);
                DestByte = 0;
                Bit = 8;
            }
        } while (SPad->ChunkLength-=3);

        /**********************************************************************/
        /*  We have finished all the source bytes.  We may be partially       */
        /*  through a destination byte.                                       */
        /**********************************************************************/
        if (Bit < 8)
        {
            *((PBYTE) SPad->DestPtr) = DestByte;
            POSTINC(SPad->DestPtr);
        }
    }
#endif
}

/******************************************************************************/
/*  FUNCTION: convert_ext1_to_int4                                            */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*  lpBMSPad  SPad;  PD00400 : Pointer to bitmap scratch                      */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  These functions all transfer one whole line from the external bitmap to   */
/*  the internal bitmap, performing any necessary color conversions.  They    */
/*  take their parameters from the scratchpad area SPad, mainly using the     */
/*  fields:                                                                   */
/*                                                                            */
/*    SPad->ChunkLength       Number of whole bytes to convert                */
/*    SPad->PelsLeftOver      Number of pels in incomplete last byte          */
/*    SPad->Col.ConvertTable  color conversion table (array of bytes)         */
/*    SPad->Safe              Indicates whether to check for segment          */
/*                            boundaries or not.                              */
/*    SPad->SrcPtr            Pointer to current position in external bitmap  */
/*    SPad->DestPtr           Pointer to current position in internal bitmap  */
/*                                                                            */
/*  Each routine contains two arms, depending on the value of SPad->Safe.  If */
/*  it is TRUE, this means that there are no segment boundaries contained in  */
/*  this line, and thus we can use the increment (++) operator on pointers to */
/*  increase speed.  The second arm is the same as the first, but with        */
/*  increments replaced with the POSTINC macro, which checks for segment      */
/*  boundaries.  It is VERY IMPORTANT that if you change any of these routines*/
/*  that you make sure to change BOTH arms in the same way.                   */
/*                                                                            */
/*  Also note that, since each line in the bitmap will always start on a DWORD*/
/*  (4 byte) boundary, in some cases we can use the increment (++) operator in*/
/*  the segment boundary checking arm.                                        */
/******************************************************************************/
VOID convert_ext1_to_int4(lpBMSPad SPad)

#if 0
lpBMSPad  SPad;                        /* PD00400 : Pointer to bitmap scratch */
                                       /* pad                                 */
#endif
{

    /**************************************************************************/
    /*  Local variables...                                                    */
    /**************************************************************************/
    BYTE    SrcByte;
    BYTE    DestByte = 0;
    USHORT  Nibble = 4;
    USHORT  Bit = 7;                   /* always start on top bit             */
    PUSHORT puTemp;                    /* CON3201                             */

    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    /**************************************************************************/
    /*  See if we need to worry about segment boundaries.                     */
    /**************************************************************************/
    if (SPad->Safe)
    {
#endif

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We know that we    */
        /*  don't need to worry about segment boundaries.  We do 4 pels at a  */
        /*  time, using the nibble lookup table.  Note that this routine uses */
        /*  the variant form of the ConvertTable since we need an array of    */
        /*  USHORTs instead of an array of BYTES.                             */
        /**********************************************************************/
        while (SPad->ChunkLength--)
        {
            SrcByte = *SPad->SrcPtr++;
         /* *((PUSHORT)SPad->DestPtr)++ = */
            puTemp = ((PUSHORT)SPad->DestPtr);                     /* CON3201 */
            *puTemp++ =                                            /* CON3201 */
                                      SPad->Col.Bpp1.ConvertTable[SrcByte >> 4];
         /* *((PUSHORT)SPad->DestPtr)++ = */
            *puTemp++ =                                            /* CON3201 */
                                    SPad->Col.Bpp1.ConvertTable[SrcByte & 0x0f];
            SPad->DestPtr = puTemp;                                /* CON3201 */
        }

        /**********************************************************************/
        /*  We may have some pels left over to convert from the next source   */
        /*  byte.                                                             */
        /**********************************************************************/
        if (SPad->PelsLeftOver)
        {
            SrcByte = *SPad->SrcPtr++;

            /******************************************************************/
            /*  Loop through the remaining pels, starting with the first pel, */
            /*  which is the top bit.                                         */
            /******************************************************************/
            for ( ;Bit > (7 - SPad->PelsLeftOver); Bit--)
            {
                DestByte |= (SPad->Col.Bpp1.OneBppColour[(SrcByte >> Bit) & 1]
                             << Nibble);

                /**************************************************************/
                /*  Move to the next nibble of the destination byte.  If the  */
                /*  Nibble is now 4 then we must put this DestByte to the     */
                /*  bitmap and clear it.                                      */
                /**************************************************************/
                if (Nibble ^= 4)
                {
                 /* *((PBYTE) SPad->DestPtr)++ = DestByte; */
                    pTemp         = SPad->DestPtr;                 /* CON3201 */
                    *pTemp++      = DestByte;                      /* CON3201 */
                    SPad->DestPtr = pTemp;                         /* CON3201 */
                    DestByte = 0;
                }
            }
            if (!Nibble)               /* write back the last byte            */
            {
             /* *((PBYTE) SPad->DestPtr)++ = DestByte; */
                pTemp         = SPad->DestPtr;                     /* CON3201 */
                *pTemp++      = DestByte;                          /* CON3201 */
                SPad->DestPtr = pTemp;                             /* CON3201 */
            }
        }
    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    }
    else
    {

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We use the POSTINC */
        /*  macro to check for segment boundaries.  We do 4 pels at a time,   */
        /*  using the nibble lookup table.  Note that this routine uses the   */
        /*  variant form of the ConvertTable since we need an array of USHORTs*/
        /*  instead of an array of BYTES.                                     */
        /**********************************************************************/
        /* NOTE: The casting to "(PUSHORT)" below causes the "++" to          */
        /*       increment by 2.                                              */
        /*       The casting to "(PBYTE)" below allows the "++" to increment  */
        /*       by 1.         .                                              */
        /*       POSTINC always increments by 1.                              */
        /**********************************************************************/
        while (SPad->ChunkLength--)
        {
            SrcByte = *SPad->SrcPtr;
            POSTINC(SPad->SrcPtr)
            *((PUSHORT)SPad->DestPtr) =                      /* PD00680 */
                                      SPad->Col.Bpp1.ConvertTable[SrcByte >> 4];
            ((PBYTE)SPad->DestPtr)++;  /* Increment by two */     /* PD00680 */
            POSTINC(SPad->DestPtr);                               /* PD00680 */
            *((PUSHORT)SPad->DestPtr) =
                                    SPad->Col.Bpp1.ConvertTable[SrcByte & 0x0f];
            ((PBYTE)SPad->DestPtr)++;  /* We can put four at a time           */
            POSTINC(SPad->DestPtr);
        }

        /**********************************************************************/
        /*  We may have some pels left over to convert from the next source   */
        /*  byte.                                                             */
        /**********************************************************************/
        if (SPad->PelsLeftOver)
        {
            SrcByte = *SPad->SrcPtr;
            POSTINC(SPad->SrcPtr);

            /******************************************************************/
            /*  Loop through the remaining pels, starting with the first pel, */
            /*  which is the top bit.                                         */
            /******************************************************************/
            for (;Bit > (7 - SPad->PelsLeftOver); Bit--)
            {
                DestByte |= (SPad->Col.Bpp1.OneBppColour[(SrcByte>>Bit) & 1]
                             << Nibble);

                /**************************************************************/
                /*  Move to the next nibble of the destination byte.  If the  */
                /*  Nibble is now 4 then we must put this DestByte to the     */
                /*  bitmap and clear it.                                      */
                /**************************************************************/
                if (Nibble ^= 4)
                {
                    *((PBYTE) SPad->DestPtr) = DestByte;
                    POSTINC(SPad->DestPtr);
                    DestByte = 0;
                }
            }
            if (!Nibble)               /* write back the last byte            */
            {
                *((PBYTE) SPad->DestPtr) = DestByte;
                POSTINC(SPad->DestPtr);
            }
        }
    }
#endif
}

/******************************************************************************/
/*  FUNCTION: convert_ext4_to_int4                                            */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*  lpBMSPad  SPad;  PD00400 : Pointer to bitmap scratch                      */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  These functions all transfer one whole line from the external bitmap to   */
/*  the internal bitmap, performing any necessary color conversions.  They    */
/*  take their parameters from the scratchpad area SPad, mainly using the     */
/*  fields:                                                                   */
/*                                                                            */
/*    SPad->ChunkLength       Number of whole bytes to convert                */
/*    SPad->PelsLeftOver      Number of pels in incomplete last byte          */
/*    SPad->Col.ConvertTable  color conversion table (array of bytes)         */
/*    SPad->Safe              Indicates whether to check for segment          */
/*                            boundaries or not.                              */
/*    SPad->SrcPtr            Pointer to current position in external bitmap  */
/*    SPad->DestPtr           Pointer to current position in internal bitmap  */
/*                                                                            */
/*  Each routine contains two arms, depending on the value of SPad->Safe.  If */
/*  it is TRUE, this means that there are no segment boundaries contained in  */
/*  this line, and thus we can use the increment (++) operator on pointers to */
/*  increase speed.  The second arm is the same as the first, but with        */
/*  increments replaced with the POSTINC macro, which checks for segment      */
/*  boundaries.  It is VERY IMPORTANT that if you change any of these routines*/
/*  that you make sure to change BOTH arms in the same way.                   */
/*                                                                            */
/*  Also note that, since each line in the bitmap will always start on a DWORD*/
/*  (4 byte) boundary, in some cases we can use the increment (++) operator in*/
/*  the segment boundary checking arm.                                        */
/******************************************************************************/
VOID convert_ext4_to_int4(lpBMSPad SPad)

#if 0
lpBMSPad  SPad;                        /* PD00400 : Pointer to bitmap scratch */
                                       /* pad                                 */
#endif
{

    /**************************************************************************/
    /*  Local variables...                                                    */
    /**************************************************************************/
    ULONG  TotalLength;
    BYTE   Index;

    /**************************************************************************/
    /*  See if we need to worry about segment boundaries.                     */
    /**************************************************************************/
    TotalLength = SPad->DestBytesPerLine;

    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    if (SPad->Safe)
    {
#endif

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We know that we    */
        /*  don't need to worry about segment boundaries.  We have a          */
        /*  conversion table which deals with a byte at a time so we use that.*/
        /*                                                                    */
        /*  PD00571 : Avoid trap by using BYTE index - compiler tries to use  */
        /*  SI register, which is a word, and trips over itself by going over */
        /*  the segment boundary (bad compiler...     bad!).  Also see the    */
        /*  same basic fix in the non-Safe path too.                          */
        /**********************************************************************/
        while (TotalLength--)
        {
            Index = *SPad->SrcPtr++;
         /* *((PBYTE)SPad->DestPtr)++ = SPad->Col.ConvertTable[Index]; */
            pTemp         = SPad->DestPtr;                         /* CON3201 */
            *pTemp++      = SPad->Col.ConvertTable[Index];         /* CON3201 */
            SPad->DestPtr = pTemp;                                 /* CON3201 */
        }
    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    }
    else
    {

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We use the POSTINC */
        /*  macro to check for segment boundaries.  We have a conversion table*/
        /*  which deals with a byte at a time so we use that.                 */
        /**********************************************************************/
        while (TotalLength--)
        {
            Index = *SPad->SrcPtr;     /* PD00571...                          */
            *((PBYTE)SPad->DestPtr) = SPad->Col.ConvertTable[Index];
            POSTINC(SPad->DestPtr);
            POSTINC(SPad->SrcPtr);
        }
    }
#endif
}

/******************************************************************************/
/*  FUNCTION: convert_ext8_to_int4                                            */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*  lpBMSPad  SPad;  PD00400 : Pointer to bitmap scratch                      */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  These functions all transfer one whole line from the external bitmap to   */
/*  the internal bitmap, performing any necessary color conversions.  They    */
/*  take their parameters from the scratchpad area SPad, mainly using the     */
/*  fields:                                                                   */
/*                                                                            */
/*    SPad->ChunkLength       Number of whole bytes to convert                */
/*    SPad->PelsLeftOver      Number of pels in incomplete last byte          */
/*    SPad->Col.ConvertTable  color conversion table (array of bytes)         */
/*    SPad->Safe              Indicates whether to check for segment          */
/*                            boundaries or not.                              */
/*    SPad->SrcPtr            Pointer to current position in external bitmap  */
/*    SPad->DestPtr           Pointer to current position in internal bitmap  */
/*                                                                            */
/*  Each routine contains two arms, depending on the value of SPad->Safe.  If */
/*  it is TRUE, this means that there are no segment boundaries contained in  */
/*  this line, and thus we can use the increment (++) operator on pointers to */
/*  increase speed.  The second arm is the same as the first, but with        */
/*  increments replaced with the POSTINC macro, which checks for segment      */
/*  boundaries.  It is VERY IMPORTANT that if you change any of these routines*/
/*  that you make sure to change BOTH arms in the same way.                   */
/*                                                                            */
/*  Also note that, since each line in the bitmap will always start on a DWORD*/
/*  (4 byte) boundary, in some cases we can use the increment (++) operator in*/
/*  the segment boundary checking arm.                                        */
/******************************************************************************/
VOID convert_ext8_to_int4(lpBMSPad SPad)

#if 0
lpBMSPad  SPad;                        /* PD00400 : Pointer to bitmap         */
                                       /* scratch pad                         */
#endif
{

    /**************************************************************************/
    /*  Local variables...                                                    */
    /**************************************************************************/
    USHORT  Nibble;
    BYTE    DestByte;
    BYTE    Index;

    /**************************************************************************/
    /*  Initialize a couple of variables...                                   */
    /**************************************************************************/
    Nibble = 4;
    DestByte = 0;

    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    /**************************************************************************/
    /*  See if we need to worry about segment boundaries.                     */
    /**************************************************************************/
    if (SPad->Safe)
    {
#endif

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We know that we    */
        /*  don't need to worry about segment boundaries.                     */
        /*                                                                    */
        /*  PD00571 : Avoid trap by using BYTE index - compiler tries to use  */
        /*  SI register, which is a word, and trips over itself by going over */
        /*  the segment boundary (bad compiler...     bad!).  Also see the    */
        /*  same basic fix in the non-Safe path too (fixed in PD00490).       */
        /**********************************************************************/
        while (SPad->ChunkLength--)
        {
            Index = *SPad->SrcPtr++;
            DestByte |= SPad->Col.ConvertTable[Index] << Nibble;

            /******************************************************************/
            /*  Move to the next nibble of the destination byte.  If Nibble   */
            /*  is now 4 then we must put the DestByte to the bitmap and      */
            /*  clear it.                                                     */
            /******************************************************************/
            if (Nibble ^= 4)
            {
             /* *((PBYTE)SPad->DestPtr)++ = DestByte; */
                pTemp         = SPad->DestPtr;                     /* CON3201 */
                *pTemp++      = DestByte;                          /* CON3201 */
                SPad->DestPtr = pTemp;                             /* CON3201 */
                DestByte = 0;
            }
        }

        /**********************************************************************/
        /*  We may still have one half-filled byte to write, so write it now. */
        /**********************************************************************/
        if (!Nibble)
        {
         /* *((PBYTE)SPad->DestPtr)++ = DestByte; */
            pTemp         = SPad->DestPtr;                         /* CON3201 */
            *pTemp++      = DestByte;                              /* CON3201 */
            SPad->DestPtr = pTemp;                                 /* CON3201 */
        }
    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    }
    else
    {

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We use the POSTINC */
        /*  macro to check for segment boundaries.                            */
        /**********************************************************************/
        while (SPad->ChunkLength--)
        {
            Index = *SPad->SrcPtr;     /* PD00490...                          */
            DestByte |= SPad->Col.ConvertTable[Index] << Nibble;
            POSTINC(SPad->SrcPtr);

            /******************************************************************/
            /*  Move to the next nibble of the destination byte.  If Nibble   */
            /*  is now 4 then we must put the DestByte to the bitmap and      */
            /*  clear it.                                                     */
            /******************************************************************/
            if (Nibble ^= 4)
            {
                *((PBYTE)SPad->DestPtr) = DestByte;
                POSTINC(SPad->DestPtr);
                DestByte = 0;
            }
        }

        /**********************************************************************/
        /*  We may still have one half-filled byte to write, so write it now. */
        /**********************************************************************/
        if (!Nibble)
        {
            *((PBYTE)SPad->DestPtr) = DestByte;
            POSTINC(SPad->DestPtr);
        }
    }
#endif
}

/******************************************************************************/
/*  FUNCTION: convert_ext24_to_int4                                           */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*  lpBMSPad  SPad;  PD00400 : Pointer to bitmap scratch                      */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  These functions all transfer one whole line from the external bitmap to   */
/*  the internal bitmap, performing any necessary color conversions.  They    */
/*  take their parameters from the scratchpad area SPad, mainly using the     */
/*  fields:                                                                   */
/*                                                                            */
/*    SPad->ChunkLength       Number of whole bytes to convert                */
/*    SPad->PelsLeftOver      Number of pels in incomplete last byte          */
/*    SPad->Col.ConvertTable  color conversion table (array of bytes)         */
/*    SPad->Safe              Indicates whether to check for segment          */
/*                            boundaries or not.                              */
/*    SPad->SrcPtr            Pointer to current position in external bitmap  */
/*    SPad->DestPtr           Pointer to current position in internal bitmap  */
/*                                                                            */
/*  Each routine contains two arms, depending on the value of SPad->Safe.  If */
/*  it is TRUE, this means that there are no segment boundaries contained in  */
/*  this line, and thus we can use the increment (++) operator on pointers to */
/*  increase speed.  The second arm is the same as the first, but with        */
/*  increments replaced with the POSTINC macro, which checks for segment      */
/*  boundaries.  It is VERY IMPORTANT that if you change any of these routines*/
/*  that you make sure to change BOTH arms in the same way.                   */
/*                                                                            */
/*  Also note that, since each line in the bitmap will always start on a DWORD*/
/*  (4 byte) boundary, in some cases we can use the increment (++) operator in*/
/*  the segment boundary checking arm.                                        */
/******************************************************************************/
VOID convert_ext24_to_int4(lpBMSPad SPad)

#if 0
lpBMSPad  SPad;                        /* PD00400 : Pointer to bitmap scratch */
                                       /* pad                                 */
#endif
{

    /**************************************************************************/
    /*  Local variables...                                                    */
    /**************************************************************************/
    RGB2    ThisPel;                                /* CON3201 - Now use RGB2 */
    RGB2    *prgbTemp;                                             /* CON3201 */
    BYTE    DestByte = 0;
    USHORT  Nibble = 4;
    int     ii,CurrIndex;
    int     CacheIndex = 0;

    /**************************************************************************/
    /*  Note: changed this table to match new 8 color table.  ( MJB 7/11/90 ) */
    /**************************************************************************/
    static ColourCache  CacheTable[CacheSize] = {{{0x00,0x00,0x00}, 0},
                                                 {{0x00,0x00,0xff}, 1},
                                                 {{0xff,0x00,0x00}, 2},
                                                 {{0xff,0x00,0xff}, 3},
                                                 {{0x00,0xff,0x00}, 4},
                                                 {{0x00,0xff,0xff}, 5},
                                                 {{0xff,0xff,0x00}, 6},
                                                 {{0xff,0xff,0xff}, 7},
                                                 {{0xff,0xff,0xff}, 7}};

    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    /**************************************************************************/
    /*  See if we need to worry about segment boundaries.                     */
    /**************************************************************************/
    if (SPad->Safe)
    {
#endif

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We know that we    */
        /*  don't need to worry about segment boundaries.  We maintain a table*/
        /*  of the last (CacheSize) RGB values for which we have found a      */
        /*  nearest match in the color table and check these against each new */
        /*  pel before searching the internal color table for a nearest match.*/
        /**********************************************************************/
        do
        {
         /* ThisPel = *((RGB far *) SPad->SrcPtr)++; */
            prgbTemp = ((RGB2 *) SPad->SrcPtr);                    /* CON3201 */
            ThisPel  = *prgbTemp++;                                /* CON3201 */
            SPad->SrcPtr = (PBYTE)prgbTemp;                        /* CON3201 */

            /******************************************************************/
            /*  Start at the most recent entry in the color cache.            */
            /******************************************************************/
            CurrIndex = CacheIndex;

            /******************************************************************/
            /*  Loop through the color cache.  We only use (CacheSize-1) of   */
            /*  the entries in the cache, so that if we dont find a match, we */
            /*  do not have to move back on entry to store the current color. */
            /******************************************************************/
            for (ii=0; ii < (CacheSize - 1); ii++)
            {

                /**************************************************************/
                /*  If we have found a match then exit                        */
                /**************************************************************/
                if ((CacheTable[CurrIndex].RGBValue.bRed == ThisPel.bRed) &&
                    (CacheTable[CurrIndex].RGBValue.bGreen == ThisPel.bGreen) &&
                    (CacheTable[CurrIndex].RGBValue.bBlue == ThisPel.bBlue))
                {
                    break;
                }

                /**************************************************************/
                /*  Move to next entry in color cache                         */
                /**************************************************************/
                if (++CurrIndex == CacheSize)
                {
                    CurrIndex = 0;
                }
            }

            /******************************************************************/
            /*  If we have not found a match then we need to find out which of*/
            /*  the colors in the internal color table is closest to this pel.*/
            /*  We store it in the cache, one position below what was the     */
            /*  previous most recent entry.                                   */
            /******************************************************************/
            if (ii == (CacheSize - 1))
            {
                CacheTable[CurrIndex].RGBValue = ThisPel;
                CacheTable[CurrIndex].NearestMatch =
                                                   prdc_RGBToColIndex(&ThisPel);
            }

            /******************************************************************/
            /*  Put the color into the correct nibble of DestByte             */
            /******************************************************************/
            DestByte |= CacheTable[CurrIndex].NearestMatch << Nibble;

            /******************************************************************/
            /*  The current entry in the color cache is clearly now the most  */
            /*  recently used entry.                                          */
            /******************************************************************/
            CacheIndex = CurrIndex;

            /******************************************************************/
            /*  Move to the next nibble of the destination byte.  If the      */
            /*  Nibble is now 4 then we must put this DestByte to the bitmap  */
            /*  and clear it.                                                 */
            /******************************************************************/
            if (Nibble ^= 4)
            {
             /* *((PBYTE)SPad->DestPtr)++ = DestByte; */
                pTemp         = SPad->DestPtr;                     /* CON3201 */
                *pTemp++      = DestByte;                          /* CON3201 */
                SPad->DestPtr = pTemp;                             /* CON3201 */
                DestByte = 0;
            }
        } while (SPad->ChunkLength -= 3);

        /**********************************************************************/
        /*  We have finished all the source bytes.  We may be half way through*/
        /*  a destination byte.                                               */
        /**********************************************************************/
        if (!Nibble)
        {
         /* *((PBYTE) SPad->DestPtr)++ = DestByte; */
            pTemp         = SPad->DestPtr;                         /* CON3201 */
            *pTemp++      = DestByte;                              /* CON3201 */
            SPad->DestPtr = pTemp;                                 /* CON3201 */
        }
    /**************************************************************************/
    /*  CON3201 : Don't need to worry about segment boundaries for 32-bit code*/
    /**************************************************************************/
#if 0
    }
    else
    {

        /**********************************************************************/
        /*  Transfer all of the source bytes in the line.  We use the POSTINC */
        /*  macro to check for segment boundaries.  We maintain a table of the*/
        /*  last (CacheSize) RGB values for which we have found a nearest     */
        /*  match in the color table and check these against each new pel     */
        /*  before searching the internal color table for a nearest match.    */
        /**********************************************************************/
        do
        {
            ThisPel.bBlue  = *((PBYTE) SPad->SrcPtr);
            POSTINC(SPad->SrcPtr);
            ThisPel.bGreen = *((PBYTE) SPad->SrcPtr);
            POSTINC(SPad->SrcPtr);
            ThisPel.bRed   = *((PBYTE) SPad->SrcPtr);
            POSTINC(SPad->SrcPtr);

            /******************************************************************/
            /*  Start at the most recent entry in the color cache.            */
            /******************************************************************/
            CurrIndex = CacheIndex;

            /******************************************************************/
            /*  Loop through the color cache.  We only use (CacheSize-1) of   */
            /*  the entries in the cache, so that if we dont find a match, we */
            /*  do not have to move back on entry to store the current color. */
            /*                                                                */
            /******************************************************************/
            for (ii = 0; ii < (CacheSize - 1); ii++)
            {

                /**************************************************************/
                /*  If we have found a match then exit                        */
                /**************************************************************/
                if ((CacheTable[CurrIndex].RGBValue.bRed == ThisPel.bRed) &&
                    (CacheTable[CurrIndex].RGBValue.bGreen == ThisPel.bGreen) &&
                    (CacheTable[CurrIndex].RGBValue.bBlue == ThisPel.bBlue))
                {
                    break;
                }

                /**************************************************************/
                /*  Move to next entry in color cache                         */
                /**************************************************************/
                if (++CurrIndex == CacheSize)
                {
                    CurrIndex = 0;
                }
            }

            /******************************************************************/
            /*  If we have not found a match then we need to find out which of*/
            /*  the colors in the internal color table is closest to this pel.*/
            /*  We store it in the cache, one position below what was the     */
            /*  previous most recent entry.                                   */
            /******************************************************************/
            if (ii == (CacheSize - 1))
            {
                CacheTable[CurrIndex].RGBValue = ThisPel;
                CacheTable[CurrIndex].NearestMatch =
                                                   prdc_RGBToColIndex(&ThisPel);
            }

            /******************************************************************/
            /*  Put the color into the correct nibble of DestByte             */
            /******************************************************************/
            DestByte |= CacheTable[CurrIndex].NearestMatch << Nibble;

            /******************************************************************/
            /*  The current entry in the color cache is clearly now the most  */
            /*  recently used entry.                                          */
            /******************************************************************/
            CacheIndex = CurrIndex;

            /******************************************************************/
            /*  Move to the next nibble of the destination byte.  If the      */
            /*  Nibble is now 4 then we must put this DestByte to the bitmap  */
            /*  and clear it.                                                 */
            /******************************************************************/
            if (Nibble ^= 4)
            {
                *((PBYTE) SPad->DestPtr) = DestByte;
                POSTINC(SPad->DestPtr);
                DestByte = 0;
            }
        } while (SPad->ChunkLength -= 3);

        /**********************************************************************/
        /*  We have finished all the source bytes.  We may be half way through*/
        /*  a destination byte.                                               */
        /**********************************************************************/
        if (!Nibble)
        {
            *((PBYTE)SPad->DestPtr) = DestByte;
            POSTINC(SPad->DestPtr);
        }
    }
#endif
}
#undef TFUNC
