;*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          = FFBLTSD
;
;   Description     = 386 code for the software source to destination blt
;                     operations in MESS.
;
;   Functions       = eddf_MESSBlockCopy4111
;                     eddf_MESSSrcDestMix4111
;                     eddf_MESSSrcDestWrapCopy41
;                     eddf_MESSSrcDestWrapMix41
;                     eddf_MESSBlockCopy81
;                     eddf_MESSSrcDestMix81
;                     eddf_MESSSrcDestWrapCopy81
;                     eddf_MESSSrcDestWrapMix81
;                     eddf_MESSBlockCopy16
;                     eddf_MESSSrcDestMix16
;                     eddf_MESSSrcDestWrapCopy16
;                     eddf_MESSSrcDestWrapMix16
;
;
;-------------------------------------------------------------------------

DCR89 EQU 1
ifdef DCR89
INCL_GPIBITMAPS EQU     1
include os2.inc
endif ; DCR89
include eddinclt.inc

; Include the XGA assembler include files and the MESS include files

include eddhcone.inc
include eddhtype.inc
include eddhmacr.inc

include eddfcone.inc
include eddfmacr.inc
include eddftype.inc

?DF     equ     1       ; we dont want _TEXT segment defined
include cmacros.inc

include rmacros.inc

include ffmacros.inc

        .386p


;-------------------------------------------------------------------------




_DATA           segment use32 dword public 'DATA'
                assume  cs:FLAT, ds:FLAT, es:FLAT

; Declare the external data elements we use
ifndef  _8514
externDP        ShadowXGARegs
else
include         8514.inc
externDP        Shadow8514Regs
endif
externDP        srcPixmap
externDP        dstPixmap
externDP        messSpad


IFDEF PALETTE_MGR
externW         UsePaletteMapping
externDP        PaletteMapping
ENDIF


; Declare mix tables defined in eddffast.asm
; use extrn not externDP because these do NOT have an _ at the start
; of their names
extrn        mixTrashSourcePartBY  : FAR
extrn        mixTrashSourcePartDW  : FAR
extrn        mixKeepSourcePartBY   : FAR

_DATA           ends


;-------------------------------------------------------------------------





_TEXT           segment use32 dword public 'CODE'
                assume  cs:FLAT, ds:FLAT, es:FLAT


; These functions are defined in ffbltset.asm
externP eddf_MESSSetUpSrcDest11
externP eddf_MESSSetUpSrcDest41
externP eddf_MESSSetUpSrcDest81
externP eddf_MESSSetUpSrcDest16




IF1

RestoreColorComp macro
        IFDEF _8514
        and     byte ptr _Shadow8514Regs.Color_Comp, 0Fh
        ELSE
        and     byte ptr _ShadowXGARegs.colour_comp_colour, 0Fh
        ENDIF
        endm

CheckColorComp macro pels, StandardLabel, EqualLabel

IFB <pels>
        .ERR
        %OUT bits per pel arguement is blank
ELSE
 IFDIF <pels>, <8bp>
  IFDIF <pels>, <4bp1bp>
   IFDIF <pels>, <16bp>
        .ERR
        %OUT bits per pel arguement must be 8bp, 4bp1bp
   ENDIF
  ENDIF
 ENDIF
ENDIF

        IFDEF _8514
        mov     ebx, Shadow8514Regs.Mode
        and     ebx, MD_UNDERPAINT
        cmp     ebx, MD_UP_FALSE
        ELSE
        cmp     ShadowXGARegs.colour_comp_fun, COLCOMP_ALWAYS
        ENDIF
        je      StandardLabel

        IFIDN <pels>, <4bp1bp>
        ; Modify the color compare value so that it contains
        ; two pels worth of color in the low byte.
        IFDEF _8514
        mov     al, byte ptr _Shadow8514Regs.Color_Comp
        ELSE
        mov     al, byte ptr _ShadowXGARegs.colour_comp_colour
        ENDIF
        mov     ah, al
        shl     al, 4
        shr     eax, 4
        IFDEF _8514
        mov     byte ptr _Shadow8514Regs.Color_Comp, al
        ELSE
        mov     byte ptr _ShadowXGARegs.colour_comp_colour, al
        ENDIF
        ENDIF

        ; Code for color compare.
        IFDEF _8514
        cmp     ebx, MD_UP_EQ
        ELSE
        cmp     ShadowXGARegs.colour_comp_fun, COLCOMP_SRC_NOT_EQUAL
        ENDIF
        jne     EqualLabel
        endm

;;;****************************************************************
;;;
;;; 8514 Macros
;;;
;;; These are the counterparts to the XGA macros defined in the
;;; next section.  We have to duplicate this because MASM cannot
;;; handle IFDEFs inside a macro IF.
;;;
;;;****************************************************************

IFDEF _8514

;-----------------------------------------------------------------------
; This macro combines the source pels in al with the destination pels
; (which are got into ah) using the color compare function of "destination
; pels equal". al should already be associated with SrcByte by rmacros.
; ch should be free to be used as a temporary.
; On exit from this macro al is ready to be written to the destination
; bitmap.
;-----------------------------------------------------------------------
ColCompEqual4bp macro
local   checkedPel0, checkedPel1
rName ah DestByte
        ; Get two destination pels into ah.
        mov     ahDestByte, byte ptr [ediDestIndex]
        ; Get the difference between the destination pels and the
        ; color compare value in ch. (Note that the color compare value
        ; in the shadow registers must be manipulated to contain 2 pels
        ; of color before this macro is called at 4bp).
        mov     ch, ahDestByte
        xor     ch, byte ptr _Shadow8514Regs.Color_Comp
        ; See if the top pel (pel 1) is the same as the color compare value.
        cmp     ch, 0Fh
        jle     short @F
        ; The top pel is the not color compare value. Keep the destination
        ; pel and throw away the source pel.
        shl     alSrcByte, 4
        rol     ahDestByte, 4
        jmp     short checkedPel1
@@:
        ; The top pel is the color compare value. Keep the source pel and
        ; throw away the destination pel.
        rol     alSrcByte, 4
        shl     ahDestByte, 4
checkedPel1:
        ; Now check the low pel.
        shl     ch, 4
        cmp     ch, 0Fh
        jle     short @F
        ; The low pel is the not color compare value. Keep the destination
        ; pel and throw away the source pel.
        shl     alSrcByte, 4
        rol     ahDestByte, 4
        jmp     short checkedPel0
@@:
        ; The low pel is the color compare value. Keep the source pel and
        ; throw away the destination pel.
        rol     alSrcByte, 4
        shl     ahDestByte, 4
checkedPel0:
        ; Combine the source and destination pels we decided to keep.
        or      alSrcByte, ahDestByte
rFree ah DestByte
endm


;-----------------------------------------------------------------------
; This macro combines the source pels in al with the destination pels
; (which are got into ah) using the color compare function of "source pels
; not equal". al should already be associated with SrcByte by rmacros.
; ch should be free to be used as a temporary.
; On exit from this macro al is ready to be written to the destination
; bitmap.
;-----------------------------------------------------------------------
ColCompSrcNotEqual4bp macro
local   checkedPel0, checkedPel1
rName ah DestByte
        ; Get two destination pels into ah.
        mov     ahDestByte, byte ptr [ediDestIndex]
        ; Get the difference between the original source pels and the
        ; color compare value in ch. (Note that the color compare value
        ; in the shadow registers must be manipulated to contain 2 pels
        ; of color before this macro is called at 4bp).
        xor     chOrigSrcByte, byte ptr _Shadow8514Regs.Color_Comp
        ; See if the top pel (pel 1) is the same as the color compare value.
        cmp     chOrigSrcByte, 0Fh
        jg      short @F
        ; The top pel is the color compare value. Keep the destination
        ; pel and throw away the source pel.
        shl     alSrcByte, 4
        rol     ahDestByte, 4
        jmp     short checkedPel1
@@:
        ; The top pel is the not color compare value. Keep the source pel
        ; and throw away the destination pel.
        rol     alSrcByte, 4
        shl     ahDestByte, 4
checkedPel1:
        ; Now check the low pel.
        shl     chOrigSrcByte, 4
        cmp     chOrigSrcByte, 0Fh
        jg      short @F
        ; The low pel is the not color compare value. Keep the destination
        ; pel and throw away the source pel.
        shl     alSrcByte, 4
        rol     ahDestByte, 4
        jmp     short checkedPel0
@@:
        ; The low pel is not the color compare value. Keep the source pel
        ; and throw away the destination pel.
        rol     alSrcByte, 4
        shl     ahDestByte, 4
checkedPel0:
        ; Combine the source and destination pels we decided to keep.
        or      alSrcByte, ahDestByte
rFree ah DestByte
endm


;-------------------------------------------------------------------------
;
; Macro: SrcDest pels mix_mode wrap_mode [palette_mode]
;
; This does a fast block copy (most of the time) for 16,1  8,1  4,1  and 1,1
; formats. It handles straight block copies, mixes, palette conversions, and
; wrap-around blts. The wrap-around blts are limited in direction to the
; single case of top-left to bottom-right.
;
; Parameters:
;         pels  should be either "16bp", "8bp" or "4bp1bp". The code produced
;               by "4bp1bp" handles both 4,1 and 1,1 bitmap formats.
;     mix_mode  should be either "mix" or "no_mix". This specifies whether the
;               macro should be expanded to implement mixes.
;    wrap_mode  should be either "wrap" or "no_wrap". This specifies whether
;               the macro should be expanded to implement source wrapping.
; palette_mode  should be either "palette" or "no_palette". This parameter
;               is optional. If PALETTE_MGR is defined then the palette_mode
;               must be supplied. It is an error to supply the palette_mode
;               when PALETTE_MGR is not defined. The parameter specifies
;               whether the macro should be expanded to implement palette
;               conversions.
;
; Internally:
;          eax  is used as a general purpose registers for temporary values.
;          ecx  is used as the count for rep movs instructions at 8bp.
;           cl  is used as the srcToDestShift at 4bp1bp.
;          ebx  at 8bp with palette mapping is used as the index register into
;               the paletteMapping table. At 4bp1bp with wrap-around it is used
;               to hold the end mask to be used on the last byte of data from
;               each line of source.
;          edx  is used to control the per line loop.
;          ebp  at 4bp1bp is used to wrap-around the high byte of each source
;               word fetched at the end of a source line.
;          esi  is used to index into the source pixmap.
;          edi  is used to index into the destination pixmap.
;
; Preserves:    ?
;
; Destroys:     ?
;
;
;-------------------------------------------------------------------------

SrcDest macro   pels, wrap_mode, mix_mode, comp_mode, palette_mode
        local   setUpPerLineLoop, wrapLoop, perLineLoop, dwordLoop
        local   dwordMixCodeBase, byteMixCodeBase, noDwordsToDo
        local   byteLoop, noMorePelsToDo, doNextLine, vertWrapSourceReturn
        local   doneSetUpCall, doLastByte, startByteMixCodeBase
        local   setUpByteLoop, useRealEndMask, finishedThisByte
        local   notStartingOnLastByte, gotStartHighByte, willNotNeedToWrap
        local   endByteMixCodeBase, vertWrapSource, setUpPerLineLoop, exit
        local   wordMixCodeBase, wordLoop, finishedThisWord

        ; We will use rmacros to help keep track of register usage.
rStart

        ; First we will do some checking of the arguements to see if
        ; the macro is being used correctly...

        ; and we want to set the use_rep_movs flag to indicate how to
        ; implement the inner loop of the code. If we are not using a
        ; mix or a palette conversion and we are in 8bp mode then we
        ; can just use the string copy instruction (rep movs).

        use_rep_movs = FALSE
        use_palette = FALSE

IFB <pels>
        .ERR
        %OUT bits per pel arguement is blank
ELSE
 IFDIF <pels>, <8bp>
  IFDIF <pels>, <4bp1bp>
   IFDIF <pels>, <16bp>
        .ERR
        %OUT bits per pel arguement must be 8bp, 4bp1bp
   ENDIF
  ENDIF
 ENDIF
ENDIF

IFB <wrap_mode>
        .ERR
         %OUT wrap mode arguement is blank
ELSE
 IFDIF <wrap_mode>, <wrap>
  IFDIF <wrap_mode>, <no_wrap>
        .ERR
        %OUT wrap mode arguement must be wrap or no_wrap
  ENDIF
 ENDIF
ENDIF

IFB <mix_mode>
        .ERR
        %OUT mix mode arguement is blank
ELSE
 IFDIF <mix_mode>, <mix>
  IFDIF <mix_mode>, <no_mix>
        .ERR
        %OUT mix mode arguement must be mix or no_mix
  ELSE
   IFDIF <pels>, <4bp1bp>
        ; The mix mode arguement is no_mix and we are using 8bp or 16bp
        ; so as long as we are not using a palette then we can
        ; use the rep movs instruction to implement the inner loop.
        use_rep_movs  = TRUE
   ENDIF
  ENDIF
 ENDIF
ENDIF

IFB <comp_mode>
        .ERR
        %OUT color compare mode arguement is blank
ELSE
 IFDIF <comp_mode>, <no_colcomp>
  ; We are using the color compare register so we can not use rep movs
  ; to implemt fast block copy.
  use_rep_movs  = FALSE
  IFDIF <comp_mode>, <colcomp_equal>
   IFDIF <comp_mode>, <colcomp_src_not_equal>
        .ERR
        %OUT color compare mode arguement must be no_colcomp colcomp_equal or colcomp_src_not_equal.
   ENDIF
  ENDIF
 ENDIF
ENDIF


IFB <palette_mode>
 IFDEF PALETTE_MGR
        .ERR
        %OUT Undefined palette_mode argument!
 ENDIF ;IFDEF PALETTE_MGR
ELSE
 IFNDEF PALETTE_MGR
        %OUT PALETTE_MGR undefined - ignoring palette_mode argument
 ELSE
  IFIDN <palette_mode>, <no_palette>
        use_palette = FALSE
  ELSE
   IFIDN <palette_mode>, <palette>
    IFDIF <pels>, <8bp>
        ; If we are not at 8bp then it is an error to specify palette
        ; as the palette mode.
        .ERR
        %OUT palette mode can only be used at 8 bits per pel
    ELSE
        ; The palette_mode arguement is "palette"
        use_palette = TRUE
        ; PALETTE_MGR is defined so we cannot use the rep movs
        ; instruction to implement the inner loop.
        use_rep_movs = FALSE
    ENDIF
   ELSE
        .ERR
        %OUT Invalid palette_mode argument - must be palette or no_palette
   ENDIF
  ENDIF ;IFIDN <palette_mode>
 ENDIF ;IFDEF PALETTE_MGR
ENDIF ;IFB <palette_mode>


IFDEF FIREWALLS
 IFIDN <wrap_mode>, <wrap>
        ; Wrap-around operations are limited to run from top-left to
        ; bottom-right.
        test    Shadow8514Regs.pixel_op.lo, BLTDIR_RIGHTTOLEFT+BLTDIR_BOTTOMTOTOP
        jz      short @F
        int     3
