/*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          = PIXBLT                                         */
/*                                                                    */
/*   Functions       = PixBltThroughClips                             */
/*                     PixBltThroughClipsViaPhunk                     */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/*   Change History:                                                  */
/*                                                                    */
/*   06/04/93 - DCRTURBO (GAM/KJE) Added TurboStretching function to  */
/*              improve image stretch performance.                    */
/*   08/25/93 - Defect 73126 (APAR PJ09917)  (TAV)  Added check in    */
/*              PixBltThroughClips() to make sure that the driver     */
/*              handles cached rectangles correctly.                  */
/*                                                                    */
/**********************************************************************/

/**********************************************************************/
/* structure, macro and function prototype definitions                */
/**********************************************************************/
#define INCL_DDICOMFLAGS
#define INCL_DOSMEMMGR
#define INCL_DDIMISC

#include <eddinclt.h>

#include <eddfcone.h>
#include <eddhcone.h>
#include <eddhtype.h>
#include <eddbcone.h>

#include <eddftype.h>

#include <eddaextf.h>
#include <eddfext.h>
#include <eddbextf.h>
#include <hwaccess.h>
#include <eddhmacr.h>

#include <memman.h>
#ifdef VRAMPTR
#include <eddncach.h>
extern ULONG       fSeamlessActive;
#endif /* def VRAMPTR */
/**********************************************************************/
/* <DCRTURBO>                                                         */
/**********************************************************************/
#include <strchext.h>

#ifdef _8514
#include <8514.h>
#include <hwaccess.h>
extern ULONG  PixelOp;
#endif

extern VOID CopyExternalChunkToPhunkForPixBltSource( POINTS ptsChunkPos );
extern ULONG               PixelOp;


extern RGNRECT             GetClipsControl;
extern ClipRectangle       GetClipsBounds;

extern BITBLTPB            AIxfer;
#ifdef _8514
extern MM8514Reg           Shadow8514Regs;
#else
extern MMReg               ShadowXGARegs;
#endif
#ifdef   BPP24
#include <cacheman.h>
extern PHWMAP              pHWMap;
#endif
extern BltSPad             SPad;
extern SHORT               fThreeWayWorkBlt;
extern SHORT               softDrawInUse ;
extern BitmapHeader        PhunkBMHeader;
extern BitmapHeader        DrawBitsBMHeader;
extern BOOL                UsePaletteMapping;

extern pDrawFunctionsTable      pDrawFunctions;

/**********************************************************************/
/* Temporary bitmap used while simulating a VRAM->VRAM bitblt with    */
/* BM_SRCTRANSPARENT.                                                 */
/**********************************************************************/
       BitmapHeader        bmhTemp;
       ULONG               fTempBitmapAllocated;


/**********************************************************************/
/* Declare these function locally only as it should not be used       */
/* outside this module.                                               */
/**********************************************************************/
VOID CopyChunkToPhunkForPixBltSource(pBitmapHeader  pbmhRealSrc,
                                     POINTS         ptsChunkPos );

VOID SimulateSrcTransparentPixbltToVRAM( PBITBLTPB BltParms,
                                         POINTS    ptsChunkPos );

VOID PhunkDestPixBltwithGeneratedPattern( VOID );




