/*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          = CONVBITM                                       */
/*                                                                    */
/*   Description     = Conversion between internal bitmap formats     */
/*                     BMConvIntToInt                                 */
/*                                                                    */
/*   Function        = Converts an internal bitmap from one of the    */
/*                     currently supported formats to the other and   */
/*                     obtains the memory for the converted           */
/*                     representation                                 */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#define INCL_DDIMISC
#include "eddinclt.h"

#include "eddbcone.h"
#include "eddhcone.h"

#include "eddbtypt.h"
#include "edddtypt.h"

#include "bitmaps.h"

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

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

#include "hwaccess.h"
#include "memman.h"
#include "convfuns.h"

extern RGB2             HWPalette[HW_PAL_SIZE];
extern DEVPAL           DeviceDefaultPalette;

extern DDTType          DDT;

extern BitmapHeader     DirectListEntry;
extern ULONG            pPhunkPhys;
extern PBYTE            pPhunkVirt;
extern ULONG            VRAMBaseAddress;
extern SHORT            softDrawInUse;
#ifndef   _8514
extern MMReg            ShadowXGARegs;
#else
#include "8514.h"
extern MM8514Reg        Shadow8514Regs;
#endif



/**********************************************************************/
/* CopyScreenToMemory                                                 */
/*                                                                    */
/* pbhTarget  pointer to the header of the target bitmap.             */
/*                                                                    */
/* Copies the contents of the screen VRAM to the bitmap pbhTarget.    */
/*                                                                    */
/* edb : added code to copy from VRAM to PHUNK for 74282              */
/**********************************************************************/
VOID DRIVERCALL CopyScreenToMemory(pBitmapHeader pbhTarget)
{
    ULONG  fSaveSoftDrawInUse;
    LONG   lPhunkSecondChunkYOffset; /* Start of 2nd chunk in Phunk   */
    LONG   lPhunkSecondChunkByteIncrement;  /* Start of 2nd chunk in  */
                                /*             Phunk                  */
    LONG   lVRAMYIncrement;     /* distance to move up in VRAM at     */
                                /* each copy                          */
    LONG   lTrgByteIncrement;   /* Number of bytes to copy from       */
                                /* Phunk to target at one time        */
    LONG   lTrgByteOffset;      /* Place to copy to in target         */
    ULONG  ulParity;            /* Parity counter (see comment below) */

    /******************************************************************/
    /* Turn off the software drawing flag temporarily so that we can  */
    /* access the VRAM.                                               */
    /******************************************************************/
    fSaveSoftDrawInUse = softDrawInUse;
    softDrawInUse = FALSE;

    /******************************************************************/
    /* Set up VRAM and phunk physical addresses.                      */
    /******************************************************************/
    // we will use a utility here @DMS !!!

    #ifndef   _8514
    ShadowXGARegs.PixMapBaseB = DirectListEntry.BMPhys;
    ShadowXGARegs.PixMapBaseA = pPhunkPhys;
    /******************************************************************/
    /* Set up bitmap sizes and formats.                               */
    /******************************************************************/
    ShadowXGARegs.PixMapWidthA  = DirectListEntry.Info.HWWidth;
    ShadowXGARegs.PixMapHeightA = DirectListEntry.Info.HWHeight;
    ShadowXGARegs.PixMapFormatA = (BYTE)DirectListEntry.Info.HWFormat;

    ShadowXGARegs.PixMapWidthB  = DirectListEntry.Info.HWWidth;
    ShadowXGARegs.PixMapHeightB = DirectListEntry.Info.HWHeight;
    ShadowXGARegs.PixMapFormatB = (BYTE)DirectListEntry.Info.HWFormat;

    /******************************************************************/
    /* Set up all registers that don't depend on which chunk we're    */
    /* copying.                                                       */
    /******************************************************************/
    ShadowXGARegs.SrcXAddr = 0;
    ShadowXGARegs.DstXAddr = 0;
    ShadowXGARegs.OpDim1 = DirectListEntry.Info.HWWidth;
    ShadowXGARegs.FgMix = ShadowXGARegs.BgMix = HWMIX_SOURCE;
    ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;

    ShadowXGARegs.PixOp = BACK_SRC_SRC_PIX_MAP |
                          FORE_SRC_SRC_PIX_MAP |
                          STEP_PXBLT |
                          SRC_PIX_MAP_B |
                          DST_PIX_MAP_A |
                          PAT_PIX_MAP_FORE |
                          MASK_PIX_MAP_OFF |
                          DRAW_MODE_DONTCARE |
                          DIR_OCTANT_LRTB;
    #else
    Shadow8514Regs.PixMapBaseB = DirectListEntry.BMPhys;
    Shadow8514Regs.PixMapBaseA = pPhunkPhys;
    /******************************************************************/
    /* Set up bitmap sizes and formats.                               */
    /******************************************************************/
    Shadow8514Regs.PixMapWidthA  = DirectListEntry.Info.HWWidth;
    Shadow8514Regs.PixMapHeightA = DirectListEntry.Info.HWHeight;
    Shadow8514Regs.PixMapFormatA = (BYTE)DirectListEntry.Info.HWFormat;

    Shadow8514Regs.PixMapWidthB  = DirectListEntry.Info.HWWidth;
    Shadow8514Regs.PixMapHeightB = DirectListEntry.Info.HWHeight;
    Shadow8514Regs.PixMapFormatB = (BYTE)DirectListEntry.Info.HWFormat;

    /******************************************************************/
    /* Set up all registers that don't depend on which chunk we're    */
    /* copying.                                                       */
    /******************************************************************/
    Shadow8514Regs.SrcXAddr = 0;
    Shadow8514Regs.DstXAddr = 0;
    Shadow8514Regs.OpDim1 = DirectListEntry.Info.HWWidth;
    Shadow8514Regs.Function_1.Mix = Shadow8514Regs.Function_0.Mix = FUNC_S;
    Shadow8514Regs.Color_Comp = COLCOMP_ALWAYS;

    Shadow8514Regs.PixOp = BACK_SRC_SRC_PIX_MAP |
                          FORE_SRC_SRC_PIX_MAP |
                          STEP_PXBLT |
                          SRC_PIX_MAP_B |
                          DST_PIX_MAP_A |
                          PAT_PIX_MAP_FORE |
                          MASK_PIX_MAP_OFF |
                          DRAW_MODE_DONTCARE |
                          DIR_OCTANT_LRTB;
    #endif

    /******************************************************************/
    /* We must work out the number of lines copied at a time.  The    */
    /* PHUNK is treated as 2 chunks of memory so that we can          */
    /* parallelize the copying from VRAM into one chunk with the copy */
    /* from the other chunk out to memory.                            */
    /******************************************************************/
    lPhunkSecondChunkYOffset = HALF_OF_PHUNK_SIZE /
                                           DirectListEntry.BytesPerLine;

    /******************************************************************/
    /* lVRAMYIncrement is 1 less than the number of rows of VRAM to   */
    /* copy at a time.                                                */
    /******************************************************************/
    lVRAMYIncrement = lPhunkSecondChunkYOffset - 1;

    /******************************************************************/
    /* Check we are not exceeding the 4k pels hardware operation size */
    /* limit. We assume that the VRAM width is less than 4K, so don't */
    /* do this test on pts.x.                                         */
    /******************************************************************/
    if (lVRAMYIncrement > 4095)
    {
        lVRAMYIncrement = 4095;
    }

    /******************************************************************/
    /* Set up the number of bytes copied at a time (used for copying  */
    /* from Phunk to target bitmap).                                  */
    /******************************************************************/
    lTrgByteIncrement = (lVRAMYIncrement + 1) *
                                           DirectListEntry.BytesPerLine;
    /******************************************************************/
    /* Set up the position to copy from when copying the second       */
    /* chunk of the Phunk.                                            */
    /******************************************************************/
    lPhunkSecondChunkByteIncrement = lPhunkSecondChunkYOffset *
                                           DirectListEntry.BytesPerLine;

    /******************************************************************/
    /* Work out the Y parameters for the intial copy.                 */
    /******************************************************************/
    #ifndef   _8514
    ShadowXGARegs.SrcYAddr = 0;
    ShadowXGARegs.OpDim2 = (USHORT)lVRAMYIncrement;
    #else
    Shadow8514Regs.SrcYAddr = 0;
    Shadow8514Regs.OpDim2 = (USHORT)lVRAMYIncrement;
    #endif
    lTrgByteOffset = 0;

    /******************************************************************/
    /* Start off the parity counter on 2. The parity counter takes    */
    /* the following values:                                          */
    /* 2: copy from VRAM into low half of Phunk;                      */
    /*                                don't copy from Phunk to memory */
    /* 1: copy from VRAM into high half of Phunk;                     */
    /*                          copy from low half of Phunk to memory */
    /* 0: copy from VRAM into low half of Phunk;                      */
    /*                         copy from high half of Phunk to memory */
    /*                                                                */
    /* The parity counter starts at 2 and then alternates between 1   */
    /* and 0.                                                         */
    /******************************************************************/
    ulParity = 2;

    /******************************************************************/
    /* Loop through the whole of VRAM                                 */
    /******************************************************************/
    #ifndef _8514   /* XGA */
    while (ShadowXGARegs.SrcYAddr <= DirectListEntry.Info.HWHeight)
    {
        /**************************************************************/
        /* Check we are not exceeding the clipped source rectangle    */
        /* bounds.  Note that the previous calculation may have       */
        /* resulted in overflow (eg pts2.y is now 65535 if bytes per  */
        /* line is 1 which is really overflow becaue pts2.y is a      */
        /* SHORT so now contains -1) so we must cast to ULONGs so     */
        /* that the comparison will work.                             */
        /**************************************************************/
        if ((ULONG)(USHORT)(ShadowXGARegs.OpDim2+ShadowXGARegs.SrcYAddr)
                                > (ULONG)DirectListEntry.Info.HWHeight)
        {
            ShadowXGARegs.OpDim2 = DirectListEntry.Info.HWHeight -
                                                 ShadowXGARegs.SrcYAddr;
        }

        /**************************************************************/
        /* Before we call off to the low level function we must       */
        /* adjust the target rectangle to correspond to the piece of  */
        /* the source we will copy into the PHUNK.  If we did not do  */
        /* this then the blt would wrap-around the source in order to */
        /* fill the target rectangle.                                 */
        /**************************************************************/
        if (ulParity & 1)
        {
           ShadowXGARegs.DstYAddr = (SHORT)lPhunkSecondChunkYOffset;
        }
        else
        {
           ShadowXGARegs.DstYAddr = 0;
        }

        /**************************************************************/
        /* Call the hardware to do the blt.                           */
        /**************************************************************/
        TransferShadowRegisters( TSR_MAP_A |
                                 TSR_MAP_B |
                                 TSR_COLOUR_MIX |
                                 TSR_COORDINATES |
                                 TSR_PIXELOP );

        /**************************************************************/
        /* Now copy from the other half of the Phunk into the memory  */
        /* bitmap passed in. This code also updates ulParity          */
        /*  - from 0 to 1                                             */
        /*  - from 1 to 0                                             */
        /*  - from 2 to 1.                                            */
        /*                                                            */
        /* Note that memcpy works here because in both screen formats */
        /* there is no padding at the end of each row of the screen   */
        /* bitmap.                                                    */
        /**************************************************************/
        if (!ulParity)
        {
            memcpy( pbhTarget->Bitmap + lTrgByteOffset,
                    pPhunkVirt + lPhunkSecondChunkByteIncrement,
                    lTrgByteIncrement );
           lTrgByteOffset += lTrgByteIncrement;
           ulParity++;
        }
        else if (!(--ulParity))
        {
            memcpy( pbhTarget->Bitmap + lTrgByteOffset,
                    pPhunkVirt,
                    lTrgByteIncrement );
           lTrgByteOffset += lTrgByteIncrement;
        }

        /**************************************************************/
        /* If the last hardware copy was short (because it is the     */
        /* last one), update lTrgByteIncremement.                     */
        /**************************************************************/
        if (ShadowXGARegs.OpDim2 < (USHORT)lVRAMYIncrement)
        {
            lTrgByteIncrement = (ShadowXGARegs.OpDim2 + 1) *
                                           DirectListEntry.BytesPerLine;
        }

        /**************************************************************/
        /* Now update to next chunk                                   */
        /**************************************************************/
        ShadowXGARegs.SrcYAddr += ShadowXGARegs.OpDim2 + 1;
    }   /* while not all of VRAM has been transfered to Phunk */
    #else
    while (Shadow8514Regs.SrcYAddr <= DirectListEntry.Info.HWHeight)
    {
        /**************************************************************/
        /* Check we are not exceeding the clipped source rectangle    */
        /* bounds.  Note that the previous calculation may have       */
        /* resulted in overflow (eg pts2.y is now 65535 if bytes per  */
        /* line is 1 which is really overflow becaue pts2.y is a      */
        /* SHORT so now contains -1) so we must cast to ULONGs so     */
        /* that the comparison will work.                             */
        /**************************************************************/
        if ((ULONG)(USHORT)(Shadow8514Regs.OpDim2+Shadow8514Regs.SrcYAddr)
                                > (ULONG)DirectListEntry.Info.HWHeight)
        {
            Shadow8514Regs.OpDim2 = DirectListEntry.Info.HWHeight -
                                                 Shadow8514Regs.SrcYAddr;
        }

        /**************************************************************/
        /* Before we call off to the low level function we must       */
        /* adjust the target rectangle to correspond to the piece of  */
        /* the source we will copy into the PHUNK.  If we did not do  */
        /* this then the blt would wrap-around the source in order to */
        /* fill the target rectangle.                                 */
        /**************************************************************/
        if (ulParity & 1)
        {
           Shadow8514Regs.DstYAddr = (SHORT)lPhunkSecondChunkYOffset;
        }
        else
        {
           Shadow8514Regs.DstYAddr = 0;
        }

        /**************************************************************/
        /* Call the hardware to do the blt.                           */
        /**************************************************************/
        TransferShadowRegisters( TSR_COORDINATES  );

        CopyVRAMToMemory( (ulParity & 1) ?
                            pPhunkVirt + lPhunkSecondChunkByteIncrement :
                            pPhunkVirt,
                          Shadow8514Regs.SrcYAddr,  // ScreenPointer
                          Shadow8514Regs.OpDim1,
                          Shadow8514Regs.OpDim2,
                          Shadow8514Regs.PixMapFormatB );

        /**************************************************************/
        /* Now copy from the other half of the Phunk into the memory  */
        /* bitmap passed in. This code also updates ulParity          */
        /*  - from 0 to 1                                             */
        /*  - from 1 to 0                                             */
        /*  - from 2 to 1.                                            */
        /*                                                            */
        /* Note that memcpy works here because in both screen formats */
        /* there is no padding at the end of each row of the screen   */
        /* bitmap.                                                    */
        /**************************************************************/
        if (!ulParity)
        {
            memcpy( pbhTarget->Bitmap + lTrgByteOffset,
                    pPhunkVirt + lPhunkSecondChunkByteIncrement,
                    lTrgByteIncrement );
           lTrgByteOffset += lTrgByteIncrement;
           ulParity++;
        }
        else if (!(--ulParity))
        {
            memcpy( pbhTarget->Bitmap + lTrgByteOffset,
                    pPhunkVirt,
                    lTrgByteIncrement );
           lTrgByteOffset += lTrgByteIncrement;
        }

        /**************************************************************/
        /* If the last hardware copy was short (because it is the     */
        /* last one), update lTrgByteIncremement.                     */
        /**************************************************************/
        if (Shadow8514Regs.OpDim2 < (USHORT)lVRAMYIncrement)
        {
            lTrgByteIncrement = (Shadow8514Regs.OpDim2 + 1) *
                                           DirectListEntry.BytesPerLine;
        }

        /**************************************************************/
        /* Now update to next chunk                                   */
        /**************************************************************/
        Shadow8514Regs.SrcYAddr += Shadow8514Regs.OpDim2 + 1;
    }   /* while not all of VRAM has been transfered to Phunk */
    #endif      /* 8514 */

    /******************************************************************/
    /* Make sure the hardware has completed.                          */
    /******************************************************************/
    WaitForRealHW;

    /******************************************************************/
    /* Do final memcpy.                                               */
    /******************************************************************/
    if (!ulParity)
    {
        memcpy( pbhTarget->Bitmap + lTrgByteOffset,
                pPhunkVirt + lPhunkSecondChunkByteIncrement,
                lTrgByteIncrement );
    }
    else
    {
        memcpy( pbhTarget->Bitmap + lTrgByteOffset,
                pPhunkVirt,
                lTrgByteIncrement );
    }

    /******************************************************************/
    /* Restore the flag SoftDrawInUse.                                */
    /******************************************************************/
    softDrawInUse = (SHORT)fSaveSoftDrawInUse;
} /* CopyScreenToMemory */