@@:
 ENDIF
ENDIF

        ; Now we have done the arguement checks we can get down to the
        ; real code bit of the macro...

        ; First of all we want to call one of the SrcDest set up functions.

IFIDN <pels>, <8bp>
        ; Call eddf_MESSSetUpSrcDest81 to initialise the values we will
        ; need in the scratch pad for most operations.
        cCall   eddf_MESSSetUpSrcDest81

ELSE  ; IFIDN <pels>, <8bp>
 IFIDN <pels>, <16bp>
        ; Call eddf_MESSSetUpSrcDest16 to initialise the values we will
        ; need in the scratch pad for most operations.
        cCall   eddf_MESSSetUpSrcDest16

 ELSE  ; IFIDN <pels>, <16bp>

        test    byte ptr dstPixmap.format, FOUR_BPP
        jnz     short @F

        ; Call eddf_MESSSetUpSrcDest11 to initialise the values we will
        ; need in the scratch pad for most operations.
        cCall   eddf_MESSSetUpSrcDest11
  IFDEF FIREWALLS
   IFDIF <comp_mode>, <no_colcomp>
        ; We should never call color compare functions at 1bp. If color
        ; compare is required it should have been implemented by changing
        ; the mixes. See transparent mixes explanation at start of bitblt
        ; code in eddnbblt.c.
        int     3
   ENDIF ; IFDIF <comp_mode>, <no_colcomp>
  ENDIF ; IFDEF FIREWALLS
        jmp     short doneSetUpCall
@@:
        ; Call eddf_MESSSetUpSrcDest41 to initialise the values we will
        ; need in the scratch pad for most operations.
        cCall   eddf_MESSSetUpSrcDest41

doneSetUpCall:

 ENDIF ; IFIDN <pels>, <16bp>  ELSE
ENDIF ; IFIDN <pels>, <8bp>  ELSE

rName edi DestIndex
rName esi SourceIndex

IFIDN <wrap_mode>, <wrap>
        ; Initialise other values in the scratch pad that we will need
        ; for the source wrapping code.

        ; Keep a copy of the source index for the start of this blt line
        ; in srcLineStartAddr.
        mov     _messSpad.srcLineStartAddr, esiSourceIndex

        ; Work out how many source lines will be drawn before the source
        ; will have to wrap vertically.
        mov     ax, srcPixmap.yLen
        inc     ax
        sub     ax, Shadow8514Regs.src_map_y
        mov     _messSpad.srcLinesBeforeWrap, ax
ENDIF ; IFIDN <wrap_mode>, <wrap>


IFIDN <mix_mode>, <mix>
        ; Initialise other values in the scratch pad that we will need
        ; for the mixing code.

        ; Get the foreground mix into bl and clear the rest of ebx so that
        ; we can use ebx as in index in extended 386 addressing modes.
rName ebx Mix
        movzx   ebxMix, byte ptr Shadow8514Regs.Function_1
        and     ebxMix, FUNC_ALU

        ; Get the offset of any byte mixes we might need to do into cx.
rName ecx ByteMixCodeOffset
        mov     ecxByteMixCodeOffset, dword ptr mixTrashSourcePartBY[ebxMix*4]

 IFDIF <pels>, <4bp1bp>
  IFIDN <comp_mode>, <no_colcomp>
        ; Work out the address in the dword mix code that we will jump to
        ; when we have a full dword to mix.
        mov     eax, dword ptr mixTrashSourcePartDW[ebxMix*4]
        add     eax, offset FLAT:dwordMixCodeBase
        mov     _messSpad.dwordsMixOffset, eax
  ENDIF ; IFIDN <comp_mode>, <no_colcomp>

 ELSE  ; IFDIF <pels>, <4bp1bp>
        ; Work out the address in the byte mixing code that we will jump to
        ; when we are mixing in the first byte of each line.
        mov     eax, dword ptr mixKeepSourcePartBY[ebxMix*4]
        add     eax, offset FLAT:startByteMixCodeBase
        mov     _messSpad.startBytesMixOffset, eax

        ; Work out the address in the byte mixing code that we will jump to
        ; when we are mixing in the last byte of each line of destination.
        mov     eax, dword ptr mixKeepSourcePartBY[ebxMix*4]
        add     eax, offset FLAT:endByteMixCodeBase
        mov     _messSpad.endBytesMixOffset, eax

 ENDIF ; IFIDN <pels>, <4bp1bp>  ELSE

 IFDIF <pels>, <16bp>
        ; Work out the address in the byte mix code that we will jump to
        ; when we are mixing using the byte loop.
        mov     eax, ecxByteMixCodeOffset
        add     eax, offset FLAT:byteMixCodeBase
        mov     _messSpad.fullBytesMixOffset, eax
 ELSE  ; IFDIF <pels>, <16bp>
        ; Work out the address in the word mix code that we will jump to
        ; when we are mixing using the word loop.
        mov     eax, ecxByteMixCodeOffset
        add     eax, offset FLAT:wordMixCodeBase
        mov     _messSpad.wordsMixOffset, eax
 ENDIF ; IFDIF <pels>, <16bp>  ELSE
rFree ebx Mix
rFree ecx ByteMixCodeOffset

ENDIF ; IFIDN <mix_mode>, <mix>



        ; Now we have everything in the scratch pad initialised we can set up
        ; the loop counters and do the main loop.

        mov     ax, Shadow8514Regs.dim2
        inc     ax
        mov     _messSpad.perLineLoopCount, ax

        ; Clear ecx and ebx so that we only have to partially load them if
        ; we need to use them inside the loop.
        xor     ecx, ecx
        xor     ebx, ebx

IFIDN <pels>, <4bp1bp>
 IFIDN <wrap_mode>, <wrap>
        ; Load the top half of ebx with the identity mask (and its inverse)
        ; so that when it is used all of the source gets copied to the
        ; destination.
        mov     bx, 00ffh
        swap    ebx
rName ebx_top IdentityMasks
 ENDIF ; IFIDN <wrap_mode>, <wrap>

        ; Load bx with the end mask and its inverse.
        .ERRE endMaskInv eq (endMask + 1)
rName bx Masks
        mov     bxMasks, word ptr _messSpad.endMask

        ; Get the srcToDestShift into the cl register.
rName cl SrcToDestShift
        mov     clSrcToDestShift, _messSpad.srcToDestShift

ENDIF ; IFIDN <pels>, <4bp1bp>


setUpPerLineLoop:

IFIDN <wrap_mode>, <wrap>

 IFIDN <pels>, <8bp>
        ; Get the number of bytes still to go on this line before
        ; we have to wrap around into ax.
        mov     eax, _messSpad.srcWidthInBytes
        sub     ax, Shadow8514Regs.src_map_x

 ELSE  ; IFIDN <pels>, <8bp>
  IFIDN <pels>, <16bp>
        ; Get the number of bytes still to go on this line before
        ; we have to wrap around into ax.
        mov     eax, _messSpad.srcWidthInBytes
        mov     dx, Shadow8514Regs.src_map_x
        shl     dx, 1
        sub     ax, dx

  ELSE  ; IFIDN <pels>, <16bp>

        ; Get the number of bytes still to go on this line before
        ; we have to wrap around into ax.
        mov     eax, _messSpad.srcWidthInBytes
        mov     dx, Shadow8514Regs.src_map_x
        test    byte ptr dstPixmap.format, FOUR_BPP
        jnz     short @F
        shr     dx, 2
@@:
        shr     dx, 1
        sub     ax, dx

        ; If the source index was adjusted in the setUpSrcDest function then
        ; esi will actually be pointing one byte to the left of the first pel
        ; in this case we must do one extra byte the first time through the
        ; wrap loop.
        .ERRE   TRUE eq 1
        .ERRE   FALSE eq 0
        add     eax, _messSpad.srcIndexAdjusted
  ENDIF ; IFIDN <pels>, <16bp>  ELSE
 ENDIF ; IFIDN <pels>, <8bp>  ELSE

rName ax BytesBeforeWrap

ENDIF ; IFIDN <wrap_mode>, <wrap>



IFIDN <pels>, <4bp1bp>

        ; We are at 4bp or 1bp and we are about to blt a line from the source
        ; to the destination. We must deal with the first and last bytes
        ; seperately from the main byte loop and use the startMask and endMask
        ; values to make sure we only effect the correct pels.

        ; Get the first byte sized chunk of the source corresponding to the
        ; first physical byte of the destination. To do this we must get a
        ; word from the source and apply the srcToDestShift to it.

        ; To get a word from the source we must access it as two bytes. This
        ; is because the source index may point just to the left of the start
        ; of the bitmap (see setUpSrcDest11 for full explanation) and so we
        ; might be accessing a word across a segment boundry.

        ; Get the word containing the source byte we want into ax and
        ; update the source index.

 IFIDN <wrap_mode>, <wrap>
        ; Save ax in dx so we can use lods and stos instructions.
        mov     dx, axBytesBeforeWrap
rFree ax BytesBeforeWrap
rName dx BytesBeforeWrap

        ; We must remember that the second byte of the word might infact
        ; have wrapped around to the beginning of the line.

        ; Set up bp so it can be used as an adjuster when the second byte of
        ; the word wraps around.
rName ebp SecondByteAdjuster
        mov     ebpSecondByteAdjuster, _messSpad.srcWidthInBytes
        neg     ebpSecondByteAdjuster

        ; See if esiSourceIndex is pointing to the last byte on this source line.
        ; dx contains the number of bytes still to go on this source line.
        cmp     dxBytesBeforeWrap, 1
        jne     short notStartingOnLastByte
        mov     ah, [esiSourceIndex+ebpSecondByteAdjuster+1]
        jmp     short gotStartHighByte

 ENDIF ; IFIDN <wrap_mode>, <wrap>


notStartingOnLastByte:
        mov     ah, [esiSourceIndex+1]
gotStartHighByte:
        lods    byte ptr [esiSourceIndex]

        ; Now rotate the source word by the srcToDestShift so that al contains
        ; the bits which correspond to the first byte in the destination.
        rol     ax, clSrcToDestShift

        ; al now contains the bits which are to be blted onto the first byte
        ; in the destination.
rName al SrcByte

        ; Get the destination byte.
rName ah DestByte
        mov     ahDestByte, [ediDestIndex]

 IFIDN <mix_mode>, <mix>
        ; Make sure we have a copy of the destination byte to use later.
        mov     ch, ahDestByte

        ; Now jump to the mixing code at the right place.
        jmp     _messSpad.startBytesMixOffset

startByteMixCodeBase:
        mixKeepSourcePart      alSrcByte, ch

        ; Get the new source byte (after mixing) into al and the
        ; original source byte into ch.
        xchg    alSrcByte, ch
  IFIDN <comp_mode>, <colcomp_src_not_equal>
rName ch OrigSrcByte
  ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

 ELSE  ; IFIDN <mix_mode>, <mix>

  IFIDN <comp_mode>, <colcomp_src_not_equal>
        mov     ch, alSrcByte
rName ch OrigSrcByte
  ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

 ENDIF ; IFIDN <mix_mode>, <mix>  ELSE


        ; Now use the start mask (and its inverse) to combine the source byte
        ; with the destination byte. (Note we use AX rather than ax to let
        ; rmacros know that we know that ax is in use for alSrcByte and
        ; ahDestByte so that it does not generate an error).
        .ERRE   startMaskInv eq (startMask + 1)
        and     AX, word ptr _messSpad.startMask
        or      alSrcByte, ahDestByte
rFree ah DestByte

        ; al contains the merged source and destination bytes so we can
        ; now write it back to the destination and update the destination
        ; index.

 IFIDN <comp_mode>, <colcomp_equal>
        ; We only want to write pels to the destination where the
        ; original destination pel was the color compare value.
        ColCompEqual4bp
 ENDIF ; IFIDN <comp_mode>, <colcomp_equal>
 IFIDN <comp_mode>, <colcomp_src_not_equal>
        ; We only want to write pels to the destination where the
        ; original (pre mixed) source pels were the color compare value.
        ColCompSrcNotEqual4bp
rFree ch OrigSrcByte
 ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

        ; Store the source pels (after masking and color comparing) in
        ; the destination bitmap.
        stos    byte ptr [ediDestIndex]
rFree al SrcByte

 IFIDN <wrap_mode>, <wrap>
        ; get ax back from its temporary store in dx
        mov     ax, dxBytesBeforeWrap
rFree dx BytesBeforeWrap
rName ax BytesBeforeWrap

        ; ax contains the number of bytes from the source index to the end
        ; of the current source line. But we have just blted the byte so we
        ; must decrement ax to reflect the increment to the source index
        ; we have just done.
        dec     axBytesBeforeWrap

 ENDIF ; IFIDN <wrap_mode>, <wrap>

ENDIF ; IFIDN <pels>, <4bp1bp>




IFDIF <pels>, <4bp1bp>
        ; Get the number of bytes in this line of the destination to be blted
        ; into dx and clear the top half of edx.
        movzx   edx, Shadow8514Regs.dim1
        inc     dx
 IFIDN <pels>, <16bp>
        shl     dx, 1
 ENDIF ; IFIDN <pels>, <16bp>

ELSE  ; IFDIF <pels>, <4bp1bp>
        ; Get the number of bytes in this line of the destination to be blted
        ; into dx and clear the top half of edx.
        mov     edx, _messSpad.totalBytes

        ; We have already blted the first byte of the line.
        ; Check to see if there are more bytes to be done. At this point
        ; dx contains the total number of bytes to be blted in this dest line.
        ; We have just blted the first byte so we can decrement this.
        dec     dx
        jz      noMorePelsToDo
ENDIF ; IFDIF <pels>, <4bp1bp>  ELSE

        ; If we are in wrap mode then we must destinguish between the number
        ; of bytes to be blted on the destination line against the number
        ; of bytes to be blted from this line of source before we have to
        ; wrap. If we are not in wrap mode then these are the same.
IFIDN <wrap_mode>, <wrap>
rName dx BytesLeftOnDestLine
ELSE  ; IFIDN <wrap_mode>, <wrap>
rName dx BytesToGoOnSrcLine
ENDIF ; IFIDN <wrap_mode>, <wrap>  ELSE


IFIDN <wrap_mode>, <wrap>

 IFIDN <pels>, <4bp1bp>
        ; We are going into the wrap loop. First of all swap ebx so that the
        ; identity mask is in bx. When going through the wrap loop for the
        ; last time we can swap ebx again to get the end mask back so that
        ; the last byte of the blt will be done correctly. Until then we
        ; use the identity mask because we want to blt all of the pels.
rFree bx Masks
rFree ebx_top IdentityMasks
        swap    ebx
rName bx IdentityMasks
rName ebx_top Masks

        ; We have already blted the first byte so it is possible that there
        ; are no more bytes left to do on this source line and so we are
        ; ready to wrap-around straight away.
        or      axBytesBeforeWrap, axBytesBeforeWrap
        jnz     short @F

        ; We must move dx into the top half of edx (dx contains the number
        ; of bytes still to do for this line of the blt) as this is what
        ; is expected on exit from the byte loop (at noMorePelsToDo).
