/*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          = EDDNBBLT                                       */
/*                                                                    */
/*   Description     = Display Device Driver minor function           */
/*                     BitBlt                                         */
/*                                                                    */
/*   Function        = BitBlt block transfers a series of bits from   */
/*                     a source bitmap to a target bitmap, optionally */
/*                     under control of a pattern.                    */
/*                                                                    */
/*   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/02/93 - Commented out spurious debug and haltproc statements  */
/*              causing problems in the dekko version of the driver.  */
/*              (Defect 88638 - BZ)                                   */
/*                                                                    */
/**********************************************************************/
#define INCL_DDICOMFLAGS
#define INCL_DOSMEMMGR
#define INCL_DDIMISC
#define INCL_GRE_BITMAPS
#include <eddinclt.h>

#include <eddbcone.h>
#include <eddecone.h>
#include <eddicone.h>
#include <eddhcone.h>
#include <eddmcone.h>

#include <eddbtypt.h>
#include <edddtypt.h>
#include <eddhtype.h>

#include <eddbextf.h>
#include <eddcextf.h>
#include <eddgextf.h>
#include <eddaextf.h>
#include <eddmextf.h>
#include <eddhextf.h>
#include <eddmextf.h>
#ifdef DCAF                                                               //DCAF
#include <dcafextf.h>                                                     //DCAF
#endif                                                                    //DCAF

#include <eddhmacr.h>

#include <eddfcone.h>
#include <eddftype.h>

#include <cursor.h>
#include <hwaccess.h>
#include <memman.h>
#ifdef VRAMPTR
#include <eddncach.h>
#endif /* VRAMPTR */

/**********************************************************************/
/* <DCRTURBO>                                                         */
/**********************************************************************/
/* Include definitions for XGA display driver stretch function        */
/* definitions and prototypes.                                        */
/**********************************************************************/
#include <strchext.h>

#ifdef _8514
#pragma message( __FILE__"(57) : Work needed: fix up mix modes")
#include <8514.h>
#endif /* _8514 */

/**********************************************************************/
/* global variables                                                   */
/**********************************************************************/
extern BltBuffEntry        Blt3WayBuffer[];
extern PPFNL               EnginesDispatchTable;
extern BOOL                DitheredPattern;
extern BITBLTPB            AIxfer;
#ifndef   _8514
extern MMReg               ShadowXGARegs;
extern pMMReg              pRealXGARegs;
extern pMMReg              pXGARegs;
#else
extern MM8514Reg           Shadow8514Regs;
extern pMM8514Reg          pReal8514Regs;
extern pMM8514Reg          p8514Regs;
extern BYTE                InverseTable[];
extern DDTType             DDT;
#endif
extern ULONG               PixelOp;
extern BYTE                RopToHWMix[];
extern BitmapHeader        NewPatternTable[];
extern BltSPad             SPad;
extern CURSORDATA          cursor_data;
extern BOOL                fXgaDead;

extern RGNRECT             GetClipsControl;
extern ClipRectangle       GetClipsBounds;

#ifdef SDBM20
extern SHORT                    softDrawInUse;
extern ULONG                    LinePatternCur;
extern ULONG                    LinePatternPhys;
extern ULONG                    LinePatternSys;
extern ULONG                    MarkerCur;
extern ULONG                    MarkerPhys;
extern ULONG                    MarkerSys;
extern ULONG                    pCurCacheBasePhy;
extern ULONG                    pSysCacheStartPhy;
extern ULONG                    pPhunkPhys;
extern drawFunctionsTable       softDrawTable;
extern drawFunctionsTable       hardDrawTable;
extern SHORT                    foregroundSession;
extern BitmapHeader             DirectListEntry;
extern BitmapHeader             PhunkBMHeader;
#endif /* SDBM20 */

#ifdef PALETTE_MGR
extern BOOL                     UsePaletteMapping;
#endif

extern pDrawFunctionsTable      pDrawFunctions;

pBitmapHeader DRIVERCALL convert_colour_to_mono(ULONG         FunN,
                                                ULONG         attr_option,
                                                PBITBLTATTRS  ArgAttrs,
                                                PDC           pdcSrc);

/**********************************************************************/
/* Make these global (rather than in the scratch pad because it       */
/* appears they get 'scratched' if they're in the scratch pad.        */
/**********************************************************************/
BitmapHeader    ExpSrcBMHeader;
BitmapHeader    ExpPatBMHeader;
BitmapHeader    ExpDstBMHeader;

pBitmapHeader   pExpSrcBMHeader;

/**********************************************************************/
/* This is used to disable clipping when doing 3 way operations to    */
/* the work bitmap                                                    */
/**********************************************************************/
SHORT           fThreeWayWorkBlt = FALSE;

/**********************************************************************/
/* The BM_SRCTRANSPARENT and BM_DESTTRANSPARENT mixes added at 2.0    */
/* blt to the destination only when the source pel (pre mixed) is not */
/* the background color (in the case of BM_SRCTRANSPARENT) or only    */
/* when the original destination pel is the background color (in the  */
/* case of BM_DESTTRANSPARENT).                                       */
/*                                                                    */
/* The XGA hardware is capable of implementing BM_DESTTRANSPARENT     */
/* directly using the color compare register, but there is no         */
/* mechanism for a direct BM_SRCTRANSPARENT mix.  Both mixes have     */
/* been added to the software drawing (MESS) code for src-dst blts at */
/* 4, 8, and 16 bits per pel.  At 1 bit per pel the ROP is simply     */
/* translated so that the mix is implemented directly by the ROP      */
/* logic.                                                             */
/*                                                                    */
/* eddb_BitBlt is responsible for setting up the software registers   */
/* with the color compare register set to COLCOMP_EQUAL,              */
/* COLCOMP_SRC_NOT_EQUAL, or COLCOMP_ALWAYS (if neither of the mixes  */
/* are needed), and the background color needed for the compare       */
/* function.  COLCOMP_SRC_NOT_EQUAL is not recognised by the XGA      */
/* hardware and is firewalled in TransferShadowRegisters. The pixblt  */
/* functions (PixBltThroughClips and PixBltThroughClipsViaPHUNK)      */
/* should be called as normal using the locations of the source and   */
/* destination to decide whether the PHUNK is required.               */
/*                                                                    */
/* The pixblt functions are responsible for setting up the            */
/* appropriate real operations going via the PHUNK if necessary.      */
/*                                                                    */
/* If the mix is BM_DESTTRANSPARENT (the color compare register will  */
/* be set up with COLCOMP_EQUAL) then the blt can be done as normal.  */
/* (Both the XGA hardware and the software drawing (MESS) code        */
/* implement the correct function directly).                          */
/*                                                                    */
/* If the mix is BM_SRCTRANSPARENT (the color compare register will   */
/* be set up with COLCOMP_SRC_NOT_EQUAL) and the destination is in    */
/* system memory then the blt can be done as normal.  (The software   */
/* drawing (MESS) code implements the correct function directly).     */
/*                                                                    */
/* If the mix is BM_SRCTRANSPARENT (the color compare register will   */
/* be set up with COLCOMP_SRC_NOT_EQUAL) and the destination is in    */
/* VRAM then the blt can not be done as normal.  (The XGA hardware    */
/* does not implement the COLCOMP_SRC_NOT_EQUAL color compare         */
/* function). If the call was made to PixBltThroughClips then it will */
/* call PixBltThroughClipsViaPHUNK. The operation then splits into    */
/* 4 cases:                                                           */
/*                                                                    */
/*  1) The ROP is a source to destination copy to VRAM                */
/*  2) The background colour is 0                                     */
/*  3) The operation is from memory to VRAM                           */
/*  4) The operation is from VRAM to VRAM                             */
/*                                                                    */
/* Case 1) ROP 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) The background colour is 0. This special case can be       */
/*         simulated using the hardwares 'generate pattern from       */
/*         source' option.                                            */
/*                                                                    */
/*      a: Copy the source to the PHUNK.                              */
/*      b: Set up 'generate pattern from source' so that the          */
/*         background mix is HWMIX_DEST and the foreground mix        */
/*         is the mix required. Copy PHUNK to dest.                   */
/*                                                                    */
/* 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                                         */
/*                                                                    */
/* The low level assembly functions in eddhbblt are unchanged.        */
/*                                                                    */
/**********************************************************************/

/**********************************************************************/
/* Constants used while translating the background mix for            */
/* BM_SRCTRANSPARENT and BM_DESTRANSPARENT at 1bpp                    */
/**********************************************************************/
#define BM_SRCTRANSPARENT_1BPP_MASK     0x00000003
#define BM_DESTTRANSPARENT_1BPP_MASK    0x00000005

/**********************************************************************/
/* FUNCTION: The actual BitBlt entry call.                            */
/**********************************************************************/
DDIENTRY eddb_BitBlt (HDC                  hdc,
                      LHANDLE              ArgSource,
                      ULONG                ArgCount,
                      PLONG                ArgCoords,
                      ULONG                ArgRop,
                      ULONG                ArgOptions,
                      PBITBLTATTRS         ArgAttrs,
                      PDC                  pdcArg,
                      ULONG                FunN)