/**********************************************************************/
/* CreateScreenShadowBitmap                                           */
/*                                                                    */
/* pbhSourceBitmap  pointer to the header for the source bitmap.      */
/*                                                                    */
/* Returns a pointer to the source bitmap header. This is a header    */
/* for a bitmap in system memory, while the source is the screen.     */
/* Therefore the bitmap must first be copied to system memory.        */
/**********************************************************************/
pBitmapHeader DRIVERCALL CreateScreenShadowBitmap(pBitmapHeader pbhSourceBitmap)
{
    BITMAPINFO2       pmiCreate;
    pBitmapHeader     pbhNewSource;

    /******************************************************************/
    /* We need to pass a BITMAPINFO2 structure to                     */
    /* CreateInternalBitmap, so set up just enough to specify the     */
    /* size of the internal bitmap.                                   */
    /******************************************************************/
    pmiCreate.cx        = pbhSourceBitmap->Info.Width;
    pmiCreate.cy        = pbhSourceBitmap->Info.Height;
    pmiCreate.cBitCount = pbhSourceBitmap->Info.BitCount;

    pbhNewSource = CreateInternalBitmap(&pmiCreate);

    if ( pbhNewSource != NULL )
    {
        CopyScreenToMemory(pbhNewSource);
    }

    return(pbhNewSource);
} /* CreateScreenShadowBitmap */