rFree dx BytesLeftOnDestLine
        swap    edx
        jmp     noMorePelsToDo

        ; Rmacros is linear so we need this for the code that follows if
        ; we did not execute the previous path.
rName dx BytesLeftOnDestLine

@@:
 ENDIF ; IFIDN <pels>, <4bp1bp>

wrapLoop:
        ; At this point ax should contain the number of bytes to go on the
        ; current line of source before we would have to wrap the source
        ; and dx contains the number of bytes to go before we reach the
        ; end of this line of the blt. The top half of edx should contain
        ; zero and will now be adjusted to contain the number of bytes that
        ; still have to be done after this line of source has been done.

        ; Compare ax with dx to see if we will wrap around the source
        ; before we reach the end of the blt.
        ; If we will finish the blt before we have to wrap then we can
        ; just jump to the main loop code. The top half of edx will be
        ; zero indicating there are no more pels to go on exit from the
        ; loop.
        cmp     axBytesBeforeWrap, dxBytesLeftOnDestLine
 IFDIF <pels>, <4bp1bp>
        jge     short willNotNeedToWrap

 ELSE  ; IFDIF <pels>, <4bp1bp>
        ; At 4bp or 1bp if the number of bytes to be blted is the same as
        ; the number of bytes left on the source line then we must still
        ; wrap around the high byte of the source word so we do not want
        ; to clear bp (-srcWidthInBytes) but we do want to use the end mask.
        jg      short willNotNeedToWrap
        je      short useRealEndMask

 ENDIF ; IFDIF <pels>, <4bp1bp>  ELSE

        ; We will wrap around the source.

        ; Adjust dx so that it contains the number of pels which will still
        ; need to be done on exit from the loop. Shift dx into the top half
        ; of edx. Move ax (the number of pels until wrap around) into dx.
        sub     dxBytesLeftOnDestLine, axBytesBeforeWrap
rFree dx BytesLeftOnDestLine
        swap    edx
        mov     dx, axBytesBeforeWrap
rName dx BytesToGoOnSrcLine
rName edx_top BytesLeftOnDestLine
rFree ax BytesBeforeWrap

        jmp     short perLineLoop

willNotNeedToWrap:

 IFIDN <pels>, <4bp1bp>
        ; Clear ebp so that when accessing the last source word we do not wrap
        ; the high byte. Until now ebp has contained -srcWidthInBytes.
        xor     ebpSecondByteAdjuster, ebpSecondByteAdjuster

useRealEndMask:
        ; Set up bx to contain the end mask and its inverse. The top half of
        ; ebx contains these. Up until now bx has contained the identity mask
        ; 00ffh which simply copies all of the source to the destination.
rFree bx IdentityMasks
rFree ebx_top Masks
        swap    ebx
rName bx Masks
rName ebx_top IdentityMasks

 ENDIF ; IFIDN <pels>, <4bp1bp>

ENDIF ; IFIDN <wrap_mode>, <wrap>

perLineLoop:

IF use_rep_movs eq TRUE

        ; We can use the rep movs instruction to implement the perLineLoop.

        ; Get the number of dwords to do into ecx
        mov     cx, dxBytesToGoOnSrcLine
        shr     ecx, 2

        ; Apply the dword adjustment
        sub     ediDestIndex, _messSpad.dwordAdjust
        sub     esiSourceIndex, _messSpad.dwordAdjust

        ; Do as many dwords as possible
        rep movs dword ptr [ediDestIndex], dword ptr [esiSourceIndex]

        ; Apply the dword adjustment
        add     ediDestIndex, _messSpad.dwordAdjust
        add     esiSourceIndex, _messSpad.dwordAdjust

        ; Get the number of stray bytes into ecx (and clear dx).
        xchg    cx, dxBytesToGoOnSrcLine
        and     ecx, 3

        ; Do any stray bytes left over.
        rep movs byte ptr [ediDestIndex], byte ptr [esiSourceIndex]

ELSE  ; IF use_rep_movs = TRUE

        ; We can not use the rep movs instruction to implement the perLineLoop
        ; because we are going to do a mix or a palette conversion or we are
        ; not at 8 bits per pel.



        ; If we are doing a color compare function then we will not try
        ; to use a dword loop because the time required to combine the
        ; source dword with the destination dword is about the same as the
        ; time to just do four bytes instead.
 IFIDN <comp_mode>, <no_colcomp>
        ; If we are at 8bp or 16bp then we will try to use a dword loop
        ; to speed things up. At 4bp and 1bp this is not such a good idea
        ; because bitmaps are stored in motorola format and combining this
        ; with the source to destination shift things become very complicated!
  IFDIF <pels>, <4bp1bp>

        ; Subtract 4 from the number of pels still to do. If the answer is
        ; less than 0 then there are no more dwords to be done.
        sub     dxBytesToGoOnSrcLine, 4
        jc      short noDwordsToDo

        ; Apply the dword adjustment to the source and destination
        sub     ediDestIndex, _messSpad.dwordAdjust
        sub     esiSourceIndex, _messSpad.dwordAdjust

dwordLoop:

        ; Get the source into eax and update the source index.
        lods    dword ptr [esiSourceIndex]
rName eax SrcDword

   IF use_palette eq TRUE
        ; We are in palette mode so we must convert the dword from the source
        ; palette to the destination palette using the PaletteMapping table.
        ; (Note we use AL and AH to overide rmacros trapping al and ah.)
        mov     bl, alPartOfSrcDword
        mov     alPartOfSrcDword, byte ptr PaletteMapping[ebx]
        mov     bl, ahPartOfSrcDword
        mov     ahPartOfSrcDword, byte ptr PaletteMapping[ebx]
        swap    eaxSrcDword
        mov     bl, alPartOfSrcDword
        mov     alPartOfSrcDword, byte ptr PaletteMapping[ebx]
        mov     bl, ahPartOfSrcDword
        mov     ahPartOfSrcDword, byte ptr PaletteMapping[ebx]
        swap    eaxSrcDword

   ENDIF ;IF use_palette eq TRUE

   IFIDN <mix_mode>, <mix>
        ; We are in mix mode so move the source into ecx and get
        ; the destination into eax.
        mov     ecx, eaxSrcDword
rFree eax SrcDword

        mov     eax, dword ptr [ediDestIndex]

        ; Now jump into the mixing code at the right place.
        jmp     _messSpad.dwordsMixOffset

dwordMixCodeBase:
        mixTrashSourcePart      ecx, eax
        ; eax now contains the new mixed source dword.
rName eax SrcDword

   ENDIF ; IFIDN <mix_mode>, <mix>

        ; Write eax (the result of the mix/palette conversion) to the
        ; destination and update the destination index.
        stos    dword ptr [ediDestIndex]
rFree eax SrcDword

        ; Subtract 4 from the number of pels still to do. If the answer is
        ; less than 0 then there are no more dwords to be done.
        sub     dxBytesToGoOnSrcLine, 4
        jnc     short dwordLoop

        ; Apply the dword adjustment to the source and destination
        add     ediDestIndex, _messSpad.dwordAdjust
        add     esiSourceIndex, _messSpad.dwordAdjust

noDwordsToDo:
        ; Now see if there are any stray bytes left over.
        add     dxBytesToGoOnSrcLine, 4
        jz      short noMorePelsToDo

  ENDIF ; IFDIF <pels>, <4bp1bp>
 ENDIF ; IFIDN <comp_mode>, <no_colcomp>


        ; If we are at 1, 4, or 8 bits per pel then we will use a byte loop
        ; to blt any remaining pels. If we are at 16 bits per pel then we
        ; will use a word loop to blt any remaining pels.
 IFDIF <pels>, <16bp>
setUpByteLoop:

  IFIDN <pels>, <4bp1bp>
        ; At 4bp or 1bp processing the byte at the end of a line needs care
        ; and so we want to special case it.
        ; We decrement dx again so that the wrap loop will exit one byte
        ; earlier so that we can deal with the last byte after we have left
        ; the wrap loop.
        dec     dxBytesToGoOnSrcLine
        jz      short doLastByte
  ENDIF ; IFIDN <pels>, <4bp1bp>

byteLoop:

        ; Get the source into al and update the source index.
  IFDIF <pels>, <4bp1bp>
        lods    byte ptr [esiSourceIndex]

   IFIDN <comp_mode>, <colcomp_src_not_equal>
        ; We only want to write pels to the destination where the
        ; original source pel is the color compare value.
        cmp     al, byte ptr _Shadow8514Regs.Color_Comp
        jne     short @F
        add     ediDestIndex, _messSpad.byteInc
        jmp     short finishedThisByte
@@:
   ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

  ELSE  ; IFDIF <pels>, <4bp1bp>
        mov     ax, word ptr [esiSourceIndex]
        rol     ax, clSrcToDestShift
        add     esiSourceIndex, _messSpad.byteInc

   IFIDN <comp_mode>, <colcomp_src_not_equal>
        ; Keep a copy of the original source pel so that we can decide
        ; which pels to write to the destination after we have been through
        ; the mixing code.
rName ch OrigSrcByte
        mov     chOrigSrcByte, al
   ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

  ENDIF ; IFDIF <pels>, <4bp1bp>  ELSE

  IF use_palette eq TRUE
        ; We are in palette mode so we must convert the byte from the source
        ; palette to the destination palette using the PaletteMapping table.
        mov     bl, al
        mov     al, byte ptr PaletteMapping[ebx]

   ENDIF ; IF use_palette eq TRUE

  IFIDN <mix_mode>, <mix>
        ; We are in mix mode so move the source into ah and get
        ; the destination into al.
        mov     ah, al
        mov     al, byte ptr [ediDestIndex]

        ; Now jump into the mixing code at the right place.
        jmp     _messSpad.fullBytesMixOffset

byteMixCodeBase:
        mixTrashSourcePart      ah, al

  ENDIF ; IFIDN <mix_mode>, <mix>

  IFIDN <comp_mode>, <colcomp_equal>
        ; We only want to write pels to the destination where the
        ; original destination pel was the color compare value.

   IFIDN <pels>, <8bp>
        mov     ah, byte ptr [ediDestIndex]
        cmp     ah, byte ptr _Shadow8514Regs.Color_Comp
        je      short @F
        mov     al, ah
@@:
   ENDIF ; IFIDN <pels>, <8bp>

   IFIDN <pels>, <4bp1bp>
rName al SrcByte
        ColCompEqual4bp
rFree al SrcByte
   ENDIF ; IFIDN <pels>, <4bp1bp>

  ENDIF ; IFIDN <comp_mode>, <colcomp_equal>


  IFIDN <comp_mode>, <colcomp_src_not_equal>
   IFIDN <pels>, <4bp1bp>
        ; We only want to write pels to the destination where the
        ; original (pre mixed) source pels were the color compare value.
rName al SrcByte
        ColCompSrcNotEqual4bp
rFree al SrcByte
rFree ch OrigSrcByte
   ENDIF ; IFIDN <pels>, <4bp1bp>

  ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

        ; Write al (the result of the mix/palette conversion) to the
        ; destination and update destination index.
        stos    byte ptr [ediDestIndex]
finishedThisByte:

        ; Loop back if there are more bytes to be done.
        dec     dxBytesToGoOnSrcLine
        jnz     short byteLoop


  IFIDN <pels>, <4bp1bp>

doLastByte:
        ; At 4bp or 1bp we must deal with the last byte carefully so that only
        ; the correct pels get blted.

   IFIDN <wrap_mode>, <wrap>
        ; The source word we get (so we can apply the srcToDestShift to it to
        ; get the bits corresponding to the destination byte) may cross the
        ; wrap-around boundry. ie. The high byte of the word may infact be the
        ; first byte of the line.

        ; We may just be finishing a line of source before we wrap around
        ; and continue the blt, or we may actually be finishing the complete
        ; line of the blt. If we are finishing the blt we may also have to
        ; wrap around in order to get hold of the high byte of the pre-shifted
        ; source word.

        ; If we are wrapping round then bp will contain -srcWidthInBytes,
        ; otherwise it will contain zero.
        ; If we are finishing the blt line the bx will contain the end mask
        ; and its inverses, otherwise it will contain 00ffh which has the
        ; effect of transfering the whole source byte to the destination.
   ENDIF ; IFIDN <wrap_mode>, <wrap>


        ; Get the word containing the byte we want from the source and
        ; update the source index.
   IFIDN <wrap_mode>, <wrap>
        mov     ah, [esiSourceIndex+ebpSecondByteAdjuster+1]
   ELSE  ; IFIDN <wrap_mode>, <wrap>
        mov     ah, [esiSourceIndex+1]
   ENDIF ; IFIDN <wrap_mode>, <wrap>  ELSE
        lods    byte ptr [esiSourceIndex]

        ; Now rotate the source word by the srcToDestShift so that al contains
        ; the bits which correspond to the first byte in the destination.
        rol     ax, clSrcToDestShift

        ; al now contains the bits which are to be blted onto the last byte
        ; in the destination.

        ; Get the destination byte.
        mov     ah, [ediDestIndex]

   IFIDN <mix_mode>, <mix>
        ; Make sure we have a copy of the destination byte to use later.
        mov     ch, ah

        ; Now jump to the mixing code at the right place.
        jmp     _messSpad.endBytesMixOffset

endByteMixCodeBase:
        mixKeepSourcePart      al, ch

        ; Get the new source byte (after mixing) into al and the
        ; original source byte into ch.
        xchg    al, ch
    IFIDN <comp_mode>, <colcomp_src_not_equal>
rName ch OrigSrcByte
    ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

   ELSE  ; IFIDN <mix_mode>, <mix>

    IFIDN <comp_mode>, <colcomp_src_not_equal>
        mov     ch, al
rName ch OrigSrcByte
    ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

   ENDIF ; IFIDN <mix_mode>, <mix>  ELSE

        ; Now use the end mask (and its inverse) to combine the source byte
        ; with the destination byte. The end mask (and its inverse) are
        ; stored in bx. (Note that bx actually contains either the masks
        ; or the identity masks depending on whether we are wrapping around
        ; or really at the end of the blt line. rmacros is does only linear
        ; code checking rather than data flow analysis and so expects bx
        ; to be associated with Masks rather than IdentityMasks at this stage).
        and     ax, bxMasks
        or      al, ah

   IFIDN <comp_mode>, <colcomp_equal>
        ; We only want to write pels to the destination where the
        ; original destination pel was the color compare value.
rName al SrcByte
        ColCompEqual4bp
rFree al SrcByte
   ENDIF ; IFIDN <comp_mode>, <colcomp_equal>
   IFIDN <comp_mode>, <colcomp_src_not_equal>
        ; We only want to write pels to the destination where the
        ; original (pre mixed) source pels were the color compare value.
rName al SrcByte
        ColCompSrcNotEqual4bp