/**********************************************************************/
/* PixBltThroughClipsViaPHUNK                                         */
/*                                                                    */
/* This function is called by BitBlt to handle the setting up of the  */
/* pixBlt operation which will be performed by the low level blting   */
/* function (SPad.BltFunction). This set up includes the manipulation */
/* of the source and target rectangles in the parameter block  so     */
/* that the low level function should not have to do any clipping,    */
/* and the copying of the source to the PHUNK (in chunks as required) */
/* if the blt involves both VRAM and system memory.                   */
/**********************************************************************/
VOID PASCAL NEAR PixBltThroughClipsViaPHUNK(VOID)
{
    /******************************************************************/
    /* A local copy of the blt parameters we were passed so that we   */
    /* can still refer to them after we have set up the next set of   */
    /* parameters in AIxfer to be passed on to the low level function.*/
    /******************************************************************/
    BITBLTPB        BltParms;

    /******************************************************************/
    /* Number of clipr rectangles still to do in the current bunch of */
    /* cached clips in the DC instance data clip cache.               */
    /******************************************************************/
    ULONG           ulCurrentClipIndex;

    /******************************************************************/
    /* Local copy of the source and target rectangles after they have */
    /* been adjusted to each clip rectangle, but before they have     */
    /* been adjusted to each PHUNK chunk.                             */
    /******************************************************************/
    RECTS           rcsClippedSrc;
    RECTS           rcsClippedTrg;

    /******************************************************************/
    /* The top left coord of the currently PHUNKed chunk in terms of  */
    /* the real source bitmap.                                        */
    /******************************************************************/
    POINTS          ptsChunkPos;

    /******************************************************************/
    /* Before we start playing around with the source and target      */
    /* rectangles we need to check to see if the blt is goig to wrap  */
    /* around. This information is needed later on once we have done  */
    /* various clipping operations and we can no longer tell whether  */
    /* the blt was going to wrap or not.                              */
    /******************************************************************/
    ULONG           fBltIsWrapAround;


    /******************************************************************/
    /* This function should only be called if the source and the      */
    /* destination are not both in VRAM or system memory. We can      */
    /* check this by looking at the physical address of each of the   */
    /* bitmaps. VRAM bitmaps should have a physical address and       */
    /* system memory bitmaps should not. (Note that there are         */
    /* exceptions to this rule, for example bitmaps in the locked     */
    /* character cache, but if the system memory bitmap is locked     */
    /* then there is still no need to go via the PHUNK). Also we can  */
    /* check that the drawing mode has been set correctly. The        */
    /* drawing mode should always be set according to the location of */
    /* the destination.                                               */
    /*                                                                */
    /* Special Case:                                                  */
    /* The XGA hardware does not support BM_SRCTRANSPARENT. If a      */
    /* VRAM to VRAM operation is required with this mix, the PHUNK    */
    /* is required as a temporary bitmap while simulating the         */
    /* BM_SRCTRANSPARENT with multiple bitblts.                       */
    /* (BM_SRCTRANSPARENT is the background mix when the value        */
    /* COLCOMP_SRC_NOT_EQUAL is in the colour compare register)       */
    /* For more information on BM_SRCTRANSPARENT see eddnbblt.c       */
    /*                                                                */
    /* Another Special Case:                                          */
    /* If we are doing a Drawbits operation (indicated by the source  */
    /* equalling DrawBitsBMHeader) then the external bitmap is        */
    /* converted into the phunk and then pixblted to the              */
    /* destination in all cases.                                      */
    /******************************************************************/
#ifdef FIREWALLS
    if (  (    (AIxfer.pbmhSrc->BMPhys  != NULL)
            && (AIxfer.pbmhDest->BMPhys != NULL)
            && !UseSoftwareUnderpaint() )
         || (  (AIxfer.pbmhSrc->BMPhys  == NULL)
            && (AIxfer.pbmhDest->BMPhys == NULL) ) )
    {
        if (AIxfer.pbmhSrc != &DrawBitsBMHeader)
        {
            haltproc();
        }
    }

    if ((softDrawInUse  &&(AIxfer.pbmhDest->BMPhys != NULL))
      ||(!softDrawInUse &&(AIxfer.pbmhDest->BMPhys == NULL)))
    {
        haltproc();
    }
#endif /* FIREWALLS */


    /******************************************************************/
    /* The structure of the function is:                              */
    /*                                                                */
#ifdef VRAMPTR
    /* if the bitmap is smaller than the max cache size               */
    /*    cache the bitmap                                            */
    /*    call PixBltThroughClips                                     */
    /* endif                                                          */
#endif /* def VRAMPTR */
    /* proc PixBltThroughClips                                        */
    /*     if source transparent simulation will need temp bitmap     */
    /*        create temporary bitmap same size as PHUNK              */
    /*     endif                                                      */
    /*     for each clip rectangle                                    */
    /*        calculate the clipped blt coords and dimensions         */
    /*        divide blt into phunk sized chunks                      */
    /*        for each chunk                                          */
    /*            work out adjusted blt coords and dimensions         */
    /*            if can do pixblt without simulation                 */
    /*                do a copy blt from src to phunk                 */
    /*                do the real blt from phunk to dst               */
    /*            else                                                */
    /*                call SimulateSrcTransparentPixBltToVRAM         */
    /*            endif                                               */
    /*        endfor                                                  */
    /*     endfor                                                     */
    /* endproc                                                        */
    /******************************************************************/

#ifdef VRAMPTR
    /******************************************************************/
    /* If the source is not VRAM and the destination is in screen and */
    /* this operation is not a  BM_SRCTRANSPARENT simulation          */
    /* then cache the bitmap in VRAM if less than VRAM_BM_CACHE_SIZE  */
    /* bytes.                                                         */
    /* Can't use cache if a palette mapping is required as this is    */
    /* done on the fly by the software drawing while going via the    */
    /* PHUNK.                                                         */
    /*                                                                */
    /******************************************************************/
    /*                                                                */
    /* Defect 54191 - If the Source bitmap is                         */
    /*                                                                */
    /* If we are doing a Drawbits operation (indicated by the source  */
    /* equalling DrawBitsBMHeader) then the external bitmap is in     */
    /* external format and we cannot take this shortcut.              */
    /*                                                                */
    /* Joe Celi (10/2/92) - At the witching hour.                     */
    /*                                                                */
    /******************************************************************/
    /* 8514 NOTES                                                     */
    /*                                                                */
    /* The 8514 driver caches in squares not strings so check width   */
    /* and height here .                                              */
    /*                                                                */
    /* The 8514 driver can cache bitmaps even when seamless apps are  */
    /* running.                                                       */
    /******************************************************************/
    if ( !AIxfer.fStretching &&
         #ifndef _8514
         !fSeamlessActive &&
         #endif
         (AIxfer.pbmhSrc->BMPhys == NULL) &&
         (AIxfer.pbmhDest->Bitmap == NULL) &&
         !UseSoftwareUnderpaint() &&
         !UsePaletteMapping &&
         AIxfer.pbmhSrc != &DrawBitsBMHeader )
    {
      #ifndef   _8514
      if ( AIxfer.pbmhSrc->BMSize <= VRAM_BM_CACHE_SIZE )
      #else
     #ifdef BPP24
     if ( !pHWMap->vertical_bmaps ) {
     #endif
      if ( AIxfer.pbmhSrc->Info.Width <= VRAM_BM_CACHE_HOR_SIZE &&
           AIxfer.pbmhSrc->Info.Height <= VRAM_BM_CACHE_VERT_SIZE )
      #endif
      {
        if ( cache_bitmap(AIxfer.pbmhSrc) )
        {
           // Caching the bitmap may have corrupted some of our Color and Mix
           // Registers.  Restore them before calling PixBltThroughClips().
           TransferShadowRegisters( TSR_COLOUR_MIX );
           PixBltThroughClips();
           return;
        }
      }
     #ifdef BPP24
     }
     else
     {
      if ( AIxfer.pbmhSrc->Info.Width <= VRAM_BM_VERT_CACHE_HOR_SIZE &&
           AIxfer.pbmhSrc->Info.Height <= VRAM_BM_VERT_CACHE_VERT_SIZE )
      {
        if ( cache_bitmap(AIxfer.pbmhSrc) )
        {
           // Caching the bitmap may have corrupted some of our Color and Mix
           // Registers.  Restore them before calling PixBltThroughClips().
           TransferShadowRegisters( TSR_COLOUR_MIX );
           PixBltThroughClips();
           return;
        }
      }
     }
     #endif
    }
#endif /* def VRAMPTR */

    #ifdef _8514
    // send these back to our special purpose functions
    // test the destination for screen marker
    // @DMS this could cause alignment bugs but isn't so far !!!

    if ( !AIxfer.fStretching                &&  // enable stretch (72963)
         (AIxfer.pbmhDest->BMPhys != NULL)  &&
         (!UsePaletteMapping)               &&
         (AIxfer.pbmhSrc->Info.BitCount == 1) )
    {
        TransferShadowRegisters( TSR_COLOUR_MIX );
        PixBltThroughClips();
        return;
    }
    #endif

    /******************************************************************/
    /* First we will take a copy of the blt parameter block.          */
    /******************************************************************/
    BltParms = *((PBITBLTPB)&AIxfer);

    /******************************************************************/
    /* First we must set up the PHUNKs bitmap header so that we can   */
    /* use it as the source for the real blt later on. We change the  */
    /* parameter block (AIxfer) to point to the PHUNKs bitmap header  */
    /* so that the low level blt function will think that the PHUNK   */
    /* is the source of the blt.                                      */
    /******************************************************************/
    PhunkBMHeader.Info.BitCount = BltParms.pbmhSrc->Info.BitCount;
    PhunkBMHeader.Info.HWFormat = BltParms.pbmhSrc->Info.HWFormat;
    AIxfer.pbmhSrc = &PhunkBMHeader;

    /******************************************************************/
    /* Before we start playing around with the source and target      */
    /* rectangles we need to check to see if the blt is goig to wrap  */
    /* around. This information is needed later on once we have done  */
    /* various clipping operations and we can no longer tell whether  */
    /* the blt was going to wrap or not.                              */
    /******************************************************************/
    if (   (   (AIxfer.rcsSrc.pts1.x - AIxfer.rcsSrc.pts2.x)
            != (AIxfer.rcsTrg.pts1.x - AIxfer.rcsTrg.pts2.x) )
        || (   (AIxfer.rcsSrc.pts1.y - AIxfer.rcsSrc.pts2.y)
            != (AIxfer.rcsTrg.pts1.y - AIxfer.rcsTrg.pts2.y) ) )
    {
        fBltIsWrapAround = TRUE;
    }
    else
    {
        fBltIsWrapAround = FALSE;
    }

    /******************************************************************/
    /* If SimulateSrcTransparentPixbltToVRAM is going to need a work  */
    /* bitmap we create it here (outside the loop).                   */
    /* It needs a temporary bitmap when we are doing a                */
    /* BM_SRCTRANSPARENT pixblt from VRAM to VRAM unless it is a      */
    /* source to destination copy, or the background colour is 0.     */
    /******************************************************************/
    fTempBitmapAllocated = FALSE;

    if (UseSoftwareUnderpaint()

        #ifdef VRAMPTR
        && (BltParms.pbmhDest->Bitmap == NULL)
        && (BltParms.pbmhSrc->Bitmap == NULL)
        #else /* ndef VRAMPTR */
        && (BltParms.pbmhDest->BMPhys != NULL)
        && (BltParms.pbmhSrc->BMPhys != NULL)
        #endif /* ndef VRAMPTR */

        #ifdef _8514
        && ( (Shadow8514Regs.Function_1.Mix != FUNC_S )
          || (Shadow8514Regs.Function_0.Mix != FUNC_S ))
        && (Shadow8514Regs.Color_Comp != 0)
        #else /* XGA */
        && ( (ShadowXGARegs.FgMix != HWMIX_SOURCE )
          || (ShadowXGARegs.BgMix != HWMIX_SOURCE ))
        && (ShadowXGARegs.ColCompVal != 0)
        #endif /* XGA */
       )
    {
        /**************************************************************/
        /* Create temporary bitmap the same size as the PHUNK.        */
        /* Note: not using eddb_AllocMemForBitmap as we don't yet     */
        /* know the width or height.                                  */
        /**************************************************************/

        /**************************************************************/
        /* allocate memory for the bitmap, leaving one spare byte     */
        /* each side for the software drawing code.                   */
        /**************************************************************/
        bmhTemp.Bitmap = AllocateMemory( EXTENDED_PHUNK_SIZE,
                                         MT_BITMAP,
                                         MO_SHARED);
        if (bmhTemp.Bitmap == NULL)
        {
            /**********************************************************/
            /* No memory for temporary bitmap.                        */
            /**********************************************************/
            goto PIXBLT_ERR_EXIT;
        }

        /**************************************************************/
        /* Adjust bitmap so that the spare bytes are either end of    */
        /* usable portion of the temporary bitmap.                    */
        /**************************************************************/
        bmhTemp.Bitmap += END_BYTES_PHUNK_OFFSET;
        fTempBitmapAllocated = TRUE;
    }

    /******************************************************************/
    /* We want to deal with only one clip rectangle at a time.        */
    /******************************************************************/
    AIxfer.cDestClipRects = 1;

    /******************************************************************/
    /* Now we must iterate through each clip rectangle.               */
    /******************************************************************/
    /******************************************************************/
    /* Set up the information we need to iterate through the clip     */
    /* rectangles. We need to look at the three way clip target flag. */
    /* If this is not set then we will are going to use the engines   */
    /* clip rectangles.                                               */
    /******************************************************************/

    if (!fThreeWayWorkBlt)
    {
        /**************************************************************/
        /* We will call back to the engine if either the clips have   */
        /* changed or we have too many clip regions for the cache.    */
        /* If the latter case is true we can optimise clipping by     */
        /* setting the bitmap bounds to the target rectangle.         */
        /* Otherwise we set them to the bitmap bounds to get valid    */
        /* clips into the cache. Note that the GetClipsBounds are     */
        /* exclusive and whereas all the other rectangles we are      */
        /* dealing with here are inclusive.                           */
        /**************************************************************/
        if (pdc->DCIEngineClips > CACHED_CLIPS)
        {
            GetClipsBounds.X0 = AIxfer.rcsTrg.pts1.x;
            GetClipsBounds.X1 = AIxfer.rcsTrg.pts2.x + (SHORT)1;
            GetClipsBounds.Y0 = pdc->DCIBoundingClip[1].Y -
                                                        AIxfer.rcsTrg.pts2.y;
            GetClipsBounds.Y1 = pdc->DCIBoundingClip[1].Y + (SHORT)1 -
                                                        AIxfer.rcsTrg.pts1.y;
        }
        else if (pdc->ClipChanged )
             {
                 /**********************************************************/
                 /* Set the bounds which intersect clip to whole drawing   */
                 /* area                                                   */
                 /**********************************************************/
                 GetClipsBounds.X0 = pdc->DCIBoundingClip[0].X;
                 GetClipsBounds.X1 = pdc->DCIBoundingClip[1].X + (SHORT)1;
                 GetClipsBounds.Y0 = pdc->DCIBoundingClip[0].Y;
                 GetClipsBounds.Y1 = pdc->DCIBoundingClip[1].Y + (SHORT)1;
             }
    }

    GetClipsControl.ircStart = 1;

    /******************************************************************/
    /* Now we want to loop through each of the clip rectangles.       */
    /******************************************************************/
    do /* for each rectangle comprising the clip region */
    {
        /**************************************************************/
        /* If clipping is enabled then try to get some clip           */
        /* rectangles otherwise set one up to be the bitmap boundry.  */
        /**************************************************************/
        if (!fThreeWayWorkBlt)
        {
            /**********************************************************/
            /* if the total number of clips comprising the region     */
            /* exceed the size of the dc cache or NotifyClipChange    */
            /* was called then get the cache updated from engine      */
            /**********************************************************/
            if ( (pdc->DCIEngineClips > CACHED_CLIPS) ||
                                                       pdc->ClipChanged )
            {
                edda_GetClipRectangles();
            }
            /**********************************************************/
            /* Update the clip rectangle start index so that next     */
            /* time round the loop we will get the next clip          */
            /* rectangles.  We do this even if we have not just       */
            /* called edda_GetClipRectangles because we may already   */
            /* have exactly CACHED_CLIPS valid clip rectangles and    */
            /* there may not be any more to get.  If we do not add    */
            /* this on here then we will get stuck in the do-while    */
            /* loop for ever!                                         */
            /**********************************************************/
            GetClipsControl.ircStart += pdc->DCIClipNum;
        }
        else
        {
            /**********************************************************/
            /* The destination is the work bitmap for three way rops. */
            /* Ignore the engine clips and set the clips to the       */
            /* target rectangle.                                      */
            /**********************************************************/

            /**********************************************************/
            /* Put the original target rectangle into the clip cache. */
            /**********************************************************/
            pdc->DCIClipRects[0].X0 = BltParms.rcsTrg.pts1.x;
            pdc->DCIClipRects[0].Y0 = BltParms.rcsTrg.pts1.y;
            pdc->DCIClipRects[0].X1 = BltParms.rcsTrg.pts2.x;
            pdc->DCIClipRects[0].Y1 = BltParms.rcsTrg.pts2.y;

            /**********************************************************/
            /* Force the cache to be refilled next time.             */
            /**********************************************************/
            pdc->ClipChanged = TRUE;

            /**********************************************************/
            /* Set the number of clips returned as if we had called   */
            /* edda_GetClipRectangle.                                 */
            /**********************************************************/
            pdc->DCIClipNum = 1;
        }

        /**************************************************************/
        /* Set the current index to be the first clip rectangle in    */
        /* the cache.                                                 */
        /**************************************************************/
        ulCurrentClipIndex = 0;

        /**************************************************************/
        /* If there are now some clip rectangles in the cache         */
        /* then iterate through these one at a time.                  */
        /**************************************************************/
        while (ulCurrentClipIndex < pdc->DCIClipNum)
        {
            /**********************************************************/
            /* Set the parameter block clips rects pointer to the     */
            /* current clip rect in the DC instance data structure.   */
            /**********************************************************/
            AIxfer.pNextDestClipRect =
                                 &pdc->DCIClipRects[ulCurrentClipIndex];

            /**********************************************************/
            /* We are now inside the for each clip rectangle loop.    */
            /* Now we want to:                                        */
            /*                                                        */
            /* calculate the clipped blt coords and dimensions        */
            /* divide blt into phunk sized chunks                     */
            /* for each chunk                                         */
            /*     work out adjusted blt coords and dimensions        */
            /*     do a copy blt from src to phunk                    */
            /*     if we can do blt from phunk to dest                */
            /*         do the real blt from phunk to dst              */
            /*     else                                               */
            /*         call SimulateSrcTransparentPixbltToVRAM        */
            /*     endif                                              */
            /* endfor                                                 */
            /*                                                        */
            /**********************************************************/

            /**********************************************************/
            /* The source and destination rectangles have already     */
            /* been set up by the calling function to be the same     */
            /* size and limited by the bounds of both the source and  */
            /* the destination bitmaps. We now want to set up our own */
            /* rectangles which we will pass on to the low level      */
            /* function which will actually do the blt. The rectangles*/
            /* we were passed are now in BltParms and the rectangles  */
            /* we will pass on will be in AIxfer.                     */
            /**********************************************************/

            /**********************************************************/
            /* Set the destination rectangle to be the rectangle      */
            /* passed by the calling function limited to the limits   */
            /* of this clip rectangle.                                */
            /**********************************************************/

            rcsClippedTrg.pts1.x =
                max(BltParms.rcsTrg.pts1.x, AIxfer.pNextDestClipRect->X0);
            rcsClippedTrg.pts1.y =
                max(BltParms.rcsTrg.pts1.y, AIxfer.pNextDestClipRect->Y0);

            rcsClippedTrg.pts2.x =
                min(BltParms.rcsTrg.pts2.x, AIxfer.pNextDestClipRect->X1);
            rcsClippedTrg.pts2.y =
                min(BltParms.rcsTrg.pts2.y, AIxfer.pNextDestClipRect->Y1);

            /**********************************************************/
            /* Set up the source rectangle to be the rectangle passed */
            /* by the calling function adjusted by the same amounts   */
            /* that we have just adjusted the destination rectangle.  */
            /* We will work this out in rcsClippedSrc so that we      */
            /* leave AIxfer.rcsSrc free to be set up for each chunk   */
            /* before calling the low level function.  Obviously we   */
            /* only want to do this if the blt is not a wrap around   */
            /* one.  If the blt is a wrap around one then this code   */
            /* will only work if the source of the blt fits in a      */
            /* single chunk.  This limit also exists elsewhere in the */
            /* driver.                                                */
            /**********************************************************/
            if (!fBltIsWrapAround)
            {
                rcsClippedSrc.pts1.x = BltParms.rcsSrc.pts1.x
                                       + rcsClippedTrg.pts1.x
                                       - BltParms.rcsTrg.pts1.x;

                rcsClippedSrc.pts1.y = BltParms.rcsSrc.pts1.y
                                       + rcsClippedTrg.pts1.y
                                       - BltParms.rcsTrg.pts1.y;

                rcsClippedSrc.pts2.x = BltParms.rcsSrc.pts2.x
                                       + rcsClippedTrg.pts2.x
                                       - BltParms.rcsTrg.pts2.x;

                rcsClippedSrc.pts2.y = BltParms.rcsSrc.pts2.y
                                       + rcsClippedTrg.pts2.y
                                       - BltParms.rcsTrg.pts2.y;
            }
            else
            {
                rcsClippedSrc.pts1.x = BltParms.rcsSrc.pts1.x;
                rcsClippedSrc.pts1.y = BltParms.rcsSrc.pts1.y;
                rcsClippedSrc.pts2.x = BltParms.rcsSrc.pts2.x;
                rcsClippedSrc.pts2.y = BltParms.rcsSrc.pts2.y;
            }


            /**********************************************************/
            /* The two limits on the amount that can be done in each  */
            /* chunk are the phunk size (64K) and the XGA hardware    */
            /* operating dimension limit (4K pels).  We will divide   */
            /* the source up into PHUNK sized chunks (with a limit of */
            /* 4k pels in each dimension) and copy one chunk at a     */
            /* time into the PHUNK and then pass the PHUNK on to the  */
            /* low level function as if it were the source bitmap.    */
            /**********************************************************/

            /**********************************************************/
            /* We want the source rectangle to be the whole of the    */
            /* PHUNK.  We can set the top left corner of this now and */
            /* then set the bottom right corner (AI coords!) later    */
            /* when we know the exact dimensions of each chunk.       */
            /**********************************************************/
            AIxfer.rcsSrc.pts1.x = 0;
            AIxfer.rcsSrc.pts1.y = 0;

            /**********************************************************/
            /* Now we will iterate through the source dividing it     */
            /* into chunks.  We will keep track of where we are up to */
            /* using the ptsChunkPos local variable.                  */
            /* The ptsChunkPos points to the bottom left hand corner  */
            /* of the current chunk, but is scanned across the bitmap */
            /* from left to right and top to bottom. This is to allow */
            /* the DrawBits code to optimise its conversions by       */
            /* remembering positions within an RLE bitmap.            */
            /* Before calculating the height of each chunk,           */
            /* ptsChunkPos points to the top right hand corner.  When */
            /* the height is known it is set to point to the bottom   */
            /* left hand corner of the chunk.                         */
            /**********************************************************/
            ptsChunkPos.x = rcsClippedSrc.pts1.x;
            ptsChunkPos.y = rcsClippedSrc.pts2.y;

            while (  (ptsChunkPos.x <= rcsClippedSrc.pts2.x)
                  && (ptsChunkPos.y >= rcsClippedSrc.pts1.y) )
            {
                /******************************************************/
                /* First work out the x limit of the chunk size,      */
                /* AIxfer.rcsSrc.pts2.x.  This is the width of the    */
                /* chunk minus one.  (pts1.x is zero and we are       */
                /* dealing with inclusive rectangles).                */
                /******************************************************/
                AIxfer.rcsSrc.pts2.x = rcsClippedSrc.pts2.x
                                     - ptsChunkPos.x;

                /******************************************************/
                /* Check we are not exceeding the 4k pels limit.      */
                /******************************************************/
                if (AIxfer.rcsSrc.pts2.x > 4095)
                {
                    AIxfer.rcsSrc.pts2.x = 4095;
                }

                /******************************************************/
                /* Set the PhunkBMHeader widths up now we know the    */
                /* width of the chunk.                                */
                /******************************************************/
                PhunkBMHeader.Info.Width = AIxfer.rcsSrc.pts2.x + (USHORT)1;
                switch (PhunkBMHeader.Info.BitCount)
                {
                   #ifdef   BPP24
                    case 24 :
                        // @DMS might need to or this with one !!!
                        PhunkBMHeader.Info.HWWidth = AIxfer.rcsSrc.pts2.x;
                        PhunkBMHeader.BytesPerLine =
                                   (PhunkBMHeader.Info.Width * (USHORT)3);
                        break;
                   #endif
                    case 16 :
                        PhunkBMHeader.Info.HWWidth = AIxfer.rcsSrc.pts2.x;
                        PhunkBMHeader.BytesPerLine =
                                   (PhunkBMHeader.Info.Width * (USHORT)2);
                        break;
                    case 8 :
                        PhunkBMHeader.Info.HWWidth = AIxfer.rcsSrc.pts2.x;
                        PhunkBMHeader.BytesPerLine =
                                                 PhunkBMHeader.Info.Width;
                        break;
                    case 4 :
                        PhunkBMHeader.Info.HWWidth =
                                      AIxfer.rcsSrc.pts2.x | (USHORT)1;
                        PhunkBMHeader.BytesPerLine =
                              (AIxfer.rcsSrc.pts2.x / (USHORT)2 + (USHORT)1);
                        break;
                    case 1 :
                        PhunkBMHeader.Info.HWWidth =
                                      AIxfer.rcsSrc.pts2.x | (USHORT)7;
                        PhunkBMHeader.BytesPerLine =
                              (AIxfer.rcsSrc.pts2.x / (USHORT)8 + (USHORT)1);
                        break;
#ifdef FIREWALLS
                    default:
                         haltproc();
#endif /* FIREWALLS */
                }


                /******************************************************/
                /* If this is the first chunk to be done starting at  */
                /* this y position then we must work out how many     */
                /* lines we can fit in the PHUNK.  Otherwise we must  */
                /* use the same number of lines as we used for the    */
                /* previous chunk (ie.  the chunk directly to the     */
                /* left of this chunk).  In other words, all the      */
                /* chunks in the same row must have the same number   */
                /* of lines in them.                                  */
                /******************************************************/
                if (ptsChunkPos.x == rcsClippedSrc.pts1.x)
                {
                    /**************************************************/
                    /* We must work out the height of this row of     */
                    /* chunks.                                        */
                    /**************************************************/
                    AIxfer.rcsSrc.pts2.y =
                      (USHORT)((PHUNK_SIZE /
                                 (LONG)PhunkBMHeader.BytesPerLine) - 1);

                    /**************************************************/
                    /* Check we are not exceeding the clipped source  */
                    /* rectanlgle bounds. ULONG casts are used in     */
                    /* the comparison in case .BytesPerLine is 1 and  */
                    /* so pts2.y may be a large positive SHORT which  */
                    /* would be seem as a -ve when compared with a    */
                    /* USHORT or LONG.                                */
                    /**************************************************/

                    if ((ULONG)ptsChunkPos.y <
                        (ULONG)(USHORT)AIxfer.rcsSrc.pts2.y +
                                            (ULONG)rcsClippedSrc.pts1.y)
                    {
                        AIxfer.rcsSrc.pts2.y =
                           (USHORT)((ULONG)ptsChunkPos.y -
                                    (ULONG)(USHORT)rcsClippedSrc.pts1.y);
                    }

                    /**************************************************/
                    /* Check we are not exceeding the 4k pels         */
                    /* hardware operation size limit.                 */
                    /**************************************************/
                    if (AIxfer.rcsSrc.pts2.y > 4095)
                    {
                        AIxfer.rcsSrc.pts2.y = 4095;
                    }

                    /**************************************************/
                    /* Move the chunk position to the bottom left     */
                    /* hand corner of the chunk.                      */
                    /**************************************************/
                    ptsChunkPos.y -= AIxfer.rcsSrc.pts2.y;

                    /**************************************************/
                    /* Set the PhunkBMHeader heights now that we know */
                    /* the height of this row of chunks.              */
                    /**************************************************/
                    PhunkBMHeader.Info.Height   = AIxfer.rcsSrc.pts2.y +
                                                  (USHORT)1;
                    PhunkBMHeader.Info.HWHeight = AIxfer.rcsSrc.pts2.y;

                    PhunkBMHeader.BMSize =
                                  ((LONG)PhunkBMHeader.BytesPerLine)
                                  *(LONG)PhunkBMHeader.Info.Height;

#ifdef FIREWALLS
                    if ( (PhunkBMHeader.BMSize > PHUNK_SIZE)
                         || (PhunkBMHeader.BMSize < 1)  )
                    {
                        haltproc();
                    }
#endif /* FIREWALLS */

                }

                /******************************************************/
                /* 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.  Obviously we only want to do this if   */
                /* the blt is not a wrap around one.  If the blt is a */
                /* wrap around one then this code will only work if   */
                /* the source of the blt fits in a single chunk.      */
                /* This limit also exists elsewhere in the driver.    */
                /******************************************************/
                if (!fBltIsWrapAround)
                {
                    AIxfer.rcsTrg.pts1.x =   BltParms.rcsTrg.pts1.x
                                           - BltParms.rcsSrc.pts1.x
                                           + ptsChunkPos.x;
                    AIxfer.rcsTrg.pts1.y =   BltParms.rcsTrg.pts1.y
                                           - BltParms.rcsSrc.pts1.y
                                           + ptsChunkPos.y;
                    AIxfer.rcsTrg.pts2.x =   AIxfer.rcsTrg.pts1.x
                                           + AIxfer.rcsSrc.pts2.x
                                           - AIxfer.rcsSrc.pts1.x;
                    AIxfer.rcsTrg.pts2.y =   AIxfer.rcsTrg.pts1.y
                                           + AIxfer.rcsSrc.pts2.y
                                           - AIxfer.rcsSrc.pts1.y;
                }

                /******************************************************/
                /* We now have the source rectangle and the PHUNK     */
                /* bitmap header set up.                              */
                /* We must decide if we can do the actual bitblt or   */
                /* whether we have to simulate it (need to simulate   */
                /* BM_SRCTRANSPARENT bitblts when the destination is  */
                /* VRAM).                                             */
                /******************************************************/
                if (   !UseSoftwareUnderpaint()
#ifdef VRAMPTR
                    || (BltParms.pbmhDest->Bitmap != NULL) )
#else /* ndef VRAMPTR */
                    || (BltParms.pbmhDest->BMPhys == NULL) )
#endif /* ndef VRAMPTR */
                {
                    /**************************************************/
                    /* Now we must load the PHUNK with the chunk of   */
                    /* the real source that the source rectangle      */
                    /* corresponds to.  To do this we will call off   */
                    /* to our special sub-function.                   */
                    /**************************************************/
                    /* <DCRTURBO>                                     */
                    /**************************************************/
                    /* If stretching, call the function which does an */
                    /* expansion or contraction of the original source*/
                    /* bitmap while moving the pixels into the Phunk. */
                    /* Otherwise call the non-stretch copy function.  */
                    /**************************************************/
                    if (AIxfer.fStretching)
                       StretchCopyChunkToPhunk(ptsChunkPos);

                    else
                       CopyChunkToPhunkForPixBltSource(BltParms.pbmhSrc,
                                                       ptsChunkPos);

                    /**************************************************/
                    /* The PHUNK is now set up with a chunk of the    */
                    /* source in it.                                  */
                    /* We are now ready to call off to the low level  */
                    /* function.                                      */
                    /* Force the blt direction to bottom to top so    */
                    /* that the blt to screen within the chunk goes   */
                    /* in the same direction as the bltting of the    */
                    /* chunks.                                        */
                    /**************************************************/
                    /**************************************************/
                    /* Defect 57552.                                  */
                    /* Excel 2.2 drawing outside window area with     */
                    /* a Seamless application active.                 */
                    /* Problem was due to blt direction being         */
                    /* switched, with no code in PatDestBlt to        */
                    /* alter coords.                                  */
                    /* Therefore only change the blt direction if     */
                    /* the blt is SrcDest.                            */
                    /* John Batty - 12/7/92.                          */
                    /**************************************************/
                    /*     idea for 8514!                             */
                    /* Richard Wooley - 2/2/93                        */
                    /**************************************************/
#ifndef _8514
                    if (SPad.BltFunction ==
                                    (*pDrawFunctions)[index_SrcDestBlt])
                    {
                        PixelOp |= BLTDIR_BOTTOMTOTOP;
                        SPad.BltFunction();
                        PixelOp &= ~BLTDIR_BOTTOMTOTOP;
                    }
                    else
                    {
                        SPad.BltFunction();
                    }
#else
                    SPad.BltFunction();
#endif
                }
                else
                {
                    /**************************************************/
                    /* Need to simulate a BM_SRCTRANSPARENT pixblt    */
                    /* because the destination is in VRAM             */
                    /**************************************************/
                    SimulateSrcTransparentPixbltToVRAM(&BltParms,
                                                       ptsChunkPos);
                }

                /******************************************************/
                /* Now that we have done that chunk we must update    */
                /* our position and see if there are any more chunks  */
                /* to be done; we will work from left to right then   */
                /* top to bottom (AI coords!).                        */
                /******************************************************/
                ptsChunkPos.x += AIxfer.rcsSrc.pts2.x + 1;
                if (ptsChunkPos.x > rcsClippedSrc.pts2.x)
                {
                    ptsChunkPos.x = rcsClippedSrc.pts1.x;
                    ptsChunkPos.y -= 1;
                }

            } /* while ptsChunkPos is within rcsClippedSrc */


            /**********************************************************/
            /* Increment our current clip rectangle index into the    */
            /* DCs cache.                                             */
            /**********************************************************/
            ulCurrentClipIndex++;

            /**********************************************************/
            /* Loop back and process the next clip rectangle in the   */
            /* current bunch in the cache (if there is one).          */
            /**********************************************************/

        } /* while (ulCurrentClipIndex < pdc->DCIClipNum) */

        /**************************************************************/
        /* Refill the cache with clip rectangles if there are more.   */
        /**************************************************************/
    } while (  (pdc->DCIClipNum == CACHED_CLIPS)
            && (GetClipsControl.ircStart <= pdc->DCIEngineClips) );