/**********************************************************************/
/* GetTargetRGBs                                                      */
/*                                                                    */
/* usForegroundIndex Foreground physical colour index                 */
/* usBackgroundIndex Background physical colour index                 */
/* pForegroundRGB pointer to the RGB for bForegroundIndex (output)    */
/* pBackgroundRGB pointer to the RGB for bBackgroundIndex (output)    */
/*                                                                    */
/* Converts the target colour indices into RGB values. In the         */
/* color table model these are indices into the HWPalette, in the     */
/* palette mode these are indices into the logical palette UNLESS     */
/* the target is the screen (in which case they would be indices      */
/* into the HWPalette). However target cannot be the screen since it  */
/* is mono.                                                           */
/**********************************************************************/
VOID DRIVERCALL GetTargetRGBs(USHORT  usForegroundIndex,
                              USHORT  usBackgroundIndex,
                              PRGB2   pForegroundRGB,
                              PRGB2   pBackgroundRGB)
{
    if (pdc->DCIColFormat == LCOLF_PALETTE)
    {
        /**************************************************************/
        /* Target has a palette so get RGB from there                 */
        /**************************************************************/
        *pForegroundRGB = pdc->Palette->entries[usForegroundIndex].rgb;
        *pBackgroundRGB = pdc->Palette->entries[usBackgroundIndex].rgb;
    }
    else
    {
        /**************************************************************/
        /* Target does not have a palette so get from h/w palette     */
        /**************************************************************/
        *pForegroundRGB = HWPalette[usForegroundIndex];
        *pBackgroundRGB = HWPalette[usBackgroundIndex];
    }
} /* GetTargetRGBs */