rFree al SrcByte
rFree ch OrigSrcByte
   ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

        ; al contains the merged source and destination bytes so we can
        ; now write it back to the destination and update the destination
        ; index.
        stos    byte ptr [ediDestIndex]

  ENDIF ; IFIDN <pels>, <4bp1bp>


 ELSE  ; IFDIF <pels>, <16bp>
        ; We are at 16 bits per pel so we will use a word loop to blt
        ; any remaining pels.

wordLoop:
        ; Get the source into ax and update the source index.
        lods    word ptr [esiSourceIndex]

  IFIDN <comp_mode>, <colcomp_src_not_equal>
        ; We only want to write pels to the destination where the
        ; original source pel is the color compare value.
        cmp     ax, word ptr _Shadow8514Regs.Color_Comp
        jne     short @F
        add     ediDestIndex, _messSpad.byteInc
        add     ediDestIndex, _messSpad.byteInc
        jmp     short finishedThisWord
@@:
  ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

  IFIDN <mix_mode>, <mix>
        ; We are in mix mode so move the source into cx and get
        ; the destination into ax.
        mov     cx, ax
        mov     ax, word ptr [ediDestIndex]

        ; Now jump into the mixing code at the right place.
        jmp     _messSpad.wordsMixOffset

wordMixCodeBase:
        ; We will actually do a dword mix (mixing words would not be
        ; as fast) and ignore the top half of the registers.
        mixTrashSourcePart      ecx, eax

  ENDIF ; IFIDN <mix_mode>, <mix>

  IFIDN <comp_mode>, <colcomp_equal>
        ; We only want to write pels to the destination where the
        ; original destination pel was the color compare value.
        mov     cx, word ptr [ediDestIndex]
        cmp     cx, word ptr _Shadow8514Regs.Color_Comp
        je      short @F
        mov     ax, cx
@@:
  ENDIF ; IFIDN <comp_mode>, <colcomp_equal>

        ; Write ax (the result of the mix) to the
        ; destination and update destination index.
        stos    word ptr [ediDestIndex]
finishedThisWord:

        ; Loop back if there are more bytes to be done.
        sub     dxBytesToGoOnSrcLine, 2
        jnz     short wordLoop
 ENDIF ; IFDIF <pels>, <16bpp>  ELSE

noMorePelsToDo:

ENDIF ; IFIDN <use_rep_movs>, <TRUE>  ELSE



        ; We have done a line of the source. If we are in wrap_mode
        ; then we have to see if we have finished this line of the
        ; blt or if we just need to wrap the source around again.
        ; If we are not in wrap_mode then we have finished this line
        ; of the blt and we must now adjust the source and destination
        ; indexes so that they point to the next lines to be processed.

        ; First adjust the source index.

IFIDN <wrap_mode>, <wrap>
        ; Now we must either go onto the next line or we must wrap around
        ; the source. If there are no more pels to do then we have finished
        ; this line. The number of pels still to do is stored in the top
        ; half of edx. Also we know that dx is zero at this point.
rFree dx BytesToGoOnSrcLine
rFree edx_top BytesLeftOnDestLine
        or      edx, edx
        jz      short doNextLine

        ; We must wrap around the source.

        ; Get the number of pels still to go into dx and clear the top half
        ; of edx.
        shr     edx, 16

        ; Get the number of bytes on this source line before
        ; we would have to wrap around into ax.
        mov     eax, _messSpad.srcWidthInBytes

        ; Set the source index pointer back to the beginning of this line
        ; of source.
        sub     esiSourceIndex, eax

        ; Loop back to the code which decides whether we are going to have
        ; to do a whole line of the source and wrap, or whether we are going
        ; to finish the blt with this line of source.
        jmp     wrapLoop

doNextLine:

        ; Now we have finished the current line of the blt we must go on to
        ; do the next line. We might have to do a vertical wrap of the source.

        dec     _messSpad.srcLinesBeforeWrap
        jz      short vertWrapSource

        ; Set up the source index to be one line further on than it was at the
        ; beginning of the current line.
        mov     esiSourceIndex, _messSpad.srcLineStartAddr
        add     esiSourceIndex, _messSpad.srcWidthInBytes

vertWrapSourceReturn:
        ; Keep a copy of the source index at the beginning of the blt line.
        mov     _messSpad.srcLineStartAddr, esiSourceIndex


ELSE  ; IFIDN <wrap_mode>, <wrap>

        ; Add the source line increment to the source index.
        add     esiSourceIndex, _messSpad.srcLineInc

ENDIF ; IFIDN <wrap_mode>, <wrap>  ELSE

        ; We have adjusted the source index to point to the next line.
        ; We must now adjust the destination index to point to the next
        ; line also.

        ; Add the destination line incement to the destination index.
        add     ediDestIndex, _messSpad.dstLineInc

        ; Decrement the number of lines to go and loop back.
        dec     _messSpad.perLineLoopCount
        jnz     setUpPerLineLoop

        ; We have finished!


IFIDN <wrap_mode>, <wrap>
        jmp     short exit

vertWrapSource:
        ; Do a vertical wrap of the source here.


        ; Set the source index to point to the first byte to be blted
        ; in the first line of the source.
        mov     esiSourceIndex, srcPixmap.startAddr

 IFIDN <pels>, <8bp>
        movzx   eax, Shadow8514Regs.src_map_x
        add     esiSourceIndex, eax

 ELSE  ; IFIDN <pels>, <8bp>
  IFIDN <pels>, <16bp>
        movzx   eax, Shadow8514Regs.src_map_x
        shl     eax, 1
        add     esiSourceIndex, eax

  ELSE  ; IFIDN <pels>, <16bp>

        ; Calculate the offset of the byte containing the first pel.
        movzx   eax, Shadow8514Regs.src_map_x
        test    byte ptr dstPixmap.format, FOUR_BPP
        jnz     short @F
        shr     eax, 2
@@:
        shr     eax, 1

        add     esiSourceIndex, eax

        ; If the source index was adjusted in the setUpSrcDest function
        ; then it will need adjust here for just the same reasons.
        .ERRE   TRUE eq 1
        .ERRE   FALSE eq 0
        sub     esiSourceIndex, _messSpad.srcIndexAdjusted

  ENDIF ; IFIDN <pels>, <16bp>  ELSE
 ENDIF ; IFIDN <pels>, <8bp>  ELSE


        ; Set the number of lines to go before the next vertical wrap.
        mov     ax, srcPixmap.yLen
        inc     ax
        mov     _messSpad.srcLinesBeforeWrap, ax

        ; Return to the main code in the correct place.
        jmp     vertWrapSourceReturn
ENDIF ; IFIDN <wrap_mode>, <wrap>

exit:

rEnd

endm SrcDest

ELSE    ; !_8514

;;;****************************************************************
;;;
;;; XGA Macros
;;;
;;; These are the counterparts to the 8514 macros defined in the
;;; previous section.  We have to duplicate this because MASM cannot
;;; handle IFDEFs inside a macro IF.
;;;
;;;****************************************************************

;-----------------------------------------------------------------------
; This macro combines the source pels in al with the destination pels
; (which are got into ah) using the color compare function of "destination
; pels equal". al should already be associated with SrcByte by rmacros.
; ch should be free to be used as a temporary.
; On exit from this macro al is ready to be written to the destination
; bitmap.
;-----------------------------------------------------------------------
ColCompEqual4bp macro
local   checkedPel0, checkedPel1
rName ah DestByte
        ; Get two destination pels into ah.
        mov     ahDestByte, byte ptr [ediDestIndex]
        ; Get the difference between the destination pels and the
        ; color compare value in ch. (Note that the color compare value
        ; in the shadow registers must be manipulated to contain 2 pels
        ; of color before this macro is called at 4bp).
        mov     ch, ahDestByte
        xor     ch, byte ptr _ShadowXGARegs.colour_comp_colour
        ; See if the top pel (pel 1) is the same as the color compare value.
        cmp     ch, 0Fh
        jle     short @F
        ; The top pel is the not color compare value. Keep the destination
        ; pel and throw away the source pel.
        shl     alSrcByte, 4
        rol     ahDestByte, 4
        jmp     short checkedPel1
@@:
        ; The top pel is the color compare value. Keep the source pel and
        ; throw away the destination pel.
        rol     alSrcByte, 4
        shl     ahDestByte, 4
checkedPel1:
        ; Now check the low pel.
        shl     ch, 4
        cmp     ch, 0Fh
        jle     short @F
        ; The low pel is the not color compare value. Keep the destination
        ; pel and throw away the source pel.
        shl     alSrcByte, 4
        rol     ahDestByte, 4
        jmp     short checkedPel0
@@:
        ; The low pel is the color compare value. Keep the source pel and
        ; throw away the destination pel.
        rol     alSrcByte, 4
        shl     ahDestByte, 4
checkedPel0:
        ; Combine the source and destination pels we decided to keep.
        or      alSrcByte, ahDestByte
rFree ah DestByte
endm


;-----------------------------------------------------------------------
; This macro combines the source pels in al with the destination pels
; (which are got into ah) using the color compare function of "source pels
; not equal". al should already be associated with SrcByte by rmacros.
; ch should be free to be used as a temporary.
; On exit from this macro al is ready to be written to the destination
; bitmap.
;-----------------------------------------------------------------------
ColCompSrcNotEqual4bp macro
local   checkedPel0, checkedPel1
rName ah DestByte
        ; Get two destination pels into ah.
        mov     ahDestByte, byte ptr [ediDestIndex]
        ; Get the difference between the original source pels and the
        ; color compare value in ch. (Note that the color compare value
        ; in the shadow registers must be manipulated to contain 2 pels
        ; of color before this macro is called at 4bp).
        xor     chOrigSrcByte, byte ptr _ShadowXGARegs.colour_comp_colour
        ; See if the top pel (pel 1) is the same as the color compare value.
        cmp     chOrigSrcByte, 0Fh
        jg      short @F
        ; The top pel is the color compare value. Keep the destination
        ; pel and throw away the source pel.
        shl     alSrcByte, 4
        rol     ahDestByte, 4
        jmp     short checkedPel1
@@:
        ; The top pel is the not color compare value. Keep the source pel
        ; and throw away the destination pel.
        rol     alSrcByte, 4
        shl     ahDestByte, 4
checkedPel1:
        ; Now check the low pel.
        shl     chOrigSrcByte, 4
        cmp     chOrigSrcByte, 0Fh
        jg      short @F
        ; The low pel is the not color compare value. Keep the destination
        ; pel and throw away the source pel.
        shl     alSrcByte, 4
        rol     ahDestByte, 4
        jmp     short checkedPel0
@@:
        ; The low pel is not the color compare value. Keep the source pel
        ; and throw away the destination pel.
        rol     alSrcByte, 4
        shl     ahDestByte, 4
checkedPel0:
        ; Combine the source and destination pels we decided to keep.
        or      alSrcByte, ahDestByte
rFree ah DestByte
endm


;-------------------------------------------------------------------------
;
; Macro: SrcDest pels mix_mode wrap_mode [palette_mode]
;
; This does a fast block copy (most of the time) for 16,1  8,1  4,1  and 1,1
; formats. It handles straight block copies, mixes, palette conversions, and
; wrap-around blts. The wrap-around blts are limited in direction to the
; single case of top-left to bottom-right.
;
; Parameters:
;         pels  should be either "16bp", "8bp" or "4bp1bp". The code produced
;               by "4bp1bp" handles both 4,1 and 1,1 bitmap formats.
;     mix_mode  should be either "mix" or "no_mix". This specifies whether the
;               macro should be expanded to implement mixes.
;    wrap_mode  should be either "wrap" or "no_wrap". This specifies whether
;               the macro should be expanded to implement source wrapping.
; palette_mode  should be either "palette" or "no_palette". This parameter
;               is optional. If PALETTE_MGR is defined then the palette_mode
;               must be supplied. It is an error to supply the palette_mode
;               when PALETTE_MGR is not defined. The parameter specifies
;               whether the macro should be expanded to implement palette
;               conversions.
;
; Internally:
;          eax  is used as a general purpose registers for temporary values.
;          ecx  is used as the count for rep movs instructions at 8bp.
;           cl  is used as the srcToDestShift at 4bp1bp.
;          ebx  at 8bp with palette mapping is used as the index register into
;               the paletteMapping table. At 4bp1bp with wrap-around it is used
;               to hold the end mask to be used on the last byte of data from
;               each line of source.
;          edx  is used to control the per line loop.
;          ebp  at 4bp1bp is used to wrap-around the high byte of each source
;               word fetched at the end of a source line.
;          esi  is used to index into the source pixmap.
;          edi  is used to index into the destination pixmap.
;
; Preserves:    ?
;
; Destroys:     ?
;
;
;-------------------------------------------------------------------------

SrcDest macro   pels, wrap_mode, mix_mode, comp_mode, palette_mode
        local   setUpPerLineLoop, wrapLoop, perLineLoop, dwordLoop
        local   dwordMixCodeBase, byteMixCodeBase, noDwordsToDo
        local   byteLoop, noMorePelsToDo, doNextLine, vertWrapSourceReturn
        local   doneSetUpCall, doLastByte, startByteMixCodeBase
        local   setUpByteLoop, useRealEndMask, finishedThisByte
        local   notStartingOnLastByte, gotStartHighByte, willNotNeedToWrap
        local   endByteMixCodeBase, vertWrapSource, setUpPerLineLoop, exit
        local   wordMixCodeBase, wordLoop, finishedThisWord

        ; We will use rmacros to help keep track of register usage.
rStart

        ; First we will do some checking of the arguements to see if
        ; the macro is being used correctly...

        ; and we want to set the use_rep_movs flag to indicate how to
        ; implement the inner loop of the code. If we are not using a
        ; mix or a palette conversion and we are in 8bp mode then we
        ; can just use the string copy instruction (rep movs).

        use_rep_movs = FALSE
        use_palette = FALSE

IFB <pels>
        .ERR
        %OUT bits per pel arguement is blank
ELSE
 IFDIF <pels>, <8bp>
  IFDIF <pels>, <4bp1bp>
   IFDIF <pels>, <16bp>
        .ERR
        %OUT bits per pel arguement must be 8bp, 4bp1bp
   ENDIF
  ENDIF
 ENDIF
ENDIF

IFB <wrap_mode>
        .ERR
         %OUT wrap mode arguement is blank
ELSE
 IFDIF <wrap_mode>, <wrap>
  IFDIF <wrap_mode>, <no_wrap>
        .ERR
        %OUT wrap mode arguement must be wrap or no_wrap
  ENDIF
 ENDIF
ENDIF

IFB <mix_mode>
        .ERR
        %OUT mix mode arguement is blank
ELSE
 IFDIF <mix_mode>, <mix>
  IFDIF <mix_mode>, <no_mix>
        .ERR
        %OUT mix mode arguement must be mix or no_mix
  ELSE
   IFDIF <pels>, <4bp1bp>
        ; The mix mode arguement is no_mix and we are using 8bp or 16bp
        ; so as long as we are not using a palette then we can
        ; use the rep movs instruction to implement the inner loop.
        use_rep_movs  = TRUE
   ENDIF
  ENDIF
 ENDIF