PIXBLT_ERR_EXIT:
    if (fTempBitmapAllocated)
    {
        /**************************************************************/
        /* A temporary bitmap was allocated (for BM_SRCTRANSPARENT    */
        /* simulation). Free up the memory (remembering that it has   */
        /* been adjusted by some offset bytes for the MESS routines). */
        /**************************************************************/
        bmhTemp.Bitmap -= END_BYTES_PHUNK_OFFSET;
        FreeMemory(bmhTemp.Bitmap);
    }
}



VOID CopyChunkToPhunkForPixBltSource(pBitmapHeader  pbmhRealSrc,
                                     POINTS         ptsChunkPos )
{
    /******************************************************************/
    /* Local copies of the shadow registers which will have been set  */
    /* up by the calling function.                                    */
    /******************************************************************/
    #ifndef _8514
    BYTE            SavedFgMix;
    BYTE            SavedBgMix;
    BYTE            SavedColCompCond;
    #else
    MIX             SavedFgMix;
    MIX             SavedBgMix;
    PIXMODE         SavedColCompCond;
    ULONG           ScreenPointer;
    #endif
    SHORT           SavedsoftDrawInUse ;

    /******************************************************************/
    /* The calling function has set up the source rectangle in        */
    /* AIxfer.rcsSrc and the PHUNK bitmap header.  AIxfer.pbmhSrc now */
    /* points to the Phunks bitmap header so that the low level blt   */
    /* function which will be called off to later will treat the      */
    /* phunk as its source.  The real (original) source bitmap header */
    /* is passed as a parameter.  We must load the PHUNK with the     */
    /* chunk of the real source that the source rect corresponds to.  */
    /* The source rect position is passed to us in the ptsChunkPos    */
    /* parameter.  We will do a PixBlt src copy (which will be done   */
    /* by either the hardware or the software drawing code depending  */
    /* on whether the source is in VRAM or system memory).  BUT the   */
    /* higher level BitBlt code will already have set up mixes (and   */
    /* colours), so we must take a copy of the mixes because we must  */
    /* set these to do the blt to the PHUNK, and then we can restore  */
    /* them once the blt has been done.                               */
    /*                                                                */
    /* If we are currently doing a drawbits operation (indicated by   */
    /* the real source bitmap header being DrawBitsBMHeader) then     */
    /* the copying to the phunk needs to convert from an external     */
    /* format. This is done by CopyExternalChunkToPhunkForPixbltSrc.  */
    /******************************************************************/
    if (pbmhRealSrc == &DrawBitsBMHeader)
    {
        CopyExternalChunkToPhunkForPixBltSource( ptsChunkPos );
        goto COPY_CHUNK_TO_PHUNK_EXIT;
    }

    #ifdef _8514
    SavedFgMix = Shadow8514Regs.Function_1;
    SavedBgMix = Shadow8514Regs.Function_0;
    SavedColCompCond = Shadow8514Regs.Mode;
    #else /* XGA */
    SavedFgMix = ShadowXGARegs.FgMix;
    SavedBgMix = ShadowXGARegs.BgMix;
    SavedColCompCond = ShadowXGARegs.ColCompCond;
    #endif /* XGA */

    /******************************************************************/
    /* Set up the hardware mixes.                                     */
    /******************************************************************/
    #ifdef _8514
    Shadow8514Regs.Function_1.Mix = FUNC_S;
    Shadow8514Regs.Function_0.Mix = FUNC_S;
    Shadow8514Regs.Mode.UnderPaint = MD_UP_FALSE;
    Shadow8514Regs.Function_1.SrcSelect = FUNC_2OP_COPY;
    Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COPY;
    #else /* XGA */
    ShadowXGARegs.FgMix = HWMIX_SOURCE;
    ShadowXGARegs.BgMix = HWMIX_SOURCE;
    ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;
    #endif /* XGA */

    /******************************************************************/
    /* Set up destination pixmap details (the PHUNK) and the source   */
    /* pixmap details (the real source).                              */
    /******************************************************************/
#ifdef VRAMPTR
    if (pbmhRealSrc->Bitmap == NULL)
#else /* ndef VRAMPTR */
    if (pbmhRealSrc->BMPhys != NULL)
#endif /* ndef VRAMPTR */
//  if (softDrawInUse)
    {
        /**************************************************************/
        /* The source is in VRAM (and the real dest is in system      */
        /* memory).  We want to copy from the real source in VRAM to  */
        /* the PHUNK so that the low level routine later can use the  */
        /* PHUNK as its source and do the real blt using the software */
        /* drawing code.                                              */
        /**************************************************************/
        #ifndef   _8514
        ShadowXGARegs.PixMapBaseB = pbmhRealSrc->BMPhys;
        ShadowXGARegs.PixMapBaseA = PhunkBMHeader.BMPhys;
        #else
        Shadow8514Regs.PixMapBaseB = pbmhRealSrc->BMPhys;
        Shadow8514Regs.PixMapBaseA = PhunkBMHeader.BMPhys;
        #endif
    }
    else
    {
        /**************************************************************/
        /* The source is in system memory (and the real destination   */
        /* is in VRAM).  We want to copy from the real souce in       */
        /* system memory to the PHUNK so that the low level routine   */
        /* later can use the PHUNK as its source and do the real blt  */
        /* using the hardware.                                        */
        /**************************************************************/
        #ifndef   _8514
        ShadowXGARegs.PixMapBaseB = (ULONG)pbmhRealSrc->Bitmap;
        ShadowXGARegs.PixMapBaseA = (ULONG)PhunkBMHeader.Bitmap;
        #else
        Shadow8514Regs.PixMapBaseB = (ULONG)pbmhRealSrc->Bitmap;
        Shadow8514Regs.PixMapBaseA = (ULONG)PhunkBMHeader.Bitmap;
        #endif
    }

    #ifndef _8514   /* XGA */
    ShadowXGARegs.PixMapWidthA  = PhunkBMHeader.Info.HWWidth;
    ShadowXGARegs.PixMapHeightA = PhunkBMHeader.Info.HWHeight;
    ShadowXGARegs.PixMapFormatA = (BYTE)PhunkBMHeader.Info.HWFormat;

    ShadowXGARegs.PixMapWidthB  = pbmhRealSrc->Info.HWWidth;
    ShadowXGARegs.PixMapHeightB = pbmhRealSrc->Info.HWHeight;
    ShadowXGARegs.PixMapFormatB = (BYTE)pbmhRealSrc->Info.HWFormat;

    /******************************************************************/
    /* Set up blt details                                             */
    /******************************************************************/
    ShadowXGARegs.SrcXAddr = ptsChunkPos.x;
    ShadowXGARegs.SrcYAddr = ptsChunkPos.y;

    ShadowXGARegs.DstXAddr = ShadowXGARegs.DstYAddr = 0;

    ShadowXGARegs.OpDim1 = AIxfer.rcsSrc.pts2.x
                           - AIxfer.rcsSrc.pts1.x;
    ShadowXGARegs.OpDim2 = AIxfer.rcsSrc.pts2.y
                           - AIxfer.rcsSrc.pts1.y;

    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.PixMapWidthA  = PhunkBMHeader.Info.HWWidth;
    Shadow8514Regs.PixMapHeightA = PhunkBMHeader.Info.HWHeight;
    Shadow8514Regs.PixMapFormatA = (BYTE)PhunkBMHeader.Info.HWFormat;

    Shadow8514Regs.PixMapWidthB  = pbmhRealSrc->Info.HWWidth;
    Shadow8514Regs.PixMapHeightB = pbmhRealSrc->Info.HWHeight;
    Shadow8514Regs.PixMapFormatB = (BYTE)pbmhRealSrc->Info.HWFormat;

    /******************************************************************/
    /* Set up blt details                                             */
    /******************************************************************/
    Shadow8514Regs.SrcXAddr = ptsChunkPos.x;
    Shadow8514Regs.SrcYAddr = ptsChunkPos.y;

    Shadow8514Regs.DstXAddr = Shadow8514Regs.DstYAddr = 0;

    Shadow8514Regs.OpDim1 = AIxfer.rcsSrc.pts2.x
                           - AIxfer.rcsSrc.pts1.x;
    Shadow8514Regs.OpDim2 = AIxfer.rcsSrc.pts2.y
                           - AIxfer.rcsSrc.pts1.y;

    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

    /******************************************************************/
    /* If the source is VRAM then we must do the blt to the PHUNK     */
    /* using the hardware and the blt from the PHUNK to the           */
    /* destination using the software drawing code.  Otherwise we     */
    /* must do the blt to the PHUNK using the software drawing code   */
    /* and the blt from the PHUNK to the VRAM destination using the   */
    /* hardware.  Note that in both cases, if the UsePaletteMapping   */
    /* flag is set then the palette conversion will be done by the    */
    /* software drawing stage of the blt on the fly so there is never */
    /* any need to call eddb_ConvertPhunk.                            */
    /******************************************************************/

#ifdef VRAMPTR
    if (pbmhRealSrc->Bitmap == NULL)
#else /* ndef VRAMPTR */
    if (pbmhRealSrc->BMPhys != NULL)
#endif /* ndef VRAMPTR */
    {
        #ifdef _8514
        /**************************************************************/
        /* For the 8514, we call down to a low level routine that     */
        /* does a simple copy into the PHUNK.                         */
        /**************************************************************/

        ScreenPointer = ptsChunkPos.y + ( ptsChunkPos.x << 16 );
        TransferShadowRegisters( TSR_COORDINATES  );

        CopyVRAMToMemory( PhunkBMHeader.Bitmap,
                          ScreenPointer,
                          AIxfer.rcsSrc.pts2.x - AIxfer.rcsSrc.pts1.x,
                          AIxfer.rcsSrc.pts2.y - AIxfer.rcsSrc.pts1.y,
                          Shadow8514Regs.PixMapFormatB );

        #else /* XGA */
        /**************************************************************/
        /* Destination is system memory.  We must copy VRAM source to */
        /* the PHUNK using hardware.                                  */
        /**************************************************************/
        SavedsoftDrawInUse = softDrawInUse;
        softDrawInUse = FALSE;
        TransferShadowRegisters( TSR_MAP_A |
                                 TSR_MAP_B |
                                 TSR_COLOUR_MIX |
                                 TSR_COORDINATES |
                                 TSR_PIXELOP );
        softDrawInUse = SavedsoftDrawInUse;
        /**************************************************************/
        /* Whenever we use HW to copy to the PHUNK we must wait for   */
        /* the HW to complete before we continue otherwise we will    */
        /* get into problems later when we access the PHUNK with the  */
        /* software.                                                  */
        /**************************************************************/
        WaitForRealHW;
        #endif /* XGA */
    }
    else
    {

        /**************************************************************/
        /* Destination is VRAM.  We must copy system memory to the    */
        /* PHUNK using software drawing code. Whenever we write to    */
        /* the PHUNK using the software drawing code we must first    */
        /* wait for the hardware to complete in case it is already    */
        /* copying something from the PHUNK.                          */
        /**************************************************************/
        #ifndef   _8514
        WaitForRealHWFunction();
        #endif

        SavedsoftDrawInUse = softDrawInUse;
        softDrawInUse = TRUE;
        eddf_MESS();
        softDrawInUse = SavedsoftDrawInUse;

    }

    /******************************************************************/
    /* The PHUNK is now set up with a chunk of source in it.  We must */
    /* restore the registers set up by the calling function before    */
    /* returning.                                                     */
    /******************************************************************/
    #ifdef _8514
    Shadow8514Regs.Function_1 = SavedFgMix;
    Shadow8514Regs.Function_0 = SavedBgMix;
    Shadow8514Regs.Mode =       SavedColCompCond;

    TransferShadowRegisters( TSR_COLOUR_MIX );

    #else /* XGA */
    ShadowXGARegs.FgMix = SavedFgMix;
    ShadowXGARegs.BgMix = SavedBgMix;
    ShadowXGARegs.ColCompCond = SavedColCompCond;

    #endif /* XGA */

COPY_CHUNK_TO_PHUNK_EXIT:
    ;
}