/**********************************************************************/
/* MakeConvertToMonoTable                                             */
/*                                                                    */
/* ForegroundRGB      target foreground RGB                           */
/* BackgroundRGB      target background RGB                           */
/* pSourcePalette     pointer to the palette for the source           */
/* usTableSize        size of table to create                         */
/* usPaletteEntrySize size of one entry in the pSourcePalette         */
/*                                                                    */
/* Set up table, usTableSize entries long,  to map between a source   */
/* and a target pel. Cycle through each of the possible source pels   */
/* and set the table to 0 if the pel is closer to the target          */
/* background colour than to the foregound and vice versa.            */
/**********************************************************************/
VOID DRIVERCALL MakeConvertToMonoTable(RGB2   ForegroundRGB,
                                       RGB2   BackgroundRGB,
                                       PBYTE  pSourcePalette,
                                       USHORT usTableSize,
                                       USHORT usPaletteEntrySize)
{
    ULONG   i;

    for (i = 0;
         i < usTableSize;
         i++, pSourcePalette += usPaletteEntrySize )
    {
        if ( rgb2_diff(BackgroundRGB,*(PRGB2)pSourcePalette) >
             rgb2_diff(ForegroundRGB,*(PRGB2)pSourcePalette)  )
        {
            SPad.ausConvertTable[i] = MONO_BM_FOREGROUND;
        }
        else /* pel is closer to Background */
        {
            SPad.ausConvertTable[i] = MONO_BM_BACKGROUND;
        }
    }
} /* MakeConvertToMonoTable */