ENDIF

IFB <comp_mode>
        .ERR
        %OUT color compare mode arguement is blank
ELSE
 IFDIF <comp_mode>, <no_colcomp>
  ; We are using the color compare register so we can not use rep movs
  ; to implemt fast block copy.
  use_rep_movs  = FALSE
  IFDIF <comp_mode>, <colcomp_equal>
   IFDIF <comp_mode>, <colcomp_src_not_equal>
        .ERR
        %OUT color compare mode arguement must be no_colcomp colcomp_equal or colcomp_src_not_equal.
   ENDIF
  ENDIF
 ENDIF
ENDIF

IFB <palette_mode>
 IFDEF PALETTE_MGR
        .ERR
        %OUT Undefined palette_mode argument!
 ENDIF ;IFDEF PALETTE_MGR
ELSE
 IFNDEF PALETTE_MGR
        %OUT PALETTE_MGR undefined - ignoring palette_mode argument
 ELSE
  IFIDN <palette_mode>, <no_palette>
        use_palette = FALSE
  ELSE
   IFIDN <palette_mode>, <palette>
    IFDIF <pels>, <8bp>
        ; If we are not at 8bp then it is an error to specify palette
        ; as the palette mode.
        .ERR
        %OUT palette mode can only be used at 8 bits per pel
    ELSE
        ; The palette_mode arguement is "palette"
        use_palette = TRUE
        ; PALETTE_MGR is defined so we cannot use the rep movs
        ; instruction to implement the inner loop.
        use_rep_movs = FALSE
    ENDIF
   ELSE
        .ERR
        %OUT Invalid palette_mode argument - must be palette or no_palette
   ENDIF
  ENDIF ;IFIDN <palette_mode>
 ENDIF ;IFDEF PALETTE_MGR
ENDIF ;IFB <palette_mode>


IFDEF FIREWALLS
 IFIDN <wrap_mode>, <wrap>
        ; Wrap-around operations are limited to run from top-left to
        ; bottom-right.
        test    ShadowXGARegs.pixel_op.lo, BLTDIR_RIGHTTOLEFT+BLTDIR_BOTTOMTOTOP
        jz      short @F
        int     3
@@:
 ENDIF
ENDIF

        ; Now we have done the arguement checks we can get down to the
        ; real code bit of the macro...

        ; First of all we want to call one of the SrcDest set up functions.

IFIDN <pels>, <8bp>
        ; Call eddf_MESSSetUpSrcDest81 to initialise the values we will
        ; need in the scratch pad for most operations.
        cCall   eddf_MESSSetUpSrcDest81

ELSE  ; IFIDN <pels>, <8bp>
IFIDN <pels>, <16bp>
        ; Call eddf_MESSSetUpSrcDest16 to initialise the values we will
        ; need in the scratch pad for most operations.
        cCall   eddf_MESSSetUpSrcDest16

ELSE  ; IFIDN <pels>, <16bp>

        test    byte ptr dstPixmap.format, FOUR_BPP
        jnz     short @F

        ; Call eddf_MESSSetUpSrcDest11 to initialise the values we will
        ; need in the scratch pad for most operations.
        cCall   eddf_MESSSetUpSrcDest11
IFDEF FIREWALLS
IFDIF <comp_mode>, <no_colcomp>
        ; We should never call color compare functions at 1bp. If color
        ; compare is required it should have been implemented by changing
        ; the mixes. See transparent mixes explanation at start of bitblt
        ; code in eddnbblt.c.
        int     3
ENDIF ; IFDIF <comp_mode>, <no_colcomp>
ENDIF ; IFDEF FIREWALLS
        jmp     short doneSetUpCall
@@:
        ; Call eddf_MESSSetUpSrcDest41 to initialise the values we will
        ; need in the scratch pad for most operations.
        cCall   eddf_MESSSetUpSrcDest41

doneSetUpCall:

ENDIF ; IFIDN <pels>, <16bp>  ELSE
ENDIF ; IFIDN <pels>, <8bp>  ELSE

rName edi DestIndex
rName esi SourceIndex

IFIDN <wrap_mode>, <wrap>
        ; Initialise other values in the scratch pad that we will need
        ; for the source wrapping code.

        ; Keep a copy of the source index for the start of this blt line
        ; in srcLineStartAddr.
        mov     _messSpad.srcLineStartAddr, esiSourceIndex

        ; Work out how many source lines will be drawn before the source
        ; will have to wrap vertically.
        mov     ax, srcPixmap.yLen
        inc     ax
        sub     ax, ShadowXGARegs.src_map_y
        mov     _messSpad.srcLinesBeforeWrap, ax
ENDIF ; IFIDN <wrap_mode>, <wrap>


IFIDN <mix_mode>, <mix>
        ; Initialise other values in the scratch pad that we will need
        ; for the mixing code.

        ; Get the foreground mix into bl and clear the rest of ebx so that
        ; we can use ebx as in index in extended 386 addressing modes.
rName ebx Mix
        movzx   ebxMix, byte ptr ShadowXGARegs.fg_mix

        ; Get the offset of any byte mixes we might need to do into cx.
rName ecx ByteMixCodeOffset
        mov     ecxByteMixCodeOffset, dword ptr mixTrashSourcePartBY[ebxMix*4]

IFDIF <pels>, <4bp1bp>
IFIDN <comp_mode>, <no_colcomp>
        ; Work out the address in the dword mix code that we will jump to
        ; when we have a full dword to mix.
        mov     eax, dword ptr mixTrashSourcePartDW[ebxMix*4]
        add     eax, offset FLAT:dwordMixCodeBase
        mov     _messSpad.dwordsMixOffset, eax
ENDIF ; IFIDN <comp_mode>, <no_colcomp>

ELSE  ; IFDIF <pels>, <4bp1bp>
        ; Work out the address in the byte mixing code that we will jump to
        ; when we are mixing in the first byte of each line.
        mov     eax, dword ptr mixKeepSourcePartBY[ebxMix*4]
        add     eax, offset FLAT:startByteMixCodeBase
        mov     _messSpad.startBytesMixOffset, eax

        ; Work out the address in the byte mixing code that we will jump to
        ; when we are mixing in the last byte of each line of destination.
        mov     eax, dword ptr mixKeepSourcePartBY[ebxMix*4]
        add     eax, offset FLAT:endByteMixCodeBase
        mov     _messSpad.endBytesMixOffset, eax

ENDIF ; IFIDN <pels>, <4bp1bp>  ELSE

IFDIF <pels>, <16bp>
        ; Work out the address in the byte mix code that we will jump to
        ; when we are mixing using the byte loop.
        mov     eax, ecxByteMixCodeOffset
        add     eax, offset FLAT:byteMixCodeBase
        mov     _messSpad.fullBytesMixOffset, eax
ELSE  ; IFDIF <pels>, <16bp>
        ; Work out the address in the word mix code that we will jump to
        ; when we are mixing using the word loop.
        mov     eax, ecxByteMixCodeOffset
        add     eax, offset FLAT:wordMixCodeBase
        mov     _messSpad.wordsMixOffset, eax
ENDIF ; IFDIF <pels>, <16bp>  ELSE
rFree ebx Mix
rFree ecx ByteMixCodeOffset

ENDIF ; IFIDN <mix_mode>, <mix>



        ; Now we have everything in the scratch pad initialised we can set up
        ; the loop counters and do the main loop.

        mov     ax, ShadowXGARegs.dim2
        inc     ax
        mov     _messSpad.perLineLoopCount, ax

        ; Clear ecx and ebx so that we only have to partially load them if
        ; we need to use them inside the loop.
        xor     ecx, ecx
        xor     ebx, ebx

IFIDN <pels>, <4bp1bp>
IFIDN <wrap_mode>, <wrap>
        ; Load the top half of ebx with the identity mask (and its inverse)
        ; so that when it is used all of the source gets copied to the
        ; destination.
        mov     bx, 00ffh
        swap    ebx
rName ebx_top IdentityMasks
ENDIF ; IFIDN <wrap_mode>, <wrap>

        ; Load bx with the end mask and its inverse.
        .ERRE endMaskInv eq (endMask + 1)
rName bx Masks
        mov     bxMasks, word ptr _messSpad.endMask

        ; Get the srcToDestShift into the cl register.
rName cl SrcToDestShift
        mov     clSrcToDestShift, _messSpad.srcToDestShift

ENDIF ; IFIDN <pels>, <4bp1bp>


setUpPerLineLoop:


IFIDN <wrap_mode>, <wrap>

IFIDN <pels>, <8bp>
        ; Get the number of bytes still to go on this line before
        ; we have to wrap around into ax.
        mov     eax, _messSpad.srcWidthInBytes
        sub     ax, ShadowXGARegs.src_map_x

ELSE  ; IFIDN <pels>, <8bp>
IFIDN <pels>, <16bp>
        ; Get the number of bytes still to go on this line before
        ; we have to wrap around into ax.
        mov     eax, _messSpad.srcWidthInBytes
        mov     dx, ShadowXGARegs.src_map_x
        shl     dx, 1
        sub     ax, dx

ELSE  ; IFIDN <pels>, <16bp>

        ; Get the number of bytes still to go on this line before
        ; we have to wrap around into ax.
        mov     eax, _messSpad.srcWidthInBytes
        mov     dx, ShadowXGARegs.src_map_x
        test    byte ptr dstPixmap.format, FOUR_BPP
        jnz     short @F
        shr     dx, 2
@@:
        shr     dx, 1
        sub     ax, dx

        ; If the source index was adjusted in the setUpSrcDest function then
        ; esi will actually be pointing one byte to the left of the first pel
        ; in this case we must do one extra byte the first time through the
        ; wrap loop.
        .ERRE   TRUE eq 1
        .ERRE   FALSE eq 0
        add     eax, _messSpad.srcIndexAdjusted
ENDIF ; IFIDN <pels>, <16bp>  ELSE
ENDIF ; IFIDN <pels>, <8bp>  ELSE

rName ax BytesBeforeWrap

ENDIF ; IFIDN <wrap_mode>, <wrap>



IFIDN <pels>, <4bp1bp>

        ; We are at 4bp or 1bp and we are about to blt a line from the source
        ; to the destination. We must deal with the first and last bytes
        ; seperately from the main byte loop and use the startMask and endMask
        ; values to make sure we only effect the correct pels.

        ; Get the first byte sized chunk of the source corresponding to the
        ; first physical byte of the destination. To do this we must get a
        ; word from the source and apply the srcToDestShift to it.

        ; To get a word from the source we must access it as two bytes. This
        ; is because the source index may point just to the left of the start
        ; of the bitmap (see setUpSrcDest11 for full explanation) and so we
        ; might be accessing a word across a segment boundry.

        ; Get the word containing the source byte we want into ax and
        ; update the source index.

IFIDN <wrap_mode>, <wrap>
        ; Save ax in dx so we can use lods and stos instructions.
        mov     dx, axBytesBeforeWrap
rFree ax BytesBeforeWrap
rName dx BytesBeforeWrap

        ; We must remember that the second byte of the word might infact
        ; have wrapped around to the beginning of the line.

        ; Set up bp so it can be used as an adjuster when the second byte of
        ; the word wraps around.
rName ebp SecondByteAdjuster
        mov     ebpSecondByteAdjuster, _messSpad.srcWidthInBytes
        neg     ebpSecondByteAdjuster

        ; See if esiSourceIndex is pointing to the last byte on this source line.
        ; dx contains the number of bytes still to go on this source line.
        cmp     dxBytesBeforeWrap, 1
        jne     short notStartingOnLastByte
        mov     ah, [esiSourceIndex+ebpSecondByteAdjuster+1]
        jmp     short gotStartHighByte

ENDIF ; IFIDN <wrap_mode>, <wrap>


notStartingOnLastByte:
        mov     ah, [esiSourceIndex+1]
gotStartHighByte:
        lods    byte ptr [esiSourceIndex]

        ; Now rotate the source word by the srcToDestShift so that al contains
        ; the bits which correspond to the first byte in the destination.
        rol     ax, clSrcToDestShift

        ; al now contains the bits which are to be blted onto the first byte
        ; in the destination.
rName al SrcByte

        ; Get the destination byte.
rName ah DestByte
        mov     ahDestByte, [ediDestIndex]

IFIDN <mix_mode>, <mix>
        ; Make sure we have a copy of the destination byte to use later.
        mov     ch, ahDestByte

        ; Now jump to the mixing code at the right place.
        jmp     _messSpad.startBytesMixOffset

startByteMixCodeBase:
        mixKeepSourcePart      alSrcByte, ch

        ; Get the new source byte (after mixing) into al and the
        ; original source byte into ch.
        xchg    alSrcByte, ch
IFIDN <comp_mode>, <colcomp_src_not_equal>
rName ch OrigSrcByte
ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

ELSE  ; IFIDN <mix_mode>, <mix>

IFIDN <comp_mode>, <colcomp_src_not_equal>
        mov     ch, alSrcByte
rName ch OrigSrcByte
ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

ENDIF ; IFIDN <mix_mode>, <mix>  ELSE


        ; Now use the start mask (and its inverse) to combine the source byte
        ; with the destination byte. (Note we use AX rather than ax to let
        ; rmacros know that we know that ax is in use for alSrcByte and
        ; ahDestByte so that it does not generate an error).
        .ERRE   startMaskInv eq (startMask + 1)
        and     AX, word ptr _messSpad.startMask
        or      alSrcByte, ahDestByte
rFree ah DestByte

        ; al contains the merged source and destination bytes so we can
        ; now write it back to the destination and update the destination
        ; index.

IFIDN <comp_mode>, <colcomp_equal>
        ; We only want to write pels to the destination where the
        ; original destination pel was the color compare value.
        ColCompEqual4bp
ENDIF ; IFIDN <comp_mode>, <colcomp_equal>
IFIDN <comp_mode>, <colcomp_src_not_equal>
        ; We only want to write pels to the destination where the
        ; original (pre mixed) source pels were the color compare value.
        ColCompSrcNotEqual4bp
rFree ch OrigSrcByte
ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

        ; Store the source pels (after masking and color comparing) in
        ; the destination bitmap.
        stos    byte ptr [ediDestIndex]
rFree al SrcByte

IFIDN <wrap_mode>, <wrap>
        ; get ax back from its temporary store in dx
        mov     ax, dxBytesBeforeWrap
rFree dx BytesBeforeWrap
rName ax BytesBeforeWrap

        ; ax contains the number of bytes from the source index to the end
        ; of the current source line. But we have just blted the byte so we
        ; must decrement ax to reflect the increment to the source index
        ; we have just done.
        dec     axBytesBeforeWrap

ENDIF ; IFIDN <wrap_mode>, <wrap>

ENDIF ; IFIDN <pels>, <4bp1bp>




IFDIF <pels>, <4bp1bp>
        ; Get the number of bytes in this line of the destination to be blted
        ; into dx and clear the top half of edx.
        movzx   edx, ShadowXGARegs.dim1
        inc     dx
