/*DDK*************************************************************************/
/*                                                                           */
/* 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.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*                                                                    */
/*   Module          = CONVINT                                        */
/*                                                                    */
/*   Description     = Display Device Driver subroutines to convert   */
/*                     between the device driver internal format and  */
/*                     and the PM formats                             */
/*                                                                    */
/*   Function        = ConvertIntToExt                                */
/*                     TableIntToPM                                   */
/*                                                                    */
/*                                                                    */
/*   77638 - JOHNB     Added support for 16 bit external bitmaps.     */
/*                     These will only be used when we are using      */
/*                     16 bit internal bitmaps ( we are in 64K        */
/*                     color mode )                                   */
/*                                                                    */
/**********************************************************************/
#define INCL_DDIMISC
#define INCL_WINSYS
#include "eddinclt.h"

#include "eddccone.h"
#include "edddtypt.h"

#include "eddcextf.h"
#include "eddgextf.h"

#include "eddhcone.h"
#include "eddhtype.h"
#include "eddhmacr.h"

#include "bitmaps.h"
#include "convfuns.h"


extern COLORTABLETYPE   DefaultFourBppTable[DFLT_LOG_COL_TABLE_SIZE];
extern PRGB2            MemoryDeviceDefaultPalette;
extern USHORT           SizeOfHWPalette;
extern DDTType          DDT;

extern BOOL             fRealizeSupported;


/**********************************************************************/
/* private functions                                                  */
/**********************************************************************/
VOID DRIVERCALL SetExternalColorTable(VOID);
BOOL DRIVERCALL TableIntToPM(VOID);

VOID DRIVERCALL ConvertInt1ToExt8(VOID);
VOID DRIVERCALL ConvertInt4ToExt8(VOID);
VOID DRIVERCALL ConvertInt8ToExt4(VOID);
VOID DRIVERCALL ConvertInt1ToExt24(VOID);
VOID DRIVERCALL ConvertInt1ToExt16(VOID);                          /* @77638 */
VOID DRIVERCALL ConvertInt4ToExt24(VOID);
VOID DRIVERCALL ConvertInt8ToExt24(VOID);
VOID DRIVERCALL ConvertInt8ToExt24pal(VOID);
VOID DRIVERCALL ConvertInt1ToExt24palindex(VOID);
VOID DRIVERCALL ConvertInt8ToExt24palindex(VOID);
ULONG DRIVERCALL NearestRestrictedColourIndex(PBYTE  pbColourTable,
                                              ULONG  ulColTabIncrement,
                                              RGB2   rgb,
                                              ULONG  ulMaxIndex);
VOID DRIVERCALL ConvertInt16ToExt24(VOID);
VOID DRIVERCALL ConvertInt16ToExt8(VOID);
VOID DRIVERCALL ConvertInt16ToExt4(VOID);
VOID DRIVERCALL ConvertInt16ToExt1(VOID);
#ifdef BPP24
VOID DRIVERCALL ConvertInt24ToExt8(VOID);
VOID DRIVERCALL ConvertInt24ToExt4(VOID);
VOID DRIVERCALL ConvertInt24ToExt1(VOID);
PFNV DRIVERCALL From24BppInternalFn(VOID);
#endif
PFNV DRIVERCALL From16BppConvertFn(VOID);
PFNV DRIVERCALL From8BppConvertFn(VOID);
PFNV DRIVERCALL From4BppConvertFn(VOID);
PFNV DRIVERCALL From1BppConvertFn(VOID);
VOID DRIVERCALL ConvertIntToExt( PBYTE         pbTargetBitmap,
                                 PBITMAPINFO2  pTargetHeader,
                                 pBitmapHeader pbhSourceBitmap,
                                 PPOINTL       pptlScanStart,
                                 LONG          lScanLines);
VOID DRIVERCALL GetPaletteEncoding(PRGB  pExtRGB);
VOID DRIVERCALL GetPalEncodeWithConvTab(PRGB pExtRGB);
VOID DRIVERCALL GetMonoTable(PRGB pExtRGB);
VOID DRIVERCALL GetSrcMonoCTWithConvTab(PRGB pExtRGB);
VOID DRIVERCALL GetConvTabFromLogicalPalette(VOID);
VOID DRIVERCALL GetConvTabFromPhysicalPalette(VOID);
VOID DRIVERCALL GetDstMonoCTWithConvTab(PRGB pExtRGB);
VOID DRIVERCALL GetSelectedPalette(PRGB pExtRGB);
BOOL DRIVERCALL MapManyRGBToLess(VOID);
BOOL DRIVERCALL GetSelectedPalWithConvTab(PRGB pExtRGB);
VOID DRIVERCALL GetDefaultHWPalette(PRGB pExtRGB);
VOID DRIVERCALL GetRealizableTable(PRGB pExtRGB);
VOID DRIVERCALL Get4Or8BppTable(PRGB pExtRGB);
VOID DRIVERCALL SetExternalColorTable(VOID);
RGB2 DRIVERCALL DisplayedRGB(ULONG ulIndex);
VOID DRIVERCALL MapTo4BppWithConvTab(PRGB pExtRGB);
VOID DRIVERCALL Get8BppTableFrom16Bpp(PRGB pExtRGB);
VOID DRIVERCALL Get4BppTableFrom16Bpp(PRGB pExtRGB);
VOID DRIVERCALL GetFrom16BppColourTable(PRGB pExtRGB);
BOOL DRIVERCALL TableIntToPM(VOID);
PFNV DRIVERCALL GetConvertFn(VOID);




/**********************************************************************/
/* NOTE:                                                              */
/*   These routines are primarily used by GetBitmapBits.              */
/*                                                                    */
/* However they may also be used from DeviceDeleteBitmap.  In this    */
/* situation, pdc is NULL, and so information which might have come   */
/* from the DC instance is not avaliable.                             */
/**********************************************************************/

/**********************************************************************/
/* ConvertInt1ToExt8                                                  */
/*                                                                    */
/* Converts a single scan line from internal 1bpp to external 8bpp.   */
/* No conversion table is required because 0 (1bpp) -> 0 (8bpp)       */
/*                                     and 1 (1bpp) -> 1 (8bpp)       */
/**********************************************************************/
VOID DRIVERCALL ConvertInt1ToExt8(VOID)
{
    ULONG   j;
    BYTE    bSrcByte;
    ULONG   ulTrgULONG;
    ULONG   ulExtraBits;

    /**************************************************************/
    /* each source byte of eight pixels maps to 8 target bytes    */
    /**************************************************************/
    for ( j = SPad.cx / 8; j--; )
    {
        /**************************************************************/
        /* Get the source 8 pels.                                     */
        /**************************************************************/
        bSrcByte = *SPad.pbSrcPointer++;

        /**************************************************************/
        /* If our source BYTE of 8 pels is considered as              */
        /*      abcdefgh                                              */
        /*                                                            */
        /* then we want to write (using intel!) 2 ULONGs containing   */
        /*      0000000d0000000c0000000b0000000a                      */
        /*          abcdefgh                       SrcByte << 20      */
        /*                   abcdefgh              SrcByte << 11      */
        /*                            abcdefgh     SrcByte << 2       */
        /*                                     a   SrcByte >> 7       */
        /*                                                            */
        /*  and 0000000h0000000g0000000f0000000e                      */
        /*      abcdefgh                           SrcByte << 24      */
        /*               abcdefgh                  SrcByte << 15      */
        /*                        abcdefgh         SrcByte << 6       */
        /*                                 abcde   SrcByte >> 3       */
        /**************************************************************/
        ulTrgULONG = (((ULONG)bSrcByte << 20) |   /* get a into place */
                      ((ULONG)bSrcByte << 11) |   /* get b into place */
                      ((ULONG)bSrcByte <<  2) |   /* get c into place */
                      ((ULONG)bSrcByte >>  7))    /* get d into place */
                     & 0x01010101;         /* mask to keep right bits */

        *((PULONG)SPad.pbTrgPointer)++ = ulTrgULONG;

        ulTrgULONG = (((ULONG)bSrcByte << 24) |   /* get e into place */
                      ((ULONG)bSrcByte << 15) |   /* get f into place */
                      ((ULONG)bSrcByte <<  6) |   /* get g into place */
                      ((ULONG)bSrcByte >>  3))    /* get h into place */
                     & 0x01010101;         /* mask to keep right bits */

        *((PULONG)SPad.pbTrgPointer)++ = ulTrgULONG;
    } /* for each byte on the row */

    /******************************************************************/
    /* finish off any incomplete bytes at the end of the row          */
    /* SrcPointer already points to the correct source byte           */
    /******************************************************************/
    ulExtraBits = SPad.cx & 7;
    if (ulExtraBits)
    {
        bSrcByte = *SPad.pbSrcPointer++;
        while (ulExtraBits--)
        {
            /**********************************************************/
            /* Take the leftmost bit.                                 */
            /**********************************************************/
            *SPad.pbTrgPointer++ = (BYTE)((bSrcByte & 0x80) >> 7);
            /**********************************************************/
            /* Move the next bit into the leftmost position.          */
            /**********************************************************/
            bSrcByte <<= 1;
        }
    }
} /* ConvertInt1ToExt8 */


/**********************************************************************/
/* ConvertInt4ToExt8                                                  */
/*                                                                    */
/* Converts a single scan line from internal 4bpp to external 8bpp.   */
/* No conversion table is required because x (4bpp) -> x (8bpp)       */
/**********************************************************************/
VOID DRIVERCALL ConvertInt4ToExt8(VOID)
{
    ULONG   j;
    BYTE    bSrcByte;

    /******************************************************************/
    /* for each source byte which is to be converted - two pixels per */
    /* byte                                                           */
    /******************************************************************/
    for ( j = SPad.cx / 2; j--; )
    {
        /**************************************************************/
        /* get the next byte of data out the source                   */
        /**************************************************************/
        bSrcByte = *SPad.pbSrcPointer++;

        /**************************************************************/
        /* now update the target - each source index (4 bits) expands */
        /* to 8 bits in the target                                    */
        /**************************************************************/
        *SPad.pbTrgPointer++ = (BYTE)((bSrcByte & 0xF0)>>4);
        *SPad.pbTrgPointer++ = (BYTE)( bSrcByte & 0x0F    );

    } /* for each pel on the row */

    /******************************************************************/
    /* check for an odd pixel at the end of the source row            */
    /******************************************************************/
    if ( SPad.cx & 1 )
    {
        *SPad.pbTrgPointer++ = (BYTE)((*SPad.pbSrcPointer & 0xF0) >> 4);
    }
} /* ConvertInt4ToExt8 */