/**********************************************************************/
/* ConvertTableFor8Bpp                                                */
/*                                                                    */
/* pdcSource         pointer to the source device context             */
/* usColour          Foreground physical colour index                 */
/* usBackColour      Background physical colour index                 */
/*                                                                    */
/* Constructs a table, SPad.abConvertTable, giving the mapping        */
/* between the source colours and the target indices, bColour and     */
/* bBackColour.                                                       */
/**********************************************************************/
VOID DRIVERCALL ConvertTableFor8Bpp(PDC     pdcSource,
                                    USHORT  usColour,
                                    USHORT  usBackColour)
{
    RGB2         ForegroundRGB;
    RGB2         BackgroundRGB;

    /******************************************************************/
    /* Convert target indices to RGB values.                          */
    /******************************************************************/
    GetTargetRGBs(usColour,
                  usBackColour,
                  &ForegroundRGB,
                  &BackgroundRGB);

    /******************************************************************/
    /* If our source dc is NULL then we have a source bitmap which is */
    /* not selected into a dc. Assume such a source to have no        */
    /* logical palette.                                               */
    /******************************************************************/
    if ( (pdcSource != NULL) &&
         (pdcSource->DCIColFormat == LCOLF_PALETTE) )
    {
        /**************************************************************/
        /* We have a palette in the source DC.                        */
        /**************************************************************/
        MakeConvertToMonoTable(ForegroundRGB,
                               BackgroundRGB,
                               (PBYTE)pdcSource->Palette->entries,
                               pdcSource->Palette->usCountStored,
                               sizeof(PALENTRY));
    }
    else
    {
        /**************************************************************/
        /* We are converting from the hardware palette.               */
        /**************************************************************/
        MakeConvertToMonoTable(ForegroundRGB,
                               BackgroundRGB,
                               (PBYTE)HWPalette,
                               256,
                               sizeof(RGB2));
    }

} /* ConvertTableFor8Bpp */