IFIDN <pels>, <16bp>
        shl     dx, 1
ENDIF ; IFIDN <pels>, <16bp>

ELSE  ; IFDIF <pels>, <4bp1bp>
        ; Get the number of bytes in this line of the destination to be blted
        ; into dx and clear the top half of edx.
        mov     edx, _messSpad.totalBytes

        ; We have already blted the first byte of the line.
        ; Check to see if there are more bytes to be done. At this point
        ; dx contains the total number of bytes to be blted in this dest line.
        ; We have just blted the first byte so we can decrement this.
        dec     dx
        jz      noMorePelsToDo
ENDIF ; IFDIF <pels>, <4bp1bp>  ELSE

        ; If we are in wrap mode then we must destinguish between the number
        ; of bytes to be blted on the destination line against the number
        ; of bytes to be blted from this line of source before we have to
        ; wrap. If we are not in wrap mode then these are the same.
IFIDN <wrap_mode>, <wrap>
rName dx BytesLeftOnDestLine
ELSE  ; IFIDN <wrap_mode>, <wrap>
rName dx BytesToGoOnSrcLine
ENDIF ; IFIDN <wrap_mode>, <wrap>  ELSE


IFIDN <wrap_mode>, <wrap>

IFIDN <pels>, <4bp1bp>
        ; We are going into the wrap loop. First of all swap ebx so that the
        ; identity mask is in bx. When going through the wrap loop for the
        ; last time we can swap ebx again to get the end mask back so that
        ; the last byte of the blt will be done correctly. Until then we
        ; use the identity mask because we want to blt all of the pels.
rFree bx Masks
rFree ebx_top IdentityMasks
        swap    ebx
rName bx IdentityMasks
rName ebx_top Masks

        ; We have already blted the first byte so it is possible that there
        ; are no more bytes left to do on this source line and so we are
        ; ready to wrap-around straight away.
        or      axBytesBeforeWrap, axBytesBeforeWrap
        jnz     short @F

        ; We must move dx into the top half of edx (dx contains the number
        ; of bytes still to do for this line of the blt) as this is what
        ; is expected on exit from the byte loop (at noMorePelsToDo).
rFree dx BytesLeftOnDestLine
        swap    edx
        jmp     noMorePelsToDo

        ; Rmacros is linear so we need this for the code that follows if
        ; we did not execute the previous path.
rName dx BytesLeftOnDestLine

@@:
ENDIF ; IFIDN <pels>, <4bp1bp>

wrapLoop:
        ; At this point ax should contain the number of bytes to go on the
        ; current line of source before we would have to wrap the source
        ; and dx contains the number of bytes to go before we reach the
        ; end of this line of the blt. The top half of edx should contain
        ; zero and will now be adjusted to contain the number of bytes that
        ; still have to be done after this line of source has been done.

        ; Compare ax with dx to see if we will wrap around the source
        ; before we reach the end of the blt.
        ; If we will finish the blt before we have to wrap then we can
        ; just jump to the main loop code. The top half of edx will be
        ; zero indicating there are no more pels to go on exit from the
        ; loop.
        cmp     axBytesBeforeWrap, dxBytesLeftOnDestLine
IFDIF <pels>, <4bp1bp>
        jge     short willNotNeedToWrap

ELSE  ; IFDIF <pels>, <4bp1bp>
        ; At 4bp or 1bp if the number of bytes to be blted is the same as
        ; the number of bytes left on the source line then we must still
        ; wrap around the high byte of the source word so we do not want
        ; to clear bp (-srcWidthInBytes) but we do want to use the end mask.
        jg      short willNotNeedToWrap
        je      short useRealEndMask

ENDIF ; IFDIF <pels>, <4bp1bp>  ELSE

        ; We will wrap around the source.

        ; Adjust dx so that it contains the number of pels which will still
        ; need to be done on exit from the loop. Shift dx into the top half
        ; of edx. Move ax (the number of pels until wrap around) into dx.
        sub     dxBytesLeftOnDestLine, axBytesBeforeWrap
rFree dx BytesLeftOnDestLine
        swap    edx
        mov     dx, axBytesBeforeWrap
rName dx BytesToGoOnSrcLine
rName edx_top BytesLeftOnDestLine
rFree ax BytesBeforeWrap

        jmp     short perLineLoop

willNotNeedToWrap:

IFIDN <pels>, <4bp1bp>
        ; Clear ebp so that when accessing the last source word we do not wrap
        ; the high byte. Until now ebp has contained -srcWidthInBytes.
        xor     ebpSecondByteAdjuster, ebpSecondByteAdjuster

useRealEndMask:
        ; Set up bx to contain the end mask and its inverse. The top half of
        ; ebx contains these. Up until now bx has contained the identity mask
        ; 00ffh which simply copies all of the source to the destination.
rFree bx IdentityMasks
rFree ebx_top Masks
        swap    ebx
rName bx Masks
rName ebx_top IdentityMasks

ENDIF ; IFIDN <pels>, <4bp1bp>

ENDIF ; IFIDN <wrap_mode>, <wrap>

perLineLoop:

IF use_rep_movs eq TRUE

        ; We can use the rep movs instruction to implement the perLineLoop.

        ; Get the number of dwords to do into ecx
        mov     cx, dxBytesToGoOnSrcLine
        shr     ecx, 2

        ; Apply the dword adjustment
        sub     ediDestIndex, _messSpad.dwordAdjust
        sub     esiSourceIndex, _messSpad.dwordAdjust

        ; Do as many dwords as possible
        rep movs dword ptr [ediDestIndex], dword ptr [esiSourceIndex]

        ; Apply the dword adjustment
        add     ediDestIndex, _messSpad.dwordAdjust
        add     esiSourceIndex, _messSpad.dwordAdjust

        ; Get the number of stray bytes into ecx (and clear dx).
        xchg    cx, dxBytesToGoOnSrcLine
        and     ecx, 3

        ; Do any stray bytes left over.
        rep movs byte ptr [ediDestIndex], byte ptr [esiSourceIndex]

ELSE  ; IF use_rep_movs = TRUE

        ; We can not use the rep movs instruction to implement the perLineLoop
        ; because we are going to do a mix or a palette conversion or we are
        ; not at 8 bits per pel.



        ; If we are doing a color compare function then we will not try
        ; to use a dword loop because the time required to combine the
        ; source dword with the destination dword is about the same as the
        ; time to just do four bytes instead.
IFIDN <comp_mode>, <no_colcomp>
        ; If we are at 8bp or 16bp then we will try to use a dword loop
        ; to speed things up. At 4bp and 1bp this is not such a good idea
        ; because bitmaps are stored in motorola format and combining this
        ; with the source to destination shift things become very complicated!
IFDIF <pels>, <4bp1bp>

        ; Subtract 4 from the number of pels still to do. If the answer is
        ; less than 0 then there are no more dwords to be done.
        sub     dxBytesToGoOnSrcLine, 4
        jc      short noDwordsToDo

        ; Apply the dword adjustment to the source and destination
        sub     ediDestIndex, _messSpad.dwordAdjust
        sub     esiSourceIndex, _messSpad.dwordAdjust

dwordLoop:

        ; Get the source into eax and update the source index.
        lods    dword ptr [esiSourceIndex]
rName eax SrcDword

IF use_palette eq TRUE
        ; We are in palette mode so we must convert the dword from the source
        ; palette to the destination palette using the PaletteMapping table.
        ; (Note we use AL and AH to overide rmacros trapping al and ah.)
        mov     bl, alPartOfSrcDword
        mov     alPartOfSrcDword, byte ptr PaletteMapping[ebx]
        mov     bl, ahPartOfSrcDword
        mov     ahPartOfSrcDword, byte ptr PaletteMapping[ebx]
        swap    eaxSrcDword
        mov     bl, alPartOfSrcDword
        mov     alPartOfSrcDword, byte ptr PaletteMapping[ebx]
        mov     bl, ahPartOfSrcDword
        mov     ahPartOfSrcDword, byte ptr PaletteMapping[ebx]
        swap    eaxSrcDword

ENDIF ;IF use_palette eq TRUE

IFIDN <mix_mode>, <mix>
        ; We are in mix mode so move the source into ecx and get
        ; the destination into eax.
        mov     ecx, eaxSrcDword
rFree eax SrcDword

        mov     eax, dword ptr [ediDestIndex]

        ; Now jump into the mixing code at the right place.
        jmp     _messSpad.dwordsMixOffset

dwordMixCodeBase:
        mixTrashSourcePart      ecx, eax
        ; eax now contains the new mixed source dword.
rName eax SrcDword

ENDIF ; IFIDN <mix_mode>, <mix>

        ; Write eax (the result of the mix/palette conversion) to the
        ; destination and update the destination index.
        stos    dword ptr [ediDestIndex]
rFree eax SrcDword

        ; Subtract 4 from the number of pels still to do. If the answer is
        ; less than 0 then there are no more dwords to be done.
        sub     dxBytesToGoOnSrcLine, 4
        jnc     short dwordLoop

        ; Apply the dword adjustment to the source and destination
        add     ediDestIndex, _messSpad.dwordAdjust
        add     esiSourceIndex, _messSpad.dwordAdjust

noDwordsToDo:
        ; Now see if there are any stray bytes left over.
        add     dxBytesToGoOnSrcLine, 4
        jz      short noMorePelsToDo

ENDIF ; IFDIF <pels>, <4bp1bp>
ENDIF ; IFIDN <comp_mode>, <no_colcomp>


        ; If we are at 1, 4, or 8 bits per pel then we will use a byte loop
        ; to blt any remaining pels. If we are at 16 bits per pel then we
        ; will use a word loop to blt any remaining pels.
IFDIF <pels>, <16bp>
setUpByteLoop:

IFIDN <pels>, <4bp1bp>
        ; At 4bp or 1bp processing the byte at the end of a line needs care
        ; and so we want to special case it.
        ; We decrement dx again so that the wrap loop will exit one byte
        ; earlier so that we can deal with the last byte after we have left
        ; the wrap loop.
        dec     dxBytesToGoOnSrcLine
        jz      short doLastByte
ENDIF ; IFIDN <pels>, <4bp1bp>

byteLoop:

        ; Get the source into al and update the source index.
IFDIF <pels>, <4bp1bp>
        lods    byte ptr [esiSourceIndex]

IFIDN <comp_mode>, <colcomp_src_not_equal>
        ; We only want to write pels to the destination where the
        ; original source pel is the color compare value.
        cmp     al, byte ptr _ShadowXGARegs.colour_comp_colour
        jne     short @F
        add     ediDestIndex, _messSpad.byteInc
        jmp     short finishedThisByte
@@:
ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

ELSE  ; IFDIF <pels>, <4bp1bp>
        mov     ax, word ptr [esiSourceIndex]
        rol     ax, clSrcToDestShift
        add     esiSourceIndex, _messSpad.byteInc

IFIDN <comp_mode>, <colcomp_src_not_equal>
        ; Keep a copy of the original source pel so that we can decide
        ; which pels to write to the destination after we have been through
        ; the mixing code.
rName ch OrigSrcByte
        mov     chOrigSrcByte, al
ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

ENDIF ; IFDIF <pels>, <4bp1bp>  ELSE


IF use_palette eq TRUE
        ; We are in palette mode so we must convert the byte from the source
        ; palette to the destination palette using the PaletteMapping table.
        mov     bl, al
        mov     al, byte ptr PaletteMapping[ebx]
ENDIF ;IF use_palette eq TRUE


IFIDN <mix_mode>, <mix>
        ; We are in mix mode so move the source into ah and get
        ; the destination into al.
        mov     ah, al
        mov     al, byte ptr [ediDestIndex]

        ; Now jump into the mixing code at the right place.
        jmp     _messSpad.fullBytesMixOffset

byteMixCodeBase:
        mixTrashSourcePart      ah, al

ENDIF ; IFIDN <mix_mode>, <mix>

IFIDN <comp_mode>, <colcomp_equal>
        ; We only want to write pels to the destination where the
        ; original destination pel was the color compare value.

IFIDN <pels>, <8bp>
        mov     ah, byte ptr [ediDestIndex]
        cmp     ah, byte ptr _ShadowXGARegs.colour_comp_colour
        je      short @F
        mov     al, ah
@@:
ENDIF ; IFIDN <pels>, <8bp>

IFIDN <pels>, <4bp1bp>
rName al SrcByte
        ColCompEqual4bp
rFree al SrcByte
ENDIF ; IFIDN <pels>, <4bp1bp>

ENDIF ; IFIDN <comp_mode>, <colcomp_equal>


IFIDN <comp_mode>, <colcomp_src_not_equal>
IFIDN <pels>, <4bp1bp>
        ; We only want to write pels to the destination where the
        ; original (pre mixed) source pels were the color compare value.
rName al SrcByte
        ColCompSrcNotEqual4bp
rFree al SrcByte
rFree ch OrigSrcByte
ENDIF ; IFIDN <pels>, <4bp1bp>

ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

        ; Write al (the result of the mix/palette conversion) to the
        ; destination and update destination index.
        stos    byte ptr [ediDestIndex]
finishedThisByte:

        ; Loop back if there are more bytes to be done.
        dec     dxBytesToGoOnSrcLine
        jnz     short byteLoop


IFIDN <pels>, <4bp1bp>

doLastByte:
        ; At 4bp or 1bp we must deal with the last byte carefully so that only
        ; the correct pels get blted.

IFIDN <wrap_mode>, <wrap>
        ; The source word we get (so we can apply the srcToDestShift to it to
        ; get the bits corresponding to the destination byte) may cross the
        ; wrap-around boundry. ie. The high byte of the word may infact be the
        ; first byte of the line.

        ; We may just be finishing a line of source before we wrap around
        ; and continue the blt, or we may actually be finishing the complete
        ; line of the blt. If we are finishing the blt we may also have to
        ; wrap around in order to get hold of the high byte of the pre-shifted
        ; source word.

        ; If we are wrapping round then bp will contain -srcWidthInBytes,
        ; otherwise it will contain zero.
        ; If we are finishing the blt line the bx will contain the end mask
        ; and its inverses, otherwise it will contain 00ffh which has the
        ; effect of transfering the whole source byte to the destination.
ENDIF ; IFIDN <wrap_mode>, <wrap>


        ; Get the word containing the byte we want from the source and
        ; update the source index.
IFIDN <wrap_mode>, <wrap>
        mov     ah, [esiSourceIndex+ebpSecondByteAdjuster+1]
ELSE  ; IFIDN <wrap_mode>, <wrap>
        mov     ah, [esiSourceIndex+1]
ENDIF ; IFIDN <wrap_mode>, <wrap>  ELSE
        lods    byte ptr [esiSourceIndex]

        ; Now rotate the source word by the srcToDestShift so that al contains
        ; the bits which correspond to the first byte in the destination.
        rol     ax, clSrcToDestShift

        ; al now contains the bits which are to be blted onto the last byte
        ; in the destination.

        ; Get the destination byte.
        mov     ah, [ediDestIndex]