VOID PixBltThroughClips(VOID)

{
    /******************************************************************/
    /* This function calls off to a low level blt function after      */
    /* setting up the clip rectangles. The calling function should    */
    /* already have set up the AIxfer parameter block ready for the   */
    /* low level function.                                            */
    /******************************************************************/

    /******************************************************************/
    /* If we are attempting a blt with a background mix of            */
    /* BM_SRC_TRANSPARENT (indicated by colour compare condition of   */
    /* COLCOMP_SRC_NOT_EQUAL) and the destination is VRAM then we     */
    /* need to simulate the operation via the PHUNK. For details of   */
    /* how BM_SRCTRANSPARENT is simulated see eddnbblt.c              */
    /******************************************************************/
    if ( UseSoftwareUnderpaint()
       #ifdef VRAMPTR
       && (AIxfer.pbmhDest->Bitmap == NULL) )
       #else /* ndef VRAMPTR */
       && (AIxfer.pbmhDest->BMPhys != NULL) )
       #endif /* ndef VRAMPTR */
    {
        PixBltThroughClipsViaPHUNK();
        goto EXIT_PIXBLTTHROUGHCLIPS;
    }


    /******************************************************************/
    /* Set the AIxfer clip rectangle pointer to point to the first    */
    /* clip rectangle in the dc cache.                                */
    /******************************************************************/
    AIxfer.pNextDestClipRect = &pdc->DCIClipRects[0];

    if (fThreeWayWorkBlt)
    {
        /**************************************************************/
        /* The destination of the blt is the work bitmap of a three   */
        /* way ROP operation so we do not want to clip the operation. */
        /**************************************************************/

        /**************************************************************/
        /* We will use the target rectangle as the clip rectangle     */
        /**************************************************************/
        pdc->DCIClipRects[0].X0 = AIxfer.rcsTrg.pts1.x;
        pdc->DCIClipRects[0].Y0 = AIxfer.rcsTrg.pts1.y;
        pdc->DCIClipRects[0].X1 = AIxfer.rcsTrg.pts2.x + (USHORT)1;
        pdc->DCIClipRects[0].Y1 = AIxfer.rcsTrg.pts2.y + (USHORT)1;

        /**************************************************************/
        /* Only one clip rectangle                                    */
        /**************************************************************/
        AIxfer.cDestClipRects = 1;

        /**************************************************************/
        /* Force the cache to be refilled next time.                  */
        /**************************************************************/
        pdc->ClipChanged = TRUE;

        /**************************************************************/
        /* Now do the business...                                     */
        /**************************************************************/
        SPad.BltFunction();

    }
    else
    {
        /******************************************************************/
        /* We will call back to the engine if either the clips have       */
        /* or we have too many clip regions for the cache. If the latter  */
        /* case is true we can optimise clipping by setting the clip      */
        /* bounds to the target rectangle. Otherwise set them to the      */
        /* bitmap bounds to get valid clips into the cache                */
        /******************************************************************/
        if (pdc->DCIEngineClips > CACHED_CLIPS)
        {
            GetClipsBounds.X0 = AIxfer.rcsTrg.pts1.x;
            GetClipsBounds.X1 = AIxfer.rcsTrg.pts2.x + (USHORT)1;
            GetClipsBounds.Y0 = pdc->DCIBoundingClip[1].Y -
                                                        AIxfer.rcsTrg.pts2.y;
            GetClipsBounds.Y1 = pdc->DCIBoundingClip[1].Y + (USHORT)1 -
                                                        AIxfer.rcsTrg.pts1.y;
        }
        else if (pdc->ClipChanged )
             {
                 /**************************************************************/
                 /* Set the bounds which intersect clip to whole drawing area  */
                 /**************************************************************/
                 GetClipsBounds.X0 = pdc->DCIBoundingClip[0].X;
                 GetClipsBounds.X1 = pdc->DCIBoundingClip[1].X + (USHORT)1;
                 GetClipsBounds.Y0 = pdc->DCIBoundingClip[0].Y;
                 GetClipsBounds.Y1 = pdc->DCIBoundingClip[1].Y + (USHORT)1;
             }

        /******************************************************************/
        /* do the appropriate blt to all clip regions                     */
        /******************************************************************/
        GetClipsControl.ircStart = 1;
        do /* for each rectangle comprising the clip region */
        {
            /**************************************************************/
            /* set the GetClips control structure number of rectangles    */
            /* returned to zero so that we will exit loop if all processed*/
            /**************************************************************/
            GetClipsControl.crcReturned = 0;

            /**************************************************************/
            /* if the total number of clips comprising the region exceed  */
            /* the size of the dc cache or NotifyClipChange was called    */
            /* then get the cache updated from engine                     */
            /**************************************************************/
            if ( (pdc->DCIEngineClips > CACHED_CLIPS) ||
                                                       pdc->ClipChanged )
            {
                edda_GetClipRectangles();
                /**********************************************************/
                /* reset the start rectangle for next iteration           */
                /**********************************************************/
                GetClipsControl.ircStart += GetClipsControl.crcReturned;

            }

            /**************************************************************/
            /* if there are now some clip rectangles in the cache         */
            /* then call the low level function which can cope with       */
            /* drawing to all the cached clip rectangles                  */
            /**************************************************************/
            if (pdc->DCIClipNum)
            {
                AIxfer.cDestClipRects = pdc->DCIClipNum;
                SPad.BltFunction();
            }

            /**************************************************************/
            /* 73126 TAV - Changed "while" comparison from non-zero to    */
            /* prevent engine from getting called multiple times for      */
            /* rectangles already cached.                                 */
            /**************************************************************/

        } while ((GetClipsControl.crcReturned >= CACHED_CLIPS) &&
                 (GetClipsControl.ircStart    <= pdc->DCIEngineClips));
    }