/**********************************************************************/
/* ConvertInt8ToExt4                                                  */
/*                                                                    */
/* Converts a single scan line from internal 8bpp to external 4bpp.   */
/* A conversion table has previously been setup.                      */
/**********************************************************************/
VOID DRIVERCALL ConvertInt8ToExt4(VOID)
{
    ULONG   j;
    BYTE    bTrgIndex;

    /**************************************************************/
    /* two source bytes map to each target byte                   */
    /**************************************************************/
    for ( j = SPad.cx / 2; j--; )
    {
        /**********************************************************/
        /* get the target index corresponding to the first source */
        /* byte, shift left by 4 and OR in the target index       */
        /* corresponding to the second source byte                */
        /**********************************************************/
        bTrgIndex =
                (BYTE)(SPad.ausConvertTable[*SPad.pbSrcPointer++] << 4);
        *SPad.pbTrgPointer++ =
           bTrgIndex | (BYTE)SPad.ausConvertTable[*SPad.pbSrcPointer++];
    } /* for each pel on the row */
    /******************************************************************/
    /* if there's an odd byte at the end of the row, handle it now.   */
    /******************************************************************/
    if ( SPad.cx & 1 )
    {
        *SPad.pbTrgPointer++ =
                (BYTE)(SPad.ausConvertTable[*SPad.pbSrcPointer++] << 4);
    }
} /* ConvertInt8ToExt4 */


/**********************************************************************/
/* ConvertInt1ToExt24                                                 */
/*                                                                    */
/* Converts a single scan line from internal 1bpp to external 24bpp.  */
/* No conversion table is needed since 0 -> black                     */
/*                                     1 -> white                     */
/**********************************************************************/
VOID DRIVERCALL ConvertInt1ToExt24(VOID)
{
    ULONG   j;
    BYTE    bSrcByte;

    /**************************************************************/
    /* for each full byte which is to be converted                */
    /**************************************************************/
    for ( j = SPad.cx / 8; j--; )
    {
        bSrcByte  = *SPad.pbSrcPointer++;

        /**************************************************************/
        /* Use a macro to make the following code more readable.      */
        /**************************************************************/
/* Start of macro definition */
#define TestSrcBitAndWriteRGB(mask)                                    \
    if (bSrcByte & mask)                                               \
    {                                                                  \
        /*************************************************************/\
        /* Bit is 1 so write out white as a word then a byte of 0xFF */\
        /*************************************************************/\
        *((PUSHORT)SPad.pbTrgPointer)++ = 0xFFFF;                      \
        *SPad.pbTrgPointer++ = 0xFF;                                   \
    }                                                                  \
    else                                                               \
    {                                                                  \
        /*************************************************************/\
        /* Bit is 0 so write out black as a word then a byte of 0x00 */\
        /*************************************************************/\
        *((PUSHORT)SPad.pbTrgPointer)++ = 0x0000;                      \
        *SPad.pbTrgPointer++ = 0x00;                                   \
    }
/* End of macro definition */

        /**************************************************************/
        /* now write the 8 target pels this represents                */
        /**************************************************************/
        TestSrcBitAndWriteRGB(0x80);
        TestSrcBitAndWriteRGB(0x40);
        TestSrcBitAndWriteRGB(0x20);
        TestSrcBitAndWriteRGB(0x10);
        TestSrcBitAndWriteRGB(0x08);
        TestSrcBitAndWriteRGB(0x04);
        TestSrcBitAndWriteRGB(0x02);
        TestSrcBitAndWriteRGB(0x01);
    }   /* for each pel on the row                            */

    /******************************************************************/
    /* are there any odd pixels still to do                           */
    /******************************************************************/
    j = SPad.cx & 7;
    if (j)
    {
        bSrcByte = *SPad.pbSrcPointer++;
        while (j--)
        {
            /**********************************************************/
            /* Consider the leftmost bit.                             */
            /**********************************************************/
            TestSrcBitAndWriteRGB(0x80);
            /**********************************************************/
            /* Move the next bit into the leftmost position.          */
            /**********************************************************/
            bSrcByte <<= 1;
        }
    }
} /* ConvertInt1ToExt24 */

/**********************************************************************/      
/* ConvertInt1ToExt16             @77638 added new function           */      
/*                                                                    */      
/* Converts a single scan line from internal 1bpp to external 16bpp.  */      
/* No conversion table is needed since 0 -> black                     */      
/*                                     1 -> white                     */      
/**********************************************************************/      
VOID DRIVERCALL ConvertInt1ToExt16(VOID)                                      
{                                                                             
    ULONG   j;                                                                
    BYTE    bSrcByte;                                                         
                                                                              
    /**************************************************************/          
    /* for each full byte which is to be converted                */          
    /**************************************************************/          
    for ( j = SPad.cx / 8; j--; )                                             
    {                                                                         
        bSrcByte  = *SPad.pbSrcPointer++;                                     
                                                                              
        /**************************************************************/      
        /* Use a macro to make the following code more readable.      */      
        /**************************************************************/      
/* Start of macro definition */

#define TestSrcBitAndWrite16bppRGB(mask)                               \
    if (bSrcByte & mask)                                               \
    {                                                                  \
        /*************************************************************/\
        /* Bit is 1 so write out white as a word then a byte of 0xFF */\
        /*************************************************************/\
        *((PUSHORT)SPad.pbTrgPointer)++ = 0xFFFF;                      \
    }                                                                  \
    else                                                               \
    {                                                                  \
        /*************************************************************/\
        /* Bit is 0 so write out black as a word then a byte of 0x00 */\
        /*************************************************************/\
        *((PUSHORT)SPad.pbTrgPointer)++ = 0x0000;                      \
    }
/* End of macro definition */                                                 
                                                                              
        /**************************************************************/      
        /* now write the 8 target pels this represents                */      
        /**************************************************************/      
        TestSrcBitAndWrite16bppRGB(0x80);                                     
        TestSrcBitAndWrite16bppRGB(0x40);                                     
        TestSrcBitAndWrite16bppRGB(0x20);                                     
        TestSrcBitAndWrite16bppRGB(0x10);                                     
        TestSrcBitAndWrite16bppRGB(0x08);                                     
        TestSrcBitAndWrite16bppRGB(0x04);                                     
        TestSrcBitAndWrite16bppRGB(0x02);                                     
        TestSrcBitAndWrite16bppRGB(0x01);                                     
    }   /* for each pel on the row                            */              
                                                                              
    /******************************************************************/      
    /* are there any odd pixels still to do                           */      
    /******************************************************************/      
    j = SPad.cx & 7;                                                          
    if (j)                                                                    
    {                                                                         
        bSrcByte = *SPad.pbSrcPointer++;                                      
        while (j--)                                                           
        {                                                                     
            /**********************************************************/      
            /* Consider the leftmost bit.                             */      
            /**********************************************************/      
            TestSrcBitAndWrite16bppRGB(0x80);                                 
            /**********************************************************/      
            /* Move the next bit into the leftmost position.          */      
            /**********************************************************/      
            bSrcByte <<= 1;                                                   
        }                                                                     
    }                                                                         
} /* ConvertInt1ToExt16 */                                                    


/**********************************************************************/
/* ConvertInt4ToExt24                                                 */
/*                                                                    */
/* Converts a single scan line from internal 4bpp to external 24bpp.  */
/**********************************************************************/
VOID DRIVERCALL ConvertInt4ToExt24(VOID)
{
    ULONG       j;
    BYTE        bSrcByte;
    ULONG       TrgIndex1;
    ULONG       TrgIndex2;
    RGB2        RGBVal1;
    RGB2        RGBVal2;
    ULONG       ulCTIndex;
    BOOL        fRealizable;

    if (fRealizeSupported &&
        pdc != NULL       &&
        (pdc->DCIColStatus & LCOL_REALIZABLE) )
    {
        fRealizable = TRUE;
    }
    else
    {
        fRealizable = FALSE;
    }

    /**************************************************************/
    /* for each byte which is to be converted (2 internal pels)   */
    /**************************************************************/
    for ( j = SPad.cx / 2; j--; )
    {
        /**************************************************************/
        /* Get a source byte (2 pels).                                */
        /**************************************************************/
        bSrcByte  = *SPad.pbSrcPointer++;

        /**************************************************************/
        /* Get the individual pel indices.                            */
        /**************************************************************/
        TrgIndex1 = ((bSrcByte & 0xF0) >> 4);
        TrgIndex2 = ( bSrcByte & 0x0F      );

        /******************************************************/
        /* Need to write an actual RGB value. This comes      */
        /* from the LCT if it realizable and if there is a    */
        /* valid entry, otherwise the RGB value comes         */
        /* directly from the default physical palette         */
        /*                                                    */
        /* RGB is stored in the external bitmap as:           */
        /*    1st byte (blue)                                 */
        /*    2nd byte (green)                                */
        /*    3rd byte (red)                                  */
        /******************************************************/
        if ( fRealizable )
        {
            ulCTIndex = PhyToLogIndex(TrgIndex1);
            if ( ulCTIndex != CLR_NOINDEX )
            {
                /**************************************************/
                /* There is a realizable LCT with a valid entry   */
                /* so read the RGB value from it.                 */
                /**************************************************/
                RGBVal1 = pdc->DCIColorTable[ulCTIndex].LogRGB;
            }
            else
            {
                /**************************************************/
                /* Read the RGB value directly from the default   */
                /* physical palette.                              */
                /**************************************************/
                RGBVal1 = MemoryDeviceDefaultRGB2(TrgIndex1);
            }

            ulCTIndex = PhyToLogIndex(TrgIndex2);
            if ( ulCTIndex != CLR_NOINDEX )
            {
                /**************************************************/
                /* There is a realizable LCT with a valid entry   */
                /* so read the RGB value from it.                 */
                /**************************************************/
                RGBVal2 = pdc->DCIColorTable[ulCTIndex].LogRGB;
            }
            else
            {
                /******************************************************/
                /* Read the RGB value directly from the default       */
                /* physical palette.                                  */
                /******************************************************/
                RGBVal2 = MemoryDeviceDefaultRGB2(TrgIndex2);
            }
        }
        else
        {
            /**************************************************/
            /* Read the RGB value directly from the default   */
            /* physical palette.                              */
            /**************************************************/
            RGBVal1 = MemoryDeviceDefaultRGB2(TrgIndex1);
            RGBVal2 = MemoryDeviceDefaultRGB2(TrgIndex2);
        }

        /**************************************************************/
        /* Write pels into the target.                                */
        /**************************************************************/
        *SPad.pbTrgPointer++ = RGBVal1.bBlue;
        *SPad.pbTrgPointer++ = RGBVal1.bGreen;
        *SPad.pbTrgPointer++ = RGBVal1.bRed;
        *SPad.pbTrgPointer++ = RGBVal2.bBlue;
        *SPad.pbTrgPointer++ = RGBVal2.bGreen;
        *SPad.pbTrgPointer++ = RGBVal2.bRed;
    }   /* for each pel on the row                            */

    /******************************************************************/
    /* is there an odd pixel still to do                              */
    /******************************************************************/
    if (SPad.cx & 1)
    {
        bSrcByte  = *SPad.pbSrcPointer;

        TrgIndex1 = ((bSrcByte & 0xF0) >> 4);

        /******************************************************/
        /* Need to write an actual RGB value. This comes      */
        /* from the LCT if it realizable and if there is a    */
        /* valid entry, otherwise the RGB value comes         */
        /* directly from the default physical palette         */
        /*                                                    */
        /* RGB is stored in the external bitmap as:           */
        /*    1st byte (blue)                                 */
        /*    2nd byte (green)                                */
        /*    3rd byte (red)                                  */
        /******************************************************/
        if ( fRealizable )
        {
            ulCTIndex = PhyToLogIndex(TrgIndex1);
            if ( ulCTIndex != CLR_NOINDEX )
            {
                /**************************************************/
                /* There is a realizable LCT with a valid entry   */
                /* so read the RGB value from it.                 */
                /**************************************************/
                RGBVal1 = pdc->DCIColorTable[ulCTIndex].LogRGB;
            }
            else
            {
                /**************************************************/
                /* Read the RGB value directly from the default   */
                /* physical palette.                              */
                /**************************************************/
                RGBVal1 = MemoryDeviceDefaultRGB2(TrgIndex1);
            }

            ulCTIndex = PhyToLogIndex(TrgIndex2);
            if ( ulCTIndex != CLR_NOINDEX )
            {
                /**************************************************/
                /* There is a realizable LCT with a valid entry   */
                /* so read the RGB value from it.                 */
                /**************************************************/
                RGBVal2 = pdc->DCIColorTable[ulCTIndex].LogRGB;
            }
            else
            {
                /**************************************************/
                /* Read the RGB value directly from the default   */
                /* physical palette.                              */
                /**************************************************/
                RGBVal2 = MemoryDeviceDefaultRGB2(TrgIndex2);
            }
        }
        /**************************************************************/
        /* Write pel into the target.                                 */
        /**************************************************************/
        *SPad.pbTrgPointer++ = RGBVal1.bBlue;
        *SPad.pbTrgPointer++ = RGBVal1.bGreen;
        *SPad.pbTrgPointer++ = RGBVal1.bRed;
    }
} /* ConvertInt4ToExt24 */