IFIDN <mix_mode>, <mix>
        ; Make sure we have a copy of the destination byte to use later.
        mov     ch, ah

        ; Now jump to the mixing code at the right place.
        jmp     _messSpad.endBytesMixOffset

endByteMixCodeBase:
        mixKeepSourcePart      al, ch

        ; Get the new source byte (after mixing) into al and the
        ; original source byte into ch.
        xchg    al, ch
IFIDN <comp_mode>, <colcomp_src_not_equal>
rName ch OrigSrcByte
ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

ELSE  ; IFIDN <mix_mode>, <mix>

IFIDN <comp_mode>, <colcomp_src_not_equal>
        mov     ch, al
rName ch OrigSrcByte
ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

ENDIF ; IFIDN <mix_mode>, <mix>  ELSE

        ; Now use the end mask (and its inverse) to combine the source byte
        ; with the destination byte. The end mask (and its inverse) are
        ; stored in bx. (Note that bx actually contains either the masks
        ; or the identity masks depending on whether we are wrapping around
        ; or really at the end of the blt line. rmacros is does only linear
        ; code checking rather than data flow analysis and so expects bx
        ; to be associated with Masks rather than IdentityMasks at this stage).
        and     ax, bxMasks
        or      al, ah

IFIDN <comp_mode>, <colcomp_equal>
        ; We only want to write pels to the destination where the
        ; original destination pel was the color compare value.
rName al SrcByte
        ColCompEqual4bp
rFree al SrcByte
ENDIF ; IFIDN <comp_mode>, <colcomp_equal>
IFIDN <comp_mode>, <colcomp_src_not_equal>
        ; We only want to write pels to the destination where the
        ; original (pre mixed) source pels were the color compare value.
rName al SrcByte
        ColCompSrcNotEqual4bp
rFree al SrcByte
rFree ch OrigSrcByte
ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

        ; al contains the merged source and destination bytes so we can
        ; now write it back to the destination and update the destination
        ; index.
        stos    byte ptr [ediDestIndex]

ENDIF ; IFIDN <pels>, <4bp1bp>


ELSE  ; IFDIF <pels>, <16bp>
        ; We are at 16 bits per pel so we will use a word loop to blt
        ; any remaining pels.

wordLoop:
        ; Get the source into ax and update the source index.
        lods    word ptr [esiSourceIndex]

IFIDN <comp_mode>, <colcomp_src_not_equal>
        ; We only want to write pels to the destination where the
        ; original source pel is the color compare value.
        cmp     ax, word ptr _ShadowXGARegs.colour_comp_colour
        jne     short @F
        add     ediDestIndex, _messSpad.byteInc
        add     ediDestIndex, _messSpad.byteInc
        jmp     short finishedThisWord
@@:
ENDIF ; IFIDN <comp_mode>, <colcomp_src_not_equal>

IFIDN <mix_mode>, <mix>
        ; We are in mix mode so move the source into cx and get
        ; the destination into ax.
        mov     cx, ax
        mov     ax, word ptr [ediDestIndex]

        ; Now jump into the mixing code at the right place.
        jmp     _messSpad.wordsMixOffset

wordMixCodeBase:
        ; We will actually do a dword mix (mixing words would not be
        ; as fast) and ignore the top half of the registers.
        mixTrashSourcePart      ecx, eax

ENDIF ; IFIDN <mix_mode>, <mix>

IFIDN <comp_mode>, <colcomp_equal>
        ; We only want to write pels to the destination where the
        ; original destination pel was the color compare value.
        mov     cx, word ptr [ediDestIndex]
        cmp     cx, word ptr _ShadowXGARegs.colour_comp_colour
        je      short @F
        mov     ax, cx
@@:
ENDIF ; IFIDN <comp_mode>, <colcomp_equal>

        ; Write ax (the result of the mix) to the
        ; destination and update destination index.
        stos    word ptr [ediDestIndex]
finishedThisWord:

        ; Loop back if there are more bytes to be done.
        sub     dxBytesToGoOnSrcLine, 2
        jnz     short wordLoop
ENDIF ; IFDIF <pels>, <16bpp>  ELSE

noMorePelsToDo:

ENDIF ; IFIDN <use_rep_movs>, <TRUE>  ELSE



        ; We have done a line of the source. If we are in wrap_mode
        ; then we have to see if we have finished this line of the
        ; blt or if we just need to wrap the source around again.
        ; If we are not in wrap_mode then we have finished this line
        ; of the blt and we must now adjust the source and destination
        ; indexes so that they point to the next lines to be processed.

        ; First adjust the source index.

IFIDN <wrap_mode>, <wrap>
        ; Now we must either go onto the next line or we must wrap around
        ; the source. If there are no more pels to do then we have finished
        ; this line. The number of pels still to do is stored in the top
        ; half of edx. Also we know that dx is zero at this point.
rFree dx BytesToGoOnSrcLine
rFree edx_top BytesLeftOnDestLine
        or      edx, edx
        jz      short doNextLine

        ; We must wrap around the source.

        ; Get the number of pels still to go into dx and clear the top half
        ; of edx.
        shr     edx, 16

        ; Get the number of bytes on this source line before
        ; we would have to wrap around into ax.
        mov     eax, _messSpad.srcWidthInBytes

        ; Set the source index pointer back to the beginning of this line
        ; of source.
        sub     esiSourceIndex, eax

        ; Loop back to the code which decides whether we are going to have
        ; to do a whole line of the source and wrap, or whether we are going
        ; to finish the blt with this line of source.
        jmp     wrapLoop

doNextLine:

        ; Now we have finished the current line of the blt we must go on to
        ; do the next line. We might have to do a vertical wrap of the source.

        dec     _messSpad.srcLinesBeforeWrap
        jz      short vertWrapSource

        ; Set up the source index to be one line further on than it was at the
        ; beginning of the current line.
        mov     esiSourceIndex, _messSpad.srcLineStartAddr
        add     esiSourceIndex, _messSpad.srcWidthInBytes

vertWrapSourceReturn:
        ; Keep a copy of the source index at the beginning of the blt line.
        mov     _messSpad.srcLineStartAddr, esiSourceIndex


ELSE  ; IFIDN <wrap_mode>, <wrap>

        ; Add the source line increment to the source index.
        add     esiSourceIndex, _messSpad.srcLineInc

ENDIF ; IFIDN <wrap_mode>, <wrap>  ELSE

        ; We have adjusted the source index to point to the next line.
        ; We must now adjust the destination index to point to the next
        ; line also.

        ; Add the destination line incement to the destination index.
        add     ediDestIndex, _messSpad.dstLineInc

        ; Decrement the number of lines to go and loop back.
        dec     _messSpad.perLineLoopCount
        jnz     setUpPerLineLoop

        ; We have finished!


IFIDN <wrap_mode>, <wrap>
        jmp     short exit

vertWrapSource:
        ; Do a vertical wrap of the source here.


        ; Set the source index to point to the first byte to be blted
        ; in the first line of the source.
        mov     esiSourceIndex, srcPixmap.startAddr

IFIDN <pels>, <8bp>
        movzx   eax, ShadowXGARegs.src_map_x
        add     esiSourceIndex, eax

ELSE  ; IFIDN <pels>, <8bp>
IFIDN <pels>, <16bp>
        movzx   eax, ShadowXGARegs.src_map_x
        shl     eax, 1
        add     esiSourceIndex, eax

ELSE  ; IFIDN <pels>, <16bp>

        ; Calculate the offset of the byte containing the first pel.
        movzx   eax, ShadowXGARegs.src_map_x
        test    byte ptr dstPixmap.format, FOUR_BPP
        jnz     short @F
        shr     eax, 2
@@:
        shr     eax, 1

        add     esiSourceIndex, eax

        ; If the source index was adjusted in the setUpSrcDest function
        ; then it will need adjust here for just the same reasons.
        .ERRE   TRUE eq 1
        .ERRE   FALSE eq 0
        sub     esiSourceIndex, _messSpad.srcIndexAdjusted

ENDIF ; IFIDN <pels>, <16bp>  ELSE
ENDIF ; IFIDN <pels>, <8bp>  ELSE


        ; Set the number of lines to go before the next vertical wrap.
        mov     ax, srcPixmap.yLen
        inc     ax
        mov     _messSpad.srcLinesBeforeWrap, ax

        ; Return to the main code in the correct place.
        jmp     vertWrapSourceReturn
ENDIF ; IFIDN <wrap_mode>, <wrap>



exit:


rEnd

endm SrcDest

ENDIF ;;; XGA Version of macros

ENDIF ; IF1


;-------------------------------------------------------------------------
;
; Function: eddf_MESSBlockCopy4111
;
; This does a fast block copy for 4,1 formats and 1,1 formats
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSBlockCopy4111, <PUBLIC>, <ebp,ebx>
cBegin

        CheckColorComp 4bp1bp, standardBC4111, colCompEqualBC4111

        SrcDest 4bp1bp no_wrap no_mix colcomp_src_not_equal no_palette
        jmp     exitBC4111

colCompEqualBC4111:
        SrcDest 4bp1bp no_wrap no_mix colcomp_equal no_palette
        jmp     exitBC4111

standardBC4111:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 4bp1bp no_wrap no_mix no_colcomp no_palette

exitBC4111:
        ; Make sure that color compare value holds only one pel of
        ; color on exit in case we modified it earlier.
        RestoreColorComp
cEnd


;-------------------------------------------------------------------------
; Function: eddf_MESSSrcDestMix4111
;
; This does a mix on a source and destination for 4,1 format and 1,1
; format
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSSrcDestMix4111, <PUBLIC>, <ebp,ebx>
cBegin

        CheckColorComp 4bp1bp, standardSDM4111, colCompEqualSDM4111

        SrcDest 4bp1bp no_wrap mix colcomp_src_not_equal no_palette
        jmp     exitSDM4111

colCompEqualSDM4111:
        SrcDest 4bp1bp no_wrap mix colcomp_equal no_palette
        jmp     exitSDM4111

standardSDM4111:
        ; Code for copy without color compare function.
        SrcDest 4bp1bp no_wrap mix no_colcomp no_palette

exitSDM4111:
        ; Make sure that color compare value holds only one pel of
        ; color on exit in case we modified it earlier.
        RestoreColorComp
cEnd




;-------------------------------------------------------------------------
; Function: eddf_MESSSrcDestWrapCopy41
;
; This does a source to destination copy, allowing the source to wrap
; around, for 4,1 format
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structure
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSSrcDestWrapCopy41, <PUBLIC>, <ebp,ebx>
cBegin

        CheckColorComp 4bp1bp, standardSDWC4111, colCompEqualSDWC4111

        SrcDest 4bp1bp wrap no_mix colcomp_src_not_equal no_palette
        jmp     exitSDWC4111

colCompEqualSDWC4111:
        SrcDest 4bp1bp wrap no_mix colcomp_equal no_palette
        jmp     exitSDWC4111

standardSDWC4111:
        ; Code for copy without color compare function.
        SrcDest 4bp1bp wrap no_mix no_colcomp no_palette

exitSDWC4111:
        ; Make sure that color compare value holds only one pel of
        ; color on exit in case we modified it earlier.
        RestoreColorComp
cEnd




;-------------------------------------------------------------------------
; Function: eddf_MESSSrcDestWrapMix41
;
; This does a source to destination mix, allowing the source to wrap
; around, for 4,1 format
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structure
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSSrcDestWrapMix41, <PUBLIC>, <ebp,ebx>
cBegin

        CheckColorComp 4bp1bp, standardSDWM4111, colCompEqualSDWM4111

        SrcDest 4bp1bp wrap mix colcomp_src_not_equal no_palette
        jmp     exitSDWM4111

colCompEqualSDWM4111:
        SrcDest 4bp1bp wrap mix colcomp_equal no_palette
        jmp     exitSDWM4111

standardSDWM4111:
        ; Code for copy without color compare function.
        SrcDest 4bp1bp wrap mix no_colcomp no_palette

exitSDWM4111:
        ; Make sure that color compare value holds only one pel of
        ; color on exit in case we modified it earlier.
        RestoreColorComp
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSBlockCopy81
;
; This does a fast block copy for 8,1 formats.
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSBlockCopy81, <PUBLIC>, <ebx>
cBegin

IFDEF PALETTE_MGR
        cmp     UsePaletteMapping, TRUE
        je      palManBC81
ENDIF

        CheckColorComp 8bp, standardBC81, colCompEqualBC81

        SrcDest 8bp no_wrap no_mix colcomp_src_not_equal no_palette
        jmp     exitBC81
colCompEqualBC81:
        SrcDest 8bp no_wrap no_mix colcomp_equal no_palette
        jmp     exitBC81

IFDEF PALETTE_MGR
palManBC81:
        ; Code for palette conversion with or without a color compare function.
        CheckColorComp 8bp, standardPalManBC81, colCompEqualPalManBC81

        SrcDest 8bp no_wrap no_mix colcomp_src_not_equal palette
        jmp     exitBC81
colCompEqualPalManBC81:
        SrcDest 8bp no_wrap no_mix colcomp_equal palette
        jmp     exitBC81

standardPalManBC81:
        ; Code for palette conversion without color compare.
        SrcDest 8bp no_wrap no_mix no_colcomp palette
        jmp     short exitBC81

ENDIF ; PALETTE_MGR


standardBC81:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 8bp no_wrap no_mix no_colcomp no_palette

exitBC81:

cEnd

ifdef BPP24
;-------------------------------------------------------------------------
;
; Function: eddf_MESSBlockCopy24
;
; This does a fast block copy for 8,1 formats.
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSBlockCopy24, <PUBLIC>, <ebx>
cBegin

        ; @DMS we may get away with just doing some mult by three on the width
        ; here - .... and it seems to be working fine !!!
        mov     ax,Shadow8514Regs.dim1
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        mov     Shadow8514Regs.dim1,ax

        mov     ax,srcPixmap.xLen
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        mov     srcPixmap.xLen,ax

        mov     ax,dstPixmap.xLen
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        mov     dstPixmap.xLen,ax

        mov     ax,Shadow8514Regs.src_map_x
        mov     dx,3
        mul     dx
        test    Shadow8514Regs.pixel_op.lo, BLTDIR_RIGHTTOLEFT
        jz      short @F
        add     ax,2
@@:
        mov     Shadow8514Regs.src_map_x,ax

        mov     ax,Shadow8514Regs.dest_map_x
        mov     dx,3
        mul     dx
        test    Shadow8514Regs.pixel_op.lo, BLTDIR_RIGHTTOLEFT
        jz      short @F
        add     ax,2
@@:
        mov     Shadow8514Regs.dest_map_x,ax


IFDEF PALETTE_MGR
        cmp     UsePaletteMapping, TRUE
        je      palManBC24
ENDIF

        CheckColorComp 8bp, standardBC24, colCompEqualBC24

        SrcDest 8bp no_wrap no_mix colcomp_src_not_equal no_palette
        jmp     exitBC24
colCompEqualBC24:
        SrcDest 8bp no_wrap no_mix colcomp_equal no_palette
        jmp     exitBC24