EXIT_PIXBLTTHROUGHCLIPS:
    ;
}

/**********************************************************************/
/* This function simulates a BM_SRCTRANSPARENT bitblt when the        */
/* destination is VRAM                                                */
/* There are 4 cases to consider:                                     */
/*                                                                    */
/*  1) The pixblt is a source to destination copy to VRAM             */
/*  2) The pixblt has a background color of 0.                        */
/*  3) The pixblt is from memory to VRAM                              */
/*  4) The pixblt is from VRAM to VRAM                                */
/*                                                                    */
/* Case 1) pixblt is a source to destination copy to VRAM             */
/*         is simple as no mixing is envloved and as it is the most   */
/*         likely use for BM_SRCTRANSPARENT it uses the following     */
/*         fast path:                                                 */
/*                                                                    */
/*      a: Copy the source to the PHUNK                               */
/*      b: Copy the dest to the PHUNK, updating background only       */
/*         (ie a BM_DESTTRANSPARENT operation)                        */
/*      c: Copy the PHUNK to the dest                                 */
/*                                                                    */
/* Case 2) pixblt has a background colour of 0. This case has been    */
/*         singled out because the hardware can accomplish a          */
/*         BM_SRCTRANSPARENT mix in this special case. The pattern    */
/*         bitmap can be generated from the source. (Note : OK to     */
/*         use pattern bitmap as BM_SRCTRANSPARENT does not apply     */
/*         to blts involving a pattern). The background mix can       */
/*         be used to implement the transparency.                     */
/*                                                                    */
/*      a:  Copy source to PHUNK                                      */
/*      b:  Set background mix to HWMIX_DEST, use source to generate  */
/*          pattern and copy PHUNK to destination.                    */
/*                                                                    */
/* Case 3) Memory to VRAM is best implemented by making use of the    */
/*         MESS.                                                      */
/*                                                                    */
/*      a: Copy the dest to the PHUNK                                 */
/*      b: Use MESS to mix source onto PHUNK with BM_SRCTRANSPARENT   */
/*      c: Copy PHUNK to dest                                         */
/*                                                                    */
/* Case 4) VRAM to VRAM. Again we have to make use of the MESS, but   */
/*         as neither source or dest are in memory we need to create  */
/*         a temporary work bitmap:                                   */
/*                                                                    */
/*      a: Copy source to PHUNK                                       */
/*      b: Copy PHUNK to temporary bitmap                             */
/*      c: Copy dest to PHUNK                                         */
/*      d: Use MESS to mix temporary bitmap onto PHUNK                */
/*      e: Copy PHUNK to dest                                         */
/*                                                                    */
/**********************************************************************/
VOID SimulateSrcTransparentPixbltToVRAM( PBITBLTPB pBltParms,
                                         POINTS    ptsChunkPos)
{
    BYTE            SavedFgMix;
    BYTE            SavedBgMix;
    RECTS           rcsTemp;
    SHORT           SavedsoftDrawInUse ;
    #ifdef   _8514
    ULONG           ScreenPointer;
    #endif

    /******************************************************************/
    /* Note : On entry to this routine the destination is set up to   */
    /* be the PHUNK.                                                  */
    /******************************************************************/

    /******************************************************************/
    /* To get here the ColCompCond register must have been            */
    /* COLCOMP_SRC_NOT_EQUAL. This is not supported by the hardware   */
    /* and these simulations require the default value.               */
    /******************************************************************/
#ifdef _8514
    Shadow8514Regs.Mode.UnderPaint = MD_UP_FALSE;
#else
    ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;
#endif /* ~_8514 */

    /**************************************************************/
    /* Record mixes to reset later as the first blt will over-    */
    /* write them.                                                */
    /**************************************************************/

#ifdef _8514
    SavedFgMix = Shadow8514Regs.Function_1.Mix;
    SavedBgMix = Shadow8514Regs.Function_0.Mix;
#else
    SavedFgMix = ShadowXGARegs.FgMix;
    SavedBgMix = ShadowXGARegs.BgMix;
#endif /* ~_8514 */

    SavedsoftDrawInUse = softDrawInUse;

    /******************************************************************/
    /* Decide which case of the simulation is best to use.            */
    /******************************************************************/
#ifdef _8514
    if (Shadow8514Regs.Function_1.Mix == FUNC_S)
#else
    if ( ShadowXGARegs.FgMix == HWMIX_SOURCE)
#endif /* ~_8514 */
    {
        /**************************************************************/
        /* Case 1: Fast path for source to destination copy           */
        /**************************************************************/

        /**************************************************************/
        /* a: Copy source to PHUNK                                    */
        /**************************************************************/
        CopyChunkToPhunkForPixBltSource(pBltParms->pbmhSrc,
                                        ptsChunkPos);

        /**************************************************************/
        /* b: Copy dest to PHUNK, updating background only            */
        /**************************************************************/

        /**************************************************************/
        /* Set source and destination for this sub-bitblt to the      */
        /* original destination and the PHUNK.                        */
        /**************************************************************/

        AIxfer.pbmhSrc  = pBltParms->pbmhDest;
        AIxfer.pbmhDest = &PhunkBMHeader;

        rcsTemp       = AIxfer.rcsSrc;
        AIxfer.rcsSrc = AIxfer.rcsTrg;
        AIxfer.rcsTrg = rcsTemp;

        /**************************************************************/
        /* blt dest onto PHUNK background                             */
        /**************************************************************/
#ifdef _8514
        TransferShadowRegisters( TSR_COLOUR_MIX );

        ScreenPointer = AIxfer.rcsSrc.pts1.y + ( AIxfer.rcsSrc.pts1.x << 16 );

        CopyDestToMemory( PhunkBMHeader.Bitmap,
                          ScreenPointer,
                          AIxfer.rcsSrc.pts2.x - AIxfer.rcsSrc.pts1.x,
                          AIxfer.rcsSrc.pts2.y - AIxfer.rcsSrc.pts1.y,
#ifndef   S3
                          EIGHT_BPP );
#else
                          PhunkBMHeader.Info.HWFormat);
#endif
#else
        ShadowXGARegs.ColCompCond = COLCOMP_EQUAL;
        softDrawInUse = FALSE;
        SimpleSourceDestPixBlt();
#endif /* ~_8514 */

        /**************************************************************/
        /* c: Copy PHUNK to dest                                      */
        /**************************************************************/

        /**************************************************************/
        /* Set source and destination for this sub-bitblt to the      */
        /* PHUNK and the original destination.                        */
        /**************************************************************/

        AIxfer.pbmhSrc  = &PhunkBMHeader;
        AIxfer.pbmhDest = pBltParms->pbmhDest;

        rcsTemp       = AIxfer.rcsSrc;
        AIxfer.rcsSrc = AIxfer.rcsTrg;
        AIxfer.rcsTrg = rcsTemp;

        /**************************************************************/
        /* Copy PHUNK to destination                                  */
        /**************************************************************/
#ifdef _8514
        Shadow8514Regs.Mode.UnderPaint = MD_UP_FALSE;
        softDrawInUse = FALSE;
#else
        ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;
#endif /* ~_8514 */

        SimpleSourceDestPixBlt();
    }