{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG               Error;        /* error value to be logged     */
    ULONG               CorrResult;   /* correlated result            */
    RECTS               TrgRect;      /* target coordinates           */
    RECTS               SrcRect;      /* source coordinates           */
    RECTS               ExcludeRect;  /* exclusion rectangle          */
    PDC                 pdcSrc;       /* source DC magic number       */
    ULONG               NewClipOrder; /* changed clip region order    */
    BOOL                ReOrderClips; /* TRUE if clip regions reorder */
    BOOL                fWorldCoords;   // flag for world coordinates
    ULONG               PhysPatColor;  /* pattern physical colour     */
    ULONG               PhysPatBackColor; /* pattern phys backgrd colr*/
    ULONG               LogPatColor;   /* pattern physical colour     */
    ULONG               LogPatBackColor;  /* pattern phys backgrd colr*/
    ULONG               PhysSrcColor;  /* source physical colour      */
    ULONG               PhysSrcBackColor; /* source phys backgrd color*/
    pBitmapHeader       DstBMHeader;   /* pointer to dest bm header   */
    pBitmapHeader       SrcBMHeader;   /* pointer to source bm header */
    pBltInst            Instruction;   /* next 3 way blt instruction  */
    ULONG               i;             /* loop variable               */
    ULONG               BltDirection;  /* pixel op direction octant   */
    ULONG               Blt3WayIndex;  /* index to 3way blt buffer    */

    ULONG               stretchReturnCode;
                                       /* <DCRTURBO>                  */
                                       /* Return code from function   */
                                       /* calls.                      */

/******************************************************************************/

    /******************************************************************/
    /* <DCRTURBO>                                                     */
    /******************************************************************/
    /******************************************************************/
    /* Initialize Stretch Checking return code as error value to      */
    /* indicate that no stretching validation has been done.          */
    /******************************************************************/
    stretchReturnCode = RC_ERROR;

/* @88638   OutputString("Entering eddb_BitBlt...");  */
/* @88638   haltproc();                               */

    /******************************************************************/
    /* rop independent set-up: early validation and set-up is         */
    /* independent of the rop being used                              */
    /******************************************************************/
    /******************************************************************/
    /* pass the call to the default handler if                        */
    /*  - the target coords are in World coords                       */
    /*  - the target rectangle and the source rectangle are           */
    /*      different sizes (implying compression or stretching)      */
    /*  - the target coords are not ordered bottom left, top right    */
    /* If COM_DEVICE is set we cannot return the call to the          */
    /* engine for simulation                                          */
    /******************************************************************/
    if ( !(FunNTest(COM_DEVICE)) )
    {
        if (  (ArgOptions & BBO_TARGWORLD)   ||
              ( (ArgCount >= 4) &&
                    ( (ArgCoords[2] - ArgCoords[0] !=
                       ArgCoords[6] - ArgCoords[4]) ||
                      (ArgCoords[3] - ArgCoords[1] !=
                       ArgCoords[7] - ArgCoords[5]) ) )   ||
              ( (ArgCoords[0] > ArgCoords[2]) ||
                (ArgCoords[1] > ArgCoords[3]) )   )
        {

            /**********************************************************/
            /* <DCRTURBO> - Begin changes.                            */
            /**********************************************************/
            /**********************************************************/
            /* If the following is true:                              */
            /*                                                        */
            /*    o There are four points in the ArgCoords.           */
            /*    o There is a differnece in the extents between      */
            /*      the source and destination blit areas.            */
            /*    o The target coordinates are not flipped in either  */
            /*      X and/or the Y direction.                         */
            /* ...then, call the stretch validation function to       */
            /* determine if the XGA driver can handle stretch         */
            /* function requested by the OS/2 Graphics Engine. If the */
            /* XGA Display Driver can handle it, this function will   */
            /* do the appropriate initialization to setup for the XGA */
            /* Display Driver stretch functions that will be called   */
            /* later on. Otherwise, the call will be passed back to   */
            /* the Graphics Engine for it to handle it.               */
            /**********************************************************/
            fWorldCoords = FALSE;
            if ((ArgCount >= 4)
                &&
                ((ArgCoords[2]-ArgCoords[0] != ArgCoords[6]-ArgCoords[4])
                  ||
                 (ArgCoords[3]-ArgCoords[1] != ArgCoords[7]-ArgCoords[5])
                )
                &&
                !((ArgCoords[0] > ArgCoords[2])
                   ||
                  (ArgCoords[1] > ArgCoords[3])
                )
               )
            {
                // If BBO_TARGWORLD is set, this is a WCBitBlt call and
                // the target rectangle is in world coordinates and is
                // inclusive/inclusive (vs. inclusive/exclusive) meaning
                // the top and right sides should be included in the blt.
                if (ArgOptions & BBO_TARGWORLD)
                {
                    fWorldCoords = TRUE;
                    ++ArgCoords[2];
                    ++ArgCoords[3];
                }

               stretchReturnCode = IsValidStretchRequest (hdc,
                  ArgSource,
                  ArgCoords,
                  ArgRop,
                  ArgOptions,
                  &pdcSrc,
                  &SrcRect,
                  pdcArg,
                  FunN
               );
            } /* if */

            /**********************************************************/
            /* If the return code is anything other than RC_OK, then  */
            /* pass control back to the Graphics Engine via a call    */
            /* back.                                                  */
            /**********************************************************/
            if (stretchReturnCode != RC_OK)
            {
                if (fWorldCoords)
                {
                    --ArgCoords[2];
                    --ArgCoords[3];
                }

               return( EnginesDispatchTable[NGreBitblt & 0xff](
                  hdc,
                  ArgSource,
                  ArgCount,
                  ArgCoords,
                  ArgRop,
                  ArgOptions,
                  ArgAttrs,
                  pdcArg,
                  FunN )
               );

            } /* if */

            /**********************************************************/
            /* <DCRTURBO> - End changes.                              */
            /**********************************************************/

        } /* if */
    } /* if */

    /******************************************************************/
    /* Bitblt is illegal within both a path and area: if it occurs    */
    /* then log an error and exit                                     */
    /******************************************************************/
    if ( FunNTest(COM_AREA | COM_PATH) )
    {
        if (FunNTest(COM_AREA))
        {
            Error = PMERR_INV_IN_AREA;
        }
        else
        {
            Error = PMERR_INV_IN_PATH;
        }

        goto BITBLT_FAST_LOGERR_EXIT;
    }

    /******************************************************************/
    /* Check for an invalid rop: this driver only allows 0 to 0xff    */
    /* plus 0x80ca (the grey rop)                                     */
    /******************************************************************/
    if (ArgRop & 0xFFFF7F00)
    {
        Error = PMERR_INV_BITBLT_MIX;

        goto BITBLT_FAST_LOGERR_EXIT;
    }

    /******************************************************************/
    /* At least two coordinates are needed for all rops (specifying   */
    /* the target). This is also checked by the gpi                   */
    /******************************************************************/
    if ( ArgCount < 2 )
    {
        Error = PMERR_INV_LENGTH_OR_COUNT;

        goto BITBLT_FAST_LOGERR_EXIT;
    }

    /******************************************************************/
    /* If the target rectangle is null then we can exit immediately.  */
    /******************************************************************/
    if ((ArgCoords[0] == ArgCoords[2]) ||
        (ArgCoords[1] == ArgCoords[3]) )
    {
        /******************************************************************/
        /* <DCRTURBO>                                                     */
        /******************************************************************/
        /* Set the global AIxfer flag to initialize the image stretch     */
        /* operation flag so that when a bitblt operation call is made    */
        /* it will not inadvertantly call the stretching function based   */
        /* on an indeterminant state of this global stretch flag.         */
        /******************************************************************/

        if (stretchReturnCode == RC_OK)
        {
            AIxfer.fStretching = FALSE;
            ExitDriver(pdcArg, FunN, EDF_STANDARD);
        }

        return(OK);
    }
    /******************************************************************/
    /* check for the grey rop: if selected then use rop 0xfa,         */
    /* foreground leavealone and background overpaint                 */
    /* (its not actually that close, but we can adjust it later on)   */
    /* note that the flag is still set in the high byte so we can     */
    /* still recognise this as being the GREY_ROP later               */
    /* All further use of ArgRop (except to identify the GREYROP) is  */
    /* done as (BYTE)ArgRop.                                          */
    /******************************************************************/
    if ( ArgRop & ROP_GREYROP_FLAG )
    {
        ArgRop = ROP_GREYROP | ROP_GREYROP_FLAG;
    }

    /******************************************************************/
    /* default to successful return code                              */
    /******************************************************************/
    CorrResult = OK;


    /******************************************************************/
    /* get exclusive access to the driver                             */
    /* If stretching, then we have already executed EnterDriver() in  */
    /* the stretch initialization functions, therefore bypass this    */
    /* EnterDriver() call.                                            */
    /******************************************************************/
    if (stretchReturnCode != RC_OK)
    {
       EnterDriver(pdcArg, FunN, EDF_STANDARD);

    } /* if */

    /******************************************************************/
    /* Set these up to be null EXPLICITLY before we do anything so we */
    /* can determine if they were allocated, and thus if they need to */
    /* be freed up on exit                                            */
    /******************************************************************/
    ExpPatBMHeader.Bitmap = NULL;
    pExpSrcBMHeader = NULL;

    /******************************************************************/
    /* Apply the DC command mask to the command bits                  */
    /******************************************************************/
    COMMANDBITS(FunN) &= pdc->DCICommandMask;

    /******************************************************************/
    /* The occasions when this variable is set are so complex I think */
    /* there are case when it doesnt get written to at all.           */
    /* Thus a line to initialize it.                                  */
    /******************************************************************/
    ReOrderClips = FALSE;

    /******************************************************************/
    /* If we are being asked to draw, the target device context must  */
    /* have a selected bitmap.                                        */
    /******************************************************************/
    if ( (FunNTest(COM_DRAW)) &&
         (pdc->DCIBitmapType == BITMAP_NOT_SELECTED) )
    {
        Error = PMERR_BITMAP_NOT_SELECTED;
        goto BITBLT_LOGERR_EXIT;
    }

    if ((FunNTest(COM_CORRELATE)) && (pdc->DCICorrInvalid))
    {
        /**************************************************************/
        /* Will be doing correlation so get the correlation rectangles*/
        /* up to date                                                 */
        /**************************************************************/
        if (! eddg_ClipPickWindow())
        {
            goto BITBLT_ERR_EXIT;
        }
    }

    /******************************************************************/
    /* the first word of the HAC parameter block is always a pointer  */
    /* to the destination bitmap header                               */
    /******************************************************************/
    AIxfer.pbmhDest = pdc->DCISelListEntry;

    /******************************************************************/
    /* PTR 56569                                                      */
    /* PTR 58867                                                      */
    /* If we are dead and the destination is the screen then we need  */
    /* to avoid drawing. We do this by turning off the COM_DRAW bit.  */
    /******************************************************************/
    if ( fXgaDead && (AIxfer.pbmhDest == &DirectListEntry) )
    {
        COMMANDBITS(FunN) &= ~((USHORT)(COM_DRAW >> 16));
    }

    /******************************************************************/
    /* Convert target co-ordinates into AI coordinates.  An           */
    /* an adjustment is applied to the target coordinates to allow    */
    /* for Winthorn having top and right edges exclusive.             */
    /******************************************************************/
    TrgRect.pts1.x = pdc->DCIOrigin.X + ArgCoords[0];
    TrgRect.pts2.x = pdc->DCIOrigin.X + ArgCoords[2] - 1;
    TrgRect.pts1.y = pdc->DCIConvFactor - ArgCoords[3] + 1;
    TrgRect.pts2.y = pdc->DCIConvFactor - ArgCoords[1];

    /******************************************************************/
    /* Set the colour compare condition that is in the shadow         */
    /* registers to the default value.                                */
    /*                                                                */
    /* Note: Setting the Color Compare test to TRUE will inhibit any  */
    /*       updates to the destination.  i.e.  Blt does nothing.     */
    /******************************************************************/

    #ifdef _8514
    Shadow8514Regs.Mode.PatternSrc = MD_PS_ONES;
    Shadow8514Regs.Mode.UnderPaint = MD_UP_FALSE;
    Shadow8514Regs.Mode.PlaneMode  = MD_AF_W_NORMAL;
    #else /* XGA */
    ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;
    #endif /* XGA */


/******************************************************************************/
    /******************************************************************/
    /* determine which of the four rop types is being used            */
    /* -  source and destination                                      */
    /* -  source, pattern and destination                             */
    /* -  pattern and destination                                     */
    /* -  destination only                                            */
    /******************************************************************/

    /******************************************************************/
    /* A source is required for this rop if bits 0,1 and 4,5 are      */
    /* different to bits 2,3 and 6,7                                  */
    /******************************************************************/
    if ( (((BYTE)ArgRop & 0x33)) << 2 !=
          ((BYTE)ArgRop & 0xcc) )
    {
        /**************************************************************/
        /* go and do those parts of the processing common to both     */
        /* source/destination and three-way blts                      */
        /**************************************************************/
        goto SOURCE_3WAY_COMMON;
    }
    else /* no source required */
    {
        /**************************************************************/
        /* go and do those parts of the processing common to both     */
        /* pattern/destination and destination only blts              */
        /**************************************************************/
        goto PATT_DSTONLY_COMMON;
    }

    /******************************************************************/
    /* code to handle the four different rop types                    */
    /* -  source and destination                                      */
    /* -  source, pattern and destination                             */
    /* -  pattern and destination                                     */
    /* -  destination only                                            */
    /******************************************************************/

    /******************************************************************/
    /* source and destination rop                                     */
    /******************************************************************/
SOURCE_3WAY_COMMON:
    /******************************************************************/
    /* at least three coordinates are required if a source is         */
    /* specified: two for the target and one for the source bottom    */
    /* left corner. If there are more than three coordinates the      */
    /* others are ignored, the source size being taken to be the same */
    /* as the target (if the source is fully specified and it is a    */
    /* different size to the target the blt will have been passed to  */
    /* the default handler earlier)                                   */
    /******************************************************************/
    if ( ArgCount < 3 )
    {
        Error = PMERR_INV_LENGTH_OR_COUNT;
        goto BITBLT_LOGERR_EXIT;
    }
    /******************************************************************/
    /* <DCRTURBO>                                                     */
    /******************************************************************/
    /* If we are stretching the image, then we do not need to do      */
    /* any initiailization for the blitting since the stretch         */
    /* initialization routines have already done this for us.         */
    /* (see STRETCH.C)                                                */
    /******************************************************************/
    if (!AIxfer.fStretching)
    {
       /***************************************************************/
       /* The options parameter has a bit indicating if the source    */
       /* parameter is a bitmap handle or dc handle                   */
       /***************************************************************/
       if (ArgOptions & BLTMODE_SRC_BITMAP)
       {
           /***********************************************************/
           /* The source is a bitmap handle. Use Get Driver Info to   */
           /* get driver magic number (a pointer to the bitmap header)*/
           /* associated with this handle                             */
           /***********************************************************/
           if ( ((AIxfer.pbmhSrc) =
           (pBitmapHeader)GetDriverInfo32(ArgSource, DI_HBITMAP, hdc)) ==
           (pBitmapHeader)ERROR_NEG)
           {
               CorrResult = ERROR_ZERO;
               goto BITBLT_EXIT;
           }


           /***********************************************************/
           /* calculate the bottom left x coordinate and the top      */
           /* right y coordinate                                      */
           /* the other two coordinates can be calculated later       */
           /* using these values and the target coordinates           */
           /***********************************************************/
           SrcRect.pts1.x = ArgCoords[4];
           SrcRect.pts2.y = AIxfer.pbmhSrc->Info.HWHeight - ArgCoords[5];

#ifdef PALETTE_MGR
           /***********************************************************/
           /* Set pdcSrc to NULL so that we can pass it to            */
           /* eddb_CreatePalMapping so that it knows there is no      */
           /* source DC.                                              */
           /***********************************************************/
           pdcSrc = FNULL;
#endif /* PALETTE_MGR */

       }
       else
       {
           /***********************************************************/
           /* The source is a DC handle. Use GetDriverInfo32 to get th*/
           /* driver magic number (a pointer to the DC instance data) */
           /* associated with this handle                             */
           /***********************************************************/
           if ( ( pdcSrc =
           (PDC)GetDriverInfo32( ArgSource, DI_HDC, hdc) ) ==
           (PDC)ERROR_NEG )
           {
               CorrResult = ERROR_ZERO;
               goto BITBLT_EXIT;
           }

           /***********************************************************/
           /* the source must have a currently selected bitmap from   */
           /* which the data to be bltted is taken                    */
           /***********************************************************/
           if (pdcSrc->DCIBitmapType == BITMAP_NOT_SELECTED)
           {
               Error = PMERR_BITMAP_NOT_SELECTED;
               goto BITBLT_LOGERR_EXIT;
           }

           AIxfer.pbmhSrc = pdcSrc->DCISelListEntry;

           /***********************************************************/
           /* calculate the bottom left x coordinate and the top      */
           /* right y coordinate                                      */
           /* the other two coordinates can be calculated later       */
           /* using these values and the target coordinates           */
           /***********************************************************/
           /***********************************************************/
           /* Having to support the COM_TRANSFORM bit here is a new   */
           /* requirement which occured due to the flood fill algorith*/
           /* in the engine.                                          */
           /*                                                         */
           /* This code for when the transform bit is set works, but  */
           /* this is not really documented, so be aware that this may*/
           /* need further work.                                      */
           /***********************************************************/
           if ( FunNTest(COM_TRANSFORM) )
           {
               /*******************************************************/
               /* The source coordinates are relative to the DC origin*/
               /* convert them.                                       */
               /*******************************************************/
               SrcRect.pts1.x = pdcSrc->DCIOrigin.X + ArgCoords[4];
               SrcRect.pts2.y = pdcSrc->DCIConvFactor - ArgCoords[5];
           }
           else
           {
               /*******************************************************/
               /* The source coordinates are not relative to the DC,  */
               /* simply flip the Y coordinate.                       */
               /*******************************************************/
               SrcRect.pts1.x = ArgCoords[4];
               SrcRect.pts2.y = pdcSrc->DCISelListEntry->Info.HWHeight -
                                ArgCoords[5];
           } /* else */
       } /* else */
    } /* if */

    /******************************************************************/
    /* If we are dead and the source is the screen then we need       */
    /* to avoid drawing. We do this by turning off the COM_DRAW bit.  */
    /******************************************************************/
    if ( fXgaDead && (AIxfer.pbmhSrc == &DirectListEntry) )
    {
        COMMANDBITS(FunN) &= ~((USHORT)(COM_DRAW >> 16));
    }

    /******************************************************************/
    /* calculate the source rectangle top right x coordinate and the  */
    /* bottom left y coordinate, using the dimensions of the target   */
    /* rectangle                                                      */
    /******************************************************************/
    SrcRect.pts2.x = SrcRect.pts1.x + TrgRect.pts2.x - TrgRect.pts1.x;
    SrcRect.pts1.y = SrcRect.pts2.y + TrgRect.pts1.y - TrgRect.pts2.y;

    if (SrcRect.pts1.x < 0)
    {
        /**************************************************************/
        /* left edge is to the left of the bitmap                     */
        /**************************************************************/

        if (SrcRect.pts2.x < 0)
        {
            /**********************************************************/
            /* right edge is also to the left of the bitmap, ie. the  */
            /* source is entirely outwith the bitamp so exit          */
            /**********************************************************/
            goto BITBLT_EXIT;
        }

        /**************************************************************/
        /* right edge is within or to right of the bitmap, so adjust  */
        /* the source left edge to be the edge of the bitmap and      */
        /* adjust the left edge of the target by the same amount      */
        /**************************************************************/
        TrgRect.pts1.x -= SrcRect.pts1.x;
        SrcRect.pts1.x = 0;
    }

    if (SrcRect.pts1.y < 0)
    {
        /**************************************************************/
        /* bottom edge is below the bottom of the bitmap              */
        /**************************************************************/

        if (SrcRect.pts2.y < 0)
        {
            /**********************************************************/
            /* top edge is also below the bottom of the bitmap, ie the*/
            /* source is entirely outwith the bitamp so exit          */
            /**********************************************************/
            goto BITBLT_EXIT;
        }

        /**************************************************************/
        /* top edge is within or above top of the bitmap, so adjust   */
        /* the source bottom edge to be the edge of the bitmap and    */
        /* adjust the bottom edge of the target by the same amount    */
        /**************************************************************/
        TrgRect.pts1.y -= SrcRect.pts1.y;
        SrcRect.pts1.y = 0;
    }

    if (SrcRect.pts2.x > AIxfer.pbmhSrc->Info.HWWidth)
    {
        /**************************************************************/
        /* right edge is to the right of the bitmap                   */
        /**************************************************************/

        if (SrcRect.pts1.x > AIxfer.pbmhSrc->Info.HWWidth)
        {
            /**********************************************************/
            /* left edge is also to the right of the bitmap, ie. the  */
            /* source is entirely outwith the bitamp so exit          */
            /**********************************************************/
            goto BITBLT_EXIT;
        }

        /**************************************************************/
        /* left edge is within the bitmap, so adjust the source right */
        /* edge to be the edge of the bitmap and adjust the right edge*/
        /* of the target by the same amount                           */
        /**************************************************************/
        TrgRect.pts2.x -= SrcRect.pts2.x - AIxfer.pbmhSrc->Info.HWWidth;
        SrcRect.pts2.x = AIxfer.pbmhSrc->Info.HWWidth;
    }

    if (SrcRect.pts2.y > AIxfer.pbmhSrc->Info.HWHeight)
    {
        /**************************************************************/
        /* top edge is above the top of the bitmap                    */
        /**************************************************************/

        if (SrcRect.pts1.y > AIxfer.pbmhSrc->Info.HWHeight)
        {
            /**********************************************************/
            /* bottom edge is also above the top of the bitmap, ie the*/
            /* source is entirely outwith the bitamp so exit          */
            /**********************************************************/
            goto BITBLT_EXIT;
        }

        /**************************************************************/
        /* bottom edge is within the bitmap, so adjust the source top */
        /* edge to be the edge of the bitmap and adjust the edge of   */
        /* the target by the same amount                              */
        /**************************************************************/
        TrgRect.pts2.y -= SrcRect.pts2.y - AIxfer.pbmhSrc->Info.HWHeight;
        SrcRect.pts2.y = AIxfer.pbmhSrc->Info.HWHeight;
    }

    /******************************************************************/
    /* update bounds to target rectangle; the bounds are not          */
    /* affected by clipping of the target                             */
    /******************************************************************/
    if ( FunNTest(COM_ALT_BOUND | COM_BOUND) )
    {
        eddg_AddBounds ((pDevRect)&TrgRect,
                         FunN,
                         COORD_AI);
    }

#ifdef DCAF                                                               //DCAF
    /******************************************************************/  //DCAF
    /* Accumulate DCAF screen bounds if required                      */  //DCAF
    /******************************************************************/  //DCAF
    if ( DCAFBoundsRequired(FunN) )                                       //DCAF
    {                                                                     //DCAF
        AccumulateScreenBoundsThroughClips( (pDevRect)&TrgRect,           //DCAF
                                            COORD_AI );                   //DCAF
    }                                                                     //DCAF
#endif                                                                    //DCAF

    /******************************************************************/
    /* if correlate bit is set then do the correlation                */
    /******************************************************************/
    if ( FunNTest(COM_CORRELATE) && (pdc->DCICorrNum))
    {
        CorrResult = eddg_CheckRectCorrelation(
                                  (pDevRect)&TrgRect);
    }

    /******************************************************************/
    /* if the draw bit is reset, no further work is required          */
    /******************************************************************/
    if ( !(FunNTest(COM_DRAW)) )
    {
        goto BITBLT_EXIT;
    }

    /******************************************************************/
    /* calculate the blt dimensions and put the starting coordinate   */
    /* in the parameter block, clipping the target to the bitmap      */
    /******************************************************************/
    if ( TrgRect.pts1.x < 0 )
    {
        /**************************************************************/
        /* exit now if the the right edge of the target is to the left*/
        /* of the left edge                                           */
        /**************************************************************/
        if ( TrgRect.pts2.x < 0 )
        {
            goto BITBLT_EXIT;
        }

        AIxfer.rcsSrc.pts1.x = SrcRect.pts1.x - TrgRect.pts1.x;
        AIxfer.rcsTrg.pts1.x = 0;
    }
    else
    {
        AIxfer.rcsSrc.pts1.x = SrcRect.pts1.x;
        AIxfer.rcsTrg.pts1.x = TrgRect.pts1.x;
    }

    /******************************************************************/
    /* if the bottom edge of the target is below  the bottom of the   */
    /* bitmap then set the destination y coordinate to 0 (the bottom  */
    /* edge of the bitmap), otherwise use the calculated coordinate   */
    /******************************************************************/
    if ( TrgRect.pts1.y < 0 )
    {
        /**************************************************************/
        /* exit now if the the top edge of the target is below the    */
        /* bottom edge                                                */
        /**************************************************************/
        if ( TrgRect.pts2.y < 0 )
        {
            goto BITBLT_EXIT;
        }

        AIxfer.rcsSrc.pts1.y = SrcRect.pts1.y - TrgRect.pts1.y;
        AIxfer.rcsTrg.pts1.y = 0;

    }
    else
    {
        AIxfer.rcsSrc.pts1.y = SrcRect.pts1.y;
        AIxfer.rcsTrg.pts1.y = TrgRect.pts1.y;
    }

    /******************************************************************/
    /* if the right edge of the target is to the right of the bitmap  */
    /* then set the right edge to be the bitmap hardware width,       */
    /* otherwise use the calculated right edge                        */
    /******************************************************************/
    if ( TrgRect.pts2.x > AIxfer.pbmhDest->Info.HWWidth)
    {
        AIxfer.rcsSrc.pts2.x = SrcRect.pts2.x - (TrgRect.pts2.x -
                                      AIxfer.pbmhDest->Info.HWWidth);
        AIxfer.rcsTrg.pts2.x = AIxfer.pbmhDest->Info.HWWidth;
    }
    else
    {
        AIxfer.rcsSrc.pts2.x = SrcRect.pts2.x;
        AIxfer.rcsTrg.pts2.x = TrgRect.pts2.x;
    }

    if ( AIxfer.rcsTrg.pts1.x > AIxfer.rcsTrg.pts2.x)
    {
        goto BITBLT_EXIT;
    }

    /******************************************************************/
    /* if the top edge of the target is above the top of the bitmap,  */
    /* then set the top edge to be the bitmap hardware height,        */
    /* otherwise use the calculated top edge                          */
    /******************************************************************/
    if ( TrgRect.pts2.y > AIxfer.pbmhDest->Info.HWHeight )
    {
        AIxfer.rcsSrc.pts2.y = SrcRect.pts2.y - (TrgRect.pts2.y -
                                     AIxfer.pbmhDest->Info.HWHeight);
        AIxfer.rcsTrg.pts2.y = AIxfer.pbmhDest->Info.HWHeight;
    }
    else
    {
        AIxfer.rcsSrc.pts2.y = SrcRect.pts2.y;
        AIxfer.rcsTrg.pts2.y = TrgRect.pts2.y;
    }
    if ( AIxfer.rcsTrg.pts1.y > AIxfer.rcsTrg.pts2.y)
    {
        goto BITBLT_EXIT;
    }

    /******************************************************************/
    /* if necessary, exclude the cursor (and disable further cursor   */
    /* drawing until we're finished with the hardware).               */
    /******************************************************************/
    if ( cursor_data.cursor_status & CURSOR_SOFTWARE )
    {
        if (pdc->DCIBitmapType == BITMAP_IS_SCREEN)
        {
            if (!AIxfer.pbmhSrc->Bitmap)
            {
                /******************************************************/
                /* both desination and the source are the screen      */
                /* so exclude from the rectangle which includes both  */
                /* the source and the desination                      */
                /******************************************************/
                ExcludeRect.pts1.x = min(AIxfer.rcsTrg.pts1.x,
                                         AIxfer.rcsSrc.pts1.x);
                ExcludeRect.pts2.x = max(AIxfer.rcsTrg.pts2.x,
                                         AIxfer.rcsSrc.pts2.x);
                ExcludeRect.pts1.y = min(AIxfer.rcsTrg.pts1.y,
                                         AIxfer.rcsSrc.pts1.y);
                ExcludeRect.pts2.y = max(AIxfer.rcsTrg.pts2.y,
                                         AIxfer.rcsSrc.pts2.y);
                eddm_ExcludeCursor((pDevPoint)&ExcludeRect, COORD_AI);
            }
            else
            {
                /******************************************************/
                /* exclude from the target rectangle                  */
                /******************************************************/
                eddm_ExcludeCursor((pDevPoint)&AIxfer.rcsTrg, COORD_AI);
            }
        }
        else if (!AIxfer.pbmhSrc->Bitmap)
        {
            /**********************************************************/
            /* source is the screen so exclude from the source        */
            /**********************************************************/
            eddm_ExcludeCursor((pDevPoint)&AIxfer.rcsSrc,
                               COORD_AI | CALLED_FROM_BLT);
        }
        else
        {
            /**********************************************************/
            /* neither the source or the target are the screen but    */
            /* we must at least disable the cursor drawing because    */
            /* we need to use the hardware                            */
            /**********************************************************/
            disable_cursor();
        }
    } /* software cursor active */

    /******************************************************************/
    /* now find out if this is a 3-way blt or just source and dest    */
    /* and go and finish it off                                       */
    /* a pattern is required (3-way blt) if the high and low nibbles  */
    /* of the rop are not equal                                       */
    /******************************************************************/
    if ( (((BYTE)ArgRop >> 4) ^ (BYTE)ArgRop) & 0x0f  )
    {
        goto THREE_WAY_BLT;
    }
    else /* no pattern required */
    {
        goto SRC_DST_BLT;
    }

/******************************************************************************/
SRC_DST_BLT:

#ifdef SDBM20
#ifdef PALETTE_MGR
    /******************************************************************/
    /* If both the source and destination are colour bitmaps and      */
    /* they are not the same bitmap then we want to call              */
    /* eddb_CreatePalMapping. If a palette mapping is required        */
    /* then usePaletteMapping will be set.                            */
    /******************************************************************/

    if ( (AIxfer.pbmhDest->Info.BitCount != 1)
      && (AIxfer.pbmhSrc->Info.BitCount != 1)
      && (AIxfer.pbmhDest != AIxfer.pbmhSrc)
      && (!(ArgOptions & BBO_NO_COLOR_INFO)) )
    {
        eddb_CreatePalMapping( pdcSrc );

#ifdef VRAMPTR
        /**************************************************************/
        /* If we are doing a palette mapping then we need to get the  */
        /* bitmap out of the cache as the mapping is done on the fly  */
        /* by software drawing.                                       */
        /**************************************************************/
        if ( UsePaletteMapping )
        {
           if ( BITMAP_IS_CACHED(AIxfer.pbmhSrc) )
           {
             evict_cached_bitmap(AIxfer.pbmhSrc->bm_cache_slot);
           }
        }
#endif /* VRAMPTR */
    }
#endif /* PALETTE_MGR */

    /**************************************************************/
    /* Now it is time to set the drawing mode correctly..         */
    /**************************************************************/
    /**************************************************************/
    /* Here is the plan:                                          */
    /*                                                            */
    /* If the source and destination are both the screen then we  */
    /* will use hardware drawing mode.                            */
    /*                                                            */
    /* If the destination is the screen and the source is a bitmap*/
    /* then we will copy the source to the PHUNK and use hardware */
    /* drawing mode.                                              */
    /*                                                            */
    /* 8514 will use custom routines for this case !!!            */
    /*                                                            */
    /* If the source is the screen and the destination is a bitmap*/
    /* then we will copy the source to the PHUNK and use software */
    /* drawing mode.                                              */
    /*                                                            */
    /* If the source and destination are both bitmaps then we will*/
    /* use software drawing mode.                                 */
    /*                                                            */
    /**************************************************************/
#ifdef PALETTE_MGR
    /**************************************************************/
    /* Here is the rest of the plan:                              */
    /*                                                            */
    /* When blting from screen to screen we will never need to do */
    /* any palette conversions. (All palette conversion are done  */
    /* using a nearest RGB match from the source bitmap palette   */
    /* to the destination bitmap palette. This is simpler than    */
    /* considering the individual DCs that might be contained in  */
    /* the screen especially as converting from an RGB value to   */
    /* a palette index is not a reversible process and could lead */
    /* to the       colour conversion being carried out.)         */
    /*                                                            */
    /* When blting from screen to memory or memory to memory we   */
    /* will be in software drawing mode. The palette conversion   */
    /* will be done as part of the software emulation of the blt  */
    /* by the eddf_mess blting functions.                         */
    /*                                                            */
    /* When blting from memory to screen we will be in hardware   */
    /* drawing mode. The source (memory bitmap) will be copied    */
    /* to the PHUNK and the palette conversion will be done as    */
    /* an intermediate operation on the PHUNK by a ConvertPHUNK   */
    /* call.                                                      */
    /*                                                            */
    /**************************************************************/
#endif /* PALETTE_MGR */

    if (AIxfer.pbmhDest == &DirectListEntry)
    {
        SetDrawModeHard;
    }
    else
    {
        SetDrawModeSoft;
    }

#endif /* SDBM20 */

    /******************************************************************/
    /* if the destination bitmap is in screen format but the          */
    /* source is monochrome then the blt must be expanding. The       */
    /* hardware allows expansion only for the pattern pixel map so    */
    /* we must use a pattern and destination blt to achieve this      */
    /******************************************************************/
    if ( (AIxfer.pbmhDest->Info.BitCount != 1) &&
         (AIxfer.pbmhSrc->Info.BitCount == 1) )
    {
        /**************************************************************/
        /* initialise the pixel operation to be used                  */
        /* -  background source: background colour                    */
        /* -  foreground source: foreground colour                    */
        /* -  step: PxBlt                                             */
        /* -  source pixel map: don't care                            */
        /* -  destination pixel map: Map A                            */
        /* -  pattern pixel map: Map C                                */
        /* -  mask pixel map: disabled                                */
        /* -  drawing mode: don't care                                */
        /* -  direction octant: left to right, top to bottom          */
        /**************************************************************/
        PixelOp = BACK_SRC_BACK_COL |
                  FORE_SRC_FORE_COL |
                  STEP_PXBLT |
                  SRC_PIX_MAP_DONTCARE |
                  DST_PIX_MAP_A |
                  PAT_PIX_MAP_C |
                  MASK_PIX_MAP_OFF |
                  DRAW_MODE_DONTCARE |
                  DIR_OCTANT_LRTB;
        /**************************************************************/
        /* set the foreground and background colours for the blt.     */
        /* These are taken from the target atrribute bundle           */
        /* unless colour information was passed in the parameters     */
        /**************************************************************/
        #ifndef   _8514
        if (ArgOptions & BLTMODE_ATTRS_PRES)
        {
            ShadowXGARegs.FgCol = (USHORT)LogToPhyIndex(ArgAttrs->lColor);
            ShadowXGARegs.BgCol = (USHORT)LogToPhyIndex(ArgAttrs->lBackColor);
        }
        else /* use attribute bundle colours */
        {
            ShadowXGARegs.FgCol = (USHORT)pdc->DCIImagColatts.ForeColor;
            ShadowXGARegs.BgCol = (USHORT)pdc->DCIImagColatts.BackColor;
        }
        #else
        /**************************************************************/
        /* set the foreground and background colours for the blt.     */
        /* These are taken from the target atrribute bundle           */
        /* unless colour information was passed in the parameters     */
        /**************************************************************/
        if (ArgOptions & BLTMODE_ATTRS_PRES)
        {
            Shadow8514Regs.Color_1 = LogToPhyIndex(ArgAttrs->lColor);
            Shadow8514Regs.Color_0 = LogToPhyIndex(ArgAttrs->lBackColor);
        }
        else /* use attribute bundle colours */
        {
            Shadow8514Regs.Color_1 = pdc->DCIImagColatts.ForeColor;
            Shadow8514Regs.Color_0 = pdc->DCIImagColatts.BackColor;
        }

        // @DMS look into making all blts do this !!!
        if ( pdc->DCIChanged & (NOTDEFAULT_ImagAttrs + NEW_MARKER_SYMBOL) )
        {
          if ( BITMAP_IS_CACHED(AIxfer.pbmhSrc) )
          {
            evict_cached_bitmap(AIxfer.pbmhSrc->bm_cache_slot);
          }
        }
        #endif

    }

    else /* same source, target formats OR mono target, colour source */
    {
        /**************************************************************/
        /* initialise the pixel operation to be used                  */
        /* -  background source: source pixel map                     */
        /* -  foreground source: source pixel map                     */
        /* -  step: PxBlt                                             */
        /* -  source pixel map: Map B                                 */
        /* -  destination pixel map: Map A                            */
        /* -  pattern pixel map: foreground (fixed)                   */
        /* -  mask pixel map: disabled                                */
        /* -  drawing mode: don't care                                */
        /* -  direction octant: left to right, top to bottom          */
        /**************************************************************/
        PixelOp = 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;

        /**************************************************************/
        /* See if we are doing a copy between same format bitmaps     */
        /* or the color source, mono target case.                     */
        /**************************************************************/
        #ifdef   _8514
        if (!UseSoftwareMix(pdc->DCICurImgAts.ibnd.usBackMixMode))
        #endif
        if ( AIxfer.pbmhDest->Info.BitCount ==
             AIxfer.pbmhSrc->Info.BitCount )
        {

            /**************************************************************/
            /* if the source and target are the same format then they may */
            /* be the same bitmap: if so, care must be taken in the       */
            /* ordering of clip regions when the source and target        */
            /* overlap, to ensure parts of the source are not overwritten */
            /* before being read.                                         */
            /* Also, the direction of the bitmap must be considered, for  */
            /* the same reason.                                           */
            /**************************************************************/
            /**********************************************************/
            /* determine if the source and target are in the same     */
            /* bitmap and are overlapping                             */
            /**********************************************************/
            if ( (AIxfer.pbmhDest ==
                  AIxfer.pbmhSrc)
             &&( ((TrgRect.pts1.x <= SrcRect.pts2.x) &&
                  (TrgRect.pts2.x >= SrcRect.pts1.x)) ||
                 ((TrgRect.pts1.y <= SrcRect.pts2.y) &&
                  (TrgRect.pts2.y >= SrcRect.pts1.y)) ) )
            {
                /******************************************************/
                /* if the source left edge is to the left of the      */
                /* destination left edge then we clip in a right to   */
                /* left direction. If the current horizontal          */
                /* direction is left to right then set the            */
                /* ReOrderClips flag to indicate reordering           */
                /******************************************************/
                if (SrcRect.pts1.x < TrgRect.pts1.x)
                {
                    ReOrderClips =
                     ( (pdc->DCIEngineClips > 1) &&
                      ((pdc->DCIClipOrder == RECTDIR_LFRT_TOPBOT) ||
                       (pdc->DCIClipOrder == RECTDIR_LFRT_BOTTOP)) );

                    /**************************************************/
                    /* The value to pass to the engine for right to   */
                    /* left clipping is 2.                            */
                    /**************************************************/
                    NewClipOrder = 2;
                }

                else /* blt in left to right direction */
                {
                    /**************************************************/
                    /* the value to pass to the engine for left to    */
                    /* right clip region ordering is 1.               */
                    /**************************************************/
                    NewClipOrder = 1;

                    /**************************************************/
                    /* if current clip order is right to left then    */
                    /* set ReOrderClips to indicate we need a change  */
                    /**************************************************/
                    ReOrderClips =
                     ( (pdc->DCIEngineClips > 1) &&
                       (SrcRect.pts1.x > TrgRect.pts1.x) &&
                      ((pdc->DCIClipOrder == RECTDIR_RTLF_TOPBOT) ||
                       (pdc->DCIClipOrder == RECTDIR_RTLF_BOTTOP)) );
                }


                /******************************************************/
                /* if the source is above the destination then we     */
                /* blt in a top to bottom direction (remember h/w and */
                /* Winthorn coordinates are inverted in y). If the    */
                /* current direction is bottom to top then set the    */
                /* ReOrderClips flag to indicate reordering           */
                /******************************************************/
                if ( SrcRect.pts1.y > TrgRect.pts1.y )
                {
                    ReOrderClips |=
                     ( (pdc->DCIEngineClips > 1) &&
                      ((pdc->DCIClipOrder == RECTDIR_LFRT_BOTTOP) ||
                       (pdc->DCIClipOrder == RECTDIR_RTLF_BOTTOP)) );
                }
                else if ( SrcRect.pts1.y < TrgRect.pts1.y )
                {
                    NewClipOrder += 2;

                    ReOrderClips |=
                     ( (pdc->DCIEngineClips > 1) &&
                      ((pdc->DCIClipOrder == RECTDIR_LFRT_TOPBOT) ||
                       (pdc->DCIClipOrder == RECTDIR_RTLF_TOPBOT)) );
                }

                /******************************************************/
                /* change the pixel op direction octant if the blt    */
                /* direction is not left to right, top to bottom      */
                /* If the direction is changed the start coords       */
                /* must be altered to reflect this                    */
                /******************************************************/
                switch (NewClipOrder)
                {
                    case 1:
                        /**********************************************/
                        /* nothing: use the left to right, top to     */
                        /* bottom already set up                      */
                        /**********************************************/
                        break;

                    case 2:
                        /**********************************************/
                        /* set right to left, top to bottom           */
                        /**********************************************/
                        PixelOp ^= DIR_OCTANT_LRTB ^ DIR_OCTANT_RLTB;
                        break;

                    case 3:
                        /**********************************************/
                        /* set left to right, bottom to top           */
                        /**********************************************/
                        PixelOp ^= DIR_OCTANT_LRTB ^ DIR_OCTANT_LRBT;
                        break;

                    case 4:
                        /**********************************************/
                        /* set right to left, bottom to top           */
                        /**********************************************/
                        PixelOp ^= DIR_OCTANT_LRTB ^ DIR_OCTANT_RLBT;
                        break;
                }

                /******************************************************/
                /* If the clips have changed or there are too many    */
                /* clips for the cache ensure that we get information */
                /* upto date to call back to the engine               */
                /******************************************************/
                if ( (pdc->DCIEngineClips > CACHED_CLIPS) ||
                                                   pdc->ClipChanged )
                {
                    ReOrderClips = TRUE;
                }

                /******************************************************/
                /* If we need to reorder the clip rectangles then set */
                /* the new order in the GetClips control structure    */
                /* and indicate that the clips have changed to ensure */
                /* that we always get the clip rectangles in the new  */
                /* order                                              */
                /******************************************************/
                if ( ReOrderClips )
                {
                    pdc->DCIClipOrder = NewClipOrder;
#ifdef POST174
                    GetClipsControl.ulDirection = NewClipOrder;
#else /* POST174 */
                    GetClipsControl.usDirection = NewClipOrder;
#endif /* POST174 */
                    pdc->ClipChanged = TRUE;
                }
            } /* overlapping source and destination */
        }
        else /* colour source, mono target */
        {
            /**************************************************************/
            /* if the source and target are not the same then the source  */
            /* is colour and the target mono (since colour target, mono   */
            /* source detected above).                                    */
            /* The hardware isn't up to this challenge so we need to      */
            /* compress the source using software                         */
            /**************************************************************/
            AIxfer.pbmhSrc = convert_colour_to_mono(FunN,
                                                    ArgOptions,
                                                    ArgAttrs,
                                                    pdcSrc);
            if (AIxfer.pbmhSrc == FNULL)
            {
                goto BITBLT_ERR_EXIT;
            }
        }
    // @DMS should set src.select to copy here

    } /* same source, target formats OR mono target, colour source */

    /******************************************************************/
    /* set the foreground and background mixes                        */
    /******************************************************************/
    #ifdef _8514
    Shadow8514Regs.Function_1.SrcSelect = FUNC_2OP_COPY;
    Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COPY;
    Shadow8514Regs.Function_1.Mix = RopToHWMix[(BYTE)ArgRop >> 4];
    Shadow8514Regs.Function_0.Mix = RopToHWMix[(BYTE)ArgRop & 0x0f];
    #else /* XGA */
    ShadowXGARegs.FgMix = RopToHWMix[(BYTE)ArgRop >> 4];
    ShadowXGARegs.BgMix = RopToHWMix[(BYTE)ArgRop & 0x0f];
    #endif /* XGA */

    /******************************************************************/
    /* We need to check for the new (to OS/2 2.0) background mixes,   */
    /* BM_SRCTRANSPARENT and BM_DESTTRANSPARENT. With 1bpp these      */
    /* mixes can be achieved by modifying the hardware mix value,     */
    /* otherwise the colour compare registers can be used.            */
    /*                                                                */
    /* The above mixes can be achieved by setting the colour compare  */
    /* value to the current background colour and the colour compare  */
    /* condition to:                                                  */
    /*     COLCOMP_EQUAL for BM_DESTTRANSPARENT and                   */
    /*     COLCOMP_SRC_NOT_EQUAL for BM_SRCTRANSPARENT                */
    /*                                                                */
    /******************************************************************/
    if (UseColorCompare(pdc->DCICurImgAts.ibnd.usBackMixMode))
    {
        /**************************************************************/
        /* set up the colour compare registers to allow for the       */
        /* background mix                                             */
        /**************************************************************/
        convert_BMix_to_ColComp(ArgOptions, ArgAttrs);

    }

    /******************************************************************/
    /* transfer the values we have set in the shadow registers to the */
    /* values in the real hw registers if needed                      */
    /*                                                                */
    /* If we are doing a BM_SRCTRANSPARENT operation the ColCompCond  */
    /* register contains a code only recognised by the MESS (software */
    /* drawing), and the actual blt will be implemented via several   */
    /* intermidiate blts. We don't therefore want to transfer the     */
    /* registers when we have BM_SRCTRANSPARENT set.                  */
    /******************************************************************/
    if (!UseSoftwareMix(pdc->DCICurImgAts.ibnd.usBackMixMode))
    {
         TransferShadowRegisters( TSR_COLOUR_MIX );
    }

    /******************************************************************/
    /* Set-up complete, so blt the source to the destination.         */
    /******************************************************************/
    SPad.BltFunction = (*pDrawFunctions)[index_SrcDestBlt];

    /******************************************************************/
    /* If the source and the destination are not both VRAM or both    */
    /* system memory then we must blt via the PHUNK.                  */
    /* 74206 -- must go ViaPHUNK if we are stretching                 */
    /******************************************************************/
    if ( !AIxfer.fStretching &&
         ((AIxfer.pbmhSrc  != &DirectListEntry &&
           AIxfer.pbmhDest != &DirectListEntry)
       || (AIxfer.pbmhDest == &DirectListEntry &&
           AIxfer.pbmhSrc->BMPhys != NULL)) )
    {
        PixBltThroughClips();
    }
    else
    {
        PixBltThroughClipsViaPHUNK();
    }


#ifdef VRAMPTR
    /******************************************************************/
    /* If the target bitmap is cached then evict it since it has      */
    /* been drawn to.                                                 */
    /******************************************************************/
    if ( BITMAP_IS_CACHED(AIxfer.pbmhDest) )
    {
      evict_cached_bitmap(AIxfer.pbmhDest->bm_cache_slot);
    }
#endif /* VRAMPTR */

    goto BITBLT_EXIT;
    /******************************************************************/
    /* source, pattern and destination rop                            */
    /******************************************************************/
THREE_WAY_BLT:

    /******************************************************************/
    /* All three way blts require a pattern. If the pattern symbol or */
    /* set has changed then we need to get the new data               */
    /******************************************************************/
    if ( pdc->DCIChanged & NEW_PATTERN_SYMBOL )
    {
        if ( !edda_PatternSetUp() )
        {
            goto BITBLT_ERR_EXIT;
        }
    }

    /******************************************************************/
    /* keep a copy of the bitmap header pointers since we             */
    /* may overwrite the AIxfer data block                            */
    /******************************************************************/
    DstBMHeader = AIxfer.pbmhDest;
    SrcBMHeader = AIxfer.pbmhSrc;

    /******************************************************************/
    /* get the logical pattern colours (these are either passed in as */
    /* parameters or taken from the target pattern attribute bundle)  */
    /* and convert to the physical colours used by the hardware       */
    /******************************************************************/
    if (ArgOptions & BLTMODE_ATTRS_PRES)
    {
        PhysPatColor     = LogToPhyIndex(ArgAttrs->lColor);
        PhysPatBackColor = LogToPhyIndex(ArgAttrs->lBackColor);
    }
    else /* use attribute bundle colours */
    {
        PhysPatColor     = pdc->DCIPattColatts.ForeColor;
        PhysPatBackColor = pdc->DCIPattColatts.BackColor;
    }


    /******************************************************************/
    /* keep a copy of the destination and source rectangles as these  */
    /* are altered in the parameter block for each operation          */
    /* comprising the blt                                             */
    /******************************************************************/
    TrgRect.pts1 = AIxfer.rcsTrg.pts1;
    TrgRect.pts2 = AIxfer.rcsTrg.pts2;
    SrcRect.pts1 = AIxfer.rcsSrc.pts1;
    SrcRect.pts2 = AIxfer.rcsSrc.pts2;

    /******************************************************************/
    /* Initialise blt direction variable to left ,right, top  bottom  */
    /******************************************************************/
    BltDirection = DIR_OCTANT_LRTB;

    /******************************************************************/
    /* if the source and target are in the same bitmap and overlap    */
    /* then the blt direction may need to be changed and the clip     */
    /* regions reordered                                              */
    /******************************************************************/
    if ( DstBMHeader == SrcBMHeader )
    {
        if ( ((TrgRect.pts1.x <= SrcRect.pts2.x) &&
              (TrgRect.pts2.x >= SrcRect.pts1.x)) ||
             ((TrgRect.pts1.y <= SrcRect.pts2.y) &&
              (TrgRect.pts2.y >= SrcRect.pts1.y)) )
        {
            /**********************************************************/
            /* if the source left edge is to the left of the          */
            /* destination left edge then we clip in a right to       */
            /* left direction. If the current horizontal              */
            /* direction is left to right then set the                */
            /* ReOrderClips flag to indicate reordering               */
            /**********************************************************/
            if (SrcRect.pts1.x < TrgRect.pts1.x)
            {
                ReOrderClips =
                 ( (pdc->DCIEngineClips > 1) &&
                  ((pdc->DCIClipOrder == RECTDIR_LFRT_TOPBOT) ||
                   (pdc->DCIClipOrder == RECTDIR_LFRT_BOTTOP)) );

                /******************************************************/
                /* The value to pass to the engine for right to       */
                /* left clipping is 2.                                */
                /******************************************************/
                NewClipOrder = 2;

            }

            else /* blt in left to right direction */
            {
                /******************************************************/
                /* the value to pass to the engine for left to        */
                /* right clip region ordering is 1.                   */
                /******************************************************/
                NewClipOrder = 1;

                /******************************************************/
                /* if current clip order is right to left then        */
                /* set ReOrderClips to indicate we need a change      */
                /******************************************************/
                ReOrderClips =
                 ( (pdc->DCIEngineClips > 1) &&
                   (SrcRect.pts1.x > TrgRect.pts1.x) &&
                  ((pdc->DCIClipOrder == RECTDIR_RTLF_TOPBOT) ||
                   (pdc->DCIClipOrder == RECTDIR_RTLF_BOTTOP)) );
            }


            /**********************************************************/
            /* if the source is above the destination then we         */
            /* blt in a top to bottom direction (remember h/w and     */
            /* Winthorn coordinates are inverted in y). If the        */
            /* current direction is bottom to top then set the        */
            /* ReOrderClips flag to indicate reordering               */
            /**********************************************************/
            if ( SrcRect.pts1.y > TrgRect.pts1.y )
            {
                ReOrderClips |=
                 ( (pdc->DCIEngineClips > 1) &&
                  ((pdc->DCIClipOrder == RECTDIR_LFRT_BOTTOP) ||
                   (pdc->DCIClipOrder == RECTDIR_RTLF_BOTTOP)) );
            }
            else if ( SrcRect.pts1.y < TrgRect.pts1.y )
            {
                NewClipOrder += 2;

                ReOrderClips |=
                 ( (pdc->DCIEngineClips > 1) &&
                  ((pdc->DCIClipOrder == RECTDIR_LFRT_TOPBOT) ||
                   (pdc->DCIClipOrder == RECTDIR_RTLF_TOPBOT)) );
            }

            /**********************************************************/
            /* change the pixel op direction octant if the blt        */
            /* direction is not left to right, top to bottom          */
            /* If the direction is changed the start coords           */
            /* must be altered to reflect this                        */
            /**********************************************************/
            switch (NewClipOrder)
            {
                case 1:
                    /**************************************************/
                    /* nothing: use the left to right, top to         */
                    /* bottom already set up                          */
                    /**************************************************/
                    break;

                case 2:
                    /**************************************************/
                    /* set right to left, top to bottom               */
                    /**************************************************/
                    BltDirection ^= DIR_OCTANT_LRTB ^ DIR_OCTANT_RLTB;
                    break;

                case 3:
                    /**************************************************/
                    /* set left to right, bottom to top               */
                    /**************************************************/
                    BltDirection ^= DIR_OCTANT_LRTB ^ DIR_OCTANT_LRBT;
                    break;

                case 4:
                    /**************************************************/
                    /* set right to left, bottom to top               */
                    /**************************************************/
                    BltDirection ^= DIR_OCTANT_LRTB ^ DIR_OCTANT_RLBT;
                    break;
            }

            /**********************************************************/
            /* If the clips have changed or there are too many clips  */
            /* for the cache ensure that we get information upto date */
            /* to call back to the engine                             */
            /**********************************************************/
            if ( (pdc->DCIEngineClips > CACHED_CLIPS) ||
                                                   pdc->ClipChanged )
            {
                ReOrderClips = TRUE;
            }

            /**********************************************************/
            /* If we need to reorder the clip rectangles then set the */
            /* new order in the GetClips control structure and        */
            /* indicate that the clips have changed to ensure that we */
            /* always get the clip rectangles in the new order        */
            /**********************************************************/
            if ( ReOrderClips )
            {
                pdc->DCIClipOrder = NewClipOrder;
#ifdef POST174
                GetClipsControl.ulDirection = NewClipOrder;
#else /* POST174 */
                GetClipsControl.usDirection = NewClipOrder;
#endif /* POST174 */
                pdc->ClipChanged = TRUE;
            }
        } /* overlapping source and destination */


    } /* same bitmaps */

    else
    {
        if ( (DstBMHeader->Info.BitCount != 1) &&
             (SrcBMHeader->Info.BitCount == 1) )
        /**************************************************************/
        /* if the destination bitmap is in screen format but the      */
        /* source is monochrome then the blt must be expanding. The   */
        /* hardware allows expansion only for the pattern pixel map   */
        /* we must use a pattern and destination blt to achieve this  */
        /* It is important that the expanding blt is done as first    */
        /* operation of the blt since this is the only one for which  */
        /* the pixel op will be set up for expansion                  */
        /**************************************************************/
        {
            /**********************************************************/
            /* get the physical foreground and background for the     */
            /* source These are taken from the target atrribute bundle*/
            /* unless colour information was passed in the parameters */
            /**********************************************************/
            if (ArgOptions & BLTMODE_ATTRS_PRES)
            {
                PhysSrcColor     = LogToPhyIndex(ArgAttrs->lColor);
                PhysSrcBackColor = LogToPhyIndex(ArgAttrs->lBackColor);
            }

            else /* use attribute bundle colours */
            {
                PhysSrcColor     = pdc->DCIImagColatts.ForeColor;
                PhysSrcBackColor = pdc->DCIImagColatts.BackColor;
            }

        } /* mono source colour destination */

        else
        {
            if ( (DstBMHeader->Info.BitCount == 1) &&
                 (SrcBMHeader->Info.BitCount != 1) )
            /**********************************************************/
            /* if the source is colour and the target is monochrome   */
            /* then we need to compress the source using software     */
            /* since the hardware can't cope                          */
            /**********************************************************/
            {
                SrcBMHeader =
                AIxfer.pbmhSrc = convert_colour_to_mono(FunN,
                                                        ArgOptions,
                                                        ArgAttrs,
                                                        pdcSrc);
                if (SrcBMHeader == FNULL)
                {
                    goto BITBLT_ERR_EXIT;
                }
            }
        }
    } /* different bitmaps */

    /******************************************************************/
    /* a three way blt must be done in several steps since the        */
    /* hardware will only do a two-way colour blt (if a 3-way h/w blt */
    /* is used, all pattern colour information is lost                */
    /* The Blt3WayBuffer in the data segment contains information on  */
    /* the sequence of operations comprising the blt. Its structure   */
    /* is:                                                            */
    /* BOOL    CreateNew    TRUE if a new 'work' bitmap is needed for */
    /*                      intermediate steps - occurs if the dest   */
    /*                      used more than once in the blt, eg.       */
    /*                      (D xor P) and (D xor S)                   */
    /* USHORT  Size         number of instances of Instruction        */
    /* pBltInst Instruction                                           */
    /* There is one occurrence of BltInst for each operation in the   */
    /* blt. Its structure is:                                         */
    /* BYTE   Source        0 = use destination 1 = 'work'            */
    /*                      2 = source, 3 = pattern, 4 = none or      */
    /*                      same as last time                         */
    /* BYTE   Destination   0 = use destination, 1 = 'work', 2 = none */
    /*                      or same as last time                      */
    /* BYTE   Mix           the hardware mix to be used: foreground   */
    /*                      and background are always the same since  */
    /*                      each operation is two way, and the value  */
    /*                      may be 0xff indicating that the same mix  */
    /*                      as that used previously applies           */
    /* PFN    BltFunction   near pointer to the hardware interface    */
    /*                      function (eddh_PatDestBlt, eddh_SrcDestBlt*/
    /*                      or eddh_DestOnlyBlt)                      */
    /******************************************************************/
    /* the instruction buffer only has entries for rops 0 to 0x7f.    */
    /* This is because the others can be done by a bitwise not of the */
    /* corresponding rop in the range 0 to 0x7f. rop 0x80 is          */
    /* ~rop 0x7f, rop 0x81 is ~rop 0x7e and in general rop n is       */
    /* ~rop (0xff - n).                                               */
    /* the correct effect for rops greater than 0x7f can be achieved  */
    /* by negating the mix used in the last operation specified in the*/
    /* instruction buffer for the corresponding rop less than 0x80.   */
    /* This is easy to do since any hardware mix value xor 0x0f gives */
    /* the negative of the mix.                                       */
    /******************************************************************/
    /******************************************************************/
    /* get the index to the instruction buffer from the rop           */
    /******************************************************************/

    if ( (BYTE)ArgRop & 0x80)
    {
        /**************************************************************/
        /* rop in range 0x80 - 0xff so find the corresponding rop     */
        /* less than 0x80                                             */
        /**************************************************************/
        Blt3WayIndex = 0xff - (BYTE)ArgRop;

        /**************************************************************/
        /* get a local pointer to the instructions for this rop       */
        /**************************************************************/
        Instruction = Blt3WayBuffer[Blt3WayIndex].Instruction;

        /**************************************************************/
        /* alter the mix for the last operation comprising the blt    */
        /**************************************************************/
        #ifndef   _8514
        Instruction[Blt3WayBuffer[Blt3WayIndex].Size - 1].Mix ^= 0x0f;
        #else
        Instruction[Blt3WayBuffer[Blt3WayIndex].Size - 1].Mix =
        InverseTable[Instruction[Blt3WayBuffer[Blt3WayIndex].Size - 1].Mix];
        #endif

    }
    else /* rop in range 0 - 0x7f */
    {
        /**************************************************************/
        /* the low byte of the rop can be used directly as the index  */
        /**************************************************************/
        Blt3WayIndex = (BYTE)ArgRop;

        /**************************************************************/
        /* get a local pointer to the instructions for this rop       */
        /**************************************************************/
        Instruction = Blt3WayBuffer[Blt3WayIndex].Instruction;
    }

    /******************************************************************/
    /* create a bitmap for intermediate results if necessary          */
    /******************************************************************/
    if ( Blt3WayBuffer[Blt3WayIndex].CreateNew )
    {
        /**************************************************************/
        /* initialise the bitmap header fields needed for             */
        /* AllocMemForBitmap                                          */
        /**************************************************************/
        ExpPatBMHeader.Info.Width    = TrgRect.pts2.x -
                                       TrgRect.pts1.x +
                                       (USHORT)1;
        ExpPatBMHeader.Info.Height   = TrgRect.pts2.y -
                                       TrgRect.pts1.y +
                                       (USHORT)1;
        ExpPatBMHeader.Info.BitCount = AIxfer.pbmhDest->Info.BitCount;

        /**************************************************************/
        /* allocate memory for the bitmap                             */
        /**************************************************************/
        if ( OK != eddb_AllocMemForBitmap(&ExpPatBMHeader) )
        {
            goto BITBLT_ERR_EXIT;
        }
    }
    else /* no work bitmap needed */
    {
        ExpPatBMHeader.Bitmap = NULL;
    }

    for (i = Blt3WayBuffer[Blt3WayIndex].Size ;i-- ; Instruction++)
    {
        /**************************************************************/
        /* set up the parameter block destination fields according to */
        /* the destination map specified in the blt buffer            */
        /**************************************************************/
        if ( !Instruction->Destination )
        {
            /**********************************************************/
            /* use destination map                                    */
            /**********************************************************/
            AIxfer.pbmhDest = DstBMHeader;
            AIxfer.rcsTrg.pts1 = TrgRect.pts1;
            AIxfer.rcsTrg.pts2 = TrgRect.pts2;

            /**********************************************************/
            /* Blting to the actual destination so use clip rectangles*/
            /**********************************************************/
            fThreeWayWorkBlt = FALSE;
        }

        else if ( Instruction->Destination == 1 )
        {
            /**********************************************************/
            /* use the work map                                       */
            /**********************************************************/
            AIxfer.pbmhDest = &ExpPatBMHeader;
            AIxfer.rcsTrg.pts1.x =
            AIxfer.rcsTrg.pts1.y = 0;
            AIxfer.rcsTrg.pts2.x = ExpPatBMHeader.Info.Width - (USHORT)1;
            AIxfer.rcsTrg.pts2.y = ExpPatBMHeader.Info.Height - (USHORT)1;

            /**********************************************************/
            /* If we're using the work map then we must not clip the  */
            /* blt - any clipping required will be done in the blts   */
            /* to the destination.                                    */
            /**********************************************************/
            fThreeWayWorkBlt = TRUE;
        }

        /**************************************************************/
        /* set the blt parameter block depending on whether the       */
        /* source is a pattern or not                                 */
        /**************************************************************/
        if ( Instruction->Source == BT_PAT )
        {
            /**********************************************************/
            /* use a pattern as the source                            */
            /**********************************************************/
            AIxfer.pbmhSrc = pdc->TempPattern;

            /**********************************************************/
            /* Set the pattern origin.  If the destination is the     */
            /* real destination then just use the DC pattern origin.  */
            /* If the destination is the work bitmap then we must     */
            /* adjust the origin because the target rectangle will    */
            /* now start at (0,0).                                    */
            /**********************************************************/
            if (fThreeWayWorkBlt)
            {
                AIxfer.ptsPatOrig.x = pdc->DCIPatternOrigin.X
                                     - TrgRect.pts1.x;
                AIxfer.ptsPatOrig.y = pdc->DCIPatternOrigin.Y
                                     - TrgRect.pts1.y;
            }
            else
            {
                AIxfer.ptsPatOrig.x = pdc->DCIPatternOrigin.X;
                AIxfer.ptsPatOrig.y = pdc->DCIPatternOrigin.Y;
            }

           /***********************************************************/
           /* We set the source rectangle up to be the whole of the   */
           /* bitmap so that the pixblt code we call later knows that */
           /* the source (which in this case is the pattern) is of    */
           /* the "wrap-round" type and so will not try to adjust the */
           /* source rectangle when blting chunks through the PHUNK.  */
           /***********************************************************/
           AIxfer.rcsSrc.pts1.x = 0;
           AIxfer.rcsSrc.pts1.y = 0;
           AIxfer.rcsSrc.pts2.x = AIxfer.pbmhSrc->Info.HWWidth;
           AIxfer.rcsSrc.pts2.y = AIxfer.pbmhSrc->Info.HWHeight;


#ifdef SDBM20
            /**********************************************************/
            /* We are going to do a pattern destination operation so  */
            /* we can now decide whether to use software or hardware  */
            /* drawing mode. The pattern is always in system memory   */
            /* (and may also have a copy in VRAM) and so we only care */
            /* about the destination - if it is in VRAM then we must  */
            /* use hardware drawing mode.                             */
            /**********************************************************/
            if (AIxfer.pbmhDest == &DirectListEntry)
            {
                SetDrawModeHard;
            }
            else
            {
                SetDrawModeSoft;
            }

#ifdef PALETTE_MGR
            /**********************************************************/
            /* We never have to do palette conversions when we are not*/
            /* blting between two colour bitmaps.                     */
            /**********************************************************/
            UsePaletteMapping = FALSE;
#endif /* PALETTE_MGR */

#endif /* SDBM20 */

            /**********************************************************/
            /* initialise the pixel operation for a pattern blt       */
            /* -  background source: background colour                */
            /* -  foreground source: foreground colour                */
            /* -  step: PxBlt                                         */
            /* -  source pixel map: don't care                        */
            /* -  destination pixel map: Map A                        */
            /* -  pattern pixel map: Map B                            */
            /* -  mask pixel map: boundary disabled                   */
            /* -  drawing mode: don't care                            */
            /* -  direction octant: left to right, top to bottom      */
            /**********************************************************/
            PixelOp = BACK_SRC_BACK_COL |
                      FORE_SRC_FORE_COL |
                      STEP_PXBLT |
                      SRC_PIX_MAP_DONTCARE |
                      DST_PIX_MAP_A |
                      PAT_PIX_MAP_B |
                      MASK_PIX_MAP_OFF |
                      DRAW_MODE_DONTCARE |
                      DIR_OCTANT_LRTB;

            /**********************************************************/
            /* set up the hardware foreground and background colours  */
            /**********************************************************/
            #ifdef _8514
            Shadow8514Regs.Function_1.SrcSelect = FUNC_2OP_COL1;
            Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COL0;
            Shadow8514Regs.Color_1 = PhysPatColor;
            Shadow8514Regs.Color_0 = PhysPatBackColor;
            #else /* XGA */
            ShadowXGARegs.FgCol = PhysPatColor;
            ShadowXGARegs.BgCol = PhysPatBackColor;
            #endif /* XGA */

            /**********************************************************/
            /* The new pixblt code expects the rcsSrc to be set up    */
            /* to be the size of the source. The pattern origin       */
            /* will have to be passed by another mechanism yet to     */
            /* be written!                                            */
            /**********************************************************/
//          if (Instruction->Destination == 1)
//          {
//              /******************************************************/
//              /* The destination is the work bitmap so we need to   */
//              /* adjust the pattern origin so it lines up correctly */
//              /******************************************************/
//              AIxfer.rcsSrc.pts1.x -= TrgRect.pts1.x;
//              AIxfer.rcsSrc.pts1.y -= TrgRect.pts1.y;
//          }
        }

        else /* source is a source bitmap */
        {
            /**********************************************************/
            /* may be source, work, destination or none               */
            /**********************************************************/
            switch ( Instruction->Source )
            {
                case BT_DEST:
                    /**************************************************/
                    /* destination                                    */
                    /**************************************************/
                    AIxfer.pbmhSrc = DstBMHeader;
                    AIxfer.rcsSrc.pts1 = TrgRect.pts1;
                    AIxfer.rcsSrc.pts2 = TrgRect.pts2;
                    break;

                case BT_WORK:
                    /**************************************************/
                    /* work                                           */
                    /**************************************************/
                    AIxfer.pbmhSrc = &ExpPatBMHeader;
                    AIxfer.rcsSrc.pts1.x = 0;
                    AIxfer.rcsSrc.pts1.y = 0;
                    AIxfer.rcsSrc.pts2.x =
                                       ExpPatBMHeader.Info.Width - (USHORT)1;
                    AIxfer.rcsSrc.pts2.y =
                                      ExpPatBMHeader.Info.Height - (USHORT)1;
                    break;

                case BT_SRC:
                    /**************************************************/
                    /* source                                         */
                    /**************************************************/
                    AIxfer.pbmhSrc = SrcBMHeader;
                    AIxfer.rcsSrc.pts1 = SrcRect.pts1;
                    AIxfer.rcsSrc.pts2 = SrcRect.pts2;
                    break;

                default:
                    /**************************************************/
                    /* no source or same as last operation so no set  */
                    /* up necessary                                   */
                    /**************************************************/
                    break;

            } /* switch (Instruction->Source) */

#ifdef SDBM20
            /**************************************************************/
            /* We are going to do a source destination operation:         */
            /*                                                            */
            /* If the source and destination are both the screen then we  */
            /* will use hardware drawing mode.                            */
            /*                                                            */
            /* If the destination is the screen and the source is a bitmap*/
            /* then we will copy the source to the PHUNK and use hardware */
            /* drawing mode.                                              */
            /*                                                            */
            /* If the source is the screen and the destination is a bitmap*/
            /* then we will copy the source to the PHUNK and use software */
            /* drawing mode.                                              */
            /*                                                            */
            /* If the source and destination are both bitmaps then we will*/
            /* use software drawing mode.                                 */
            /*                                                            */
            /**************************************************************/
            if ( AIxfer.pbmhDest == &DirectListEntry )
            {
                SetDrawModeHard;
            }
            else
            {
                SetDrawModeSoft;
            }

#ifdef PALETTE_MGR
            /**************************************************************/
            /* If both the source and destination are colour bitmaps and  */
            /* they are not the same bitmap then we want to call          */
            /* eddb_CreatePalMapping. If a palette mapping is required    */
            /* then usePaletteMapping will be set.                        */
            /**************************************************************/
            if ( (AIxfer.pbmhDest->Info.BitCount != 1)
              && (AIxfer.pbmhSrc->Info.BitCount != 1)
              && (AIxfer.pbmhDest != AIxfer.pbmhSrc)
              && (!(ArgOptions & BBO_NO_COLOR_INFO)) )
            {
                eddb_CreatePalMapping( pdcSrc );

#ifdef VRAMPTR
                /******************************************************/
                /* If we are doing a palette mapping then we need to  */
                /* get the bitmap out of the cache as the mapping is  */
                /* done on the fly by software drawing.               */
                /******************************************************/
                if ( UsePaletteMapping )
                {
                  if ( BITMAP_IS_CACHED(AIxfer.pbmhSrc) )
                  {
                    evict_cached_bitmap(AIxfer.pbmhSrc->bm_cache_slot);
                  }
                }
#endif /* VRAMPTR */
            }
#endif /* PALETTE_MGR */

#endif /* SDBM20 */

            /**********************************************************/
            /* if the source is expanding then set up the hardware    */
            /* colours and an expanding blt pixelop                   */
            /**********************************************************/
            if ( AIxfer.pbmhSrc->Info.BitCount !=
                 AIxfer.pbmhDest->Info.BitCount )
            {
                #ifdef _8514
                Shadow8514Regs.Color_1 = PhysSrcColor;
                Shadow8514Regs.Color_0 = PhysSrcBackColor;
                #else /* XGA */
                ShadowXGARegs.FgCol = PhysSrcColor;
                ShadowXGARegs.BgCol = PhysSrcBackColor;
                #endif /* XGA */

                /******************************************************/
                /* initialise the pixel for an expanding source blt   */
                /* -  background source: background colour            */
                /* -  foreground source: foreground colour            */
                /* -  step: PxBlt                                     */
                /* -  source pixel map: don't care                    */
                /* -  destination pixel map: Map A                    */
                /* -  pattern pixel map: Map C                        */
                /* -  mask pixel map: disabled                        */
                /* -  drawing mode: don't care                        */
                /* -  direction octant: left to right, top to bottom  */
                /******************************************************/
                PixelOp = BACK_SRC_BACK_COL |
                          FORE_SRC_FORE_COL |
                          STEP_PXBLT |
                          SRC_PIX_MAP_DONTCARE |
                          DST_PIX_MAP_A |
                          PAT_PIX_MAP_C |
                          MASK_PIX_MAP_OFF |
                          DRAW_MODE_DONTCARE |
                          DIR_OCTANT_LRTB;

            }

            else /* not an expanding source blt */
            {

                /******************************************************/
                /* initialise pixel operation for a source dest blt   */
                /* -  background source: source pixel map             */
                /* -  foreground source: source pixel map             */
                /* -  step: PxBlt                                     */
                /* -  source pixel map: Map B                         */
                /* -  destination pixel map: Map A                    */
                /* -  pattern pixel map: foreground (fixed)           */
                /* -  mask pixel map: disabled                        */
                /* -  drawing mode: don't care                        */
                /* -  direction octant: as set up earlier             */
                /******************************************************/
                PixelOp = 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 |
                          BltDirection;


            }

        #ifdef   _8514
        Shadow8514Regs.Function_1.SrcSelect =
        Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COPY;
        #endif

        } /* source is a source bitmap */

        /**************************************************************/
        /* move the function to be used into the scratchpad so we can */
        /* get to the appropriate function later                      */
        /**************************************************************/
        SPad.BltFunction = (*pDrawFunctions)[Instruction->BltFunction];

        /**************************************************************/
        /* set the foreground and background mixes                    */
        /**************************************************************/
        #ifdef _8514
        Shadow8514Regs.Function_1.Mix =
        Shadow8514Regs.Function_0.Mix = Instruction->Mix;
        #else /* XGA */
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = Instruction->Mix;
        #endif /* XGA */

        /******************************************************************/
        /* transfer the values we have set in the shadow registers to the */
        /* values in the real hw registers if needed                      */
        /******************************************************************/
        TransferShadowRegisters( TSR_COLOUR_MIX );

        /**************************************************************/
        /* Setup complete, so do this blt.                            */
        /* If the source and the destination are not both VRAM or     */
        /* both system memory then we must blt via the PHUNK.         */
        /* 74206 -- must go ViaPHUNK if we are stretching             */
        /**************************************************************/
        if ( !AIxfer.fStretching &&
             ((AIxfer.pbmhSrc  != &DirectListEntry &&
               AIxfer.pbmhDest != &DirectListEntry)
           || (AIxfer.pbmhDest == &DirectListEntry &&
               AIxfer.pbmhSrc->BMPhys != NULL)) )
        {
            PixBltThroughClips();
        }
        else
        {
            PixBltThroughClipsViaPHUNK();
        }

    } /* for each operation comprising the blt */

    /******************************************************************/
    /* Leave this as true for other routines                          */
    /******************************************************************/
    fThreeWayWorkBlt = FALSE;

    /******************************************************************/
    /* if the rop was bigger than 0x7f then the mix of the last       */
    /* operation comprising the blt was altered and should now be     */
    /* restored                                                       */
    /******************************************************************/
    if ( ArgRop & 0x80 )
    {
        /**************************************************************/
        /* xor the mix to undo the xor done earlier                   */
        /**************************************************************/
        #ifndef   _8514
        Blt3WayBuffer[Blt3WayIndex].Instruction[
                      Blt3WayBuffer[Blt3WayIndex].Size - 1].Mix ^= 0x0f;
        #else
        // we cant use the xor method to to different ordering
        Blt3WayBuffer[Blt3WayIndex].Instruction[
                      Blt3WayBuffer[Blt3WayIndex].Size - 1].Mix =
        InverseTable[Blt3WayBuffer[Blt3WayIndex].Instruction[
                      Blt3WayBuffer[Blt3WayIndex].Size - 1].Mix];
        #endif

    }

#ifdef VRAMPTR
    /******************************************************************/
    /* If the target bitmap is cached then evict it since it has      */
    /* been drawn to.                                                 */
    /******************************************************************/
    if ( BITMAP_IS_CACHED(AIxfer.pbmhDest) )
    {
      evict_cached_bitmap(AIxfer.pbmhDest->bm_cache_slot);
    }
#endif /* VRAMPTR */

    goto BITBLT_EXIT;

/******************************************************************************/
    /******************************************************************/
    /* pattern and destination rop                                    */
    /******************************************************************/
PATT_DSTONLY_COMMON:

    /******************************************************************/
    /* update bounds to target rectangle; the bounds are not          */
    /* affected by clipping                                           */
    /******************************************************************/
    if (FunNTest(COM_ALT_BOUND | COM_BOUND) )
    {
        eddg_AddBounds ((pDevRect)&TrgRect,
                        FunN,
                        COORD_AI);
    }

#ifdef DCAF                                                               //DCAF
    /******************************************************************/  //DCAF
    /* Accumulate DCAF screen bounds if required                      */  //DCAF
    /******************************************************************/  //DCAF
    if ( DCAFBoundsRequired(FunN) )                                       //DCAF
    {                                                                     //DCAF
        AccumulateScreenBoundsThroughClips( (pDevRect)&TrgRect,           //DCAF
                                            COORD_AI );                   //DCAF
    }                                                                     //DCAF
#endif                                                                    //DCAF

    /******************************************************************/
    /* if correlate bit is set then do the correlation                */
    /******************************************************************/
    if ((FunNTest(COM_CORRELATE)) && (pdc->DCICorrNum))
    {
        CorrResult = eddg_CheckRectCorrelation((pDevRect)&TrgRect);
    }


    /******************************************************************/
    /* if the draw bit is reset, no further work is required          */
    /******************************************************************/
    if ( !(FunNTest(COM_DRAW)) || ((BYTE)ArgRop == 0xaa) )
    {
        goto BITBLT_EXIT;
    }

    /******************************************************************/
    /* calculate the blt dimensions and put the starting coordinate   */
    /* in the parameter block, clipping the destination to the bitmap */
    /******************************************************************/
    /******************************************************************/
    /* if the left edge of the target is to the left of the bitmap    */
    /* then set the destination x coordinate to 0 (the left edge of   */
    /* the bitmap), otherwise just use the calculated coord           */
    /******************************************************************/
    if ( TrgRect.pts1.x < 0 )
    {
        /**************************************************************/
        /* exit now if the the right edge of the target is to the     */
        /* left of the left edge                                      */
        /**************************************************************/
        if ( TrgRect.pts2.x < 0 )
        {
            goto BITBLT_EXIT;
        }

        AIxfer.rcsTrg.pts1.x = 0;
    }

    else
    {
        /**************************************************************/
        /* exit now if the the left edge of the target is to the right*/
        /* of the right edge                                          */
        /**************************************************************/
        if ( TrgRect.pts1.x > AIxfer.pbmhDest->Info.HWWidth)
        {
            goto BITBLT_EXIT;
        }

        AIxfer.rcsTrg.pts1.x = TrgRect.pts1.x;
    }

    /******************************************************************/
    /* if the bottom edge of the target is below  the bottom of the   */
    /* bitmap then set the destination y coordinate to 0 (the bottom  */
    /* edge of the bitmap), otherwise use the calculated coordinate   */
    /******************************************************************/
    if ( TrgRect.pts1.y < 0 )
    {
        /**************************************************************/
        /* exit now if the top edge of the target is below the bottom */
        /* edge                                                       */
        /**************************************************************/
        if ( TrgRect.pts2.y < 0 )
        {
            goto BITBLT_EXIT;
        }

        AIxfer.rcsTrg.pts1.y = 0;
    }

    else
    {
        /**************************************************************/
        /* exit now if the bottom edge of the target is above the top */
        /* edge                                                       */
        /**************************************************************/
        if ( TrgRect.pts1.y > AIxfer.pbmhDest->Info.HWHeight)
        {
            goto BITBLT_EXIT;
        }

        AIxfer.rcsTrg.pts1.y = TrgRect.pts1.y;
    }

    /******************************************************************/
    /* if the right edge of the target is to the right of the bitmap  */
    /* then set the destination width to be the bitmap hardware width */
    /* less the start coordinate, otherwise subtract the start        */
    /* coordinate from the calculated right edge                      */
    /******************************************************************/
    AIxfer.rcsTrg.pts2.x = min(
                        AIxfer.pbmhDest->Info.HWWidth, TrgRect.pts2.x);

    if ( AIxfer.rcsTrg.pts1.x > AIxfer.rcsTrg.pts2.x)
    {
        goto BITBLT_EXIT;
    }

    /******************************************************************/
    /* if the top edge of the target is above the bitmap then set the */
    /* destination height to be the bitmap hardware height less the   */
    /* start coordinate, otherwise subtract the start coordiante from */
    /* the calculated top edge                                        */
    /******************************************************************/
    AIxfer.rcsTrg.pts2.y = min(
                       AIxfer.pbmhDest->Info.HWHeight, TrgRect.pts2.y);

    if ( AIxfer.rcsTrg.pts1.y > AIxfer.rcsTrg.pts2.y)
    {
        goto BITBLT_EXIT;
    }

    /******************************************************************/
    /* if necessary, exclude the cursor from the destination (and     */
    /* disable further cursor drawing until we're finished with the   */
    /* hardware).                                                     */
    /******************************************************************/
    if ( cursor_data.cursor_status & CURSOR_SOFTWARE )
    {
        if (pdc->DCIBitmapType == BITMAP_IS_SCREEN)
        {
            eddm_ExcludeCursor((pDevPoint)&AIxfer.rcsTrg, COORD_AI);
        }
        else
        {
            disable_cursor();
        }
    }

    /******************************************************************/
    /* now it's time for pat/dest and dest only to go their separate  */
    /* ways and complete the blt                                      */
    /* a pattern is required if the high and low nibbles of the       */
    /* rop are different                                              */
    /******************************************************************/
    if ( (((BYTE)ArgRop >> 4) ^ (BYTE)ArgRop) & 0x0f  )
    {
        goto PATT_DST_BLT;
    }
    else /* no pattern required */
    {
        goto DST_ONLY_BLT;
    }

/*****************************************************************************/

PATT_DST_BLT:

#ifdef SDBM20

    /**************************************************************/
    /* Now it is time to set the drawing mode correctly..         */
    /**************************************************************/
    /**************************************************************/
    /* If the destination is the screen then we have to use the   */
    /* hardware drawing mode. Remember that the pattern is always */
    /* in system memory (even though it may have a copy in VRAM)  */
    /**************************************************************/
    if (AIxfer.pbmhDest == &DirectListEntry)
    {
        SetDrawModeHard;
    }
    else
    {
        SetDrawModeSoft;
    }
#endif /* SDBM20 */

    /******************************************************************/
    /* get the physical pattern colour: these are either passed in as */
    /* parameters or taken from the target pattern attribute bundle   */
    /******************************************************************/
    if (ArgOptions & BLTMODE_ATTRS_PRES)
    {
        LogPatColor     = ArgAttrs->lColor;
        LogPatBackColor = ArgAttrs->lBackColor;
    }
    else /* use attribute bundle colours */
    {
        LogPatColor     = pdc->DCICurPtnAts.abnd.lColor;
        LogPatBackColor = pdc->DCICurPtnAts.abnd.lBackColor;
    }

    /******************************************************************/
    /* if the pattern symbol or set has changed then we need to get   */
    /* the new data                                                   */
    /******************************************************************/
    if ( pdc->DCIChanged & NEW_PATTERN_SYMBOL )
    {
        if ( !edda_PatternSetUp() )
        {
            goto BITBLT_ERR_EXIT;
        }
    }

    /******************************************************************/
    /* if the destination bitmap is screen format and the rop is      */
    /* pattern or pattern inverse then dithering may be used.         */
    /* SetDithColourAndPattern returns TRUE if dithering has been     */
    /* enabled                                                        */
    /******************************************************************/
    if ( !( ArgRop & ROP_GREYROP_FLAG ) &&
            eddc_SetDithColourAndPattern( LogPatColor ) )
    {
        AIxfer.ptsPatOrig.x = pdc->DCIOrigin.X;
        AIxfer.ptsPatOrig.y = pdc->DCIOrigin.Y;

        if (pdc->DCISelListEntry->Info.BitCount != 1)
        {
            /******************************************************/
            /* use the coloured dither pattern                    */
            /* Set up the source bitmap as the dithered pattern   */
            /******************************************************/
            AIxfer.pbmhSrc = &NewPatternTable[PATSYM_DITHERED];

            #ifdef _8514
            Shadow8514Regs.Function_1.SrcSelect = FUNC_2OP_COPY;
            Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COPY;
            #endif /* 8514 */

            /**********************************************************/
            /* initialise the pixel operation to be used              */
            /* -  background source: source pixel map                 */
            /* -  foreground source: source pixel map                 */
            /* -  step: PxBlt                                         */
            /* -  source pixel map: Map B                             */
            /* -  destination pixel map: Map A                        */
            /* -  pattern pixel map: foreground (fixed)               */
            /* -  mask pixel map: disabled                            */
            /* -  drawing mode: don't care                            */
            /* -  direction octant: left to right, top to bottom      */
            /**********************************************************/
            PixelOp = 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
        {
            /******************************************************/
            /* use the mono dither pattern                        */
            /* Set up the source bitmap as the dithered pattern   */
            /******************************************************/
            AIxfer.pbmhSrc = &NewPatternTable[PATSYM_MONODITH];

            #ifdef _8514
            Shadow8514Regs.Function_1.SrcSelect = FUNC_2OP_COL1;
            Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COL0;
            #endif /* 8514 */

            /**********************************************************/
            /* initialise the pixel operation to be used              */
            /* -  background source: background colour                */
            /* -  foreground source: foreground colour                */
            /* -  step: PxBlt                                         */
            /* -  source pixel map: don't care                        */
            /* -  destination pixel map: Map A                        */
            /* -  pattern pixel map: Map B                            */
            /* -  mask pixel map: boundary disabled                   */
            /* -  drawing mode: don't care                            */
            /* -  direction octant: left to right, top to bottom      */
            /**********************************************************/
            PixelOp = BACK_SRC_BACK_COL |
                      FORE_SRC_FORE_COL |
                      STEP_PXBLT |
                      SRC_PIX_MAP_DONTCARE |
                      DST_PIX_MAP_A |
                      PAT_PIX_MAP_B |
                      MASK_PIX_MAP_OFF |
                      DRAW_MODE_DONTCARE |
                      DIR_OCTANT_LRTB;

            /******************************************************/
            /* Set up the colours to use.                         */
            /* these must be 1 and 0                              */
            /******************************************************/
            #ifdef _8514
            Shadow8514Regs.Color_1 = 1;
            Shadow8514Regs.Color_0 = 0;
            #else /* XGA */
            ShadowXGARegs.FgCol = 1;
            ShadowXGARegs.BgCol = 0;
            #endif /* XGA */
        }

    }
    else /* not a dithered pattern */
    {
        if ( ArgRop & ROP_GREYROP_FLAG )
        {
            /**********************************************************/
            /* ensure we are using the halftone pattern               */
            /* remember patterns are one based not zero based         */
            /**********************************************************/
            AIxfer.pbmhSrc = &NewPatternTable[PATSYM_HALFTONE-1];

            /**********************************************************/
            /* Use the same pattern origin we would as if we were     */
            /* dithering.                                             */
            /**********************************************************/
            AIxfer.ptsPatOrig.x = pdc->DCIOrigin.X;
            AIxfer.ptsPatOrig.y = pdc->DCIOrigin.Y;
        }
        else
        {
            /**********************************************************/
            /* set the parameter block pointer to the pattern bitmap  */
            /**********************************************************/
            AIxfer.pbmhSrc = pdc->TempPattern;

            /**********************************************************/
            /* copy the pattern origin to the parameter block         */
            /**********************************************************/
            AIxfer.ptsPatOrig.x = pdc->DCIPatternOrigin.X;
            AIxfer.ptsPatOrig.y = pdc->DCIPatternOrigin.Y;
        }

        /**************************************************************/
        /* we use different pixel ops according to whether we have a  */
        /* colour or a mono pattern                                   */
        /**************************************************************/
        if (pdc->TempPattern->Info.BitCount == 1)
        {
            /**********************************************************/
            /* mono pattern                                           */
            /**********************************************************/

            #ifdef _8514
            Shadow8514Regs.Function_1.SrcSelect = FUNC_2OP_COL1;
            Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COL0;
            #endif /* 8514 */

            /**********************************************************/
            /* initialise the pixel operation to be used              */
            /* -  background source: background colour                */
            /* -  foreground source: foreground colour                */
            /* -  step: PxBlt                                         */
            /* -  source pixel map: don't care                        */
            /* -  destination pixel map: Map A                        */
            /* -  pattern pixel map: Map B                            */
            /* -  mask pixel map: boundary disabled                   */
            /* -  drawing mode: don't care                            */
            /* -  direction octant: left to right, top to bottom      */
            /**********************************************************/
            PixelOp = BACK_SRC_BACK_COL |
                      FORE_SRC_FORE_COL |
                      STEP_PXBLT |
                      SRC_PIX_MAP_DONTCARE |
                      DST_PIX_MAP_A |
                      PAT_PIX_MAP_B |
                      MASK_PIX_MAP_OFF |
                      DRAW_MODE_DONTCARE |
                      DIR_OCTANT_LRTB;

            /**********************************************************/
            /* set the foreground and background colours for the blt. */
            /* These are taken from the target atrribute bundle       */
            /* unless colour information was passed in the parameters */
            /**********************************************************/
            if (ArgOptions & BLTMODE_ATTRS_PRES)
            {
                /******************************************************/
                /* On the occasions when we get passed attributes     */
                /* they are often the same color for both fore and    */
                /* back - hence the arrangement of these calls.       */
                /******************************************************/
                #ifdef _8514
                Shadow8514Regs.Color_1 = LogToPhyIndex(LogPatColor);
                if (LogPatColor == LogPatBackColor)
                {
                    Shadow8514Regs.Color_0 = Shadow8514Regs.Color_1;
                }
                else
                {
                    Shadow8514Regs.Color_0 = LogToPhyIndex(LogPatBackColor);
                }
                #else /* XGA */
                ShadowXGARegs.FgCol = (USHORT)LogToPhyIndex(LogPatColor);
                if (LogPatColor == LogPatBackColor)
                {
                    ShadowXGARegs.BgCol = ShadowXGARegs.FgCol;
                }
                else
                {
                    ShadowXGARegs.BgCol = (USHORT)LogToPhyIndex(LogPatBackColor);
                }
                #endif /* XGA */
            }
            else /* use attribute bundle colours */
            {
                #ifdef _8514
                Shadow8514Regs.Color_1 = pdc->DCIPattColatts.ForeColor;
                Shadow8514Regs.Color_0 = pdc->DCIPattColatts.BackColor;
                #else /* XGA */
                ShadowXGARegs.FgCol = (USHORT)pdc->DCIPattColatts.ForeColor;
                ShadowXGARegs.BgCol = (USHORT)pdc->DCIPattColatts.BackColor;
                #endif /* XGA */
            }
        }
        else
        {
            /**********************************************************/
            /* pattern is colour                                      */
            /* note this is the same pixelop as we use for dithered   */
            /* patterns (ie dithered patterns are coloured patterns)  */
            /**********************************************************/
            #ifdef _8514
            Shadow8514Regs.Function_1.SrcSelect = FUNC_2OP_COPY;
            Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COPY;
            #endif /* 8514 */

            /**********************************************************/
            /* initialise the pixel operation to be used              */
            /* -  background source: source pixel map                 */
            /* -  foreground source: source pixel map                 */
            /* -  step: PxBlt                                         */
            /* -  source pixel map: Map B                             */
            /* -  destination pixel map: Map A                        */
            /* -  pattern pixel map: foreground (fixed)               */
            /* -  mask pixel map: disabled                            */
            /* -  drawing mode: don't care                            */
            /* -  direction octant: left to right, top to bottom      */
            /**********************************************************/
            PixelOp = 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;

        }

    } /* not dithered pattern */

    /******************************************************************/
    /* set the foreground and background mixes                        */
    /* rops involving only pattern and destination are treated        */
    /* differently from others. The foreground and background mix are */
    /* the same although the high nibble of the rop differs from the  */
    /* low. This is because the rop is already expressed in terms of  */
    /* the pattern and destination, eg. pattern OR dest means we or   */
    /* the pattern and destination regardless of whether the pattern  */
    /* bit is a zero or one (this actually occurs with a source and   */
    /* destination rop also, but the rop has high and low nibbles     */
    /* For these rops, the foreground mix is carried out on the       */
    /* destination and foreground colour (set to be pattern           */
    /* foreground) whenever the pattern pixel is 1. The background    */
    /* mix is carried out on the destination and background colour    */
    /* (set to be pattern background) whenever the pattern pixel is 0 */
    /* Hence, the mixes are expressed in terms of source and dest     */
    /* and the pattern actually acts as a mask.                       */
    /******************************************************************/

    /******************************************************************/
    /* we mapped the GREY_ROP to come via this path, but the action   */
    /* is slightly different, so restore the proper action by         */
    /* adjusting the foreground mix to leavealone and the background  */
    /* to overpaint                                                   */
    /******************************************************************/
    if ( ArgRop & ROP_GREYROP_FLAG )
    {

        #ifdef _8514
        Shadow8514Regs.Function_1.SrcSelect = FUNC_2OP_COL1;
        Shadow8514Regs.Function_1.Mix       = FUNC_D;
        /**************************************************************/
        /* Defect 74015 - S3 fails on the first 4 ROPs of pattern     */
        /* BLTs using MD_PS_ONES (which is where we'll end up in the  */
        /* 24 bit case). So we'll simulate the ROP with Src OR Dest.  */
        /**************************************************************/
        #ifdef BPP24
        if ( DDT.fScreenFlags & USE_24BPP )
        {
           Shadow8514Regs.Function_1.Mix    = FUNC_S_OR_D;
           /**********************************************************/
           /* Defect 74958 - This work-around of the S3 hardware     */
           /* assumes we are laying a black/color pattern. Excel is  */
           /* using a white/white pattern, which was wiping out the  */
           /* destination. So, we'll make sure we have color/black.  */
           /**********************************************************/
           if ( Shadow8514Regs.Color_0 && Shadow8514Regs.Color_1 )
              Shadow8514Regs.Color_1 = 0;
        }
        #endif

        Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COL0;
        Shadow8514Regs.Function_0.Mix       = FUNC_S;
        #else /* XGA */
        ShadowXGARegs.FgMix = HWMIX_DEST;
        ShadowXGARegs.BgMix = HWMIX_SOURCE;
        #endif /* XGA */

    }

    #ifdef _8514
    else
    {
         BYTE mix;

         switch ((BYTE)ArgRop )
         {
             case 0xf0 : {                            // Pattern Copy
                  mix = FUNC_S;
                  break;
             }
             case 0xfa : {                            // Pattern OR Destination
                  mix = FUNC_S_OR_D;
                  break;
             }
             case 0x0f : {                            // Pattern Inverse
                  mix = FUNC_NS;
                  break;
             }
             case 0xaf : {                            // NOT Pattern OR Destination
                  mix = FUNC_NS_OR_D;
                  break;
             }
             case 0xf5 : {                            // Pattern OR NOT Destination
                  mix = FUNC_S_OR_ND;
                  break;
             }
             case 0x5f : {                            // NOT Pattern OR NOT Destination
                  mix = FUNC_NS_OR_ND;
                  break;
             }
             case 0x5a : {                            // Pattern XOR Destination
                  mix = FUNC_S_XOR_D;
                  break;
             }
             case 0xa5 : {                            // Pattern XOR NOT Destination
                  mix = FUNC_S_XNOR_D;
                  break;
             }
             case 0x05 : {                            // NOT Pattern AND NOT Destination
                  mix = FUNC_NS_AND_ND;
                  break;
             }
             case 0x50 : {                            // Pattern AND NOT Destination
                  mix = FUNC_S_AND_ND;
                  break;
             }
             case 0xa0 : {                            // Pattern AND Destination
                  mix = FUNC_S_AND_D;
                  break;
             }
             case 0x0a : {                             // NOT Pattern AND Destination
                  mix = FUNC_NS_AND_D;
                  break;
                }
             default :   {
                  mix = FUNC_S_AND_D;
                  break;
             }

         }

         Shadow8514Regs.Function_1.Mix = mix;
         Shadow8514Regs.Function_0.Mix = mix;
    }

    #else /* XGA */

    else if ( (BYTE)ArgRop == 0xf0 )
    {
    /******************************************************************/
    /* pattern copy                                                   */
    /******************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_SOURCE;
    }
    else if ( (BYTE)ArgRop == 0xfa )
    {
    /******************************************************************/
    /* pattern or destination                                         */
    /******************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_SOURCE_OR_DEST;
    }
    else if ( (BYTE)ArgRop == 0x0f )
    {
    /******************************************************************/
    /* pattern inverse                                                */
    /******************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_NOTSOURCE;
    }
    else if ( (BYTE)ArgRop == 0xaf )
    {
    /******************************************************************/
    /* not pattern or destination                                     */
    /******************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_NOTSOURCE_OR_DEST;
    }
    else if ( (BYTE)ArgRop == 0xf5 )
    {
    /******************************************************************/
    /* pattern or not destination                                     */
    /******************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_SOURCE_OR_NOTDEST;
    }
    else if ( (BYTE)ArgRop == 0x5f )
    {
    /******************************************************************/
    /* not pattern or not destination                                 */
    /******************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_NOTSOURCE_OR_NOTDEST;
    }
    else if ( (BYTE)ArgRop == 0x5a )
    {
    /******************************************************************/
    /* pattern xor destination                                        */
    /******************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_SOURCE_XOR_DEST;
    }
    else if ( (BYTE)ArgRop == 0xa5 )
    {
    /******************************************************************/
    /* pattern xor not destination                                    */
    /******************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_SOURCE_XOR_NOTDEST;
    }
    else if ( (BYTE)ArgRop == 0x05 )
    {
    /******************************************************************/
    /* not pattern and not destination                                */
    /******************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_NOTSOURCE_AND_NOTDEST;
    }
    else if ( (BYTE)ArgRop == 0x50 )
    {
    /******************************************************************/
    /* pattern and not destination                                    */
    /******************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_SOURCE_AND_NOTDEST;
    }
    else if ( (BYTE)ArgRop == 0xa0 )
    {
    /******************************************************************/
    /* pattern and destination                                        */
    /******************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_SOURCE_AND_DEST;
    }
    else /* ( (BYTE)ArgRop == 0x0a ) */
    {
    /******************************************************************/
    /* not pattern and destination                                    */
    /******************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_NOTSOURCE_AND_DEST;
    }

    #endif /* XGA */

    /******************************************************************/
    /* transfer the values we have set in the shadow registers to the */
    /* values in the real hw registers if needed                      */
    /******************************************************************/
    TransferShadowRegisters( TSR_COLOUR_MIX );

    /******************************************************************/
    /* We set the source rectangle up to be the whole of the bitmap   */
    /* so that the pixblt code we call later knows that the source    */
    /* (which in this case is the pattern) is of the "wrap-round"     */
    /* type and so will not try to adjust the source rectangle when   */
    /* blting chunks through the PHUNK.                               */
    /******************************************************************/
    AIxfer.rcsSrc.pts1.x = 0;
    AIxfer.rcsSrc.pts1.y = 0;
    AIxfer.rcsSrc.pts2.x = AIxfer.pbmhSrc->Info.HWWidth;
    AIxfer.rcsSrc.pts2.y = AIxfer.pbmhSrc->Info.HWHeight;

    /******************************************************************/
    /* Now we have done all the set up we need to we can go and do    */
    /* the blt.                                                       */
    /******************************************************************/
    SPad.BltFunction = (*pDrawFunctions)[index_PatDestBlt];


    /******************************************************************/
    /* If the source and the destination are not both VRAM or both    */
    /* system memory then we must blt via the PHUNK.  If the pattern  */
    /* (source) has a physical address then we know that it will also */
    /* have a valid virtual address so we will never have to go via   */
    /* the PHUNK in this case.                                        */
    /* 74206 -- must go ViaPHUNK if we are stretching                 */
    /******************************************************************/
    if ( !AIxfer.fStretching &&
         ((AIxfer.pbmhSrc  != &DirectListEntry &&
           AIxfer.pbmhDest != &DirectListEntry)
       || (AIxfer.pbmhDest == &DirectListEntry &&
           AIxfer.pbmhSrc->BMPhys != NULL)) )
    {
        PixBltThroughClips();
    }
    else
    {
        PixBltThroughClipsViaPHUNK();
    }


#ifdef VRAMPTR
    /******************************************************************/
    /* If the target bitmap is cached then evict it since it has      */
    /* been drawn to.                                                 */
    /******************************************************************/
    if ( BITMAP_IS_CACHED(AIxfer.pbmhDest) )
    {
      evict_cached_bitmap(AIxfer.pbmhDest->bm_cache_slot);
    }
#endif /* VRAMPTR */

    goto BITBLT_EXIT;
    /******************************************************************/
    /* destination only rop                                           */
    /******************************************************************/
DST_ONLY_BLT:

#ifdef SDBM20
    /**************************************************************/
    /* Now it is time to set the drawing mode correctly..         */
    /**************************************************************/
    /**************************************************************/
    /* If the destination is the screen then we have to use the   */
    /* hardware drawing mode.                                     */
    /**************************************************************/
    if (AIxfer.pbmhDest == &DirectListEntry)
    {
        SetDrawModeHard;
    }
    else
    {
        SetDrawModeSoft;
    }
#endif /* SDBM20 */

    /******************************************************************/
    /* A note of explanation, dear reader...                          */
    /* During testing of a certain portable plasma display PS/2 a     */
    /* problem occurred during Pagemaker where destination invert rops*/
    /* were going wrong.  After exhaustive (yawn) investigation the   */
    /* hardware seemed to be set up correctly so the following fix    */
    /* has been 'improvised'.  If the operation is 0x55 then use      */
    /* a source invert operation and set the source up to be the same */
    /* as the destination.  Setting up the source is done in          */
    /* destonlyblt (no matter what rop is being used) but the source  */
    /* will only be used if the pixel op has been tweaked (see below) */
    /* for the 0x55 case.  Whether the problem is a genuine driver    */
    /* error (the scnerio is quite particular) or whether it is a     */
    /* hardware problem is not known at this time.                    */
    /******************************************************************/

    /******************************************************************/
    /* initialise the pixel operation to be used                      */
    /* -  background source: don't care                               */
    /* -  foreground source: don't care                               */
    /* -  step: PxBlt                                                 */
    /* -  source pixel map: map A - in case dst invert operation      */
    /* -  destination pixel map: Map A                                */
    /* -  pattern pixel map: fixed                                    */
    /* -  mask pixel map: disabled                                    */
    /* -  drawing mode: don't care                                    */
    /* -  direction octant: left to right, top to bottom              */
    /******************************************************************/
    PixelOp = STEP_PXBLT |
              DST_PIX_MAP_A |
              SRC_PIX_MAP_A |
              MASK_PIX_MAP_OFF |
              PAT_PIX_MAP_FORE |
              DIR_OCTANT_LRTB;

    /******************************************************************/
    /* set the foreground and background mixes                        */
    /* for rop 0x00 set foreground and background mixes to 0 (all 0s) */
    /* for rop 0xff set foreground and background mixes to 15 (all 1s)*/
    /* the only other rop to reach here is destinvert (0x55)          */
    /******************************************************************/
    if ( !(BYTE)ArgRop )
    {
        #ifdef _8514
        Shadow8514Regs.Function_1.SrcSelect =
        Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COPY;
        Shadow8514Regs.Function_1.Mix =
        Shadow8514Regs.Function_0.Mix = FUNC_ZEROS;
        #else /* XGA */
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_ZEROS;
        #endif /* XGA */
    }
    else if ( (BYTE)ArgRop == 0xff )
         {
             #ifdef _8514
             Shadow8514Regs.Function_1.SrcSelect =
             Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COPY;
             Shadow8514Regs.Function_1.Mix =
             Shadow8514Regs.Function_0.Mix = FUNC_ONES;
             #else /* XGA */
             ShadowXGARegs.FgMix =
             ShadowXGARegs.BgMix = HWMIX_ONES;
             #endif /* XGA */
         }

         else /* rop = 0x55 */
         {
             /**************************************************************/
             /* Time to play around with the pixelop for dest invert       */
             /* operation.                                                 */
             /**************************************************************/
             #ifndef _8514
             ShadowXGARegs.FgMix =
             ShadowXGARegs.BgMix = HWMIX_NOTSOURCE;
             #else
             Shadow8514Regs.Function_1.Mix =
             Shadow8514Regs.Function_0.Mix = FUNC_NS;
             Shadow8514Regs.Function_1.SrcSelect = FUNC_2OP_COPY;
             Shadow8514Regs.Function_0.SrcSelect = FUNC_2OP_COPY;
             #endif
             PixelOp |= BACK_SRC_SRC_PIX_MAP | FORE_SRC_SRC_PIX_MAP;

         }


    /******************************************************************/
    /* Check for the new (to OS/2 2.0) background mixes               */
    /* BM_DESTTRANSPARENT and BM_SRCTRANSPARENT.                      */
    /*                                                                */
    /* Here, BM_SRCTRANSPARENT does not make much sense (ie there is  */
    /* no source), but by assuming that no source means there are no  */
    /* source background pixels we can in effect ignore the           */
    /* BM_SRCTRANSPARENT option.                                      */
    /*                                                                */
    /* BM_DESTTRANSPARENT is implemented by setting the colour compare*/
    /* condition to COLCOMP_EQUAL and the colour compare value to the */
    /* background colour.                                             */
    /******************************************************************/
    // UseColorCompare() would work but SRCTRANSPARENT doesn't make sense
    if (pdc->DCICurImgAts.ibnd.usBackMixMode == BM_DESTTRANSPARENT)
    {
        convert_BMix_to_ColComp(ArgOptions, ArgAttrs);
    }
    else
    {
        #ifdef _8514
        Shadow8514Regs.Mode.PatternSrc = MD_PS_COPY;
        Shadow8514Regs.Mode.UnderPaint = MD_UP_FALSE;
        Shadow8514Regs.Mode.PlaneMode  = MD_AF_W_NORMAL;
        #else /* XGA */
        ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;
        #endif /* XGA */
    }

    /******************************************************************/
    /* transfer the values we have set in the shadow registers to the */
    /* values in the real hw registers if needed                      */
    /******************************************************************/
    TransferShadowRegisters( TSR_COLOUR_MIX );

    /******************************************************************/
    /* Now we have done all the set up we need to we can go and do    */
    /* the blt.                                                       */
    /******************************************************************/
    SPad.BltFunction = (*pDrawFunctions)[index_DestOnlyBlt];

    /**************************************************************/
    /* The drawing mode is always selected so that there is never */
    /* any need to do any locking/PHUNKing of the destination     */
    /* bitmap.                                                    */
    /**************************************************************/
    PixBltThroughClips();

#ifdef VRAMPTR
    /******************************************************************/
    /* If the target bitmap is cached then evict it since it has      */
    /* been drawn to.                                                 */
    /******************************************************************/
    if ( BITMAP_IS_CACHED(AIxfer.pbmhDest) )
    {
      evict_cached_bitmap(AIxfer.pbmhDest->bm_cache_slot);
    }
#endif /* VRAMPTR */

    goto BITBLT_EXIT;
    /******************************************************************/
    /* exit point: return to calling function with appropriate return */
    /* code. Tidy-up (profile exit, exit driver, etc.) done as        */
    /* necessary depending on the type of exit                        */
    /******************************************************************/

/**********************************************************************/
BITBLT_EXIT:

#ifdef PALETTE_MGR
    /******************************************************************/
    /* Set UsePaletteMapping to FALSE so that non-BITBLT functions    */
    /* which call PixBltThroughClips and PixBltThroughClipsViaPHUNK   */
    /* do not have to worry about it.                                 */
    /******************************************************************/
    UsePaletteMapping = FALSE;
#endif /* PALETTE_MGR */

    /******************************************************************/
    /* delete any work bitmaps that were created                      */
    /******************************************************************/
    if (ExpPatBMHeader.Bitmap)
    {
        eddb_FreeMemForBitmap(&ExpPatBMHeader);
    }
    if (pExpSrcBMHeader)
    {
        FreeMemory(pExpSrcBMHeader);
    }

    /******************************************************************/
    /* If we reordered the clip regions, set the value for direction  */
    /* in the control structure to the default                        */
    /******************************************************************/
    if ( ReOrderClips )
    {
#ifdef POST174
        GetClipsControl.ulDirection = RECTDIR_LFRT_TOPBOT;
#else /* POST174 */
        GetClipsControl.usDirection = RECTDIR_LFRT_TOPBOT;
#endif /* POST174 */
    }

    reenable_cursor();


    /******************************************************************/
    /* <DCRTURBO>                                                     */
    /******************************************************************/
    /* Set the global AIxfer flag to initialize the image stretch     */
    /* operation flag so that when a bitblt operation call is made    */
    /* it will not inadvertantly call the stretching function based   */
    /* on an indeterminant state of this global stretch flag.         */
    /******************************************************************/
    AIxfer.fStretching = FALSE;

    ExitDriver(pdcArg, FunN, EDF_STANDARD);
    return (CorrResult);


/**********************************************************************/
BITBLT_ERR_EXIT:

    /******************************************************************/
    /* delete any work bitmaps that were created                      */
    /******************************************************************/
    if (ExpPatBMHeader.Bitmap)
    {
        eddb_FreeMemForBitmap(&ExpPatBMHeader);
    }
    if (pExpSrcBMHeader)
    {
        FreeMemory(pExpSrcBMHeader);
    }

    reenable_cursor();

    /******************************************************************/
    /* <DCRTURBO>                                                     */
    /******************************************************************/
    /* Set the global AIxfer flag to initialize the image stretch     */
    /* operation flag so that when a bitblt operation call is made    */
    /* it will not inadvertantly call the stretching function based   */
    /* on an indeterminant state of this global stretch flag.         */
    /******************************************************************/
    AIxfer.fStretching = FALSE;

    ExitDriver(pdcArg, FunN, EDF_STANDARD);
    return(ERROR_ZERO);

BITBLT_LOGERR_EXIT:
    /******************************************************************/
    /* delete any work bitmaps that were created                      */
    /******************************************************************/
    if (ExpPatBMHeader.Bitmap)
    {
        eddb_FreeMemForBitmap(&ExpPatBMHeader);
    }
    if (pExpSrcBMHeader)
    {
        FreeMemory(pExpSrcBMHeader);
    }

    reenable_cursor();
BITBLT_FAST_LOGERR_EXIT:

    /******************************************************************/
    /* <DCRTURBO>                                                     */
    /******************************************************************/
    /* Set the global AIxfer flag to initialize the image stretch     */
    /* operation flag so that when a bitblt operation call is made    */
    /* it will not inadvertantly call the stretching function based   */
    /* on an indeterminant state of this global stretch flag.         */
    /******************************************************************/
    AIxfer.fStretching = FALSE;

    ExitDriver(pdcArg, FunN, EDF_STANDARD);
    LogError(Error);
    return(ERROR_ZERO);


} /* eddb_BitBlt */

/******************************************************************************/
/* FUNCTION:                                                                  */
/******************************************************************************/
VOID DRIVERCALL eddb_BltThroughClips(VOID (DRIVERCALL *BltFunction)())
{
    /******************************************************************/
    /* This routine does different things depending on                */
    /* fThreeWayWorkBlt.                                              */
    /******************************************************************/
    if (fThreeWayWorkBlt)
    {
        /******************************************************************/
        /* Comes here if destination is the work bitmap for three way     */
        /* rops - ignores engine clips and sets clips to target rectangle */
        /******************************************************************/

        /******************************************************************/
        /* Put the target rectangle into the clip cache                   */
        /******************************************************************/
        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;

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

        /******************************************************************/
        /* Force the cache to be refilled next time..                     */
        /******************************************************************/
        pdc->ClipChanged = TRUE;
    }
    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;
                BltFunction();
            }

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

} /* eddb_BltThroughClips */

/******************************************************************************/
/* FUNCTION:                                                                  */
/******************************************************************************/
VOID DRIVERCALL eddb_DrawThroughClips(VOID (DRIVERCALL *Function)(),
                                      USHORT *          pNumClips)

{
    /******************************************************************/
    /* do the appropriate drawing function 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 if all processed     */
        /**************************************************************/
        GetClipsControl.crcReturned = 0;

        /**************************************************************/
        /* if the total number of clips comprising the region exceeds */
        /* the size of the dc cache or the cache contents are changed */
        /* then call the engine to get valid rectangles into the cache*/
        /**************************************************************/
        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)
        {
            *pNumClips = pdc->DCIClipNum;
            Function();
        }

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

} /* eddb_DrawThroughClips */

/******************************************************************************/
/* FUNCTION:                                                                  */
/******************************************************************************/
pBitmapHeader convert_colour_to_mono(ULONG         FunN,
                                     ULONG         attr_option,
                                     PBITBLTATTRS  ArgAttrs,
                                     PDC           pdcSrc)
{
    ULONG               PhysSrcColor;  /* source physical colour      */
    ULONG               PhysSrcBackColor; /* source phys backgrd color*/

    /******************************************************************/
    /* if no drawing is required then there is nothing to do          */
    /******************************************************************/
    if ( FunNTest(COM_DRAW) )
    {
        /**************************************************************/
        /* if the attributes are on the stack, get the colours from   */
        /* there                                                      */
        /**************************************************************/
        /**********************************************************/
        /* get the colours to use from the target DC or the       */
        /* parameters                                             */
        /**********************************************************/
        if (attr_option & BLTMODE_ATTRS_PRES)
        {
            PhysSrcColor     = LogToPhyIndex(ArgAttrs->lColor);
            PhysSrcBackColor = LogToPhyIndex(ArgAttrs->lBackColor);
        }
        else /* use attribute bundle colours */
        {
            PhysSrcColor     = pdc->DCIImagColatts.ForeColor;
            PhysSrcBackColor = pdc->DCIImagColatts.BackColor;
        }

        /**********************************************************/
        /* do the conversion using pExpSrcBMHeader for the new    */
        /* bitmap                                                 */
        /**********************************************************/
        pExpSrcBMHeader = BMConvIntToInt(pdcSrc,
                                         AIxfer.pbmhSrc,
                                         PhysSrcColor,
                                         PhysSrcBackColor);

        if (pExpSrcBMHeader == FNULL)
        {
            /**********************************************************/
            /* Pass back the error indicator.                         */
            /**********************************************************/
            return(FNULL);
        }

        /**********************************************************/
        /* put the new bitmap header in the blt parameter block   */
        /**********************************************************/
        AIxfer.pbmhSrc = pExpSrcBMHeader;

   } /* COM_DRAW set */

   /*******************************************************************/
   /* Return the new bitmap header.                                   */
   /*******************************************************************/
   return(pExpSrcBMHeader);

} /* convert_colour_to_mono */
/******************************************************************************/
/* FUNCTION:                                                                  */
/*                                                                            */
/* This routine converts the background mixes BM_SRCTRANSPARENT and           */
/* BM_DESTTRANSPARENT to the required values in the colour compare registers. */
/* See descriptions of BM_SRCTRANSPARENT and BM_DESTTRANSPARENT at the top    */
/* of this module.                                                            */
/*                                                                            */
/* The way hardware usually documents these mix modes is as follows:          */
/*                                                                            */
/* BM_SRCTRANSPARENT <=> Don't update the bitmap if the source pel is         */
/*                       equal to the compare color (i.e., background)        */
/* BM_DESTTRANSPARENT <=> Don't update the bitmap if the destination pel is   */
/*                        not equal to the compare color (i.e., background)   */
/*                                                                            */
/* These mixes can be implemented more efficiently for 1bpp by simply         */
/* adjusting the original background mix.                                     */
/******************************************************************************/

VOID convert_BMix_to_ColComp(ULONG ArgOptions,
                             PBITBLTATTRS  ArgAttrs)
{
#ifndef _8514
    ULONG               lBackMixMask;  /* mask for BM_SRCTRANSPARENT  */
    ULONG               LogBackColor;  /* logical background colour   */
#endif /* ~_8514 */
    /******************************************************************/
    /* Adjust the background mix for 1bpp bitmaps, set up the colour  */
    /* compare registers for the other bitmap formats.                */
    /******************************************************************/

    if (AIxfer.pbmhDest->Info.BitCount == 1)
    {
        /**********************************************************/
        /* The background hardware mix value is constructed from  */
        /* the bits that result from the combinations of source   */
        /* and destination:                                       */
        /*                                                        */
        /* Eg HWMIX_SOURCE_OR_DEST                                */
        /*          source  dest   result                         */
        /*            0      0       0   a                        */
        /*            0      1       1   b                        */
        /*            1      0       1   c                        */
        /*            1      1       1   d                        */
        /*  has a code of abcd = 0111, ie 7                       */
        /*                                                        */
        /* The transparent mixes for 1bpp can therefore be        */
        /* implemented by adjusting the mix code.                 */
        /*                                                        */
        /* Eg for BM_DESTTRANSPARENT with background == 0, bits   */
        /*    b and d must remain unchanged and bits a and c set  */
        /*    to the values according to the mix. This is achieved*/
        /*    by setting bits b and d to 1. Ie mask = mask & 0101 */
        /*                                                        */
        /* For 1bpp BM_SRCTRANSPARENT and BM_DESTTRANSPARENT can  */
        /* therefore be implemented by:                           */
        /*                                                        */
        /* BM_SRCTRANSPARENT (background = 0)                     */
        /*          mix = mix & 0011                              */
        /*                                                        */
        /* BM_SRCTRANSPARENT (background = 1)                     */
        /*          mix = mix | 0011                              */
        /*                                                        */
        /* BM_DESTTRANSPARENT (background = 0)                    */
        /*          mix = mix & 0101                              */
        /*                                                        */
        /* BM_DESTTRANSPARENT (background = 1)                    */
        /*          mix = mix | 0101                              */
        /**********************************************************/

        /**********************************************************/
        /* The above scheme only works for the combinatorial      */
        /* mixes (mixes 0 -> 15). We do not use the other mixes   */
        /**********************************************************/
#ifdef FIREWALLS
#ifndef _8514
        if ( (ShadowXGARegs.BgMix <  0) ||
             (ShadowXGARegs.BgMix > 15) )
        {
            haltproc();
        }
#endif /* ~_8514 */
#endif /* FIREWALLS */

        #ifdef _8514
        /**********************************************************/
        /* Set the colour compare value to the background colour. */
        /* (either passed in or stored in DC)                     */
        /**********************************************************/
        Shadow8514Regs.Color_Comp =
            (ArgOptions & BLTMODE_ATTRS_PRES) ?
             LogToPhyIndex(ArgAttrs->lBackColor):
             pdc->DCIImagColatts.BackColor;

        /**********************************************************/
        /* Set the colour compare condition according to the mix. */
        /**********************************************************/
        Shadow8514Regs.Mode.UnderPaint =
            (pdc->DCICurImgAts.ibnd.usBackMixMode == BM_SRCTRANSPARENT) ?
             (BYTE)MD_UP_EQ :
             (BYTE)MD_UP_NE;
        Shadow8514Regs.Mode.PatternSrc = MD_PS_ONES;
        Shadow8514Regs.Mode.PlaneMode = MD_AF_W_NORMAL;

        #else /* ~_8514 */

        /**********************************************************/
        /* Select the mask according to the operation             */
        /**********************************************************/
        lBackMixMask =
            (pdc->DCICurImgAts.ibnd.usBackMixMode == BM_SRCTRANSPARENT) ?
            BM_SRCTRANSPARENT_1BPP_MASK :
            BM_DESTTRANSPARENT_1BPP_MASK;

        /**********************************************************/
        /* Find out the background colour                         */
        /**********************************************************/
        LogBackColor = (ArgOptions & BLTMODE_ATTRS_PRES) ?
                      ArgAttrs->lBackColor :
                      pdc->DCIImagColatts.BackColor;

        /**********************************************************/
        /* Adjust the mix to allow for transparency               */
        /**********************************************************/

        if (LogBackColor == 0)
            ShadowXGARegs.BgMix &= lBackMixMask;
        else
            ShadowXGARegs.BgMix |= lBackMixMask;

        #endif /* ~_8514 */

    }
    else
    {
        #ifdef _8514
        /**********************************************************/
        /* Set the colour compare value to the background colour. */
        /* (either passed in or stored in DC)                     */
        /**********************************************************/
        Shadow8514Regs.Color_Comp =
            (ArgOptions & BLTMODE_ATTRS_PRES) ?
             LogToPhyIndex(ArgAttrs->lBackColor):
             pdc->DCIImagColatts.BackColor;

        /**********************************************************/
        /* Set the colour compare condition according to the mix. */
        /**********************************************************/
        Shadow8514Regs.Mode.UnderPaint =
            (pdc->DCICurImgAts.ibnd.usBackMixMode == BM_SRCTRANSPARENT) ?
             (BYTE)MD_UP_EQ :
             (BYTE)MD_UP_NE;
        Shadow8514Regs.Mode.PatternSrc = MD_PS_ONES;
        Shadow8514Regs.Mode.PlaneMode = MD_AF_W_NORMAL;

        #else /* ~_8514 */

        /**********************************************************/
        /* Set the colour compare value to the background colour. */
        /* (either passed in or stored in DC)                     */
        /**********************************************************/
        ShadowXGARegs.ColCompVal =
            (ArgOptions & BLTMODE_ATTRS_PRES) ?
             LogToPhyIndex(ArgAttrs->lBackColor) :
             pdc->DCIImagColatts.BackColor;

        /**********************************************************/
        /* Set the colour compare condition according to the mix. */
        /**********************************************************/
        ShadowXGARegs.ColCompCond =
            (pdc->DCICurImgAts.ibnd.usBackMixMode == BM_SRCTRANSPARENT) ?
             (BYTE)COLCOMP_SRC_NOT_EQUAL :
             (BYTE)COLCOMP_EQUAL;

        #endif /* XGA */

    }   /* Not 1bpp */
} /* convert_BMix_to_ColComp */