IFDEF PALETTE_MGR
palManBC24:
        ; Code for palette conversion with or without a color compare function.
        CheckColorComp 8bp, standardPalManBC24, colCompEqualPalManBC24

        SrcDest 8bp no_wrap no_mix colcomp_src_not_equal palette
        jmp     exitBC24
colCompEqualPalManBC24:
        SrcDest 8bp no_wrap no_mix colcomp_equal palette
        jmp     exitBC24

standardPalManBC24:
        ; Code for palette conversion without color compare.
        SrcDest 8bp no_wrap no_mix no_colcomp palette
        jmp     short exitBC24

ENDIF ; PALETTE_MGR


standardBC24:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 8bp no_wrap no_mix no_colcomp no_palette

exitBC24:

cEnd
endif



;-------------------------------------------------------------------------
;
; Function: eddf_MESSSrcDestMix81
;
; This does a mix on a source and destination for 8,1 format using
; dword operations where possible
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSSrcDestMix81, <PUBLIC>, <ebx>
cBegin

IFDEF PALETTE_MGR
        cmp     UsePaletteMapping, TRUE
        je      palManSDM81
ENDIF

        CheckColorComp 8bp, standardSDM81, colCompEqualSDM81

        SrcDest 8bp no_wrap mix colcomp_src_not_equal no_palette
        jmp     exitSDM81
colCompEqualSDM81:
        SrcDest 8bp no_wrap mix colcomp_equal no_palette
        jmp     exitSDM81

IFDEF PALETTE_MGR
palManSDM81:
        ; Code for palette conversion with or without a color compare function.
        CheckColorComp 8bp, standardPalManSDM81, colCompEqualPalManSDM81

        SrcDest 8bp no_wrap mix colcomp_src_not_equal palette
        jmp     exitSDM81
colCompEqualPalManSDM81:
        SrcDest 8bp no_wrap mix colcomp_equal palette
        jmp     exitSDM81

standardPalManSDM81:
        ; Code for palette conversion without color compare.
        SrcDest 8bp no_wrap mix no_colcomp palette
        jmp     exitSDM81

ENDIF ; PALETTE_MGR


standardSDM81:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 8bp no_wrap mix no_colcomp no_palette

exitSDM81:

cEnd

ifdef BPP24
;-------------------------------------------------------------------------
;
; Function: eddf_MESSSrcDestMix24
;
; This does a mix on a source and destination for 8,1 format using
; dword operations where possible
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSSrcDestMix24, <PUBLIC>, <ebx>
cBegin

        ; @DMS we may get away with just doing some mult by three on the width
        ; here - .... and it seems to be working fine !!!
        mov     ax,Shadow8514Regs.dim1
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        mov     Shadow8514Regs.dim1,ax

        mov     ax,srcPixmap.xLen
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        mov     srcPixmap.xLen,ax

        mov     ax,dstPixmap.xLen
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        mov     dstPixmap.xLen,ax

        mov     ax,Shadow8514Regs.src_map_x
        mov     dx,3
        mul     dx
        test    Shadow8514Regs.pixel_op.lo, BLTDIR_RIGHTTOLEFT
        jz      short @F
        add     ax,2
@@:
        mov     Shadow8514Regs.src_map_x,ax

        mov     ax,Shadow8514Regs.dest_map_x
        mov     dx,3
        mul     dx
        test    Shadow8514Regs.pixel_op.lo, BLTDIR_RIGHTTOLEFT
        jz      short @F
        add     ax,2
@@:
        mov     Shadow8514Regs.dest_map_x,ax


IFDEF PALETTE_MGR
        cmp     UsePaletteMapping, TRUE
        je      palManSDM24
ENDIF

        CheckColorComp 8bp, standardSDM24, colCompEqualSDM24

        SrcDest 8bp no_wrap mix colcomp_src_not_equal no_palette
        jmp     exitSDM24
colCompEqualSDM24:
        SrcDest 8bp no_wrap mix colcomp_equal no_palette
        jmp     exitSDM24

IFDEF PALETTE_MGR
palManSDM24:
        ; Code for palette conversion with or without a color compare function.
        CheckColorComp 8bp, standardPalManSDM24, colCompEqualPalManSDM24

        SrcDest 8bp no_wrap mix colcomp_src_not_equal palette
        jmp     exitSDM24
colCompEqualPalManSDM24:
        SrcDest 8bp no_wrap mix colcomp_equal palette
        jmp     exitSDM24

standardPalManSDM24:
        ; Code for palette conversion without color compare.
        SrcDest 8bp no_wrap mix no_colcomp palette
        jmp     exitSDM24

ENDIF ; PALETTE_MGR


standardSDM24:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 8bp no_wrap mix no_colcomp no_palette

exitSDM24:

cEnd
endif


;-------------------------------------------------------------------------
; Function: eddf_MESSSrcDestWrapCopy81
;
; This does a source to destination copy, allowing the source to wrap
; around, for 8,1 format
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structure
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSSrcDestWrapCopy81, <PUBLIC>, <ebx>
cBegin

IFDEF PALETTE_MGR
        cmp     UsePaletteMapping, TRUE
        je      palManSDWC81
ENDIF

        CheckColorComp 8bp, standardSDWC81, colCompEqualSDWC81

        SrcDest 8bp wrap no_mix colcomp_src_not_equal no_palette
        jmp     exitSDWC81
colCompEqualSDWC81:
        SrcDest 8bp wrap no_mix colcomp_equal no_palette
        jmp     exitSDWC81

IFDEF PALETTE_MGR
palManSDWC81:
        ; Code for palette conversion with or without a color compare function.
        CheckColorComp 8bp, standardPalManSDWC81, colCompEqualPalManSDWC81

        SrcDest 8bp wrap no_mix colcomp_src_not_equal palette
        jmp     exitSDWC81
colCompEqualPalManSDWC81:
        SrcDest 8bp wrap no_mix colcomp_equal palette
        jmp     exitSDWC81

standardPalManSDWC81:
        ; Code for palette conversion without color compare.
        SrcDest 8bp wrap no_mix no_colcomp palette
        jmp     exitSDWC81

ENDIF ; PALETTE_MGR


standardSDWC81:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 8bp wrap no_mix no_colcomp no_palette

exitSDWC81:

cEnd


ifdef BPP24
;-------------------------------------------------------------------------
; Function: eddf_MESSSrcDestWrapCopy24
;
; This does a source to destination copy, allowing the source to wrap
; around, for 8,1 format
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structure
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSSrcDestWrapCopy24, <PUBLIC>, <ebx>
cBegin


        ; @DMS we may get away with just doing some mult by three on the width
        ; here - .... and it seems to be working fine !!!
        mov     ax,Shadow8514Regs.dim1
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        mov     Shadow8514Regs.dim1,ax

        mov     ax,srcPixmap.xLen
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        mov     srcPixmap.xLen,ax

        mov     ax,dstPixmap.xLen
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        mov     dstPixmap.xLen,ax

        mov     ax,Shadow8514Regs.src_map_x
        mov     dx,3
        mul     dx
        mov     Shadow8514Regs.src_map_x,ax

        mov     ax,Shadow8514Regs.dest_map_x
        mov     dx,3
        mul     dx
        mov     Shadow8514Regs.dest_map_x,ax

IFDEF PALETTE_MGR
        cmp     UsePaletteMapping, TRUE
        je      palManSDWC24
ENDIF

        CheckColorComp 8bp, standardSDWC24, colCompEqualSDWC24

        SrcDest 8bp wrap no_mix colcomp_src_not_equal no_palette
        jmp     exitSDWC24
colCompEqualSDWC24:
        SrcDest 8bp wrap no_mix colcomp_equal no_palette
        jmp     exitSDWC24

IFDEF PALETTE_MGR
palManSDWC24:
        ; Code for palette conversion with or without a color compare function.
        CheckColorComp 8bp, standardPalManSDWC24, colCompEqualPalManSDWC24

        SrcDest 8bp wrap no_mix colcomp_src_not_equal palette
        jmp     exitSDWC24
colCompEqualPalManSDWC24:
        SrcDest 8bp wrap no_mix colcomp_equal palette
        jmp     exitSDWC24

standardPalManSDWC24:
        ; Code for palette conversion without color compare.
        SrcDest 8bp wrap no_mix no_colcomp palette
        jmp     exitSDWC24

ENDIF ; PALETTE_MGR


standardSDWC24:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 8bp wrap no_mix no_colcomp no_palette

exitSDWC24:

cEnd
endif


;-------------------------------------------------------------------------
; Function: eddf_MESSSrcDestWrapMix81
;
; This does a source to destination mix, allowing the source to wrap
; around, for 8,1 format
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structure
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSSrcDestWrapMix81, <PUBLIC>, <ebx>
cBegin

IFDEF PALETTE_MGR
        cmp     UsePaletteMapping, TRUE
        je      palManSDWM81
ENDIF

        CheckColorComp 8bp, standardSDWM81, colCompEqualSDWM81

        SrcDest 8bp wrap mix colcomp_src_not_equal no_palette
        jmp     exitSDWM81
colCompEqualSDWM81:
        SrcDest 8bp wrap mix colcomp_equal no_palette
        jmp     exitSDWM81

IFDEF PALETTE_MGR
palManSDWM81:
        ; Code for palette conversion with or without a color compare function.
        CheckColorComp 8bp, standardPalManSDWM81, colCompEqualPalManSDWM81

        SrcDest 8bp wrap mix colcomp_src_not_equal palette
        jmp     exitSDWM81
colCompEqualPalManSDWM81:
        SrcDest 8bp wrap mix colcomp_equal palette
        jmp     exitSDWM81

standardPalManSDWM81:
        ; Code for palette conversion without color compare.
        SrcDest 8bp wrap mix no_colcomp palette
        jmp     exitSDWM81

ENDIF ; PALETTE_MGR


standardSDWM81:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 8bp wrap mix no_colcomp no_palette

exitSDWM81:

cEnd


ifdef BPP24
;-------------------------------------------------------------------------
; Function: eddf_MESSSrcDestWrapMix24
;
; This does a source to destination mix, allowing the source to wrap
; around, for 8,1 format
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structure
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSSrcDestWrapMix24, <PUBLIC>, <ebx>
cBegin

        ; @DMS we may get away with just doing some mult by three on the width
        ; here - .... and it seems to be working fine !!!
        mov     ax,Shadow8514Regs.dim1
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        mov     Shadow8514Regs.dim1,ax

        mov     ax,srcPixmap.xLen
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        mov     srcPixmap.xLen,ax

        mov     ax,dstPixmap.xLen
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        mov     dstPixmap.xLen,ax

        mov     ax,Shadow8514Regs.src_map_x
        mov     dx,3
        mul     dx
        mov     Shadow8514Regs.src_map_x,ax

        mov     ax,Shadow8514Regs.dest_map_x
        mov     dx,3
        mul     dx
        mov     Shadow8514Regs.dest_map_x,ax


IFDEF PALETTE_MGR
        cmp     UsePaletteMapping, TRUE
        je      palManSDWM24
ENDIF

        CheckColorComp 8bp, standardSDWM24, colCompEqualSDWM24

        SrcDest 8bp wrap mix colcomp_src_not_equal no_palette
        jmp     exitSDWM24
colCompEqualSDWM24:
        SrcDest 8bp wrap mix colcomp_equal no_palette
        jmp     exitSDWM24

IFDEF PALETTE_MGR
palManSDWM24:
        ; Code for palette conversion with or without a color compare function.
        CheckColorComp 8bp, standardPalManSDWM24, colCompEqualPalManSDWM24

        SrcDest 8bp wrap mix colcomp_src_not_equal palette
        jmp     exitSDWM24
colCompEqualPalManSDWM24:
        SrcDest 8bp wrap mix colcomp_equal palette
        jmp     exitSDWM24

standardPalManSDWM24:
        ; Code for palette conversion without color compare.
        SrcDest 8bp wrap mix no_colcomp palette
        jmp     exitSDWM24

ENDIF ; PALETTE_MGR


standardSDWM24:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 8bp wrap mix no_colcomp no_palette

exitSDWM24:

cEnd
endif


;-------------------------------------------------------------------------
;
; Function: eddf_MESSBlockCopy16
;
; This does a fast block copy for 16,1 formats.
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSBlockCopy16, <PUBLIC>, <ebx>
cBegin

        CheckColorComp 16bp, standardBC16, colCompEqualBC16

        SrcDest 16bp no_wrap no_mix colcomp_src_not_equal no_palette
        jmp     exitBC16

colCompEqualBC16:
        SrcDest 16bp no_wrap no_mix colcomp_equal no_palette
        jmp     exitBC16

standardBC16:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 16bp no_wrap no_mix no_colcomp no_palette

exitBC16:
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSSrcDestMix16
;
; This does a mix on a source and destination for 16,1 format using
; dword operations where possible
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSSrcDestMix16, <PUBLIC>, <ebx>
cBegin

        CheckColorComp 16bp, standardSDM16, colCompEqualSDM16

        SrcDest 16bp no_wrap mix colcomp_src_not_equal no_palette
        jmp     exitSDM16

colCompEqualSDM16:
        SrcDest 16bp no_wrap mix colcomp_equal no_palette
        jmp     exitSDM16

standardSDM16:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 16bp no_wrap mix no_colcomp no_palette

exitSDM16:
cEnd



;-------------------------------------------------------------------------
; Function: eddf_MESSSrcDestWrapCopy16
;
; This does a source to destination copy, allowing the source to wrap
; around, for 16,1 format
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structure
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSSrcDestWrapCopy16, <PUBLIC>, <ebx>
cBegin


        CheckColorComp 16bp, standardSDWC16, colCompEqualSDWC16

        SrcDest 16bp wrap no_mix colcomp_src_not_equal no_palette
        jmp     exitSDWC16

colCompEqualSDWC16:
        SrcDest 16bp wrap no_mix colcomp_equal no_palette
        jmp     exitSDWC16

standardSDWC16:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 16bp wrap no_mix no_colcomp no_palette

exitSDWC16:
cEnd


;-------------------------------------------------------------------------
; Function: eddf_MESSSrcDestWrapMix16
;
; This does a source to destination mix, allowing the source to wrap
; around, for 16,1 format
;
; Parameters:
;       ShadowXGARegs, _messSpad, pixmap structure
;
;-------------------------------------------------------------------------
        align   4
cProc   eddf_MESSSrcDestWrapMix16, <PUBLIC>, <ebx>
cBegin

        CheckColorComp 16bp, standardSDWM16, colCompEqualSDWM16

        SrcDest 16bp wrap mix colcomp_src_not_equal no_palette
        jmp     exitSDWM16

colCompEqualSDWM16:
        SrcDest 16bp wrap mix colcomp_equal no_palette
        jmp     exitSDWM16

standardSDWM16:
        ; Code for copy without palette conversion or color compare function.
        SrcDest 16bp wrap mix no_colcomp no_palette

exitSDWM16:
cEnd

_TEXT ends


END