/**********************************************************************/
/* ConvertInt8ToExt24                                                 */
/*                                                                    */
/* Converts a single scan line from internal 8bpp to external 24bpp,  */
/* when an LCT is in use in the DC.                                   */
/**********************************************************************/
VOID DRIVERCALL ConvertInt8ToExt24(VOID)
{
    ULONG   j;
    ULONG   ulCTIndex;
    ULONG   TrgIndex;
    RGB2    RGBVal;
    BOOL    fRealizable;

    if (fRealizeSupported &&
        pdc != NULL       &&
        (pdc->DCIColStatus & LCOL_REALIZABLE))
    {
        fRealizable = TRUE;
    }
    else
    {
        fRealizable = FALSE;
    }

    /**************************************************************/
    /* for each byte which is to be converted                     */
    /**************************************************************/
    for ( j = SPad.cx; j--; )
    {
        TrgIndex = *SPad.pbSrcPointer++;

        /******************************************************/
        /* Need to write an actual RGB value. This comes      */
        /* from the LCT if it realizable and if there is a    */
        /* valid entry, otherwise the RGB value comes         */
        /* directly from the default physical palette         */
        /*                                                    */
        /* RGB is stored in the external bitmap as:           */
        /*    1st byte (blue)                                 */
        /*    2nd byte (green)                                */
        /*    3rd byte (red)                                  */
        /******************************************************/
        if ( fRealizable )
        {
            ulCTIndex = PhyToLogIndex(TrgIndex);
            if ( ulCTIndex != CLR_NOINDEX )
            {
                /**************************************************/
                /* There is a realizable LCT with a valid entry   */
                /* so read the RGB value from it.                 */
                /**************************************************/
                RGBVal = pdc->DCIColorTable[ulCTIndex].LogRGB;
            }
            else
            {
                /**************************************************/
                /* Read the RGB value directly from the default   */
                /* physical palette.                              */
                /**************************************************/
                RGBVal = MemoryDeviceDefaultRGB2(ulCTIndex);
            }
        }
        else
        {
            /**************************************************/
            /* Read the RGB value directly from the default   */
            /* physical palette.                              */
            /**************************************************/
            RGBVal = MemoryDeviceDefaultRGB2(TrgIndex);
        }

        /**************************************************************/
        /* Write pel into the target.                                 */
        /**************************************************************/
        *SPad.pbTrgPointer++ = RGBVal.bBlue;
        *SPad.pbTrgPointer++ = RGBVal.bGreen;
        *SPad.pbTrgPointer++ = RGBVal.bRed;
    }   /* for each pel on the row                            */
} /* ConvertInt8ToExt24 */


/**********************************************************************/
/* ConvertInt8ToExt24pal                                              */
/*                                                                    */
/* Converts a single scan line from internal 8bpp to external 24bpp,  */
/* when a palette is selected in the DC.                              */
/**********************************************************************/
VOID DRIVERCALL ConvertInt8ToExt24pal(VOID)
{
    ULONG   j;
    RGB2    rgbTrgRGB;

    /**************************************************************/
    /* for each byte which is to be converted                     */
    /**************************************************************/
    for ( j = SPad.cx; j--; )
    {
        /**************************************************************/
        /* Need to write an actual RGB value.                         */
        /* This comes from the logical palette                        */
        /* RGB is stored in the external bitmap as:                   */
        /*    blue,green,red                                          */
        /**************************************************************/
        rgbTrgRGB = pdc->Palette->entries[*SPad.pbSrcPointer++].rgb;

        /**************************************************************/
        /* write rgb value to the target                              */
        /**************************************************************/
        *SPad.pbTrgPointer++ = rgbTrgRGB.bBlue;
        *SPad.pbTrgPointer++ = rgbTrgRGB.bGreen;
        *SPad.pbTrgPointer++ = rgbTrgRGB.bRed;
    }   /* for each pel on the row                            */
} /* ConvertInt8ToExt24pal */


/**********************************************************************/
/* ConvertInt1ToExt24palindex                                         */
/*                                                                    */
/* Converts a single scan line from internal 1bpp to external 24bpp,  */
/* when the special palette encoding has been specified.              */
/**********************************************************************/
VOID DRIVERCALL ConvertInt1ToExt24palindex(VOID)
{
    ULONG   j;
    BYTE    bSrcByte;

    /**************************************************************/
    /* for each full byte which is to be converted                */
    /**************************************************************/
    for ( j = SPad.cx / 8; j--; )
    {
        bSrcByte  = *SPad.pbSrcPointer++;

        /**************************************************************/
        /* now write the 8 target pels this represents                */
        /**************************************************************/

        /**************************************************************/
        /* This macro makes the following code more compact.          */
        /**************************************************************/
/* Start of macro definition */
#define TestAndSet1To24Index(mask)                                     \
        if (bSrcByte & mask)                                           \
        {                                                              \
            *SPad.pbTrgPointer++ = 1;                                  \
        }                                                              \
        else                                                           \
        {                                                              \
            *SPad.pbTrgPointer++ = 0;                                  \
        }                                                              \
        /**********************************************************/   \
        /* write the other 2 bytes of the 'RGB' together          */   \
        /**********************************************************/   \
        *((PUSHORT)SPad.pbTrgPointer)++ = 0;
/* End of macro definition */

        TestAndSet1To24Index(0x80);
        TestAndSet1To24Index(0x40);
        TestAndSet1To24Index(0x20);
        TestAndSet1To24Index(0x10);
        TestAndSet1To24Index(0x08);
        TestAndSet1To24Index(0x04);
        TestAndSet1To24Index(0x02);
        TestAndSet1To24Index(0x01);
    }   /* for each pel on the row                            */

    /******************************************************************/
    /* are there any odd pixels still to do                           */
    /******************************************************************/
    j = SPad.cx & 7;
    if (j)
    {
        bSrcByte  = *SPad.pbSrcPointer;
        while (j--)
        {
            TestAndSet1To24Index(0x80);
            bSrcByte <<= 1;
        }
    }
} /* ConvertInt1ToExt24palindex */


/**********************************************************************/
/* ConvertInt8ToExt24palindex                                         */
/*                                                                    */
/* Converts a single scan line from internal 8bpp to external 24bpp,  */
/* when the special palette encoding has been specified.              */
/**********************************************************************/
VOID DRIVERCALL ConvertInt8ToExt24palindex(VOID)
{
    ULONG   j;

    /**************************************************************/
    /* for each byte which is to be converted                     */
    /**************************************************************/
    for ( j = SPad.cx; j--; )
    {
        /**************************************************************/
        /* write index value to the target                            */
        /**************************************************************/
        *SPad.pbTrgPointer++ = *SPad.pbSrcPointer++;
        /**************************************************************/
        /* write the other 2 bytes of the 'RGB' together              */
        /**************************************************************/
        *((PUSHORT)SPad.pbTrgPointer)++ = 0;
    }   /* for each pel on the row                            */
} /* ConvertInt8ToExt24palindex */


/**********************************************************************/
/* NearestRestrictedColourIndex                                       */
/*                                                                    */
/* pbColourTable     pointer to the colour table to use (may actually */
/*                   be a palette as well)                            */
/* ulColTabIncrement the amount by which pbColourTable needs to be    */
/*                   incremented to point to the next entry           */
/* rgb               the RGB value for which the nearest index is to  */
/*                   be found                                         */
/* ulMaxIndex        the maximum number of indices in the colour      */
/*                   table which can be examined for a match          */
/*                                                                    */
/* Returns the index to pbColourTable table which maps to the colour  */
/* nearest rgb. Index returned will be less than ulMaxIndex, ie.      */
/* only the first ulMaxIndex entries of pbColorTable are examined.    */
/**********************************************************************/
ULONG DRIVERCALL NearestRestrictedColourIndex(PBYTE  pbColourTable,
                                              ULONG  ulColTabIncrement,
                                              RGB2   rgb,
                                              ULONG  ulMaxIndex)
{
    ULONG   ulCount;
    ULONG   ulMinDiff;
    ULONG   ulDiff;
    ULONG   ulBestIndex;

    /******************************************************************/
    /* Check to first index outside the loop.                         */
    /******************************************************************/
    ulMinDiff = rgb2_diff(*(PRGB2)pbColourTable, rgb);

    if ( ulMinDiff == 0 )
    {
        return(0);
    }
    else /* first index does not give exact match */
    {
        ulBestIndex = 0;
        pbColourTable += ulColTabIncrement;

        for (ulCount = 1;
             ulCount < ulMaxIndex;
             ulCount++, pbColourTable += ulColTabIncrement)
        {
            ulDiff = rgb2_diff(*(PRGB2)pbColourTable,
                               rgb);

            if (ulDiff == 0)
            {
                /******************************************************/
                /* Exact match so this must be the closest!           */
                /******************************************************/
                ulBestIndex = ulCount;
                break;
            }
            else if (ulDiff < ulMinDiff)
            {
                /******************************************************/
                /* This is a closer match than the previous best.     */
                /******************************************************/
                ulMinDiff = ulDiff;
                ulBestIndex = ulCount;
            }
        } /* for each entry in colour table */
    }  /* first index does not give exact match */

    return(ulBestIndex);
} /* NearestRestrictedColourIndex */