/**********************************************************************/
/* ConvertTableFor4Bpp                                                */
/*                                                                    */
/* usColour          Foreground physical colour index                 */
/* usBackColour      Background physical colour index                 */
/*                                                                    */
/* Constructs a table, SPad.abConvertTable, giving the mapping        */
/* between the source colours and the target indices, usColour and    */
/* usBackColour.                                                      */
/*                                                                    */
/* Make this a macro since it just calls MakeConvertToMonoTable.      */
/**********************************************************************/
//VOID DRIVERCALL ConvertTableFor4Bpp(USHORT  usColour,
//                                    USHORT  usBackColour)
#define ConvertTableFor4Bpp(usColour,usBackColour)                     \
{                                                                      \
   MakeConvertToMonoTable(HWPalette[usColour],                         \
                          HWPalette[usBackColour],                     \
                          (PBYTE)HWPalette,                            \
                          16,                                          \
                          sizeof(RGB2));                               \
} /* ConvertTableFor4Bpp */


/**********************************************************************/
/* Convert16To1                                                       */
/*                                                                    */
/* Converts a scanline in 16 bpp format to a scanline in 1 bpp format.*/
/*                                                                    */
/* edb : removed extra shift as part of 74282                         */
/**********************************************************************/
VOID DRIVERCALL Convert16To1(VOID)
{
    ULONG   j;
    BYTE    bTrgIndex;
    ULONG   ulExtraBits;
    RGB16   SrcPel;

    /******************************************************************/
    /* Eight source pels map to each target byte                      */
    /******************************************************************/
    for ( j = SPad.cx / 8; j--; )
    {
        /**************************************************************/
        /* Get the target index corresponding to each of eight        */
        /* source bytes, shifting each left into a byte to be         */
        /* written to the target.                                     */
        /* NB. Don't combine these lines together because RGB16ToMono */
        /* and MotorolaToIntel are macros which access their          */
        /* parameters multiple times.                                 */
        /* Pel 1                                                      */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgIndex = MapRGB16ToMono(&SrcPel) << 7;
        /**************************************************************/
        /* Pel 2                                                      */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgIndex |= MapRGB16ToMono(&SrcPel) << 6;
        /**************************************************************/
        /* Pel 3                                                      */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgIndex |= MapRGB16ToMono(&SrcPel) << 5;
        /**************************************************************/
        /* Pel 4                                                      */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgIndex |= MapRGB16ToMono(&SrcPel) << 4;
        /**************************************************************/
        /* Pel 5                                                      */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgIndex |= MapRGB16ToMono(&SrcPel) << 3;
        /**************************************************************/
        /* Pel 6                                                      */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgIndex |= MapRGB16ToMono(&SrcPel) << 2;
        /**************************************************************/
        /* Pel 7                                                      */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgIndex |= MapRGB16ToMono(&SrcPel) << 1;
        /**************************************************************/
        /* Pel 8                                                      */
        /**************************************************************/
        SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
        ((PRGB16)SPad.pbSrcPointer)++;
        bTrgIndex |= MapRGB16ToMono(&SrcPel);

        *SPad.pbTrgPointer++ = bTrgIndex;

    } /* for each pel on the row */

    /******************************************************************/
    /* If there are extra bits at the end of the row, handle them     */
    /******************************************************************/
    ulExtraBits = SPad.cx & 7;
    if (ulExtraBits)
    {
        bTrgIndex = 0;
        for ( j = ulExtraBits; j--; )
        {
            SrcPel = MotorolaToIntel(*((PRGB16)SPad.pbSrcPointer));
            ((PRGB16)SPad.pbSrcPointer)++;
            bTrgIndex |= MapRGB16ToMono(&SrcPel);
            bTrgIndex <<= 1;
        }
        *SPad.pbTrgPointer++ = (BYTE)(bTrgIndex << (7 - ulExtraBits));
    }
} /* Convert16To1 */