#ifdef _8514
    else if (Shadow8514Regs.Color_Comp == 0)
#else
    else if (ShadowXGARegs.ColCompVal == 0)
#endif /* ~_8514 */
    {
        /**************************************************************/
        /* Case 2: The background colour is 0                         */
        /**************************************************************/

        /**************************************************************/
        /* a: Copy the source to the PHUNK                            */
        /**************************************************************/
        CopyChunkToPhunkForPixBltSource(pBltParms->pbmhSrc,
                                        ptsChunkPos);

        /**************************************************************/
        /* b: Copy PHUNK to destination, using the 'generate pattern  */
        /*    from source' option to make the background transparent. */
        /**************************************************************/
        softDrawInUse = FALSE;
#ifdef _8514
        Shadow8514Regs.Function_0.Mix = FUNC_D;
#else
        ShadowXGARegs.BgMix = HWMIX_DEST;
#endif /* ~_8514 */

        PhunkDestPixBltwithGeneratedPattern();
    }
#ifdef VRAMPTR
    else if (pBltParms->pbmhSrc->Bitmap != NULL)
#else /* ndef VRAMPTR */
    else if (pBltParms->pbmhSrc->BMPhys == NULL)
#endif /* ndef VRAMPTR */
    {
        /**************************************************************/
        /* Case 3: Memory to VRAM pixblt                              */
        /**************************************************************/

        /**************************************************************/
        /* a: Copy the dest to the PHUNK                              */
        /**************************************************************/


        /**************************************************************/
        /* Set up copy from destination to PHUNK                      */
        /**************************************************************/
#ifdef _8514
        Shadow8514Regs.Function_1.Mix = FUNC_S;
        Shadow8514Regs.Function_0.Mix = FUNC_S;
        Shadow8514Regs.Mode.UnderPaint = MD_UP_FALSE;
#else
        ShadowXGARegs.FgMix = HWMIX_SOURCE;
        ShadowXGARegs.BgMix = HWMIX_SOURCE;
        ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;
#endif /* ~_8514 */

        AIxfer.pbmhSrc  = pBltParms->pbmhDest;
        AIxfer.pbmhDest = &PhunkBMHeader;

        rcsTemp       = AIxfer.rcsTrg;
        AIxfer.rcsTrg = AIxfer.rcsSrc;
        AIxfer.rcsSrc = rcsTemp;

        softDrawInUse = FALSE;
        SimpleSourceDestPixBlt();

        /**************************************************************/
        /* Use MESS to mix source onto PHUNK with BM_SRCTRANSPARENT   */
        /* (destination is already PHUNK) using the saved mixes.      */
        /**************************************************************/

        AIxfer.pbmhSrc  = pBltParms->pbmhSrc;

        AIxfer.rcsSrc.pts1.x = ptsChunkPos.x;
        AIxfer.rcsSrc.pts1.y = ptsChunkPos.y;
        AIxfer.rcsSrc.pts2.x = ptsChunkPos.x +
                               (AIxfer.rcsTrg.pts2.x - AIxfer.rcsTrg.pts1.x);
        AIxfer.rcsSrc.pts2.y = ptsChunkPos.y +
                               (AIxfer.rcsTrg.pts2.y - AIxfer.rcsTrg.pts1.y);

#ifdef _8514
        Shadow8514Regs.Mode.UnderPaint = MD_UP_EQ;
        Shadow8514Regs.Function_1.Mix = SavedFgMix;
        Shadow8514Regs.Function_0.Mix = SavedBgMix;
#else
        ShadowXGARegs.ColCompCond = COLCOMP_SRC_NOT_EQUAL;
        ShadowXGARegs.FgMix = SavedFgMix;
        ShadowXGARegs.BgMix = SavedBgMix;
#endif /* ~_8514 */

        softDrawInUse = TRUE;
        SimpleSourceDestPixBlt();

        /**************************************************************/
        /* Copy PHUNK to dest                                         */
        /* (Destination rectangle stored in temporary location)       */
        /**************************************************************/

        AIxfer.pbmhSrc  = &PhunkBMHeader;
        AIxfer.pbmhDest = pBltParms->pbmhDest;

        AIxfer.rcsSrc   = AIxfer.rcsTrg;
        AIxfer.rcsTrg   = rcsTemp;

#ifdef _8514
        Shadow8514Regs.Function_1.Mix = FUNC_S;
        Shadow8514Regs.Function_0.Mix = FUNC_S;
        Shadow8514Regs.Mode.UnderPaint = MD_UP_FALSE;
#else
        ShadowXGARegs.FgMix = HWMIX_SOURCE;
        ShadowXGARegs.BgMix = HWMIX_SOURCE;
        ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;
#endif /* ~_8514 */

        softDrawInUse = FALSE;
        SimpleSourceDestPixBlt();

    }
    else
    {
        /**************************************************************/
        /* Case 4: VRAM to VRAM pixblt                                */
        /**************************************************************/
#ifdef FIREWALLS
        /**************************************************************/
        /* This operation requires a temporary bitmap, the same size  */
        /* as the PHUNK. Check that it has been created.              */
        /**************************************************************/
        if (!fTempBitmapAllocated)
        {
            haltproc();
        }
#endif
        /**************************************************************/
        /* Initialise the width, height and format of the temporary   */
        /* bitmap (could not be set up when created as these values   */
        /* were not known then).                                      */
        /**************************************************************/
        bmhTemp.Info.HWWidth  = PhunkBMHeader.Info.HWWidth;
        bmhTemp.Info.HWHeight = PhunkBMHeader.Info.HWHeight;
        bmhTemp.Info.HWFormat = PhunkBMHeader.Info.HWFormat;

        /**************************************************************/
        /* Record Destination rectangle as we will overwrite it       */
        /**************************************************************/
        rcsTemp    = AIxfer.rcsTrg;

        /**************************************************************/
        /* Copy source to PHUNK                                       */
        /**************************************************************/
        CopyChunkToPhunkForPixBltSource(pBltParms->pbmhSrc,
                                        ptsChunkPos);

        /**************************************************************/
        /* Copy PHUNK to temporary bitmap (source already PHUNK,      */
        /* temporary bitmaps rectangle wants start from {0,0},        */
        /* therefore it can be the same as the PHUNKs)                */
        /**************************************************************/

        AIxfer.pbmhDest = &bmhTemp;

        AIxfer.rcsTrg   = AIxfer.rcsSrc;

#ifdef _8514
        Shadow8514Regs.Function_1.Mix = FUNC_S;
        Shadow8514Regs.Function_0.Mix = FUNC_S;
        Shadow8514Regs.Mode.UnderPaint = MD_UP_FALSE;
#else
        ShadowXGARegs.FgMix = HWMIX_SOURCE;
        ShadowXGARegs.BgMix = HWMIX_SOURCE;
        ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;
#endif /* ~_8514 */

        softDrawInUse = TRUE;

        SimpleSourceDestPixBlt();

        /**************************************************************/
        /* Copy dest to PHUNK, source is currently PHUNK, destination */
        /* rectangle is held in rcsTemp.                              */
        /**************************************************************/
        AIxfer.pbmhDest = AIxfer.pbmhSrc;
        AIxfer.pbmhSrc  = pBltParms->pbmhDest;

        AIxfer.rcsTrg   = AIxfer.rcsSrc;
        AIxfer.rcsSrc   = rcsTemp;

        softDrawInUse = FALSE;
        SimpleSourceDestPixBlt();

        /**************************************************************/
        /* Use MESS to mix temporary bitmap onto PHUNK.               */
        /* (destination is already PHUNK, temporary rectangle is the  */
        /* same as the PHUNKs)                                        */
        /**************************************************************/
        AIxfer.pbmhSrc  = &bmhTemp;

        AIxfer.rcsSrc   = AIxfer.rcsTrg;

#ifdef _8514
        Shadow8514Regs.Mode.UnderPaint = MD_UP_EQ;
        Shadow8514Regs.Function_1.Mix = SavedFgMix;
        Shadow8514Regs.Function_0.Mix = SavedBgMix;
#else
        ShadowXGARegs.ColCompCond = COLCOMP_SRC_NOT_EQUAL;
        ShadowXGARegs.FgMix = SavedFgMix;
        ShadowXGARegs.BgMix = SavedBgMix;
#endif /* ~_8514 */

        softDrawInUse = TRUE;
        SimpleSourceDestPixBlt();

        /**************************************************************/
        /* Copy PHUNK to dest (destination currently PHUNK, target    */
        /* rectangle stored in temporary)                             */
        /**************************************************************/
        AIxfer.pbmhSrc    = AIxfer.pbmhDest;
        AIxfer.pbmhDest   = pBltParms->pbmhDest;

        AIxfer.rcsSrc     = AIxfer.rcsTrg;
        AIxfer.rcsTrg     = rcsTemp;

#ifdef _8514
        Shadow8514Regs.Function_1.Mix = FUNC_S;
        Shadow8514Regs.Function_0.Mix = FUNC_S;
        Shadow8514Regs.Mode.UnderPaint = MD_UP_FALSE;
#else
        ShadowXGARegs.FgMix = HWMIX_SOURCE;
        ShadowXGARegs.BgMix = HWMIX_SOURCE;
        ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;
#endif /* ~_8514 */

        softDrawInUse = FALSE;
        SimpleSourceDestPixBlt();
    }

    /******************************************************************/
    /* Restore the registers to original values - next CHUNK needs    */
    /* them set up the same.                                          */
    /******************************************************************/