/**********************************************************************/
/* ConvertInt16ToExt24                                                */
/*                                                                    */
/* Converts a single scan line from internal 16bpp to external 24bpp. */
/**********************************************************************/
VOID DRIVERCALL ConvertInt16ToExt24(VOID)
{
    ULONG   j;
    RGB16   SrcPel;

    /**************************************************************/
    /* For each pel which is to be converted:                     */
    /*   - get the 16-bit RGB out of the source and increment     */
    /*     source pointer by two                                  */
    /*   - write the blue component, then the green, then the red */
    /**************************************************************/
    for ( j = SPad.cx; j--; )
    {
        /**************************************************************/
        /* Get the source pel                                         */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;

        /**************************************************************/
        /* Write the blue component.                                  */
        /**************************************************************/
        *SPad.pbTrgPointer++ = (BYTE)BlueFromRGB16(SrcPel);

        /**************************************************************/
        /* Write the green and red components together.               */
        /* Green comes in the first byte, so in intel ordering we     */
        /* write green as the low byte and red as the high byte.      */
        /**************************************************************/
        *((PUSHORT)SPad.pbTrgPointer)++ = (USHORT)
               ((RedFromRGB16(SrcPel) << 8) | (GreenFromRGB16(SrcPel)));
    }
} /* ConvertInt16ToExt24 */


/**********************************************************************/
/* ConvertInt16ToExt8                                                 */
/*                                                                    */
/* Converts a single scan line from internal 16bpp to external 8bpp.  */
/**********************************************************************/
VOID DRIVERCALL ConvertInt16ToExt8(VOID)
{
    ULONG   j;
    RGB16   SrcPel;

    for ( j = SPad.cx; j--; )
    {
        /**************************************************************/
        /* Get the source pel                                         */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;

        *SPad.pbTrgPointer++ = (BYTE)Default8BppIndexFromRGB16(SrcPel);
    }
} /* ConvertInt16ToExt8 */


/**********************************************************************/
/* ConvertInt16ToExt4                                                 */
/*                                                                    */
/* Converts a single scan line from internal 16bpp to external 4bpp.  */
/**********************************************************************/
VOID DRIVERCALL ConvertInt16ToExt4(VOID)
{
#define TARGET_COLOURS 16

    ULONG   j;
    BYTE    bTrgByte;
    PBYTE   pExtRGB;
    RGB16   SrcPel;
    RGB2    SrcRGB;

    /******************************************************************/
    /* Work out where the external colour table starts.               */
    /******************************************************************/
    pExtRGB =
            ((PBYTE)SPad.pExternalHeader + SPad.pExternalHeader->cbFix);

    /******************************************************************/
    /* Each target pel requires two source pels.                      */
    /******************************************************************/
    for ( j = SPad.cx/2; j--; )
    {
        /**************************************************************/
        /* Get the first pel                                          */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;

        RGB2FromRGB16(SrcRGB,SrcPel);
        bTrgByte = (BYTE)
             (NearestRestrictedColourIndex(pExtRGB,
                                           SPad.usIncrement,
                                           SrcRGB,
                                           TARGET_COLOURS) << 4);

        /**************************************************************/
        /* Process the second pel                                     */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;

        RGB2FromRGB16(SrcRGB,SrcPel);
        *SPad.pbTrgPointer++ = (BYTE)
             (NearestRestrictedColourIndex(pExtRGB,
                                           SPad.usIncrement,
                                           SrcRGB,
                                           TARGET_COLOURS) | bTrgByte);
    }
    /******************************************************************/
    /* Process any odd source pel.                                    */
    /******************************************************************/
    if (SPad.cx & 1)
    {
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;

        RGB2FromRGB16(SrcRGB,SrcPel);
        *SPad.pbTrgPointer++ = (BYTE)
             (NearestRestrictedColourIndex(pExtRGB,
                                           SPad.usIncrement,
                                           SrcRGB,
                                           TARGET_COLOURS) << 4);
    }
#undef TARGET_COLOURS
} /* ConvertInt16ToExt4 */


/**********************************************************************/
/* ConvertInt16ToExt1                                                 */
/*                                                                    */
/* Converts a single scan line from internal 16bpp to external 1bpp.  */
/**********************************************************************/
VOID DRIVERCALL ConvertInt16ToExt1(VOID)
{
    ULONG   j;
    ULONG   ulExtraBits;
    BYTE    bTrgByte;
    RGB16   SrcPel;

    /******************************************************************/
    /* 8 internal pels per external byte.                             */
    /******************************************************************/
    for ( j = SPad.cx/8; j--; )
    {
        /**************************************************************/
        /* The following code could easily be compressed into a loop, */
        /* but is unrolled for speed!                                 */
        /**************************************************************/

        /**************************************************************/
        /* NB. Do not combine these statements because using macros   */
        /* means that the macro parameter is used multiple times,     */
        /* so if combined the increment would be done multiple times! */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*(PRGB16)SPad.pbSrcPointer);
        bTrgByte = MapRGB16ToMono(&SrcPel);
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Second pel.                                                */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*(PRGB16)SPad.pbSrcPointer);
        bTrgByte |= MapRGB16ToMono(&SrcPel);
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Third pel.                                                 */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*(PRGB16)SPad.pbSrcPointer);
        bTrgByte |= MapRGB16ToMono(&SrcPel);
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Fourth pel.                                                */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*(PRGB16)SPad.pbSrcPointer);
        bTrgByte |= MapRGB16ToMono(&SrcPel);
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Fifth pel.                                                 */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*(PRGB16)SPad.pbSrcPointer);
        bTrgByte |= MapRGB16ToMono(&SrcPel);
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Sixth pel.                                                 */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*(PRGB16)SPad.pbSrcPointer);
        bTrgByte |= MapRGB16ToMono(&SrcPel);
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Seventh pel.                                               */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*(PRGB16)SPad.pbSrcPointer);
        bTrgByte |= MapRGB16ToMono(&SrcPel);
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Eigth pel. nb dont shift this left!                        */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*(PRGB16)SPad.pbSrcPointer);
        bTrgByte |= MapRGB16ToMono(&SrcPel);
        ((PRGB16)SPad.pbSrcPointer)++;

        /**************************************************************/
        /* Write the external pel.                                    */
        /**************************************************************/
        *SPad.pbTrgPointer++ = bTrgByte;
    }
    /******************************************************************/
    /* Now do any odd pels.                                           */
    /******************************************************************/
    ulExtraBits = SPad.cx & 7;
    if (ulExtraBits)
    {
        bTrgByte = 0;
        for ( j = ulExtraBits; j--; )
        {
            SrcPel = MotorolaToIntel(*(PRGB16)SPad.pbSrcPointer);
            bTrgByte |= MapRGB16ToMono(&SrcPel);
            ((PRGB16)SPad.pbSrcPointer)++;
            bTrgByte <<= 1;
        }
        /**************************************************************/
        /* Write out the byte, remembering to shift the used bits     */
        /* up to the left side of the byte.                           */
        /**************************************************************/
        *SPad.pbTrgPointer++ = (BYTE)(bTrgByte << (7 - ulExtraBits));
    }
} /* ConvertInt16ToExt1 */

#ifdef   BPP24
/**********************************************************************/
/* ConvertInt24ToExt8                                                 */
/*                                                                    */
/* Converts a single scan line from internal 16bpp to external 8bpp.  */
/**********************************************************************/
VOID DRIVERCALL ConvertInt24ToExt8(VOID)
{
    ULONG   j;
    ULONG   SrcPel;

    for ( j = SPad.cx; j--; )
    {
        /**************************************************************/
        /* Get the source pel                                         */
        /**************************************************************/
        /*  The values in the color are layed out in RGB2 format      */
        /*  (BB GG RR BB GG RR . . .) the pels in our internal 24-bit */
        /*  bitmap are in RR GG BB format so the byte swapping        */
        /*  logic is reversed from what we would expect @75198 EKF    */
        /**************************************************************/
        SrcPel = *((PULONG)SPad.pbSrcPointer);
        ((PRGB)SPad.pbSrcPointer)++;

        if ( (DDT.fScreenFlags & USE_ATTDAC) ) {
           *SPad.pbTrgPointer++ = (BYTE)Default8BppIndexFromRGB24(SrcPel);
        }
        else
        {
           *SPad.pbTrgPointer++ = (BYTE)Default8BppIndexFromRGB24ATT(SrcPel);
        }
    }
} /* ConvertInt24ToExt8 */


/**********************************************************************/
/* ConvertInt24ToExt4                                                 */
/*                                                                    */
/* Converts a single scan line from internal 16bpp to external 4bpp.  */
/**********************************************************************/
VOID DRIVERCALL ConvertInt24ToExt4(VOID)
{
#define TARGET_COLOURS 16

    ULONG   j;
    BYTE    bTrgByte;
    PBYTE   pExtRGB;
    RGB2    SrcPel;

    /******************************************************************/
    /* Work out where the external colour table starts.               */
    /******************************************************************/
    pExtRGB =
            ((PBYTE)SPad.pExternalHeader + SPad.pExternalHeader->cbFix);

    /******************************************************************/
    /* Each target pel requires two source pels.                      */
    /******************************************************************/
    for ( j = SPad.cx/2; j--; )
    {
        /**************************************************************/
        /* Get the first pel                                          */
        /**************************************************************/
        /*  The values in the color are layed out in RGB2 format      */
        /*  (BB GG RR BB GG RR . . .) the pels in our internal 24-bit */
        /*  bitmap are in RR GG BB format so the byte swapping        */
        /*  logic is reversed from what we would expect @74911 EKF    */
        /**************************************************************/
        if ( !(DDT.fScreenFlags & USE_ATTDAC) ) {
           RGB2FromRGB2ATT(SrcPel,(*(PRGB2)SPad.pbSrcPointer));
        }
        else
        {
           SrcPel = *((PRGB2)SPad.pbSrcPointer);
        }
        ((PRGB)SPad.pbSrcPointer)++;

        bTrgByte = (BYTE)
             (NearestRestrictedColourIndex(pExtRGB,
                                           SPad.usIncrement,
                                           SrcPel,
                                           TARGET_COLOURS) << 4);

        /**************************************************************/
        /* Process the second pel                                     */
        /**************************************************************/
        if ( !(DDT.fScreenFlags & USE_ATTDAC) ) {
           RGB2FromRGB2ATT(SrcPel,(*(PRGB2)SPad.pbSrcPointer));
        }
        else
        {
           SrcPel = *((PRGB2)SPad.pbSrcPointer);
        }
        ((PRGB)SPad.pbSrcPointer)++;

        *SPad.pbTrgPointer++ = (BYTE)
             (NearestRestrictedColourIndex(pExtRGB,
                                           SPad.usIncrement,
                                           SrcPel,
                                           TARGET_COLOURS) | bTrgByte);
    }
    /******************************************************************/
    /* Process any odd source pel.                                    */
    /******************************************************************/
    if (SPad.cx & 1)
    {
        if ( !(DDT.fScreenFlags & USE_ATTDAC) ) {
           RGB2FromRGB2ATT(SrcPel,(*(PRGB2)SPad.pbSrcPointer));
        }
        else
        {
           SrcPel = *((PRGB2)SPad.pbSrcPointer);
        }
        ((PRGB)SPad.pbSrcPointer)++;

        *SPad.pbTrgPointer++ = (BYTE)
             (NearestRestrictedColourIndex(pExtRGB,
                                           SPad.usIncrement,
                                           SrcPel,
                                           TARGET_COLOURS) << 4);
    }
#undef TARGET_COLOURS
} /* ConvertInt24ToExt4 */