#ifdef   BPP24
/**********************************************************************/
/* Convert24To1                                                       */
/*                                                                    */
/* Converts a scanline in 24 bpp format to a scanline in 1 bpp format.*/
/*                                                                    */
/* edb : new for 74282                                                */
/**********************************************************************/
#define ScanRGBToMono(pb) (BYTE)(((USHORT)*pb++ + (USHORT)*pb++ + \
                                  (USHORT)*pb++) > WHITE_THRESHOLD)

VOID DRIVERCALL Convert24To1(VOID)
{
    ULONG   j;
    BYTE    bTrgIndex;

    // @@@@@@@ make it fast
    register PBYTE pbSource = SPad.pbSrcPointer;

    /******************************************************************/
    /* Eight source pels map to each target byte                      */
    /******************************************************************/
    for ( j = SPad.cx / 8; j--; )
    {
        bTrgIndex = ScanRGBToMono(pbSource) << 7;
        bTrgIndex |= ScanRGBToMono(pbSource) << 6;
        bTrgIndex |= ScanRGBToMono(pbSource) << 5;
        bTrgIndex |= ScanRGBToMono(pbSource) << 4;
        bTrgIndex |= ScanRGBToMono(pbSource) << 3;
        bTrgIndex |= ScanRGBToMono(pbSource) << 2;
        bTrgIndex |= ScanRGBToMono(pbSource) << 1;
        bTrgIndex |= ScanRGBToMono(pbSource);

        *SPad.pbTrgPointer++ = bTrgIndex;

    } /* for each pel on the row */

    SPad.pbSrcPointer = pbSource;

} /* Convert24To1 */
#endif


/**********************************************************************/
/* ConvertColourToMono                                                */
/*                                                                    */
/* pfnvConvertFn    bpp dependent scanline conversion function        */
/*                  pointer                                           */
/* pbhSource        pointer to the source bitmap header               */
/* pbhTarget        pointer to the target bitmap header               */
/*                                                                    */
/* Converts every pel in the internal colour bitmap into a pel in an  */
/* internal 1bpp bitmap.                                              */
/**********************************************************************/
VOID DRIVERCALL ConvertColourToMono(PFNV          pfnvConvertFn,
                                    pBitmapHeader pbhSource,
                                    pBitmapHeader pbhTarget)
{
    ULONG       i;
    PBYTE       pSourceScanLine;
    PBYTE       pTargetScanLine;

    /******************************************************************/
    /* Bring the bitmap width into local scope                        */
    /******************************************************************/
    SPad.cx = pbhSource->Info.Width;

    /******************************************************************/
    /* Point to the start of the bitmaps                              */
    /******************************************************************/
    pSourceScanLine = pbhSource->Bitmap;
    pTargetScanLine = pbhTarget->Bitmap;

    for (i = pbhSource->Info.Height; i--; )
    {
        /**************************************************************/
        /* Point the scratch pad pointers at the current line         */
        /**************************************************************/
        SPad.pbSrcPointer = pSourceScanLine;
        SPad.pbTrgPointer = pTargetScanLine;

        /**************************************************************/
        /* Call the routine to convert a single scan line             */
        /**************************************************************/
        pfnvConvertFn();

        /**************************************************************/
        /* Move to the next scanline.                                 */
        /**************************************************************/
        pSourceScanLine += pbhSource->BytesPerLine;
        pTargetScanLine += pbhTarget->BytesPerLine;
   }
} /* ConvertColourToMono */