#ifdef _8514
    Shadow8514Regs.Mode.UnderPaint = MD_UP_EQ;
    Shadow8514Regs.Function_1.Mix = SavedFgMix;
    Shadow8514Regs.Function_0.Mix = SavedBgMix;
#else
    ShadowXGARegs.ColCompCond = COLCOMP_SRC_NOT_EQUAL;
    ShadowXGARegs.FgMix = SavedFgMix;
    ShadowXGARegs.BgMix = SavedBgMix;
#endif /* ~_8514 */

    softDrawInUse = SavedsoftDrawInUse;
}


VOID SimpleSourceDestPixBlt( VOID )
/**********************************************************************/
/* This routine pixblts from the current source bitmap to the current */
/* destination bitmap, using the foreground and background mixes      */
/* in the registers.                                                  */
/* This routine does not take clipping rectangles or differences      */
/* in coordinate systems into account. The source and target          */
/* rectangles should be pre-clipped and of identical sizes            */
/**********************************************************************/
{

#ifdef FIREWALLS
    /******************************************************************/
    /* Check the source and destination rectangles are of identical   */
    /* size. That is all this routine is designed to deal with.       */
    /******************************************************************/
    if (   (   (AIxfer.rcsSrc.pts1.x - AIxfer.rcsSrc.pts2.x)
            != (AIxfer.rcsTrg.pts1.x - AIxfer.rcsTrg.pts2.x) )
        || (   (AIxfer.rcsSrc.pts1.y - AIxfer.rcsSrc.pts2.y)
            != (AIxfer.rcsTrg.pts1.y - AIxfer.rcsTrg.pts2.y) ) )
    {
        haltproc();
    }
#endif /* FIREWALLS */
    /******************************************************************/
    /* Set up blt bitmap details.                                     */
    /******************************************************************/

    if (softDrawInUse)
    {
        /**************************************************************/
        /* Using software drawing, so set the bitmap addresses to the */
        /* virtual addresses.                                         */
        /**************************************************************/

#ifdef _8514
        Shadow8514Regs.PixMapBaseB = (ULONG)AIxfer.pbmhSrc->Bitmap;
        Shadow8514Regs.PixMapBaseA = (ULONG)AIxfer.pbmhDest->Bitmap;
#else
        ShadowXGARegs.PixMapBaseB = (ULONG)AIxfer.pbmhSrc->Bitmap;
        ShadowXGARegs.PixMapBaseA = (ULONG)AIxfer.pbmhDest->Bitmap;
#endif /* ~_8514 */

    }
    else
    {
        /**************************************************************/
        /* Using Hardware drawing, so set the bitmap addresses to the */
        /* physical addresses.                                        */
        /**************************************************************/

#ifdef _8514
        Shadow8514Regs.PixMapBaseB = AIxfer.pbmhSrc->BMPhys;
        Shadow8514Regs.PixMapBaseA = AIxfer.pbmhDest->BMPhys;
#else
        ShadowXGARegs.PixMapBaseB = AIxfer.pbmhSrc->BMPhys;
        ShadowXGARegs.PixMapBaseA = AIxfer.pbmhDest->BMPhys;
#endif /* ~_8514 */

    }

    /******************************************************************/
    /* Set up bitmap sizes and formats.                               */
    /******************************************************************/

#ifdef _8514
    Shadow8514Regs.PixMapWidthA  = AIxfer.pbmhDest->Info.HWWidth;
    Shadow8514Regs.PixMapHeightA = AIxfer.pbmhDest->Info.HWHeight;
    Shadow8514Regs.PixMapFormatA = (BYTE)AIxfer.pbmhDest->Info.HWFormat;

    Shadow8514Regs.PixMapWidthB  = AIxfer.pbmhSrc->Info.HWWidth;
    Shadow8514Regs.PixMapHeightB = AIxfer.pbmhSrc->Info.HWHeight;
    Shadow8514Regs.PixMapFormatB = (BYTE)AIxfer.pbmhSrc->Info.HWFormat;

    /******************************************************************/
    /* Set up blt details.                                            */
    /******************************************************************/
    Shadow8514Regs.SrcXAddr = AIxfer.rcsSrc.pts1.x;
    Shadow8514Regs.SrcYAddr = AIxfer.rcsSrc.pts1.y;

    Shadow8514Regs.DstXAddr = AIxfer.rcsTrg.pts1.x;
    Shadow8514Regs.DstYAddr = AIxfer.rcsTrg.pts1.y;

    Shadow8514Regs.OpDim1 = AIxfer.rcsSrc.pts2.x
                           - AIxfer.rcsSrc.pts1.x;
    Shadow8514Regs.OpDim2 = AIxfer.rcsSrc.pts2.y
                           - AIxfer.rcsSrc.pts1.y;

    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;

#else
    ShadowXGARegs.PixMapWidthA  = AIxfer.pbmhDest->Info.HWWidth;
    ShadowXGARegs.PixMapHeightA = AIxfer.pbmhDest->Info.HWHeight;
    ShadowXGARegs.PixMapFormatA = (BYTE)AIxfer.pbmhDest->Info.HWFormat;

    ShadowXGARegs.PixMapWidthB  = AIxfer.pbmhSrc->Info.HWWidth;
    ShadowXGARegs.PixMapHeightB = AIxfer.pbmhSrc->Info.HWHeight;
    ShadowXGARegs.PixMapFormatB = (BYTE)AIxfer.pbmhSrc->Info.HWFormat;

    /******************************************************************/
    /* Set up blt details.                                            */
    /******************************************************************/
    ShadowXGARegs.SrcXAddr = AIxfer.rcsSrc.pts1.x;
    ShadowXGARegs.SrcYAddr = AIxfer.rcsSrc.pts1.y;

    ShadowXGARegs.DstXAddr = AIxfer.rcsTrg.pts1.x;
    ShadowXGARegs.DstYAddr = AIxfer.rcsTrg.pts1.y;

    ShadowXGARegs.OpDim1 = AIxfer.rcsSrc.pts2.x
                           - AIxfer.rcsSrc.pts1.x;
    ShadowXGARegs.OpDim2 = AIxfer.rcsSrc.pts2.y
                           - AIxfer.rcsSrc.pts1.y;

    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;
#endif /* ~_8514 */

    /******************************************************************/
    /* Call the software routines or the hardware to do the blt       */
    /******************************************************************/

    if (softDrawInUse)
    {
        WaitForRealHWFunction();
        eddf_MESS();
    }
    else
    {
        TransferShadowRegisters( TSR_MAP_A |
                                 TSR_MAP_B |
                                 TSR_COLOUR_MIX |
                                 TSR_COORDINATES |
                                 TSR_PIXELOP );
#ifdef _8514
        SPad.BltFunction();
#endif /*~ _8514 */
        WaitForRealHWFunction();
    }
}