/**********************************************************************/
/* ConvertInt24ToExt1                                                 */
/*                                                                    */
/* Converts a single scan line from internal 16bpp to external 1bpp.  */
/**********************************************************************/
VOID DRIVERCALL ConvertInt24ToExt1(VOID)
{
    ULONG   j;
    ULONG   ulExtraBits;
    BYTE    bTrgByte;
    RGB2    SrcPel;


    /******************************************************************/
    /* 8 internal pels per external byte.                             */
    /******************************************************************/
    for ( j = SPad.cx/8; j--; )
    {
        /**************************************************************/
        /* The following code could easily be compressed into a loop, */
        /* but is unrolled for speed!                                 */
        /**************************************************************/

        /**************************************************************/
        /* NB. Do not combine these statements because using macros   */
        /* means that the macro parameter is used multiple times,     */
        /* so if combined the increment would be done multiple times! */
        /**************************************************************/
        if ( DDT.fScreenFlags & USE_ATTDAC ) {
           RGB2FromRGB2ATT(SrcPel,(*(PRGB2)SPad.pbSrcPointer));
        }
        else
        {
           SrcPel = *((PRGB2)SPad.pbSrcPointer);
        }
        bTrgByte = MapRGBToMono(&SrcPel);
        ((PRGB)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Second pel.                                                */
        /**************************************************************/
        if ( DDT.fScreenFlags & USE_ATTDAC ) {
           RGB2FromRGB2ATT(SrcPel,(*(PRGB2)SPad.pbSrcPointer));
        }
        else
        {
           SrcPel = *((PRGB2)SPad.pbSrcPointer);
        }
        bTrgByte |= MapRGBToMono(&SrcPel);
        ((PRGB)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Third pel.                                                 */
        /**************************************************************/
        if ( DDT.fScreenFlags & USE_ATTDAC ) {
           RGB2FromRGB2ATT(SrcPel,(*(PRGB2)SPad.pbSrcPointer));
        }
        else
        {
           SrcPel = *((PRGB2)SPad.pbSrcPointer);
        }
        bTrgByte |= MapRGBToMono(&SrcPel);
        ((PRGB)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Fourth pel.                                                */
        /**************************************************************/
        if ( DDT.fScreenFlags & USE_ATTDAC ) {
           RGB2FromRGB2ATT(SrcPel,(*(PRGB2)SPad.pbSrcPointer));
        }
        else
        {
           SrcPel = *((PRGB2)SPad.pbSrcPointer);
        }
        bTrgByte |= MapRGBToMono(&SrcPel);
        ((PRGB)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Fifth pel.                                                 */
        /**************************************************************/
        if ( DDT.fScreenFlags & USE_ATTDAC ) {
           RGB2FromRGB2ATT(SrcPel,(*(PRGB2)SPad.pbSrcPointer));
        }
        else
        {
           SrcPel = *((PRGB2)SPad.pbSrcPointer);
        }
        bTrgByte |= MapRGBToMono(&SrcPel);
        ((PRGB)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Sixth pel.                                                 */
        /**************************************************************/
        if ( DDT.fScreenFlags & USE_ATTDAC ) {
           RGB2FromRGB2ATT(SrcPel,(*(PRGB2)SPad.pbSrcPointer));
        }
        else
        {
           SrcPel = *((PRGB2)SPad.pbSrcPointer);
        }
        bTrgByte |= MapRGBToMono(&SrcPel);
        ((PRGB)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Seventh pel.                                               */
        /**************************************************************/
        if ( DDT.fScreenFlags & USE_ATTDAC ) {
           RGB2FromRGB2ATT(SrcPel,(*(PRGB2)SPad.pbSrcPointer));
        }
        else
        {
           SrcPel = *((PRGB2)SPad.pbSrcPointer);
        }
        bTrgByte |= MapRGBToMono(&SrcPel);
        ((PRGB)SPad.pbSrcPointer)++;
        bTrgByte <<= 1;
        /**************************************************************/
        /* Eigth pel. nb dont shift this left!                        */
        /**************************************************************/
        if ( DDT.fScreenFlags & USE_ATTDAC ) {
           RGB2FromRGB2ATT(SrcPel,(*(PRGB2)SPad.pbSrcPointer));
        }
        else
        {
           SrcPel = *((PRGB2)SPad.pbSrcPointer);
        }
        bTrgByte |= MapRGBToMono(&SrcPel);
        ((PRGB)SPad.pbSrcPointer)++;

        /**************************************************************/
        /* Write the external pel.                                    */
        /**************************************************************/
        *SPad.pbTrgPointer++ = bTrgByte;
    }
    /******************************************************************/
    /* Now do any odd pels.                                           */
    /******************************************************************/
    ulExtraBits = SPad.cx & 7;
    if (ulExtraBits)
    {
        bTrgByte = 0;
        for ( j = ulExtraBits; j--; )
        {
            if ( DDT.fScreenFlags & USE_ATTDAC ) {
               RGB2FromRGB2ATT(SrcPel,(*(PRGB2)SPad.pbSrcPointer));
            }
            else
            {
               SrcPel = *((PRGB2)SPad.pbSrcPointer);
            }
            bTrgByte |= MapRGBToMono(&SrcPel);
            ((PRGB)SPad.pbSrcPointer)++;
            bTrgByte <<= 1;
        }
        /**************************************************************/
        /* Write out the byte, remembering to shift the used bits     */
        /* up to the left side of the byte.                           */
        /**************************************************************/
        *SPad.pbTrgPointer++ = (BYTE)(bTrgByte << (7 - ulExtraBits));
    }
} /* ConvertInt24ToExt1 */

/**********************************************************************/
/* ConvertInt24ToExt24                                                */
/*                                                                    */
/* Converts a single scan line from external 24bpp to internal 24bpp. */
/* (No convert table is used at 24 bpp).                              */
/**********************************************************************/
VOID ConvertInt24ToExt24(VOID)
{
    ULONG            j;
    RGB              TrgPel;

    for ( j = SPad.cx; j--; )
    {
        TrgPel = *((PRGB)SPad.pbSrcPointer);
        if ( !(DDT.fScreenFlags & USE_ATTDAC) ) {
           *((PBYTE)SPad.pbTrgPointer)++ = TrgPel.bRed;
           *((PBYTE)SPad.pbTrgPointer)++ = TrgPel.bGreen;
           *((PBYTE)SPad.pbTrgPointer)++ = TrgPel.bBlue;
        }
        else
        {
           *((PBYTE)SPad.pbTrgPointer)++ = TrgPel.bBlue;
           *((PBYTE)SPad.pbTrgPointer)++ = TrgPel.bGreen;
           *((PBYTE)SPad.pbTrgPointer)++ = TrgPel.bRed;
        }
        SPad.pbSrcPointer += sizeof(RGB);
    }
} /* ConvertInt24ToExt24 */

/**********************************************************************/
/* From24BppInternalFn                                                */
/*                                                                    */
/* Returns a pointer to the function to be used to convert from a     */
/* 16bpp internal bitmap to the external format.                      */
/**********************************************************************/
PFNV DRIVERCALL From24BppInternalFn(VOID)
{
    switch (SPad.cExternalBitCount)
    {
        case 1:
            return( ConvertInt24ToExt1 );

        case 4:
            return( ConvertInt24ToExt4 );

        case 8:
            return( ConvertInt24ToExt8 );

        case 24:
            return( ConvertInt24ToExt24 );
    }
} /* From24BppInternalFn */
#endif // 24BPP


/**********************************************************************/
/* From16BppConvertFn                                                 */
/*                                                                    */
/* Returns a pointer to the function to be used to convert from a     */
/* 16bpp internal bitmap to the external format.                      */
/**********************************************************************/
PFNV DRIVERCALL From16BppConvertFn(VOID)
{
    switch (SPad.cExternalBitCount)
    {
        case 1:
            return( ConvertInt16ToExt1 );

        case 4:
            return( ConvertInt16ToExt4 );

        case 8:
            return( ConvertInt16ToExt8 );

        case 24:
            return( ConvertInt16ToExt24 );
    }
} /* From16BppConvertFn */


/**********************************************************************/
/* From8BppConvertFn                                                  */
/*                                                                    */
/* Returns a pointer to the function to be used to convert from an    */
/* 8bpp internal bitmap to the external format.                       */
/* There is no branch for the 8bpp -> 8bpp conversion.                */
/**********************************************************************/
PFNV DRIVERCALL From8BppConvertFn(VOID)
{
    switch (SPad.cExternalBitCount)
    {
        case 1:
            return( Convert8To1 );

        case 4:
            return( ConvertInt8ToExt4 );

        case 24:
            if ( SPad.fbFlags & CONV_BCE_PALETTE )
            {
                return( ConvertInt8ToExt24palindex );
            }
            else
            {
                if ( pdc != NULL   &&
                     pdc->DCIColFormat == LCOLF_PALETTE )
                {
                    return( ConvertInt8ToExt24pal );
                }
                else
                {
                    return( ConvertInt8ToExt24 );
                }
            }
    }
} /* From8BppConvertFn */


/**********************************************************************/
/* From4BppConvertFn                                                  */
/*                                                                    */
/* Returns a pointer to the function to be used to convert from a     */
/* 4bpp internal bitmap to the external format.                       */
/* Note that we dont support palette manager at 4bpp so don't have    */
/* int4ToExt routines which support palettes.                         */
/**********************************************************************/
PFNV DRIVERCALL From4BppConvertFn(VOID)
{
    switch (SPad.cExternalBitCount)
    {
        case 1:
            return( Convert4To1 );

        case 8:
            return( ConvertInt4ToExt8 );

        case 24:
            return( ConvertInt4ToExt24 );
    }
} /* From4BppConvertFn */


/**********************************************************************/
/* From1BppConvertFn                                                  */
/*                                                                    */
/* Returns a pointer to the function to be used to convert from a     */
/* 1bpp internal bitmap to the external format.                       */
/**********************************************************************/
PFNV DRIVERCALL From1BppConvertFn(VOID)
{
    switch (SPad.cExternalBitCount)
    {
        case 4:
            return( Convert1To4 );

        case 8:
            return( ConvertInt1ToExt8 );

        case 16:                                         /* @77638 */
            return( ConvertInt1ToExt16 );                /* @77638 */

        case 24:
            if ( SPad.fbFlags & CONV_BCE_PALETTE )
            {
                return( ConvertInt1ToExt24palindex );
            }
            else
            {
                /**********************************************************/
                /* No palette specific function required for standard 1   */
                /* bpp case.                                              */
                /**********************************************************/
                return( ConvertInt1ToExt24 );
            }
    }
} /* From1BppConvertFn */


/**********************************************************************/
/* GetConvertFn                                                       */
/*                                                                    */
/* Returns a pointer to the bpp specific function to be used to do    */
/* the work of converting from internal to external format.           */
/* Returns NULL if unrecognised format (shouldn't occur).             */
/**********************************************************************/
PFNV DRIVERCALL GetConvertFn(VOID)
{
    switch (SPad.cInternalBitCount)
    {
        case 1:
            return( From1BppConvertFn());

        case 4:
            return( From4BppConvertFn());

        case 8:
            return( From8BppConvertFn());

        case 16:
            return( From16BppConvertFn());

        #ifdef BPP24
        case 24:
            return( From24BppInternalFn());
        #endif
    }
} /* GetConvertFn */


/**********************************************************************/
/* ConvertIntToExt                                                    */
/*                                                                    */
/* pbTargetBitmap     pointer to the target (external) bitmap data    */
/* pTargetHeader      pointer to the target bitmap header             */
/* pbhSourceBitmap,   pointer to the source (internal) bitmap header  */
/* pptlScanStart      pointer to the scan starting coordinate         */
/* lScanLines         number of scanlines to process                  */
/*                                                                    */
/* Main routine for converting a bitmap from internal format to       */
/* external format.                                                   */
/**********************************************************************/
VOID DRIVERCALL ConvertIntToExt( PBYTE         pbTargetBitmap,
                                 PBITMAPINFO2  pTargetHeader,
                                 pBitmapHeader pbhSourceBitmap,
                                 PPOINTL       pptlScanStart,
                                 LONG          lScanLines)
{
    /******************************************************************/
    /* set up the scratch pad values (so avoiding parameter passing)  */
    /******************************************************************/
    SPad.pbExternalBitmap  = pbTargetBitmap;
    SPad.pExternalHeader   = pTargetHeader;
    SPad.pbhInternalBitmap = pbhSourceBitmap;
    SPad.pptlScanStart     = pptlScanStart;
    SPad.lScanLines        = lScanLines;
    SPad.cx                = SPad.pbhInternalBitmap->Info.Width;
    SPad.cInternalBitCount = SPad.pbhInternalBitmap->Info.BitCount;

    if ( OldFormatBitmap(pTargetHeader) )
    {
        SPad.pfnSetRGBAndInc   = SetRGBAndInc;
        SPad.cExternalBitCount = ((PBITMAPINFO)SPad.pExternalHeader)->cBitCount;
        SPad.usIncrement       = sizeof(RGB);
        SPad.fbFlags           = 0;
    }
    else /* new format header */
    {
        SPad.pfnSetRGBAndInc   = SetRGB2AndInc;
        SPad.cExternalBitCount = SPad.pExternalHeader->cBitCount;
        SPad.usIncrement       = sizeof(RGB2);

        /**************************************************************/
        /* Check to see if we are to use the special BCE_PALETTE      */
        /* return format.  This only applies if there is a palette in */
        /* the current DC (Higher level code will have raised an      */
        /* error if they asked for the special format without having  */
        /* a palette)                                                 */
        /*                                                            */
        /* When we are called from DeviceDeleteBitmap, there is no    */
        /* DC around, so there can never be a palette selected into   */
        /* it. (pdc will be NULL in this case).                       */
        /**************************************************************/
        if (pdc != NULL                                          &&
            (pdc->DCIColFormat == LCOLF_PALETTE)                 &&
            (SPad.pExternalHeader->cbFix >=
                      SIZE_ALL_BM2_FIELDS(SPad.pExternalHeader)) &&
            (SPad.pExternalHeader->ulColorEncoding == BCE_PALETTE) )
        {
            SPad.fbFlags = CONV_BCE_PALETTE;
        }
        else
        {
            SPad.fbFlags = 0;
        }
    }

#ifdef PALETTE_MGR_POSSIBLE
    /******************************************************************/
    /* This code is a possible enhancement to this routine, but its   */
    /* not been code yet in this form!                                */
    /******************************************************************/

    /******************************************************************/
    /* Set up the external colour table, and also any conversion table*/
    /* that may be required to map internal indices to external ones  */
    /******************************************************************/
    fMapping = CreateExternalColorTable();

    if ( SPad.cSourceBitCount == SPad.cExternalBitCount )
    {
        /**************************************************************/
        /* Source and target bitcounts are the same, so all we need   */
        /* to do is flip the order of the scanlines                   */
        /**************************************************************/
        FlipTheBitmap(INT_TO_EXT_COPY);
    }
    else if (fMapping == FALSE)
    {
        /**************************************************************/
        /* The mapping is just the expansion identity                 */
        /* (The expansion identity is where we have different bits    */
        /* per pel, but for each source pel the index in the source   */
        /* is the same as the index in the target).                   */
        /**************************************************************/
        ExpandIntToWin();
    }
    else
    {
        /**************************************************************/
        /* The most general case is a full conversion using the       */
        /* conversion table                                           */
        /**************************************************************/
        ConvertPMInt(GetConvertFn(),
                     &SPad.pbSrcPointer,
                     &SPad.pbTrgPointer);
    }
#else /* PALETTE_MGR_POSSIBLE */
    /******************************************************************/
    /* Check if colour conversion is required.                        */
    /* If Bitcounts are different we will definitely need to do       */
    /* conversion between the bitmaps.                                */
    /******************************************************************/
    #ifndef   BPP24
    if ( SPad.cInternalBitCount != SPad.cExternalBitCount )
    #else
    if ( (SPad.cInternalBitCount != SPad.cExternalBitCount) ||
         (SPad.cInternalBitCount == 24) )
    #endif
    {
        /**************************************************************/
        /* set up the external color table and the conversion table   */
        /*                                                            */
        /* NB. TableIntToPM  actually returns a BOOL which tells us   */
        /* if an identity mapping is possible (ie that it did not     */
        /* bother to set up a mapping vector)                         */
        /**************************************************************/
        TableIntToPM();

        /**************************************************************/
        /* call the conversion and inversion                          */
        /**************************************************************/
        ConvertPMInt(GetConvertFn(),
                     &SPad.pbSrcPointer,
                     &SPad.pbTrgPointer);
    }
    else /* no conversion */
    {
        /**************************************************************/
        /* set up the external color table                            */
        /**************************************************************/
        SetExternalColorTable();

        /**************************************************************/
        /* no colour conversion is required and so call subroutine to */
        /* perform the flipping of the order of the rows              */
        /**************************************************************/
        FlipTheBitmap(INT_TO_EXT_COPY);
    }
#endif /* PALETTE_MGR_POSSIBLE */
} /* ConvertIntToExt */


/**********************************************************************/
/* GetPaletteEncoding                                                 */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Sets an identity mapping rather than RGB colours in the colour     */
/* table pointed to by pExtRGB.                                       */
/* The mapping goes in the blue component since this is the           */
/* first byte in the RGB2 structure.                                  */
/**********************************************************************/
VOID DRIVERCALL GetPaletteEncoding(PRGB  pExtRGB)
{
    ULONG   i;
    ULONG   ulPaletteSize;

    ulPaletteSize = 1 << SPad.cExternalBitCount;

    for (i = 0; i < ulPaletteSize; i++)
    {
        /**************************************************************/
        /* Palette encoding only applies when we are using the new    */
        /* bitmap header, and hence RGB2 values, which means each     */
        /* external color table entry is a dword.                     */
        /**************************************************************/
        *((PULONG)pExtRGB)++ = i;
    }
} /* GetPaletteEncoding */


/**********************************************************************/
/* GetPalEncodeWithConvTab                                            */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Sets an identity mapping rather than RGB colours in the colour     */
/* table pointed to by pExtRGB and also a convert table between the   */
/* internal and external tables.                                      */
/* The mapping goes in the blue component since this is the           */
/* first byte in the RGB2 structure.                                  */
/**********************************************************************/
VOID DRIVERCALL GetPalEncodeWithConvTab(PRGB pExtRGB)
{
    ULONG   i;
    ULONG   ulMaxColours;

    /******************************************************************/
    /* Set up the external color table.                               */
    /******************************************************************/
    GetPaletteEncoding(pExtRGB);

    ulMaxColours = 1 << SPad.cExternalBitCount;

    /******************************************************************/
    /* Identity map all the external values we can.                   */
    /******************************************************************/
    for (i = 0; i < ulMaxColours; i++)
    {
        SPad.ausConvertTable[i] = (BYTE)i;
    }
    /******************************************************************/
    /* Map any excess internal colours which cannot be identity       */
    /* mapped to 0.                                                   */
    /******************************************************************/
    for (ulMaxColours = 1 << SPad.cInternalBitCount; i < ulMaxColours; i++)
    {
        SPad.ausConvertTable[i] = 0;
    }
} /* GetPalEncodeWithConvTab */


/**********************************************************************/
/* GetMonoTable                                                       */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Sets up the external colour table for a monochrome bitmap. The     */
/* table is pointed to by pExtRGB.                                    */
/**********************************************************************/
VOID DRIVERCALL GetMonoTable(PRGB pExtRGB)
{
   SPad.pfnSetRGBAndInc(&pExtRGB, 0x00, 0x00, 0x00);
   SPad.pfnSetRGBAndInc(&pExtRGB, 0xFF, 0xFF, 0xFF);
} /* GetMonoTable */


/**********************************************************************/
/* GetSrcMonoCTWithConvTab                                            */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Sets up the external colour table for a monochrome source bitmap   */
/* and the conversion table from internal (source) to external tables */
/**********************************************************************/
VOID DRIVERCALL GetSrcMonoCTWithConvTab(PRGB pExtRGB)
{
    /******************************************************************/
    /* Set up the external color table.                               */
    /******************************************************************/
    GetMonoTable(pExtRGB);

    /******************************************************************/
    /* The conversion table, if used, is an identity mapping!         */
    /******************************************************************/
    SPad.ausConvertTable[0] = 0;
    SPad.ausConvertTable[1] = 1;
} /* GetSrcMonoCTWithConvTab */


/**********************************************************************/
/* GetConvTabFromLogicalPalette                                       */
/*                                                                    */
/* Sets up the conversion table when the internal bitmap uses a       */
/* logical palette.                                                   */
/**********************************************************************/
VOID DRIVERCALL GetConvTabFromLogicalPalette(VOID)
{
    ULONG   i;
    ULONG   ulUsedPaletteSize;
    ULONG   ulSourcePaletteSize;

    /*******************************************************************/
    /* Our bitmap contents are indices into our logical palette.       */
    /* We can only use the logical palette for as many entries as are  */
    /* actually valid in it.                                           */
    /*******************************************************************/
    ulSourcePaletteSize = 1 << SPad.cInternalBitCount;
    ulUsedPaletteSize =
             min(ulSourcePaletteSize, pdc->Palette->usCountStored);

    /******************************************************************/
    /* Fill in the used part of the palette.                          */
    /******************************************************************/
    for ( i = 0; i < ulUsedPaletteSize; i++ )
    {
        SPad.ausConvertTable[i] =
                            MapRGBToMono(&pdc->Palette->entries[i].rgb);
    }

    /******************************************************************/
    /* Map all remaining values to zero.                              */
    /******************************************************************/
    while (i < ulSourcePaletteSize)
    {
        SPad.ausConvertTable[i++] = 0;
    }
} /* GetConvTabFromLogicalPalette */


/**********************************************************************/
/* GetConvTabFromPhysicalPalette                                      */
/*                                                                    */
/* Sets up the conversion table when the internal bitmap uses a       */
/* logical color table.                                               */
/**********************************************************************/
VOID DRIVERCALL GetConvTabFromPhysicalPalette(VOID)
{
    ULONG   ulSourcePaletteSize;
    ULONG   i;
    RGB2    PhyRGB;

    /******************************************************************/
    /* We are in the Color Table model, where indices in bitmaps are  */
    /* indices into the device default physical palette.              */
    /******************************************************************/
    ulSourcePaletteSize = 1 << SPad.cInternalBitCount;

    for ( i = 0; i < ulSourcePaletteSize; i++ )
    {
        PhyRGB = MemoryDeviceDefaultRGB2(i);
        SPad.ausConvertTable[i] = MapRGBToMono(&PhyRGB);
    }
} /* GetConvTabFromPhysicalPalette */


/**********************************************************************/
/* GetDstMonoCTWithConvTab                                            */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Sets up the external colour table for a monochrome destination     */
/* bitmap and the conversion table from internal (source) to external */
/* (destination) tables                                               */
/**********************************************************************/
VOID DRIVERCALL GetDstMonoCTWithConvTab(PRGB pExtRGB)
{
    /******************************************************************/
    /* Set up the external mono color table.                          */
    /******************************************************************/
    GetMonoTable(pExtRGB);

    /******************************************************************/
    /* We are are going to from an internal colour bitmap to an       */
    /* external monochrome one.  After much discussion with Microsoft */
    /* it appears that we map the colour pixels to black or white     */
    /* depending on which they are nearer to (using least squares).   */
    /* The external colour table is set to white (foreground) and     */
    /* black (background)                                             */
    /******************************************************************/
    if (pdc != NULL && pdc->DCIColFormat == LCOLF_PALETTE)
    {
        GetConvTabFromLogicalPalette();
    }
    else
    {
        GetConvTabFromPhysicalPalette();
    }
} /* GetDstMonoCTWithConvTab */


/**********************************************************************/
/* GetSelectedPalette                                                 */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Copy the selected palette to the external table, pExtRGB, and fill */
/* any unused entries with black.                                     */
/**********************************************************************/
VOID DRIVERCALL GetSelectedPalette(PRGB pExtRGB)
{
    ULONG   i;
    ULONG   ulPaletteSize;

    ulPaletteSize = min(1 << SPad.cExternalBitCount,
                        pdc->Palette->usCountStored);

    /******************************************************************/
    /* Fill in the entries from the palette.                          */
    /******************************************************************/
    for (i = 0; i < ulPaletteSize; i++ )
    {
        SPad.pfnSetRGBAndInc(&pExtRGB,
                             pdc->Palette->entries[i].rgb.bRed,
                             pdc->Palette->entries[i].rgb.bGreen,
                             pdc->Palette->entries[i].rgb.bBlue);
    }

    /******************************************************************/
    /* Now fill all remaining entries with black.                     */
    /******************************************************************/
    for (ulPaletteSize = 1 << SPad.cExternalBitCount;
         i < ulPaletteSize;
         i++)
    {
        SPad.pfnSetRGBAndInc(&pExtRGB, 0, 0, 0);
    }
} /* GetSelectedPalette */


/**********************************************************************/
/* MapManyRGBToLess                                                   */
/*                                                                    */
/* Makes the internal to external conversiontable, if any, for a      */
/* source with bitcount greater than the destination.                 */
/* Returns TRUE if a mapping from internal to external is set up,     */
/* FALSE otherwise.                                                   */
/**********************************************************************/
BOOL DRIVERCALL MapManyRGBToLess(VOID)
{
    ULONG   i;
    ULONG   ulMaxSource;
    ULONG   ulMaxTarget;
    ULONG   ulUsedSource;
    ULONG   ulUsedTarget;

    /**********************************************************/
    /* we are going from more bits to less, so we must        */
    /* produce a conversion table to map the bits down into   */
    /* the restricted number of entries available.            */
    /**********************************************************/
    ulMaxSource = 1 << SPad.cInternalBitCount;
    ulMaxTarget = 1 << SPad.cExternalBitCount;
    ulUsedSource = min(ulMaxSource, pdc->Palette->usCountStored);
    ulUsedTarget = min(ulMaxTarget, pdc->Palette->usCountStored);

#ifdef OPTIMIZATION
    /**********************************************************/
    /* We still might get away without having to use a        */
    /* conversion mapping if the palette is such that our     */
    /* source (although more bits per pel than the target)    */
    /* only contains indices within the target range.         */
    /*                                                        */
    /* However our code elsewhere is not clever enough to     */
    /* do without a conversion table, so just set up          */
    /* an identity mapping.                                   */
    /**********************************************************/
    if ( ulUsedSource < ulMaxTarget )
    {
        /******************************************************/
        /* NB. dont return until we change the code elsewhere */
        /* to do without the mapping table.                   */
        /* If we don't return then we will get an identity    */
        /* mapping.                                           */
        /******************************************************/
        return (FALSE);
    }
#endif /* OPTIMIZATION */

    /**********************************************************/
    /* The mapping is the identity for all source entries     */
    /* which are valid in the target size.                    */
    /**********************************************************/
    for (i = 0; i < ulUsedTarget; i++)
    {
        SPad.ausConvertTable[i] = (USHORT)i;
    }

    /**********************************************************/
    /* now we consider the entries which have to be mapped    */
    /* down                                                   */
    /**********************************************************/
    while (i < ulUsedSource)
    {
        SPad.ausConvertTable[i] = (USHORT)
              NearestRestrictedColourIndex(
                           (PBYTE)pdc->Palette->entries,
                           sizeof(PALENTRY),
                           pdc->Palette->entries[i].rgb,
                           ulUsedTarget);
        i++;
    }

    /**********************************************************/
    /* now zero map any remaining entries since they are      */
    /* probably errors which we cant do much else with        */
    /**********************************************************/
    for ( ; i < ulMaxSource; i++)
    {
        SPad.ausConvertTable[i] = (USHORT)0;
    }

    return(TRUE);
} /* MapManyRGBToLess */


/**********************************************************************/
/* GetSelectedPalWithConvTab                                          */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Copy the selected palette to the external table, pExtRGB, filling  */
/* any unused entries with black and set up the internal to external  */
/* conversion table.                                                  */
/* Returns TRUE if a mapping from internal to external is set up,     */
/* FALSE otherwise.                                                   */
/**********************************************************************/
BOOL DRIVERCALL GetSelectedPalWithConvTab(PRGB pExtRGB)
{
    /******************************************************************/
    /* Set up the external color table.                               */
    /******************************************************************/
    GetSelectedPalette(pExtRGB);

    if (SPad.cInternalBitCount < SPad.cExternalBitCount)
    {
        /**********************************************************/
        /* no mapping needed if we are going from less bits to    */
        /* more                                                   */
        /**********************************************************/
        return(FALSE);
    }
    else /* target bitcount greater than source */
    {
        return(MapManyRGBToLess());
    }
} /* GetSelectedPalWithConvTab */


/**********************************************************************/
/* GetDefaultHWPalette                                                */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Copy the default h/w palette to the external table, pExtRGB.       */
/**********************************************************************/
VOID DRIVERCALL GetDefaultHWPalette(PRGB pExtRGB)
{
    ULONG   i;
    ULONG   ulPaletteSize;
    ULONG   ulPhyRGB;
    PBYTE   pbLogRGB;

    ulPaletteSize = 1 << SPad.cExternalBitCount;

   for (i = 0; i < ulPaletteSize; i++ )
   {
      /**************************************************/
      /* Take this entry from the DeviceDefaultPalette  */
      /**************************************************/
      ulPhyRGB = MemoryDeviceDefaultULONG(i);
      pbLogRGB = (PBYTE)&ulPhyRGB;
      SPad.pfnSetRGBAndInc(&pExtRGB,
                           pbLogRGB[2],
                           pbLogRGB[1],
                           pbLogRGB[0]);
   }

} /* GetDefaultHWPalette */


/**********************************************************************/
/* GetRealizableTable                                                 */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Copy the current, realizable colour table to the external table,   */
/* pExtRGB.                                                           */
/**********************************************************************/
VOID DRIVERCALL GetRealizableTable(PRGB pExtRGB)
{
    ULONG   i;
    ULONG   ulPaletteSize;
    RGB2    RGBValue;

    ulPaletteSize = 1 << SPad.cExternalBitCount;

    for (i = 0; i < ulPaletteSize; i++ )
    {
        /******************************************************/
        /* if this is a valid entry take it from color table  */
        /******************************************************/
        if ((i <= pdc->DCIHighIndex) &&
            (pdc->DCIColorTable[i].PhyIndex != CLR_NOPHYINDEX) )
        {
            /**************************************************/
            /* This is a valid entry in the LCT so use its    */
            /* logical RGB value.                             */
            /**************************************************/
            RGBValue = pdc->DCIColorTable[i].LogRGB;
        }
        else
        {
            /**************************************************/
            /* Take this entry from the DeviceDefaultPalette  */
            /**************************************************/
            RGBValue = MemoryDeviceDefaultRGB2(i);
        }

        SPad.pfnSetRGBAndInc(&pExtRGB,
                             RGBValue.bRed,
                             RGBValue.bGreen,
                             RGBValue.bBlue);
    }
} /* GetRealizableTable */


/**********************************************************************/
/* Get4Or8BppTable                                                    */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Copy the current colour table to the external table, pExtRGB.      */
/* If the logical colour table is realizable then copy that,          */
/* otherwise copy the palette.                                        */
/**********************************************************************/
VOID DRIVERCALL Get4Or8BppTable(PRGB pExtRGB)
{
    if (fRealizeSupported &&
        pdc != NULL       &&
        (pdc->DCIColStatus & LCOL_REALIZABLE))
    {
        GetRealizableTable(pExtRGB);
    }
    else /* non-realizable colour table */
    {
        GetDefaultHWPalette(pExtRGB);
    }
} /* Get4Or8BppTable */


/**********************************************************************/
/*                                                                    */
/* Function to create a packed external colour table.                 */
/* Only called when internal and external bitcounts are the same.     */
/* (NB. we can't be called for 24 bpp because internal bitcount is    */
/* never 24 bpp; can't be called for 16 bpp as this always requires   */
/* a conversion to external format).                                  */
/**********************************************************************/
VOID DRIVERCALL SetExternalColorTable(VOID)
{
    PRGB   pExtRGB;

    pExtRGB = (PRGB)
            ((PBYTE)SPad.pExternalHeader + SPad.pExternalHeader->cbFix);

    if ( SPad.fbFlags & CONV_BCE_PALETTE )
    {
        GetPaletteEncoding(pExtRGB);
    }
    else if (SPad.cExternalBitCount == 1)
    {
        GetMonoTable(pExtRGB);
    }
    else if (pdc != NULL && pdc->DCIColFormat == LCOLF_PALETTE)
    {
        GetSelectedPalette(pExtRGB);
    }
    else if (SPad.cExternalBitCount != 24 && SPad.cExternalBitCount != 16)    /* @77638 */
    {
        Get4Or8BppTable(pExtRGB);
    }
} /* SetExternalColorTable */


/**********************************************************************/
/* Maps Index to the RGB value which is actually used when this index */
/* is applied.                                                        */
/**********************************************************************/
RGB2 DRIVERCALL DisplayedRGB(ULONG   ulIndex)
{
    if (fRealizeSupported                     &&
        pdc != NULL                           &&
        (pdc->DCIColStatus & LCOL_REALIZABLE) &&
        (ulIndex < pdc->DCIColTabSize) )
    {
        /**********************************************/
        /* There is a LCT and it is realizable so we  */
        /* take the RGB value from it.                */
        /**********************************************/
        return(pdc->DCIColorTable[ulIndex].LogRGB);
    }
    else
    {
        /**********************************************/
        /* There is no LCT, or an unrealizable LCT so */
        /* take the RGB value from the default        */
        /* physical palette.                          */
        /**********************************************/
        return(MemoryDeviceDefaultRGB2(ulIndex));
    }
} /* DisplayedRGB */


/**********************************************************************/
/* MapTo4BppWithConvTab                                               */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Maps the internal colour table to a 4 bpp external table and makes */
/* a conversion table for translating from internal to external.      */
/**********************************************************************/
VOID DRIVERCALL MapTo4BppWithConvTab(PRGB pExtRGB)
{
    ULONG    ulIndex;
    PBYTE    pbLogRGB;
    PBYTE    pbExtRGBTable = (PBYTE)pExtRGB;

#define TARGET_COLOURS 16

    /******************************************************************/
    /* Set up the external color table.                               */
    /******************************************************************/
    for ( ulIndex = 0; ulIndex < TARGET_COLOURS ; ulIndex++)
    {
        /**********************************************************/
        /* Defect 60394 - If the DC has a 16 entry logical color  */
        /* table loaded then we should use it.                    */
        /**********************************************************/
        if( pdc->DCIHighIndex == (TARGET_COLOURS-1))
          pbLogRGB =  (PBYTE)&(pdc->DCIColorTable[ulIndex].LogRGB);
        else
          pbLogRGB =  (PBYTE)&(DefaultFourBppTable[ulIndex].LogRGB);

        SPad.pfnSetRGBAndInc(&pExtRGB,
                             pbLogRGB[2],
                             pbLogRGB[1],
                             pbLogRGB[0]);

    }

    /******************************************************************/
    /* Set up the conversion table.                                   */
    /******************************************************************/
    for ( ulIndex = 1 << SPad.cInternalBitCount; ulIndex--; )
    {
        SPad.ausConvertTable[ulIndex] = (USHORT)
            NearestRestrictedColourIndex(pbExtRGBTable,
                                         SPad.usIncrement,
                                         DisplayedRGB(ulIndex),
                                         TARGET_COLOURS);
    }
#undef TARGET_COLOURS

} /* MapTo4BppWithConvTab */


/**********************************************************************/
/* Get8BppTableFrom16Bpp                                              */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Create an 8 bpp external colour table to represent the 16 bpp      */
/* internal bitmap colours.                                           */
/*                                                                    */
/* For want of a better external color table we use a fixed set of    */
/* 256 values, whose actual mapping is all carried out by the         */
/* GetDefault8BppExtEntry macro.                                      */
/**********************************************************************/
VOID DRIVERCALL Get8BppTableFrom16Bpp(PRGB pExtRGB)
{
    ULONG   i;
    RGB2    DefaultRGB;

    for (i=0; i<256; i++)
    {
        GetDefault8BppExtEntry(DefaultRGB,i);
        SPad.pfnSetRGBAndInc(&pExtRGB,
                             DefaultRGB.bRed,
                             DefaultRGB.bGreen,
                             DefaultRGB.bBlue);
    }
} /* Get8BppTableFrom16Bpp */

/**********************************************************************/
/* Get4BppTableFrom16Bpp                                              */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Create an 4 bpp external colour table to represent the 16 bpp      */
/* internal bitmap colours.                                           */
/*                                                                    */
/**********************************************************************/
VOID DRIVERCALL Get4BppTableFrom16Bpp(PRGB pExtRGB)
{
    ULONG   i;
    PRGB2   pDefaultRGB;

    for (i=0; i<16; i++)
    {
        pDefaultRGB = &(DefaultFourBppTable[i].LogRGB);

        SPad.pfnSetRGBAndInc(&pExtRGB,
                             pDefaultRGB->bRed,
                             pDefaultRGB->bGreen,
                             pDefaultRGB->bBlue);
    }
} /* Get4BppTableFrom16Bpp */


/**********************************************************************/
/* GetFrom16BppColourTable                                            */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Creates an external colour table to represent the 16 bpp internal  */
/* bitmap colours. No convert table is needed as we do the RGB to     */
/* colour table index conversion as we build the target bitmap.       */
/* No colour table is required for converting to 24 bpp.              */
/**********************************************************************/
VOID DRIVERCALL GetFrom16BppColourTable(PRGB pExtRGB)
{
    switch ( SPad.cExternalBitCount )
    {
        case 1:
            GetMonoTable(pExtRGB);
            break;

        case 4:
            Get4BppTableFrom16Bpp(pExtRGB);
            break;

        case 8:
            Get8BppTableFrom16Bpp(pExtRGB);
            break;
    }
} /* GetFrom16BppColourTable */

#ifdef   BPP24
/**********************************************************************/
/* Get8BppTableFrom24Bpp                                              */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Create an 8 bpp external colour table to represent the 24 bpp      */
/* internal bitmap colours.                                           */
/*                                                                    */
/* For want of a better external color table we use a fixed set of    */
/* 256 values, whose actual mapping is all carried out by the         */
/* GetDefault8BppExtEntry macro.                                      */
/**********************************************************************/
VOID DRIVERCALL Get8BppTableFrom24Bpp(PRGB pExtRGB)
{
    ULONG   i;
    RGB2    DefaultRGB;

    for (i=0; i<256; i++)
    {
        GetDefault8BppExtEntry(DefaultRGB,i);
        SPad.pfnSetRGBAndInc(&pExtRGB,
                             DefaultRGB.bRed,
                             DefaultRGB.bGreen,
                             DefaultRGB.bBlue);
    }
} /* Get8BppTableFrom24Bpp */

/**********************************************************************/
/* Get4BppTableFrom24Bpp                                              */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Create an 4 bpp external colour table to represent the 16 bpp      */
/* internal bitmap colours.                                           */
/*                                                                    */
/**********************************************************************/
VOID DRIVERCALL Get4BppTableFrom24Bpp(PRGB pExtRGB)
{
    ULONG   i;
    PRGB2   pDefaultRGB;

    for (i=0; i<16; i++)
    {
        pDefaultRGB = &(DefaultFourBppTable[i].LogRGB);

        SPad.pfnSetRGBAndInc(&pExtRGB,
                             pDefaultRGB->bRed,
                             pDefaultRGB->bGreen,
                             pDefaultRGB->bBlue);
    }
} /* Get4BppTableFrom24Bpp */


/**********************************************************************/
/* GetFrom24BppColourTable                                            */
/*                                                                    */
/* pExtRGB  pointer to external colour table                          */
/*                                                                    */
/* Creates an external colour table to represent the 24 bpp internal  */
/* bitmap colours. No convert table is needed as we do the RGB to     */
/* colour table index conversion as we build the target bitmap.       */
/* No colour table is required for converting to 24 bpp.              */
/**********************************************************************/
VOID DRIVERCALL GetFrom24BppColourTable(PRGB pExtRGB)
{
    switch ( SPad.cExternalBitCount )
    {
        case 1:
            GetMonoTable(pExtRGB);
            break;

        case 4:
            Get4BppTableFrom24Bpp(pExtRGB);
            break;

        case 8:
            Get8BppTableFrom24Bpp(pExtRGB);
            break;
        // Dont need a table to get from 24bpp to 24bpp
    }
} /* GetFrom24BppColourTable */
#endif


/**********************************************************************/
/* TableIntToPM                                                       */
/*                                                                    */
/* Creates a packed external colour table and a conversion table      */
/* between the internal and external colour tables.                   */
/*                                                                    */
/* Returns TRUE is an internal to external mapping has been set up,   */
/* FALSE otherwise.                                                   */
/*                                                                    */
/* Only called when source and destination bitcounts differ.          */
/**********************************************************************/
BOOL DRIVERCALL TableIntToPM(VOID)
{
    PRGB   pExtRGB;

    pExtRGB = (PRGB)
            ((PBYTE)SPad.pExternalHeader + SPad.pExternalHeader->cbFix);

    #ifdef   BPP24
    if ( SPad.cInternalBitCount == 24 )
    {
        GetFrom24BppColourTable(pExtRGB);
    }
    else if ( SPad.cInternalBitCount == 16 )
    #else
    if ( SPad.cInternalBitCount == 16 )
    #endif
    {
        GetFrom16BppColourTable(pExtRGB);
    }
    else if ( SPad.fbFlags & CONV_BCE_PALETTE )
    {
        GetPalEncodeWithConvTab(pExtRGB);
    }
    else if (SPad.cInternalBitCount == 1)
    {
        GetSrcMonoCTWithConvTab(pExtRGB);
    }
    else if (SPad.cExternalBitCount == 1)
    {
        GetDstMonoCTWithConvTab(pExtRGB);
    }
    else if (pdc != NULL && pdc->DCIColFormat == LCOLF_PALETTE)
    {
        return(GetSelectedPalWithConvTab(pExtRGB));
    }
    else if (SPad.cExternalBitCount == 4)
    {
        MapTo4BppWithConvTab(pExtRGB);
    }
    else if (SPad.cExternalBitCount == 8)
    {
        Get4Or8BppTable(pExtRGB);
    }
    return (TRUE);
} /* TableIntToPM */