/**********************************************************************/
/* BMConvIntToInt                                                     */
/*                                                                    */
/* pdcSource        pointer to the target device context              */
/* pbhSourceBitmap  pointer to the header for the source bitmap.      */
/* bColour          Foreground physical colour index                  */
/* bBackColour      Background physical colour index                  */
/*                                                                    */
/* Converts internal colour bitmaps into internal mono bitmaps.       */
/* Returns a pointer to the bitmap header of the converted bitmap, or */
/* NULL if an error occurs.                                           */
/**********************************************************************/
pBitmapHeader DRIVERCALL BMConvIntToInt (PDC           pdcSource,
                                         pBitmapHeader pbhSourceBitmap,
                                         USHORT        usColour,
                                         USHORT        usBackColour)
{
    BOOL          fSourceShadow;
    pBitmapHeader pbhTargetBitmap;
    BITMAPINFO2   pmiTarget;

    /******************************************************************/
    /* Check to see if the source is the screen.                      */
    /******************************************************************/
    fSourceShadow = BitmapIsScreen(pbhSourceBitmap);

    if ( fSourceShadow )
    {
        /**************************************************************/
        /* Source is the screen so create a shadow copy of it in      */
        /* memory so we can convert it.                               */
        /**************************************************************/
        pbhSourceBitmap = CreateScreenShadowBitmap(pbhSourceBitmap);
        if ( pbhSourceBitmap == NULL )
        {
            /**********************************************************/
            /* We failed to create a shadow copy (lack of memory)     */
            /**********************************************************/
            return(NULL);
        }
    }

    /******************************************************************/
    /* Now create a mono bitmap for the target                        */
    /******************************************************************/
    /******************************************************************/
    /* We need to pass a BITMAPINFO2 structure to                     */
    /* CreateInternalBitmap, so set up just enough to specify the     */
    /* size of the internal bitmap.                                   */
    /******************************************************************/
    pmiTarget.cx        = pbhSourceBitmap->Info.Width;
    pmiTarget.cy        = pbhSourceBitmap->Info.Height;
    pmiTarget.cBitCount = 1;

    pbhTargetBitmap = CreateInternalBitmap(&pmiTarget);
    if ( pbhTargetBitmap != NULL )
    {
        switch (pbhSourceBitmap->Info.BitCount)
        {
            case 4:
                ConvertTableFor4Bpp(usColour,
                                    usBackColour);

                ConvertColourToMono(Convert4To1,
                                    pbhSourceBitmap,
                                    pbhTargetBitmap);
                break;

            case 8:
                ConvertTableFor8Bpp(pdcSource,
                                    usColour,
                                    usBackColour);

                ConvertColourToMono(Convert8To1,
                                    pbhSourceBitmap,
                                    pbhTargetBitmap);
                break;

            case 16:
                /******************************************************/
                /* No convert table used for 16bpp (just think of the */
                /* size of it!)                                       */
                /******************************************************/
                ConvertColourToMono(Convert16To1,
                                    pbhSourceBitmap,
                                    pbhTargetBitmap);
                break;
            #ifdef   BPP24
            case 24:
                /******************************************************/
                /* No convert table used for 24bpp (just think of the */
                /* size of it!)                                       */
                /******************************************************/
                ConvertColourToMono(Convert24To1,
                                    pbhSourceBitmap,
                                    pbhTargetBitmap);
                break;
            #endif
        }
    }

    /******************************************************************/
    /* We may have a shadow copy of the screen to free up.            */
    /******************************************************************/
    if ( fSourceShadow )
    {
        FreeMemory(pbhSourceBitmap);
    }
    return(pbhTargetBitmap);
} /* BMConvIntToInt */