VOID PhunkDestPixBltwithGeneratedPattern( VOID )
{
#ifdef _8514
#endif /* ~_8514 */
    /******************************************************************/
    /* This routine uses the hardware to copy from the PHUNK to the   */
    /* destination using a pattern generated from the PHUNK. It is    */
    /* used while simulating a BM_SRCTRANSPARENT mix when the         */
    /* background colour = 0.                                         */
    /*                                                                */
    /* Note: This routine requires that                               */
    /*       AIxfer.pbmhDest points to the destination bitmap         */
    /*       rcsTrg is the destiation rectangle                       */
    /*       rcsSrc is the PHUNK rectangle                            */
    /******************************************************************/

#ifdef FIREWALLS
    /******************************************************************/
    /* only available in hardware.                                    */
    /******************************************************************/
    if (softDrawInUse)
    {
        haltproc();
    }
    /******************************************************************/
    /* Check the source and destination rectangles are of identical   */
    /* size. That is all this routine is designed to deal with.       */
    /******************************************************************/
    if (   (   (AIxfer.rcsSrc.pts1.x - AIxfer.rcsSrc.pts2.x)
            != (AIxfer.rcsTrg.pts1.x - AIxfer.rcsTrg.pts2.x) )
        || (   (AIxfer.rcsSrc.pts1.y - AIxfer.rcsSrc.pts2.y)
            != (AIxfer.rcsTrg.pts1.y - AIxfer.rcsTrg.pts2.y) ) )
    {
        haltproc();
    }
#endif

#ifdef _8514
    /******************************************************************/
    /* set up bitmap addresses.                                       */
    /******************************************************************/
    Shadow8514Regs.PixMapBaseB = (ULONG)PhunkBMHeader.BMPhys;
    Shadow8514Regs.PixMapBaseA = AIxfer.pbmhDest->BMPhys;

    /******************************************************************/
    /* Set up bitmap sizes and formats.                               */
    /******************************************************************/

    Shadow8514Regs.PixMapWidthA  = AIxfer.pbmhDest->Info.HWWidth;
    Shadow8514Regs.PixMapHeightA = AIxfer.pbmhDest->Info.HWHeight;
    Shadow8514Regs.PixMapFormatA = (BYTE)AIxfer.pbmhDest->Info.HWFormat;

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

    /******************************************************************/
    /* Set up blt details.                                            */
    /******************************************************************/
    Shadow8514Regs.SrcXAddr = AIxfer.rcsSrc.pts1.x;
    Shadow8514Regs.SrcYAddr = AIxfer.rcsSrc.pts1.y;

    Shadow8514Regs.DstXAddr = AIxfer.rcsTrg.pts1.x;
    Shadow8514Regs.DstYAddr = AIxfer.rcsTrg.pts1.y;

    Shadow8514Regs.OpDim1 = AIxfer.rcsSrc.pts2.x
                            - AIxfer.rcsSrc.pts1.x;
    Shadow8514Regs.OpDim2 = AIxfer.rcsSrc.pts2.y
                            - AIxfer.rcsSrc.pts1.y;

    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_SRC |
                           MASK_PIX_MAP_OFF |
                           DRAW_MODE_DONTCARE |
                           DIR_OCTANT_LRTB;
#else
    /******************************************************************/
    /* set up bitmap addresses.                                       */
    /******************************************************************/
    ShadowXGARegs.PixMapBaseB = (ULONG)PhunkBMHeader.BMPhys;
    ShadowXGARegs.PixMapBaseA = AIxfer.pbmhDest->BMPhys;

    /******************************************************************/
    /* Set up bitmap sizes and formats.                               */
    /******************************************************************/

    ShadowXGARegs.PixMapWidthA  = AIxfer.pbmhDest->Info.HWWidth;
    ShadowXGARegs.PixMapHeightA = AIxfer.pbmhDest->Info.HWHeight;
    ShadowXGARegs.PixMapFormatA = (BYTE)AIxfer.pbmhDest->Info.HWFormat;

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

    /******************************************************************/
    /* Set up blt details.                                            */
    /******************************************************************/
    ShadowXGARegs.SrcXAddr = AIxfer.rcsSrc.pts1.x;
    ShadowXGARegs.SrcYAddr = AIxfer.rcsSrc.pts1.y;

    ShadowXGARegs.DstXAddr = AIxfer.rcsTrg.pts1.x;
    ShadowXGARegs.DstYAddr = AIxfer.rcsTrg.pts1.y;

    ShadowXGARegs.OpDim1 = AIxfer.rcsSrc.pts2.x
                           - AIxfer.rcsSrc.pts1.x;
    ShadowXGARegs.OpDim2 = AIxfer.rcsSrc.pts2.y
                           - AIxfer.rcsSrc.pts1.y;

    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_SRC |
                          MASK_PIX_MAP_OFF |
                          DRAW_MODE_DONTCARE |
                          DIR_OCTANT_LRTB;
#endif /* ~_8514 */
    /******************************************************************/
    /* Do the blt                                                     */
    /******************************************************************/
    TransferShadowRegisters( TSR_MAP_A |
                             TSR_MAP_B |
                             TSR_COLOUR_MIX |
                             TSR_COORDINATES |
                             TSR_PIXELOP );
    WaitForRealHWFunction();

}
