;*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.;
;*****************************************************************************/
; NB. The comments in this file have not been fully updated to reflect
; 32bit register usage.
; In particular no use is made of fs: or gs: registers in flat model.

;-------------------------------------------------------------------------
;
;   Module          = FFBLTPD
;
;   Description     = 386 code for the software pattern destination blt
;                     operations in MESS.
;
;   Functions       = eddf_MESSPatDest16
;                     eddf_MESSPatDest24
;                     eddf_MESSPatDest81
;                     eddf_MESSPatDest41
;                     eddf_MESSPatDest11
;                     eddf_MESSPatDestMixes11
;                     eddf_MESSPatCopy16
;                     eddf_MESSPatCopy24
;                     eddf_MESSPatCopy81
;                     eddf_MESSPatCopy41
;                     eddf_MESSPatCopy11
;                     eddf_MESSPatDestByte81
;                     eddf_MESSPatDestByte41
;                     eddf_MESSPatDestByte11
;                     eddf_MESSPatDestMixesByte11
;                     eddf_MESSPatCopyByte81
;                     eddf_MESSPatCopyByte41
;                     eddf_MESSPatCopyByte11
;
;
;-------------------------------------------------------------------------
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   04/28/93              68245  Defect 68245.
;-------------------------------------------------------------------------

INCL_GPIBITMAPS EQU     1
include os2.inc
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



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




_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        dstPixmap
externDP        patPixmap
externDP        messSpad


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


; Here is a big buffer which we use when doing patterns to 1,1 bitmaps
; It is 512 bytes long because (currently) a pattern can only be one
; subbitmap and a subbitmap can only be 4K pels long hence 4096/8 = 512
; If this restriction disappears (ie 2.0) then we might have to do
; something else - like have another restriction.
globalB         patBuffer,0,512


_DATA           ends


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





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


; These functions are defined in ffbltset.asm
ifdef   BPP24
externP eddf_MESSSetUpDest24
endif
externP eddf_MESSSetUpDest16
externP eddf_MESSSetUpDest81
externP eddf_MESSSetUpDest11
externP eddf_MESSSetUpDestForPat41



; Define the macros used by this module.


IF1

;;;****************************************************************
;;;
;;; 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 does pattern/destination operations for 4, 8, and 16 bits
; per pel, producing special case code for blts with no mix, and pattern
; pixmaps that are only one byte wide.

; See individual function headers for more details.

patDest macro mode, bpp, patsize
        local perLineLoop, perPelLoop, mixBgPel, mixCodeBase
        local getPatByte, morePattern, lineEnd, vertWrapPattern
        local copyPel, copyFgPel, exit

; First check that the mode and bpp parameters are valid.
    ifdif <mode>, <mix>
     ifdif <mode>, <copy>
      .err
      %out patDest macro mode parameter must be "mix" or "copy".
     endif
    endif
    if (bpp ne 4) and (bpp ne 8) and (bpp ne 16) and (bpp ne 24)
     .err
     %out patDest macro bits per pel parameter must be 4, 8, 16 or 24.
    endif
    ifnb <patsize>
     ifdif <patsize>, <byte>
      .err
      %out patDest macro pattern size parameter must be blank or "byte".
     endif
    endif
; Now do the real code.

        ; First set up the destination start address and increments.
if bpp eq 24
        ; we are set up to use this proc to get our 24bpp addrs.
        cCall   eddf_MESSSetUpDest24
endif
if bpp eq 16
        cCall   eddf_MESSSetUpDest16
endif
if bpp eq 8
        cCall   eddf_MESSSetUpDest81
endif
if bpp eq 4
        cCall   eddf_MESSSetUpDestForPat41
endif
rName edi DestIndex

        ; Now set up all the local variable values we can before we go
        ; into the main line loop.


ifdif <patsize>, <byte>
        ; First work out the pattern pixmap width in bytes and keep a
        ; copy of it in ebx.
rName eax PatWidthInBytes
rName ebx PatWidthInBytesCopy
        movzx   eaxPatWidthInBytes, patPixmap.xLen
        shr     eaxPatWidthInBytes, 3
        inc     eaxPatWidthInBytes
        mov     patWidthInBytes, eaxPatWidthInBytes
        mov     ebxPatWidthInBytesCopy, eaxPatWidthInBytes

        ; Get the pattern x start postion and work out how many bytes
        ; offset this corresponds to from the left edge of the pixmap.
rName ecx PatXInBytes
rName edx PatXInPels
        movzx   edxPatXInPels, Shadow8514Regs.patt_map_x
        mov     ecxPatXInBytes, edxPatXInPels
        shr     ecxPatXInBytes, 3
endif ; ifdif <patsize>, <byte>

        ; Work out the offset of the first pel within the first byte
        ; of the pattern to be blted.
ifidn <patsize>, <byte>
        mov     dl, byte ptr Shadow8514Regs.patt_map_x
else
rFree edx PatXInPels
endif
        and     dl, 07h
        mov     patBitOffsetOfFirstPel, dl

        ; Work out the the address of the first byte of the pattern
        ; to be blted.
ifidn <patsize>, <byte>
        mov     esi, patPixmap.startAddr
        movzx   eax, Shadow8514Regs.patt_map_y
        add     esi, eax
else
rFree eax PatWidthInBytes
        movzx   edx, Shadow8514Regs.patt_map_y
        mul     edx
        add     eax, ecxPatXInBytes
        mov     esi, patPixmap.startAddr
        add     esi, eax
        mov     patStartAddressOfThisLine, esi
endif ; ifidn <patsize>, <byte> else

rName esi PattIndex

ifdif <patsize>, <byte>
        ; Work out how many bytes of pattern will be blted before we will
        ; have to do a horizontal wrap, and keep a copy of it in a local.
rFree ebx PatWidthInBytesCopy
        sub     ebx, ecxPatXInBytes
        mov     patBytesToGoBeforeWrapAtStart, bx

        ; Work out the address of the first pattern byte that will be
        ; accessed after a vertical wrap around.
rFree ecx PatXInBytes
        add     ecx, patPixmap.startAddr
        mov     patStartAddressAfterVertWrap, ecx
endif ; ifdif <patsize>, <byte>

        ; Work out how many lines we will blt before we have to wrap
        ; the pattern vertically.
        mov     ax, patPixmap.yLen
        inc     ax
        sub     ax, Shadow8514Regs.patt_map_y
        mov     patLinesToGoBeforeWrap, ax

ifidn <mode>, <mix>
        ; Work out the address of the mix code to jump to for both
        ; foreground and background pels. (Note that if this operation
        ; is from BitBlt then the mixes will be the same, if it is from
        ; a scanLines operation then they may be different.)
        movzx   ebx, byte ptr Shadow8514Regs.Function_1
        and     ebx, FUNC_ALU
if bpp eq 24
        mov     eax, dword ptr mixTrashSourceAllDD[ebx*4]
else
if bpp eq 16
        mov     eax, dword ptr mixTrashSourceAllDW[ebx*4]
else
        mov     eax, dword ptr mixTrashSourceAllBY[ebx*4]
endif
endif   ; bpp equ 24
        add     eax, offset FLAT:mixCodeBase
        mov     fgMixJumpAddress, eax

        movzx   ebx, byte ptr Shadow8514Regs.Function_0
        and     ebx, FUNC_ALU
if bpp eq 24
        mov     eax, dword ptr mixTrashSourceAllDD[ebx*4]
else
if bpp eq 16
        mov     eax, dword ptr mixTrashSourceAllDW[ebx*4]
else
        mov     eax, dword ptr mixTrashSourceAllBY[ebx*4]
endif
endif ; bpp eq 24
        add     eax, offset FLAT:mixCodeBase
        mov     bgMixJumpAddress, eax
endif ; ifidn <mode>, <mix>

if bpp eq 24
ifidn <mode>, <copy>
        ; Get the fg colour into a register.
rName ebx FgCol
        mov     ebxFgCol, Shadow8514Regs.Color_1
endif
endif
if bpp eq 16
ifidn <mode>, <copy>
        ; Get the fg colour into a register.
rName bx FgCol
        mov     bxFgCol, Shadow8514Regs.Color_1
endif
endif
if bpp eq 8
        ; Get the fg and bg colours into registers.
rName bl FgCol
rName bh BgCol
        mov     blFgCol, byte ptr Shadow8514Regs.Color_1
        mov     bhBgCol, byte ptr Shadow8514Regs.Color_0
endif
if bpp eq 4
        ; Get a byte of foreground colour and a byte of background colour.
        mov     al, byte ptr Shadow8514Regs.Color_1
        mov     ah, al
        shl     al, 4
        shr     ax, 4
        mov     fgPels, al

        mov     al, byte ptr Shadow8514Regs.Color_0
        mov     ah, al
        shl     al, 4
        shr     ax, 4
        mov     bgPels, al
endif

        ; Set up the per line loop counter.
        mov     ax, Shadow8514Regs.dim2
        inc     ax
        mov     lineLoopCount, ax

        ; Enter the per line loop.
perLineLoop:
if bpp eq 4
        ; Get the mask for the first pel from the scratch pad.
rName bl DestMask
rName bh DestMaskInv
        mov     blDestMask, _messSpad.startMask
        mov     bhDestMaskInv, blDestMask
        not     bhDestMaskInv
endif

        ; Get the first byte of pattern data for this line and set up our
        ; position index in dh if the pattern is more than one byte wide.
rName dl PattByte
rName dh PattBytePos
        mov     dlPattByte, [esiPattIndex]
ifdif <patsize>, <byte>
        mov     dhPattBytePos, 01h
endif

        ; Adjust the pattern byte to get the first pel in the msb.
        mov     cl, patBitOffsetOfFirstPel
        rol     dlPattByte, cl
ifdif <patsize>, <byte>
        shl     dhPattBytePos, cl

        ; Work out patBytesToGoBeforeWrap.
        mov     ax, patBytesToGoBeforeWrapAtStart
        mov     patBytesToGoBeforeWrap, ax
endif

        ; Set up the per pel loop.
rName cx PelLoopCount
        mov     cxPelLoopCount, Shadow8514Regs.dim1
        inc     cxPelLoopCount

perPelLoop:
if bpp eq 4
        ; Store the per pel loop count in the top of ecx.
rFree cx PelLoopCount
        swap    ecx
rName ecx_top PelLoopCount
endif

        ; Pick up a pel from the destination
if bpp eq 24
        mov     eax, [ediDestIndex]
endif
if bpp eq 16
        mov     ax, [ediDestIndex]
endif
if bpp eq 8
        mov     al, [ediDestIndex]
endif
if bpp eq 4
ifidn <mode>, <mix>
        mov     al, [ediDestIndex]

        ; Keep a copy of the dest byte so that we can combine it with
        ; the mixed pel before writing it back to the pixmap.
        mov     cl, al
else
        mov     cl, [ediDestIndex]
endif ; ifidn <mode>, <mix> else
endif ; if bpp eq 4

        ; Shift out the corresponding pattern bit into the carry flag.
        rol     dlPattByte, 1

ifidn <mode>, <mix>
        jnc     short mixBgPel

        ; This pel is foreground - get the foreground colour and mix it.
if bpp eq 24
        mov     ebx, Shadow8514Regs.Color_1
endif
if bpp eq 16
        mov     bx, Shadow8514Regs.Color_1
endif
if bpp eq 8
        mov     ah, blFgCol
endif
if bpp eq 4
        mov     ah, fgPels
endif
        jmp     fgMixJumpAddress

mixBgPel:
        ; This pel is background - get the background colour and mix it.
if bpp eq 24
        mov     ebx, Shadow8514Regs.Color_0
endif
if bpp eq 16
        mov     bx, Shadow8514Regs.Color_0
endif
if bpp eq 8
        mov     ah, bhBgCol
endif
if bpp eq 4
        mov     ah, bgPels
endif
        jmp     bgMixJumpAddress

mixCodeBase:
if bpp eq 24
        mixTrashSourceAll       ebx, eax
else
if bpp eq 16
        mixTrashSourceAll       bx, ax
else
        mixTrashSourceAll       ah, al
endif
endif   ; bpp eq 24

else  ; ifidn <mode>, <mix>
        jc     short copyFgPel
        ; This pel is background - get the background colour and copy it.
if bpp eq 24
        mov     eax, Shadow8514Regs.Color_0
endif
if bpp eq 16
        mov     ax, Shadow8514Regs.Color_0
endif
if bpp eq 8
        mov     al, bhBgCol
endif
if bpp eq 4
        mov     al, bgPels
endif
        jmp     short copyPel

copyFgPel:
        ; This pel is foreground - get the foreground colour and copy it.
if bpp eq 24
        mov     eax, ebxFgCol
endif
if bpp eq 16
        mov     ax, bxFgCol
endif
if bpp eq 8
        mov     al, blFgCol
endif
if bpp eq 4
        mov     al, fgPels
endif

copyPel:

endif ; ifidn <mode>, <mix> else


if bpp eq 24
        ; Put the resulting pel back
        ; @DMS fix ebx defore mixing
        stos byte ptr [ediDestIndex]
        ror eax,8
        stos byte ptr [ediDestIndex]
        ror eax,8
        stos byte ptr [ediDestIndex]
endif
if bpp eq 16
        ; Put the resulting pel back
        stos word ptr [ediDestIndex]
endif
if bpp eq 8
        ; Put the resulting pel back
        stos byte ptr [ediDestIndex]
endif
if bpp eq 4
        ; We must combine this pel with the other pel in the destination
        ; byte before we write back the byte back to the pixmap.
        and     cl, bhDestMaskInv       ; get the unaltered pel
        and     al, blDestMask          ; get the mixed pel (or copied pel)
        or      al, cl                  ; stir them together
        mov     [ediDestIndex], al      ; write the result

        ; Adjust the masks ready for the next pel.
        ror     bhDestMaskInv, 4        ; shift the masks
        ror     blDestMask, 4           ; this sets the carry 1/2 the time
        adc     ediDestIndex, 0         ; increment edi if carry set

        ; Get back the per pel loop count.
rFree ecx_top PelLoopCount
        swap    ecx
rName cx PelLoopCount
endif

ifdif <patsize>, <byte>
        ; Do we need to get a new pattern byte ?
        shl     dhPattBytePos, 1
        jc      short getPatByte
endif

        ; More pels ?
        dec     cxPelLoopCount
        jnz     short perPelLoop
ifdif <patsize>, <byte>
        jmp     short lineEnd

getPatByte:
        ; Need to fetch a new pattern byte
        inc     esiPattIndex
        dec     patBytesToGoBeforeWrap
        jnz     short morePattern

        ; Need to wrap back to start of line
        mov     eax, patWidthInBytes
        mov     patBytesToGoBeforeWrap, ax
        sub     esiPattIndex, eax

morePattern:
        mov     dlPattByte, [esiPattIndex]
        mov     dhPattBytePos, 01h

        ; More pels ?
        dec     cxPelLoopCount
if bpp eq 8
        jnz     short perPelLoop
else
ifidn <mode>, <mix>
        jnz     perPelLoop
else
        jnz     short perPelLoop
endif
endif


lineEnd:
endif ; ifdif <patsize>, <byte>

        ; More lines ?

        dec     lineLoopCount
        jz      short exit


        ; Go on to do the next line of the blt...

        ; Move the destination pointer to the start of the next blt line.
        add     ediDestIndex, _messSpad.dstLineInc

        ; See if we need to wrap the pattern vertically before the next one.
        dec     patLinesToGoBeforeWrap
        jz      short vertWrapPattern

        ; We do not have to do a vertical wrap of the pattern, so just move
        ; the pattern up one line from where the last line of the blt started.
ifidn <patsize>, <byte>
        inc     esiPattIndex
else
        mov     esiPattIndex, patStartAddressOfThisLine
        add     esiPattIndex, patWidthInBytes
        mov     patStartAddressOfThisLine, esiPattIndex
endif

        jmp     perLineLoop

vertWrapPattern:
        ; We must wrap the pattern vertically.
ifidn <patsize>, <byte>
        movzx   eax, patPixmap.yLen
        sub     esiPattIndex, eax
        inc     eax
        mov     patLinesToGoBeforeWrap, ax
else
        mov     esiPattIndex, patStartAddressAfterVertWrap
        mov     ax, patPixmap.yLen
        inc     ax
        mov     patLinesToGoBeforeWrap, ax
        mov     patStartAddressOfThisLine, esiPattIndex
endif

        jmp     perLineLoop

exit:

endm

ELSE

;;;****************************************************************
;;;
;;; 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 does pattern/destination operations for 4, 8, and 16 bits
; per pel, producing special case code for blts with no mix, and pattern
; pixmaps that are only one byte wide.

; See individual function headers for more details.

patDest macro mode, bpp, patsize
        local perLineLoop, perPelLoop, mixBgPel, mixCodeBase
        local getPatByte, morePattern, lineEnd, vertWrapPattern
        local copyPel, copyFgPel, exit

; First check that the mode and bpp parameters are valid.
    ifdif <mode>, <mix>
     ifdif <mode>, <copy>
      .err
      %out patDest macro mode parameter must be "mix" or "copy".
     endif
    endif
    if (bpp ne 4) and (bpp ne 8) and (bpp ne 16)
     .err
     %out patDest macro bits per pel parameter must be 4, 8, or 16.
    endif
    ifnb <patsize>
     ifdif <patsize>, <byte>
      .err
      %out patDest macro pattern size parameter must be blank or "byte".
     endif
    endif
; Now do the real code.

        ; First set up the destination start address and increments.
if bpp eq 16
        cCall   eddf_MESSSetUpDest16
endif
if bpp eq 8
        cCall   eddf_MESSSetUpDest81
endif
if bpp eq 4
        cCall   eddf_MESSSetUpDestForPat41
endif
rName edi DestIndex

        ; Now set up all the local variable values we can before we go
        ; into the main line loop.


ifdif <patsize>, <byte>
        ; First work out the pattern pixmap width in bytes and keep a
        ; copy of it in ebx.
rName eax PatWidthInBytes
rName ebx PatWidthInBytesCopy
        movzx   eaxPatWidthInBytes, patPixmap.xLen
        shr     eaxPatWidthInBytes, 3
        inc     eaxPatWidthInBytes
        mov     patWidthInBytes, eaxPatWidthInBytes
        mov     ebxPatWidthInBytesCopy, eaxPatWidthInBytes

        ; Get the pattern x start postion and work out how many bytes
        ; offset this corresponds to from the left edge of the pixmap.
rName ecx PatXInBytes
rName edx PatXInPels
        movzx   edxPatXInPels, ShadowXGARegs.patt_map_x
        mov     ecxPatXInBytes, edxPatXInPels
        shr     ecxPatXInBytes, 3
endif ; ifdif <patsize>, <byte>

        ; Work out the offset of the first pel within the first byte
        ; of the pattern to be blted.
ifidn <patsize>, <byte>
        mov     dl, byte ptr ShadowXGARegs.patt_map_x
else
rFree edx PatXInPels
endif
        and     dl, 07h
        mov     patBitOffsetOfFirstPel, dl

        ; Work out the the address of the first byte of the pattern
        ; to be blted.
ifidn <patsize>, <byte>
        mov     esi, patPixmap.startAddr
        movzx   eax, ShadowXGARegs.patt_map_y
        add     esi, eax
else
rFree eax PatWidthInBytes
        movzx   edx, ShadowXGARegs.patt_map_y
        mul     edx
        add     eax, ecxPatXInBytes
        mov     esi, patPixmap.startAddr
        add     esi, eax
        mov     patStartAddressOfThisLine, esi
endif ; ifidn <patsize>, <byte> else

rName esi PattIndex

ifdif <patsize>, <byte>
        ; Work out how many bytes of pattern will be blted before we will
        ; have to do a horizontal wrap, and keep a copy of it in a local.
rFree ebx PatWidthInBytesCopy
        sub     ebx, ecxPatXInBytes
        mov     patBytesToGoBeforeWrapAtStart, bx

        ; Work out the address of the first pattern byte that will be
        ; accessed after a vertical wrap around.
rFree ecx PatXInBytes
        add     ecx, patPixmap.startAddr
        mov     patStartAddressAfterVertWrap, ecx
endif ; ifdif <patsize>, <byte>

        ; Work out how many lines we will blt before we have to wrap
        ; the pattern vertically.
        mov     ax, patPixmap.yLen
        inc     ax
        sub     ax, ShadowXGARegs.patt_map_y
        mov     patLinesToGoBeforeWrap, ax

ifidn <mode>, <mix>
        ; Work out the address of the mix code to jump to for both
        ; foreground and background pels. (Note that if this operation
        ; is from BitBlt then the mixes will be the same, if it is from
        ; a scanLines operation then they may be different.)
        movzx   ebx, byte ptr ShadowXGARegs.fg_mix
if bpp eq 16
        mov     eax, dword ptr mixTrashSourceAllDW[ebx*4]
else
        mov     eax, dword ptr mixTrashSourceAllBY[ebx*4]
endif
        add     eax, offset FLAT:mixCodeBase
        mov     fgMixJumpAddress, eax

        movzx   ebx, byte ptr ShadowXGARegs.bg_mix
if bpp eq 16
        mov     eax, dword ptr mixTrashSourceAllDW[ebx*4]
else
        mov     eax, dword ptr mixTrashSourceAllBY[ebx*4]
endif
        add     eax, offset FLAT:mixCodeBase
        mov     bgMixJumpAddress, eax
endif ; ifidn <mode>, <mix>

if bpp eq 16
ifidn <mode>, <copy>
        ; Get the fg colour into a register.
rName bx FgCol
        mov     bxFgCol, ShadowXGARegs.fg_colour
endif
endif
if bpp eq 8
        ; Get the fg and bg colours into registers.
rName bl FgCol
rName bh BgCol
        mov     blFgCol, byte ptr ShadowXGARegs.fg_colour
        mov     bhBgCol, byte ptr ShadowXGARegs.bg_colour
endif
if bpp eq 4
        ; Get a byte of foreground colour and a byte of background colour.
        mov     al, byte ptr ShadowXGARegs.fg_colour
        mov     ah, al
        shl     al, 4
        shr     ax, 4
        mov     fgPels, al

        mov     al, byte ptr ShadowXGARegs.bg_colour
        mov     ah, al
        shl     al, 4
        shr     ax, 4
        mov     bgPels, al
endif

        ; Set up the per line loop counter.
        mov     ax, ShadowXGARegs.dim2
        inc     ax
        mov     lineLoopCount, ax

        ; Enter the per line loop.
perLineLoop:
if bpp eq 4
        ; Get the mask for the first pel from the scratch pad.
rName bl DestMask
rName bh DestMaskInv
        mov     blDestMask, _messSpad.startMask
        mov     bhDestMaskInv, blDestMask
        not     bhDestMaskInv
endif

        ; Get the first byte of pattern data for this line and set up our
        ; position index in dh if the pattern is more than one byte wide.
rName dl PattByte
rName dh PattBytePos
        mov     dlPattByte, [esiPattIndex]
ifdif <patsize>, <byte>
        mov     dhPattBytePos, 01h
endif

        ; Adjust the pattern byte to get the first pel in the msb.
        mov     cl, patBitOffsetOfFirstPel
        rol     dlPattByte, cl
ifdif <patsize>, <byte>
        shl     dhPattBytePos, cl

        ; Work out patBytesToGoBeforeWrap.
        mov     ax, patBytesToGoBeforeWrapAtStart
        mov     patBytesToGoBeforeWrap, ax
endif

        ; Set up the per pel loop.
rName cx PelLoopCount
        mov     cxPelLoopCount, ShadowXGARegs.dim1
        inc     cxPelLoopCount

perPelLoop:
if bpp eq 4
        ; Store the per pel loop count in the top of ecx.
rFree cx PelLoopCount
        swap    ecx
rName ecx_top PelLoopCount
endif

        ; Pick up a pel from the destination
if bpp eq 16
        mov     ax, [ediDestIndex]
endif
if bpp eq 8
        mov     al, [ediDestIndex]
endif
if bpp eq 4
ifidn <mode>, <mix>
        mov     al, [ediDestIndex]

        ; Keep a copy of the dest byte so that we can combine it with
        ; the mixed pel before writing it back to the pixmap.
        mov     cl, al
else
        mov     cl, [ediDestIndex]
endif ; ifidn <mode>, <mix> else
endif ; if bpp eq 4

        ; Shift out the corresponding pattern bit into the carry flag.
        rol     dlPattByte, 1

ifidn <mode>, <mix>
        jnc     short mixBgPel

        ; This pel is foreground - get the foreground colour and mix it.
if bpp eq 16
        mov     bx, ShadowXGARegs.fg_colour
endif
if bpp eq 8
        mov     ah, blFgCol
endif
if bpp eq 4
        mov     ah, fgPels
endif
        jmp     fgMixJumpAddress

mixBgPel:
        ; This pel is background - get the background colour and mix it.
if bpp eq 16
        mov     bx, ShadowXGARegs.bg_colour
endif
if bpp eq 8
        mov     ah, bhBgCol
endif
if bpp eq 4
        mov     ah, bgPels
endif
        jmp     bgMixJumpAddress

mixCodeBase:
if bpp eq 16
        mixTrashSourceAll       bx, ax
else
        mixTrashSourceAll       ah, al
endif

else  ; ifidn <mode>, <mix>
        jc     short copyFgPel
        ; This pel is background - get the background colour and copy it.
if bpp eq 16
        mov     ax, ShadowXGARegs.bg_colour
endif
if bpp eq 8
        mov     al, bhBgCol
endif
if bpp eq 4
        mov     al, bgPels
endif
        jmp     short copyPel

copyFgPel:
        ; This pel is foreground - get the foreground colour and copy it.
if bpp eq 16
        mov     ax, bxFgCol
endif
if bpp eq 8
        mov     al, blFgCol
endif
if bpp eq 4
        mov     al, fgPels
endif

copyPel:

endif ; ifidn <mode>, <mix> else


if bpp eq 16
        ; Put the resulting pel back
        stos word ptr [ediDestIndex]
endif
if bpp eq 8
        ; Put the resulting pel back
        stos byte ptr [ediDestIndex]
endif
if bpp eq 4
        ; We must combine this pel with the other pel in the destination
        ; byte before we write back the byte back to the pixmap.
        and     cl, bhDestMaskInv       ; get the unaltered pel
        and     al, blDestMask          ; get the mixed pel (or copied pel)
        or      al, cl                  ; stir them together
        mov     [ediDestIndex], al      ; write the result

        ; Adjust the masks ready for the next pel.
        ror     bhDestMaskInv, 4        ; shift the masks
        ror     blDestMask, 4           ; this sets the carry 1/2 the time
        adc     ediDestIndex, 0         ; increment edi if carry set

        ; Get back the per pel loop count.
rFree ecx_top PelLoopCount
        swap    ecx
rName cx PelLoopCount
endif

ifdif <patsize>, <byte>
        ; Do we need to get a new pattern byte ?
        shl     dhPattBytePos, 1
        jc      short getPatByte
endif

        ; More pels ?
        dec     cxPelLoopCount
        jnz     short perPelLoop
ifdif <patsize>, <byte>
        jmp     short lineEnd

getPatByte:
        ; Need to fetch a new pattern byte
        inc     esiPattIndex
        dec     patBytesToGoBeforeWrap
        jnz     short morePattern

        ; Need to wrap back to start of line
        mov     eax, patWidthInBytes
        mov     patBytesToGoBeforeWrap, ax
        sub     esiPattIndex, eax

morePattern:
        mov     dlPattByte, [esiPattIndex]
        mov     dhPattBytePos, 01h

        ; More pels ?
        dec     cxPelLoopCount
if bpp eq 8
        jnz     short perPelLoop
else
ifidn <mode>, <mix>
        jnz     perPelLoop
else
        jnz     short perPelLoop
endif
endif


lineEnd:
endif ; ifdif <patsize>, <byte>

        ; More lines ?

        dec     lineLoopCount
        jz      short exit


        ; Go on to do the next line of the blt...

        ; Move the destination pointer to the start of the next blt line.
        add     ediDestIndex, _messSpad.dstLineInc

        ; See if we need to wrap the pattern vertically before the next one.
        dec     patLinesToGoBeforeWrap
        jz      short vertWrapPattern

        ; We do not have to do a vertical wrap of the pattern, so just move
        ; the pattern up one line from where the last line of the blt started.
ifidn <patsize>, <byte>
        inc     esiPattIndex
else
        mov     esiPattIndex, patStartAddressOfThisLine
        add     esiPattIndex, patWidthInBytes
        mov     patStartAddressOfThisLine, esiPattIndex
endif

        jmp     perLineLoop

vertWrapPattern:
        ; We must wrap the pattern vertically.
ifidn <patsize>, <byte>
        movzx   eax, patPixmap.yLen
        sub     esiPattIndex, eax
        inc     eax
        mov     patLinesToGoBeforeWrap, ax
else
        mov     esiPattIndex, patStartAddressAfterVertWrap
        mov     ax, patPixmap.yLen
        inc     ax
        mov     patLinesToGoBeforeWrap, ax
        mov     patStartAddressOfThisLine, esiPattIndex
endif

        jmp     perLineLoop

exit:

endm

ENDIF ; XGA Versions of macros.

ENDIF ; IF1


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatDest16
;
; This does a pattern to destination operation when it comes from a bitblt
; or scanlines operation.  This routine handles different foreground and
; background mixes.  This will only happen when it comes from a scanline
; call but supporting it is only a little extra set up (nothing extra in
; the loop)
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Internally:
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       dh      - pattern position data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatDest16, <PUBLIC>

        localD  fgMixJumpAddress
        localD  bgMixJumpAddress
        localD  patWidthInBytes
        localW  patLinesToGoBeforeWrap
        localW  patBytesToGoBeforeWrap
        localW  patBytesToGoBeforeWrapAtStart
        localD  patStartAddressOfThisLine
        localD  patStartAddressAfterVertWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount

cBegin
rStart
        patDest mix 16
rEnd
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatDest81
;
; This does a pattern to destination operation when it comes from a bitblt
; or scanlines operation.  This routine handles different foreground and
; background mixes.  This will only happen when it comes from a scanline
; call but supporting it is only a little extra set up (nothing extra in
; the loop)
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Internally:
;       bl      - foreground colour
;       bh      - background colour
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       dh      - pattern position data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatDest81, <PUBLIC>

        localD  fgMixJumpAddress
        localD  bgMixJumpAddress
        localD  patWidthInBytes
        localW  patLinesToGoBeforeWrap
        localW  patBytesToGoBeforeWrap
        localW  patBytesToGoBeforeWrapAtStart
        localD  patStartAddressOfThisLine
        localD  patStartAddressAfterVertWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount

cBegin
rStart
        patDest mix 8
rEnd
cEnd


ifdef   BPP24
;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatDest24
;
; This does a pattern to destination operation when it comes from a bitblt
; or scanlines operation.  This routine handles different foreground and
; background mixes.  This will only happen when it comes from a scanline
; call but supporting it is only a little extra set up (nothing extra in
; the loop)
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Internally:
;       bl      - foreground colour
;       bh      - background colour
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       dh      - pattern position data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatDest24, <PUBLIC>

        localD  fgMixJumpAddress
        localD  bgMixJumpAddress
        localD  patWidthInBytes
        localW  patLinesToGoBeforeWrap
        localW  patBytesToGoBeforeWrap
        localW  patBytesToGoBeforeWrapAtStart
        localD  patStartAddressOfThisLine
        localD  patStartAddressAfterVertWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount

cBegin
rStart
        patDest mix 24
rEnd
cEnd
endif   ;BPP24 

;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatDest41
;
; This does a pattern to destination operation when it comes from a bitblt
; or scanlines operation.  This routine handles different foreground and
; background mixes.  This will only happen when it comes from a scanline
; call but supporting it is only a little extra set up (nothing extra in
; the loop)
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Internally:
;       bl      - change bits in destination mask
;       bh      - leave bits in destination mask
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       dh      - pattern position data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatDest41, <PUBLIC>

        localD  fgMixJumpAddress
        localD  bgMixJumpAddress
        localD  patWidthInBytes
        localW  patLinesToGoBeforeWrap
        localW  patBytesToGoBeforeWrap
        localW  patBytesToGoBeforeWrapAtStart
        localD  patStartAddressOfThisLine
        localD  patStartAddressAfterVertWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount
        localB  fgPels
        localB  bgPels

cBegin
rStart
        patDest mix 4
rEnd
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatCopy16
;
; This does a pattern to destination copy when it comes from a bitblt
; or scanlines operation.
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bx      - foreground colour
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       dh      - pattern position data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatCopy16, <PUBLIC>

        localD  patWidthInBytes
        localW  patLinesToGoBeforeWrap
        localW  patBytesToGoBeforeWrap
        localW  patBytesToGoBeforeWrapAtStart
        localD  patStartAddressOfThisLine
        localD  patStartAddressAfterVertWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount

cBegin
rStart
        patDest copy 16
rEnd
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatCopy81
;
; This does a pattern to destination copy when it comes from a bitblt
; or scanlines operation.
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bl      - foreground colour
;       bh      - background colour
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       dh      - pattern position data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatCopy81, <PUBLIC>

        localD  patWidthInBytes
        localW  patLinesToGoBeforeWrap
        localW  patBytesToGoBeforeWrap
        localW  patBytesToGoBeforeWrapAtStart
        localD  patStartAddressOfThisLine
        localD  patStartAddressAfterVertWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount

cBegin
rStart
        patDest copy 8
rEnd
cEnd

ifdef   BPP24 
;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatCopy24
;
; This does a pattern to destination copy when it comes from a bitblt
; or scanlines operation.
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bl      - foreground colour
;       bh      - background colour
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       dh      - pattern position data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatCopy24, <PUBLIC>

        localD  patWidthInBytes
        localW  patLinesToGoBeforeWrap
        localW  patBytesToGoBeforeWrap
        localW  patBytesToGoBeforeWrapAtStart
        localD  patStartAddressOfThisLine
        localD  patStartAddressAfterVertWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount

cBegin
rStart
        patDest copy 24
rEnd
cEnd
endif   ;BPP24 

;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatCopy41
;
; This does a pattern to destination copy when it comes from a bitblt
; or scanlines operation.
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bl      - change bits in destination mask
;       bh      - leave bits in destination mask
;       ecx.hi  - pels loop counter
;       dl      - byte of pattern data
;       dh      - pattern position data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatCopy41, <PUBLIC>

        localD  patWidthInBytes
        localW  patLinesToGoBeforeWrap
        localW  patBytesToGoBeforeWrap
        localW  patBytesToGoBeforeWrapAtStart
        localD  patStartAddressOfThisLine
        localD  patStartAddressAfterVertWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount
        localB  fgPels
        localB  bgPels

cBegin
rStart
        patDest copy 4
rEnd
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatDestByte16
;
; This does a pattern to destination operation when it comes from a bitblt
; or scanlines operation.  This routine handles different foreground and
; background mixes.  This will only happen when it comes from a scanline
; call but supporting it is only a little extra set up (nothing extra in
; the loop).  This is a special case when the pattern is one byte wide
; (ie the default pattern set)
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bx      - foreground colour
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatDestByte16, <PUBLIC>                                ;**

        localD  fgMixJumpAddress
        localD  bgMixJumpAddress
        localW  patLinesToGoBeforeWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount

cBegin
rStart
        patDest mix 16 byte
rEnd
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatDestByte81
;
; This does a pattern to destination operation when it comes from a bitblt
; or scanlines operation.  This routine handles different foreground and
; background mixes.  This will only happen when it comes from a scanline
; call but supporting it is only a little extra set up (nothing extra in
; the loop).  This is a special case when the pattern is one byte wide
; (ie the default pattern set)
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bl      - foreground colour
;       bh      - background colour
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatDestByte81, <PUBLIC>                                ;**

        localD  fgMixJumpAddress
        localD  bgMixJumpAddress
        localW  patLinesToGoBeforeWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount

cBegin
rStart
        patDest mix 8 byte
rEnd
cEnd

ifdef   BPP24 
;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatDestByte24
;
; This does a pattern to destination operation when it comes from a bitblt
; or scanlines operation.  This routine handles different foreground and
; background mixes.  This will only happen when it comes from a scanline
; call but supporting it is only a little extra set up (nothing extra in
; the loop).  This is a special case when the pattern is one byte wide
; (ie the default pattern set)
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bl      - foreground colour
;       bh      - background colour
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatDestByte24, <PUBLIC>                                ;**

        localD  fgMixJumpAddress
        localD  bgMixJumpAddress
        localW  patLinesToGoBeforeWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount

cBegin
rStart
        patDest mix 24 byte
rEnd
cEnd
endif   ;BPP24 

;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatDestByte41
;
; This does a pattern to destination operation when it comes from a bitblt
; or scanlines operation.  This routine handles different foreground and
; background mixes.  This will only happenwhen it comes from a scanline
; call but supporting it is only a little extra set up (nothing extra in
; the loop).  This is a special case when the pattern is one byte wide
; (ie the default pattern set)
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bl      - change bits in destination mask
;       bh      - leave bits in destination mask
;       ecx.hi  - pels loop counter
;       dl      - byte of pattern data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatDestByte41, <PUBLIC>                                ;**

        localD  fgMixJumpAddress
        localD  bgMixJumpAddress
        localW  patLinesToGoBeforeWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount
        localB  fgPels
        localB  bgPels


cBegin
rStart
        patDest mix 4 byte
rEnd
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatCopyByte16
;
; This does a pattern to destination copy when it comes from a bitblt
; or scanlines operation.  This is a special case when the pattern is one
; byte wide (ie the default pattern set)
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bx      - foreground colour
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatCopyByte16, <PUBLIC>                                ;**

        localW  patLinesToGoBeforeWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount

cBegin
rStart
        patDest copy 16 byte
rEnd
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatCopyByte81
;
; This does a pattern to destination copy when it comes from a bitblt
; or scanlines operation.  This is a special case when the pattern is one
; byte wide (ie the default pattern set)
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bl      - foreground colour
;       bh      - background colour
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatCopyByte81, <PUBLIC>                                ;**

        localW  patLinesToGoBeforeWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount

cBegin
rStart
        patDest copy 8 byte
rEnd
cEnd

ifdef   BPP24 
;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatCopyByte24
;
; This does a pattern to destination copy when it comes from a bitblt
; or scanlines operation.  This is a special case when the pattern is one
; byte wide (ie the default pattern set)
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bl      - foreground colour
;       bh      - background colour
;       cx      - pels loop counter
;       dl      - byte of pattern data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatCopyByte24, <PUBLIC>                                ;**

        localW  patLinesToGoBeforeWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount

cBegin
rStart
        patDest copy 24 byte
rEnd
cEnd
endif   ;BPP24 

;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatCopyByte41
;
; This does a pattern to destination copy when it comes from a bitblt
; or scanlines operation.  This is a special case when the pattern is one
; byte wide (ie the default pattern set)
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bl      - change bits in destination mask
;       bh      - leave bits in destination mask
;       ecx.hi  - pels loop counter
;       dl      - byte of pattern data
;       edi     - destination position
;       esi     - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatCopyByte41, <PUBLIC>                                ;**

        localW  patLinesToGoBeforeWrap
        localB  patBitOffsetOfFirstPel
        localW  lineLoopCount
        localB  fgPels
        localB  bgPels


cBegin
rStart
        patDest copy 4 byte
rEnd
cEnd






;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatDest11
;
; This does a pattern to destination operation when it comes from a bitblt
; operation.  The pattern is 1,1 data and may wrap around.  Only the
; foreground mix will be required.  In order to do this we must use the
; pattern as source.  The sequence of operations is..
;
; Get a correctly aligned byte of pattern data
; From this get an aligned byte of source data (same as pattern byte or
;   inverse of pattern byte depending on fore and back colours)
; Get the byte from the destination
; Combine source and destination with fg mix (fg mix == bg mix)
; Then apply start or end masks if necessary and put it back into
;   destination
;
; Because the patterns are typically very short (8 pels wide for the
; default ones) we would spend a lot of time messing around getting the
; aligned pattern bytes (assuming we allow for patterns which are > 8
; pels wide).  Instead of doing this, before each line we will construct
; a line of the pattern of appropriate size and store it in our
; patBuffer.  For most cases this will be        slick and will be
; faster and easier than handling the horizontal wrap-around as we
; progress along each line.
;
; Parmeters:
;       ShadowXGARegs, messSPad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       ebx.lo  - startMask (bl) and ~startMask (bh)
;       ebx.hi  - endMask (bl) and ~endMask (bh)
;       cl      - src to dest shift
;       ecx.hi  - counter for setting up pattern line
;       dx      - bytes per line counter
;       es:di   - 'cached' pattern line (note es=ds)
;       fs:si   - actual pattern       |
;       gs:si   - destination position | - use esi as two halves
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatDest11, <PUBLIC>                                    ;**

        localW  linesLoop
        localD  startMixOffset          ; the offsets we need           ;**
        localD  fullMixOffset                                           ;**
        localD  endMixOffset                                            ;**
        localD  patOffsetX              ; see below                     ;**
        localD  patWidthBytes                                           ;**
        localW  patLinesToGo
        localD  patLineStartOffset                                      ;**
        localD  patCacheStartOffset                                     ;**
        localW  opLineLength
        localB  srcInvertMask

        ; patOffsetX -
        ;   The offset (in bytes) from the left of the pattern pixmap to
        ;   the first byte to use

        ; patWidthBytes -
        ;   The pattern width (in bytes)

        ; patLinesToGo -
        ;   The number of lines to go before we have to wrap around the
        ;   pattern

        ; patLineStartOffset -
        ;   The offset of the first pattern byte which we used for the last
        ;   line

        ; patCacheStartOffset -
        ;   The start address to use for fetching the cached pattern/source
        ;   it will be either patBuffer or patBuffer-1

        ; opLineLength -
        ;   The number of bytes of pattern data we need to stick into the
        ;   cache to have enough for a full line of the operation

        ; srcInvertMask -
        ;   Either 00 or FF.  This is xor'ed with the pattern byte to
        ;   produce a source byte.

cBegin
        ; Set up masks etc. with this (returns dst start addr in eax)
        cCall   eddf_MESSSetUpDest11
        mov     esi, edi                                                ;**

        ; But that didn't set up everything we need so some more
        ; stuff is required here

        ; Work out whether we should invert the 'pattern' to get the
        ; 'source'.  If the fg_colour is 0 then we should invert.
IFDEF _8514
        mov     eax, Shadow8514Regs.Color_1
ELSE
        mov     ax, ShadowXGARegs.fg_colour
ENDIF
        and     al, 01h
        xor     al, 01h
        mov     ah, 00h
        sub     ah, al
        mov     srcInvertMask, ah

        ; This will be the src/pat start address - in our data segment
        mov     ebx, offset FLAT:patBuffer                               ;**

        ; First work out the srcToDestShift (in the same way as we work
        ; it out for a srcdest11 operation)
IFDEF _8514
        mov     ax, Shadow8514Regs.patt_map_x
        mov     dx, Shadow8514Regs.dest_map_x
ELSE
        mov     ax, ShadowXGARegs.patt_map_x
        mov     dx, ShadowXGARegs.dest_map_x
ENDIF
        and     al, 07h
        and     dl, 07h
        sub     al, dl
        jc      short @f

        ; Simply use this as is and don't adjust pattern start position
        mov     _messSpad.srcToDestShift, al
        jmp     short gotShiftPD11

@@:
        ; Use 8 - the difference and adjust the start position
        add     al, 8
        mov     _messSpad.srcToDestShift, al
        dec     bx

gotShiftPD11:
        ; This is the offset to use at the start of each line - either
        ; patBuffer or patBuffer-1
        mov     patCacheStartOffset, ebx                                ;**

        ; Now work out some more stuff to do with the pattern
        movzx   eax, patPixmap.xLen                                     ;**
        inc     eax                                                     ;**
        shr     eax, 3                                                  ;**
        mov     patWidthBytes, eax                                      ;**

IFDEF _8514
        movzx   edx, Shadow8514Regs.patt_map_y                                ;**
ELSE
        movzx   edx, ShadowXGARegs.patt_map_y                                ;**
ENDIF
        mul     edx
        ; ax is offset to first line in pattern to use

IFDEF _8514
        movzx   ecx, Shadow8514Regs.patt_map_x                                ;**
ELSE
        movzx   ecx, ShadowXGARegs.patt_map_x                                ;**
ENDIF
        mov     edx, ecx                                                ;**
        shr     ecx, 3                                                  ;**
        mov     patOffsetX, ecx                                         ;**

        add     eax, ecx                                                ;**
        ; ax is the offset to the first byte in the pattern to use

        ; Remember we're using si twice in this function
        add     eax, patPixmap.startAddr                                ;**
        mov     patLineStartOffset, eax                                 ;**
        ; fs:si is the first byte in the pattern to use

        ; opLineLength is the pattern start position % 8 + width of
        ; operation.  Divide it by 8 to give it in bytes.
        and     dx, 07h
IFDEF _8514
        add     dx, Shadow8514Regs.dim1
ELSE
        add     dx, ShadowXGARegs.dim1
ENDIF
        shr     dx, 3
        inc     dx
        mov     opLineLength, dx

        ; How many lines before we wrap pattern vertically
        mov     ax, patPixmap.yLen
        inc     ax
IFDEF _8514
        sub     ax, Shadow8514Regs.patt_map_y
ELSE
        sub     ax, ShadowXGARegs.patt_map_y
ENDIF
        mov     patLinesToGo, ax

        ; Now work out all the mixing offsets which we need.  The fg mix
        ; will equal the bg mix for a BitBlt.
IFDEF _8514
        movzx   ebx, byte ptr Shadow8514Regs.Function_1                 ;**
        and     ebx, FUNC_ALU
ELSE
        movzx   ebx, byte ptr ShadowXGARegs.fg_mix                      ;**
ENDIF
        mov     edx, dword ptr [mixTrashSourcePartBY+ebx*4]             ;**

        mov     eax, offset FLAT:startMixBasePD11                       ;**
        add     eax, edx                                                ;**
        mov     startMixOffset, eax                                     ;**

        mov     eax, offset FLAT:fullMixBasePD11                        ;**
        add     eax, edx                                                ;**
        mov     fullMixOffset, eax                                      ;**

        mov     eax, offset FLAT:endMixBasePD11                         ;**
        add     eax, edx                                                ;**
        mov     endMixOffset, eax                                       ;**

        ; Now set up ebx with all those masks which we need
        mov     bl, _messSpad.endMask
        mov     bh, bl
        not     bh
        swap    ebx
        mov     bl, _messSpad.startMask
        mov     bh, bl
        not     bh

        ; And get the shift count into cl
        mov     cl, _messSpad.srcToDestShift

        ; Now we've done all that we can go into our per line loop
IFDEF _8514
        mov     ax, Shadow8514Regs.dim2
ELSE
        mov     ax, ShadowXGARegs.dim2
ENDIF
        inc     ax
        mov     linesLoop, ax

perLineLoopPD11:
        ; First we need to set up a line of pat/src data
        mov     ax, patPixmap.xLen
        cmp     ax, 07h
        jle     short eightBitPatternPD11       ;          

        ; The pattern is more than one byte..
        push    ecx                                                     ;**
        push    esi                                                     ;**
        mov     esi, patLineStartOffset                                 ;**
        inc     ax
        shr     ax, 3
        mov     dx, opLineLength
        mov     edi, offset FLAT:patBuffer                              ;**
@@:
        movzx   ecx, ax
        rep movs byte ptr [edi], [esi]                                  ;**
        sub     dx, ax
        jnc     short @b
        pop     esi                                                     ;**
        pop     ecx                                                     ;**
        jmp     short useLastPatternPD11

eightBitPatternPD11:
        ; Special case patterns which are 1 byte long
        xchg    esi, patLineStartOffset                                 ;**
        mov     al, [esi]               ; fetch pattern byte            ;**
        xchg    esi, patLineStartOffset                                 ;**
        push    ecx                                                     ;**
        mov     ah, al                  ; turn it into 4 bytes
        movzx   ecx, ax                                                 ;**
        swap    eax
        mov     ax, cx
        mov     cx, opLineLength        ; how many dwords ?
        shr     ecx, 2                                                  ;**
        inc     ecx                                                     ;**
        mov     edi, offset FLAT:patBuffer                              ;**
        rep stos dword ptr [edi]        ; stuff the buffer              ;**
        pop     ecx                                                     ;**

useLastPatternPD11:
        ; Got a line of pattern data, now get busy..
        mov     edi, patCacheStartOffset                                ;**

        ; dst is gs:si
        ; src is ds:di (its in patBuffer)

        mov     dx, word ptr _messSpad.totalBytes

        mov     ax, [edi]               ; get byte from pattern         ;**
        rol     ax, cl
        xor     al, srcInvertMask       ; turn it into a source byte

        mov     ah, [esi]               ; get byte from destination     ;**
        mov     ch, ah                  ; save that

        jmp     startMixOffset

startMixBasePD11:
        mixTrashSourcePart      al, ah

        and     ch, bh                  ; get pels from destination
        and     ah, bl                  ; get pels from result
        or      ah, ch                  ; stir them together
        mov     [esi], ah               ; write them back               ;**

        inc     si                      ; bump pointers
        inc     di

        dec     dx
        jz      loopDonePD11

        dec     dx
        jz      short endMaskPD11

        ; dx is the number of full bytes to do
pelLoopPD11:
        mov     ax, [edi]               ; get byte from pattern         ;**
        rol     ax, cl
        xor     al, srcInvertMask       ; turn it into source byte

        mov     ah, [esi]               ; get byte from destination     ;**
        jmp     fullMixOffset

fullMixBasePD11:
        mixTrashSourcePart      al, ah

        mov     [esi], ah               ; write result back             ;**

        inc     esi                     ; bump pointers                 ;**
        inc     edi                                                     ;**

        dec     dx
        jnz     short pelLoopPD11

endMaskPD11:
        mov     ax, [edi]               ; get byte from pattern         ;**
        rol     ax, cl
        xor     al, srcInvertMask       ; turn it into a source byte

        mov     ah, [esi]               ; get byte from destination     ;**
        mov     ch, ah                  ; save that
        jmp     endMixOffset

endMixBasePD11:
        mixTrashSourcePart      al, ah

        swap    ebx                     ; get end masks
        and     ch, bh                  ; get pels from destination
        and     ah, bl                  ; get pels from result
        or      ah, ch                  ; stir them together
        mov     [esi], ah               ; write them back               ;**
        swap    ebx

        inc     esi                     ; bump pointers                 ;**
        inc     edi                                                     ;**

loopDonePD11:
        add     esi, _messSpad.dstLineInc     ; next line                ;**

        ; More lines ?
        dec     linesLoop
        jz      short exitPD11

        ; More lines in pattern ?
        dec     patLinesToGo
        jz      short vertWrapPatternPD11

        ; Bump pattern address to next line
        xchg    esi, patLineStartOffset                                 ;**
        add     esi, patWidthBytes                                      ;**
        xchg    esi, patLineStartOffset                                 ;**
        jmp     perLineLoopPD11

vertWrapPatternPD11:
        ; Need to apply a vertical wrap to the pattern
        xchg    esi, patLineStartOffset                                 ;**
        mov     esi, patPixmap.startAddr                                ;**
        add     esi, patOffsetX                                         ;**
        xchg    esi, patLineStartOffset                                 ;**
        mov     ax, patPixmap.yLen
        inc     ax
        mov     patLinesToGo, ax
        dec     ax
        jz      useLastPatternPD11
        jmp     perLineLoopPD11

exitPD11:
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatDestMixes11
;
; This does a pattern to destination operation when it comes from a scanlines
; operation.  The pattern is 1,1 data and may wrap around.  Seperate
; foreground and background mixes are possible.  The operation will only be
; one pel high.  In order to do this we must use the pattern as both a
; source and a pattern.  The sequence of operations is..
;
; Get a correctly aligned byte of pattern data
; From this get an aligned byte of source data (same as pattern byte or
;   inverse of pattern byte depending on fore and back colours)
; Apply fg mix to source and destination -> fg result
; Apply bg mix to source and destination -> bg result
; pattern byte AND fg result -> fg pels
; NOT(pattern byte) AND bg result -> bg pels
; fg pels OR bg pels -> result
; Write result to destination using start or end masks if necessary
;
; Because the patterns are typically very short (8 pels wide for the
; default ones) we would spend a lot of time messing around getting the
; aligned pattern bytes (assuming we allow for patterns which are > 8
; pels wide).  Instead of doing this, before each line we will construct
; a line of the pattern of appropriate size and store it in our
; patBuffer.  For most cases this will be        slick and will be
; faster and easier than handling the horizontal wrap-around as we
; progress along each line.
;
; Parmeters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bl      - pattern byte
;       bh      - NOT(pattern byte)
;       cl      - src to dest shift
;       ecx.hi  - counter for setting up pattern line
;       dx      - bytes per line counter
;       es:di   - 'cached' pattern line (note es=ds)
;       fs:si   - actual pattern       |
;       gs:si   - destination position | - use esi as two halves
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatDestMixes11, <PUBLIC>                               ;**

        localW  linesLoop
        localD  fgStartMixOffset        ; the offsets we need           ;**
        localD  fgFullMixOffset                                         ;**
        localD  fgEndMixOffset                                          ;**
        localD  bgStartMixOffset                                        ;**
        localD  bgFullMixOffset                                         ;**
        localD  bgEndMixOffset                                          ;**
        localD  patOffsetX              ; see below                     ;**
        localD  patWidthBytes                                           ;**
        localW  patLinesToGo
        localD  patLineStartOffset                                      ;**
        localD  patCacheStartOffset                                     ;**
        localW  opLineLength
        localB  srcInvertMask

        ; patOffsetX -
        ;   The offset (in bytes) from the left of the pattern pixmap to
        ;   the first byte to use

        ; patWidthBytes -
        ;   The pattern width (in bytes)

        ; patLinesToGo -
        ;   The number of lines to go before we have to wrap around the
        ;   pattern

        ; patLineStartOffset -
        ;   The offset of the first pattern byte which we used for the last
        ;   line

        ; patCacheStartOffset -
        ;   The start address to use for fetching the cached pattern/source
        ;   it will be either patBuffer or patBuffer-1

        ; opLineLength -
        ;   The number of bytes of pattern data we need to stick into the
        ;   cache to have enough for a full line of the operation

        ; srcInvertMask -
        ;   Either 00 or FF.  This is xor'ed with the pattern byte to
        ;   produce a source byte.

cBegin
        ; Set up masks etc. with this (returns dst start addr in eax)
        cCall   eddf_MESSSetUpDest11
        mov     esi, edi                                                ;**

        ; But that didn't set up everything we need so some more
        ; stuff is required here

        ; Work out whether we should invert the 'pattern' to get the
        ; 'source'.  If the fg_colour is 0 then we should invert.
IFDEF _8514
        mov     eax, Shadow8514Regs.Color_1
ELSE
        mov     ax, ShadowXGARegs.fg_colour
ENDIF
        and     al, 01h
        xor     al, 01h
        mov     ah, 00h
        sub     ah, al
        mov     srcInvertMask, ah

        ; This will be the src/pat start address - in our data segment
        mov     ebx, offset FLAT:patBuffer                               ;**

        ; First work out the srcToDestShift (in the same way as we work
        ; it out for a srcdest11 operation)
IFDEF _8514
        mov     ax, Shadow8514Regs.patt_map_x
        mov     dx, Shadow8514Regs.dest_map_x
ELSE
        mov     ax, ShadowXGARegs.patt_map_x
        mov     dx, ShadowXGARegs.dest_map_x
ENDIF
        and     al, 07h
        and     dl, 07h
        sub     al, dl
        jc      short @f

        ; Simply use this as is and don't adjust pattern start position
        mov     _messSpad.srcToDestShift, al
        jmp     short gotShiftPDM11

@@:
        ; Use 8 - the difference and adjust the start position
        add     al, 8
        mov     _messSpad.srcToDestShift, al
        dec     ebx                                                     ;**

gotShiftPDM11:
        ; This is the offset to use at the start of each line - either
        ; patBuffer or patBuffer-1
        mov     patCacheStartOffset, ebx                                ;**

        ; Now work out some more stuff to do with the pattern
        movzx   eax, patPixmap.xLen                                     ;**
        inc     eax                                                     ;**
        shr     eax, 3                                                  ;**
        mov     patWidthBytes, eax                                      ;**

IFDEF _8514
        movzx   edx, Shadow8514Regs.patt_map_y                                ;**
ELSE
        movzx   edx, ShadowXGARegs.patt_map_y                                ;**
ENDIF
        mul     edx                                                     ;**
        ; ax is offset to first line in pattern to use

IFDEF _8514
        movzx   ecx, Shadow8514Regs.patt_map_x                                ;**
ELSE
        movzx   ecx, ShadowXGARegs.patt_map_x                                ;**
ENDIF
        mov     edx, ecx                                                ;**
        shr     ecx, 3                                                  ;**
        mov     patOffsetX, ecx                                         ;**

        add     eax, ecx                                                ;**
        ; ax is the offset to the first byte in the pattern to use

        ; Remember we're using si twice in this function
        add     eax, patPixmap.startAddr
        mov     patLineStartOffset, eax
        ; fs:si is the first byte in the pattern to use

        ; opLineLength is the pattern start position % 8 + width of
        ; operation.  Divide it by 8 to give it in bytes.
        and     dx, 07h
IFDEF _8514
        add     dx, Shadow8514Regs.dim1
ELSE
        add     dx, ShadowXGARegs.dim1
ENDIF
        shr     dx, 3
        inc     dx
        mov     opLineLength, dx

        ; How many lines before we wrap pattern vertically
        mov     ax, patPixmap.yLen
        inc     ax
IFDEF _8514
        sub     ax, Shadow8514Regs.patt_map_y
ELSE
        sub     ax, ShadowXGARegs.patt_map_y
ENDIF
        mov     patLinesToGo, ax

        ; Now work out all the mixing offsets which we need.
IFDEF _8514
        mov     ebx, Shadow8514Regs.Function_1                          ;**
        and     ebx, FUNC_ALU
ELSE
        movzx   ebx, ShadowXGARegs.fg_mix                               ;**
ENDIF
        mov     edx, dword ptr [mixTrashSourceAllBY+ebx*4]              ;**

        mov     eax, offset FLAT:fgStartMixBasePDM11                    ;**
        add     eax, edx                                                ;**
        mov     fgStartMixOffset, eax                                   ;**

        mov     eax, offset FLAT:fgFullMixBasePDM11                     ;**
        add     eax, edx                                                ;**
        mov     fgFullMixOffset, eax                                    ;**

        mov     eax, offset FLAT:fgEndMixBasePDM11                      ;**
        add     eax, edx                                                ;**
        mov     fgEndMixOffset, eax                                     ;**

IFDEF _8514
        mov     bl, byte ptr Shadow8514Regs.Function_0
ELSE
        mov     bl, ShadowXGARegs.bg_mix
ENDIF
        mov     edx, dword ptr [mixTrashSourceAllBY+ebx*4]              ;**

        mov     eax, offset FLAT:bgStartMixBasePDM11                    ;**
        add     eax, edx                                                ;**
        mov     bgStartMixOffset, eax                                   ;**

        mov     eax, offset FLAT:bgFullMixBasePDM11                     ;**
        add     eax, edx                                                ;**
        mov     bgFullMixOffset, eax                                    ;**

        mov     eax, offset FLAT:bgEndMixBasePDM11                      ;**
        add     eax, edx                                                ;**
        mov     bgEndMixOffset, eax                                     ;**

        ; Get the shift count into cl
        mov     cl, _messSpad.srcToDestShift

        ; Now we've done all that we can go into our per line loop
IFDEF _8514
        mov     ax, Shadow8514Regs.dim2
ELSE
        mov     ax, ShadowXGARegs.dim2
ENDIF
        inc     ax
        mov     linesLoop, ax

perLineLoopPDM11:
        ; First we need to set up a line of pat/src data
        mov     ax, patPixmap.xLen
        cmp     ax, 07h

        ; Defect 68244 - If we had a pattern that was less then an
        ; eight bits, we would hang if we fell through to the code
        ; directly below this jump statement.
        jle     short eightBitPatternPDM11

        ; The pattern is more than one byte..
        push    ecx                                                     ;**
        push    esi                                                     ;**
        mov     esi, patLineStartOffset                                 ;**
        inc     ax
        shr     ax, 3
        mov     dx, opLineLength
        mov     edi, offset FLAT:patBuffer                              ;**
@@:
        movzx   ecx, ax                                                 ;**
        rep movs byte ptr [edi], [esi]                                  ;**
        sub     dx, ax
        jnc     short @b
        pop     esi                                                     ;**
        pop     ecx                                                     ;**
        jmp     short useLastPatternPDM11

eightBitPatternPDM11:
        ; Special case patterns which are 1 byte long
        xchg    esi, patLineStartOffset                                 ;**
        mov     al, [esi]               ; fetch pattern byte            ;**
        xchg    esi, patLineStartOffset                                 ;**
        push    ecx                                                     ;**
        mov     ah, al                  ; turn it into 4 bytes
        movzx   ecx, ax                                                 ;**
        swap    eax
        mov     ax, cx
        mov     cx, opLineLength        ; how many dwords ?
        shr     ecx, 2                                                  ;**
        inc     ecx                                                     ;**
        mov     edi, offset FLAT:patBuffer                              ;**
        rep stos dword ptr [edi]        ; stuff the buffer              ;**
        pop     ecx                                                     ;**

useLastPatternPDM11:
        ; Got a line of pattern data, now get busy..
        mov     edi, patCacheStartOffset                                ;**

        ; dst is gs:si
        ; src/pat is ds:di (its in patBuffer)

        mov     dx, word ptr _messSpad.totalBytes

        mov     ax, [edi]               ; get byte from pattern         ;**
        rol     ax, cl                  ; align it
        mov     bl, al                  ; save it
        mov     bh, al                  ; save NOT(pattern)
        not     bh
        xor     al, srcInvertMask       ; get source byte

        mov     ah, [esi]               ; get byte from destination     ;**

        push    ax                      ; save source and destination

        jmp     fgStartMixOffset

fgStartMixBasePDM11:
        mixTrashSourceAll       al, ah

        mov     ch, ah                  ; save result of foreground mix
        pop     ax                      ; get source and destination

        jmp     bgStartMixOffset

bgStartMixBasePDM11:
        mixTrashSourceAll       al, ah

        ; fg mix result is in ch
        ; bg mix result is in ah

        and     ch, bl                  ; get foreground pels
        and     ah, bh                  ; get background pels
        or      ah, ch

        mov     bl, _messSpad.startMask  ; work out the mask and ~mask
        mov     bh, bl
        not     bh
        mov     ch, [esi]               ; get destination again         ;**
        and     ch, bh                  ; save some pels from it
        and     ah, bl                  ; get some pels from result
        or      ah, ch                  ; cram them together
        mov     [esi], ah               ; write it out                  ;**

        inc     esi                     ; bump pointers                 ;**
        inc     edi                                                     ;**

        dec     dx
        jz      loopDonePDM11

        dec     dx
        jz      endMaskPDM11

        ; dx is the number of full bytes to do
pelLoopPDM11:
        mov     ax, [edi]               ; get byte from pattern         ;**
        rol     ax, cl                  ; align it
        mov     bl, al                  ; save it
        mov     bh, al                  ; save NOT(pattern)
        not     bh
        xor     al, srcInvertMask       ; get source byte

        mov     ah, [esi]               ; get byte from destination     ;**

        push    ax                      ; save source and destination

        jmp     fgFullMixOffset

fgFullMixBasePDM11:
        mixTrashSourceAll       al, ah

        mov     ch, ah                  ; save result of foreground mix
        pop     ax                      ; get source and destination

        jmp     bgFullMixOffset

bgFullMixBasePDM11:
        mixTrashSourceAll       al, ah

        ; fg mix result is in ch
        ; bg mix result is in ah

        and     ch, bl                  ; get foreground pels
        and     ah, bh                  ; get background pels
        or      ah, ch
        mov     [esi], ah               ; write it out                  ;**

        inc     esi                     ; bump pointers                 ;**
        inc     edi                                                     ;**

        dec     dx
        jnz     pelLoopPDM11

endMaskPDM11:
        mov     ax, [edi]               ; get byte from pattern         ;**
        rol     ax, cl                  ; align it
        mov     bl, al                  ; save it
        mov     bh, al                  ; save NOT(pattern)
        not     bh
        xor     al, srcInvertMask       ; get source byte

        mov     ah, [esi]               ; get byte from destination     ;**

        push    ax                      ; save source and destination

        jmp     fgEndMixOffset

fgEndMixBasePDM11:
        mixTrashSourceAll       al, ah

        mov     ch, ah                  ; save result of foreground mix
        pop     ax                      ; get source and destination

        jmp     bgEndMixOffset

bgEndMixBasePDM11:
        mixTrashSourceAll       al, ah

        ; fg mix result is in ch
        ; bg mix result is in ah

        and     ch, bl                  ; get foreground pels
        and     ah, bh                  ; get background pels
        or      ah, ch

        mov     bl, _messSpad.endMask    ; work out the mask and ~mask
        mov     bh, bl
        not     bh
        mov     ch, [esi]               ; get destination again         ;**
        and     ch, bh                  ; save some pels from it
        and     ah, bl                  ; get some pels from result
        or      ah, ch                  ; cram them together
        mov     [esi], ah               ; write it out                  ;**

        inc     esi                     ; bump pointers                 ;**
        inc     edi                                                     ;**

loopDonePDM11:
        add     esi, _messSpad.dstLineInc     ; next line                ;**

        ; More lines ?
        dec     linesLoop
        jz      short exitPDM11

        ; More lines in pattern ?
        dec     patLinesToGo
        jz      short vertWrapPatternPDM11

        ; Bump pattern address to next line
        xchg    esi, patLineStartOffset                                 ;**
        add     esi, patWidthBytes                                      ;**
        xchg    esi, patLineStartOffset                                 ;**
        jmp     perLineLoopPDM11

vertWrapPatternPDM11:
        ; Need to apply a vertical wrap to the pattern
        xchg    esi, patLineStartOffset                                 ;**
        mov     esi, patPixmap.startAddr                                ;**
        add     esi, patOffsetX                                         ;**
        xchg    esi, patLineStartOffset                                 ;**
        mov     ax, patPixmap.yLen
        inc     ax
        mov     patLinesToGo, ax
        dec     ax
        jz      useLastPatternPDM11
        jmp     perLineLoopPDM11

exitPDM11:
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatCopy11
;
; This does a pattern to destination copy when it comes from a bitblt
; or scanline operation.
;
; Because the patterns are typically very short (8 pels wide for the
; default ones) we would spend a lot of time messing around getting the
; aligned pattern bytes (assuming we allow for patterns which are > 8
; pels wide).  Instead of doing this, before each line we will construct
; a line of the pattern of appropriate size and store it in our
; patBuffer.  For most cases this will be        slick and will be
; faster and easier than handling the horizontal wrap-around as we
; progress along each line.
;
; Parmeters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       ebx.lo  - startMask (bl) and ~startMask (bh)
;       ebx.hi  - endMask (bl) and ~endMask (bh)
;       cl      - src to dest shift
;       ecx.hi  - counter for setting up pattern line
;       dx      - bytes per line counter
;       es:di   - 'cached' pattern line (note es=ds)
;       fs:si   - actual pattern      |
;       gs:si   - destination pointer | - use esi as two halves
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatCopy11, <PUBLIC>                                    ;**

        localW  linesLoop
        localD  patOffsetX              ; see below                     ;**
        localD  patAddr                                                 ;**
        localD  patWidthBytes                                           ;**
        localW  patLinesToGo
        localD  patLineStartOffset                                      ;**
        localW  srcLinesLength
        localD  patCacheStartOffset                                     ;**
        localW  opLineLength
        localB  srcInvertMask

        ; patOffsetX -
        ;   The offset (in bytes) from the left of the pattern pixmap to
        ;   the first byte to use

        ; patWidthBytes -
        ;   The pattern width (in bytes)

        ; patLinesToGo -
        ;   The number of lines to go before we have to wrap around the
        ;   pattern

        ; patLineStartOffset -
        ;   The offset of the first pattern byte which we used for the last
        ;   line

        ; patCacheStartOffset -
        ;   The start address to use for fetching the cached pattern/source
        ;   it will be either patBuffer or patBuffer-1

        ; opLineLength -
        ;   The number of bytes of pattern data we need to stick into the
        ;   cache to have enough for a full line of the operation

        ; srcInvertMask -
        ;   Either 00 or FF.  This is xor'ed with the pattern byte to
        ;   produce a source byte.

cBegin
        ; Set up masks etc. with this (returns dst start addr in eax)
        cCall   eddf_MESSSetUpDest11
        mov     esi, edi                                                ;**

        ; But that didn't set up everything we need so some more
        ; stuff is required here

        ; Work out whether we should invert the 'pattern' to get the
        ; 'source'.  If the fg_colour is 1 then we should invert.
IFDEF _8514
        mov     eax, Shadow8514Regs.Color_1
ELSE
        mov     ax, ShadowXGARegs.fg_colour
ENDIF
        and     al, 01h
        xor     al, 01h
        mov     ah, 00h
        sub     ah, al
        mov     srcInvertMask, ah

        ; This will be the src/pat start address - in our data segment
        mov     ebx, offset FLAT:patBuffer                               ;**

        ; First work out the srcToDestShift (in the same way as we work
        ; it out for a srcdest11 operation)
IFDEF _8514
        mov     ax, Shadow8514Regs.patt_map_x
        mov     dx, Shadow8514Regs.dest_map_x
ELSE
        mov     ax, ShadowXGARegs.patt_map_x
        mov     dx, ShadowXGARegs.dest_map_x
ENDIF
        and     al, 07h
        and     dl, 07h
        sub     al, dl
        jc      short @f

        ; Simply use this as is and don't adjust pattern start position
        mov     _messSpad.srcToDestShift, al
        jmp     short gotShiftPC11

@@:
        ; Use 8 - the difference and adjust the start position
        add     al, 8
        mov     _messSpad.srcToDestShift, al
        dec     ebx                                                     ;**

gotShiftPC11:
        ; This is the offset to use at the start of each line - either
        ; patBuffer or patBuffer-1
        mov     patCacheStartOffset, ebx                                ;**

        ; Now work out some more stuff to do with the pattern
        movzx   eax, patPixmap.xLen                                     ;**
        inc     eax                                                     ;**
        shr     eax, 3                                                  ;**
        mov     patWidthBytes, eax                                      ;**

IFDEF _8514
        movzx   edx, Shadow8514Regs.patt_map_y                                ;**
ELSE
        movzx   edx, ShadowXGARegs.patt_map_y                                ;**
ENDIF
        mul     edx                                                     ;**
        ; ax is offset to first line in pattern to use

IFDEF _8514
        movzx   ecx, Shadow8514Regs.patt_map_x                                ;**
ELSE
        movzx   ecx, ShadowXGARegs.patt_map_x                                ;**
ENDIF
        mov     edx, ecx                                                ;**
        shr     ecx, 3                                                  ;**
        mov     patOffsetX, ecx                                         ;**

        add     eax, ecx                                                ;**
        ; ax is the offset to the first byte in the pattern to use

        ; Remember we're using si twice in this routine
        add     eax, patPixmap.startAddr                                ;**
        mov     patLineStartOffset, eax                                 ;**
        ; fs:si is the first byte in the pattern to use

        ; opLineLength is the pattern start position % 8 + width of
        ; operation.  Divide it by 8 to give it in bytes.
        and     dx, 07h
IFDEF _8514
        add     dx, Shadow8514Regs.dim1
ELSE
        add     dx, ShadowXGARegs.dim1
ENDIF
        shr     dx, 3
        inc     dx
        mov     opLineLength, dx

        ; How many lines before we wrap pattern vertically
        mov     ax, patPixmap.yLen
        inc     ax
IFDEF _8514
        sub     ax, Shadow8514Regs.patt_map_y
ELSE
        sub     ax, ShadowXGARegs.patt_map_y
ENDIF
        mov     patLinesToGo, ax

        ; Now set up ebx with all those masks which we need
        mov     bl, _messSpad.endMask
        mov     bh, bl
        not     bh
        swap    ebx
        mov     bl, _messSpad.startMask
        mov     bh, bl
        not     bh

        ; And get the shift count into cl
        mov     cl, _messSpad.srcToDestShift

        ; Now we've done all that we can go into our per line loop
IFDEF _8514
        mov     ax, Shadow8514Regs.dim2
ELSE
        mov     ax, ShadowXGARegs.dim2
ENDIF
        inc     ax
        mov     linesLoop, ax

perLineLoopPC11:
        ; First we need to set up a line of pat/src data

        ;**************************************************************
        ; At the moment we will just handle the case where pattern
        ; is one byte long
        ;**************************************************************

        mov     ax, patPixmap.xLen
        cmp     ax, 07h
        jz      short eightBitPatternPC11

        ; The pattern is more than one byte..
        push    ecx                                                     ;**
        push    esi                                                     ;**
        mov     esi, patLineStartOffset                                 ;**
        inc     ax
        shr     ax, 3
        mov     dx, opLineLength
        mov     edi, offset FLAT:patBuffer                              ;**
@@:
        movzx   ecx, ax                                                 ;**
        rep movs byte ptr [edi], [esi]                                  ;**
        sub     dx, ax
        jnc     short @b
        pop     esi                                                     ;**
        pop     ecx                                                     ;**
        jmp     short useLastPatternPC11

eightBitPatternPC11:
        ; Special case patterns which are 1 byte long
        xchg    esi, patLineStartOffset                                 ;**
        mov     al, [esi]               ; fetch pattern byte            ;**
        xchg    esi, patLineStartOffset                                 ;**
        push    ecx
        mov     ah, al                  ; turn it into 4 bytes
        movzx   ecx, ax                                                 ;**
        swap    eax
        mov     ax, cx
        mov     cx, opLineLength        ; how many dwords ?
        shr     ecx, 2                                                  ;**
        inc     ecx                                                     ;**
        mov     edi, offset FLAT:patBuffer                              ;**
        rep stos dword ptr [edi]        ; stuff the buffer              ;**
        pop     ecx                                                     ;**

useLastPatternPC11:
        ; Got a line of pattern data, now get busy..
        mov     edi, patCacheStartOffset                                ;**

        ; dst is gs:si
        ; src is ds:di (its in patBuffer)

        mov     dx, word ptr _messSpad.totalBytes

        ; Get pat byte
        mov     ax, [edi]               ; get byte from pattern         ;**
        rol     ax, cl
        xor     al, srcInvertMask       ; turn it into a source byte

        ; Get destination
        mov     ah, [esi]               ; get byte from destination     ;**

        and     ah, bh                  ; get pels from destination
        and     al, bl                  ; get pels from source
        or      ah, al                  ; slap them together
        mov     [esi], ah               ; write them back               ;**

        inc     esi                     ; bump pointers                 ;**
        inc     edi                                                     ;**

        dec     dx
        jz      short loopDonePC11

        dec     dx
        jz      short endMaskPC11

        ; dx is the number of full bytes to do
pelLoopPC11:
        mov     ax, [edi]               ; get byte from pattern         ;**
        rol     ax, cl
        xor     al, srcInvertMask       ; turn it into source byte

        mov     [esi], al               ; stuff it into destination     ;**

        inc     esi                                                     ;**
        inc     edi                                                     ;**

        dec     dx
        jnz     short pelLoopPC11

endMaskPC11:
        mov     ax, [edi]               ; get byte from pattern         ;**
        rol     ax, cl
        xor     al, srcInvertMask       ; turn it into a source byte

        mov     ah, [esi]               ; get byte from destination     ;**

        swap    ebx                     ; get end masks
        and     ah, bh                  ; get pels from destination
        and     al, bl                  ; get pels from source
        or      ah, al                  ; squeeze them together
        mov     [esi], ah               ; write them back               ;**
        swap    ebx

        inc     esi                     ; bump pointers                 ;**
        inc     edi                                                     ;**

loopDonePC11:
        add     esi, _messSpad.dstLineInc     ; next line                ;**

        ; More lines ?
        dec     linesLoop
        jz      short exitPC11

        ; More lines in pattern ?
        dec     patLinesToGo
        jz      short vertWrapPatternPC11

        ; Bump pattern address to next line
        xchg    esi, patLineStartOffset                                 ;**
        add     esi, patWidthBytes                                      ;**
        xchg    esi, patLineStartOffset                                 ;**
        jmp     perLineLoopPC11

vertWrapPatternPC11:
        ; Need to apply a vertical wrap to the pattern
        xchg    esi, patLineStartOffset                                 ;**
        mov     esi, patPixmap.startAddr                                ;**
        add     esi, patOffsetX                                         ;**
        xchg    esi, patLineStartOffset                                 ;**
        mov     ax, patPixmap.yLen
        inc     ax
        mov     patLinesToGo, ax
        dec     ax
        jz      useLastPatternPC11
        jmp     perLineLoopPC11
exitPC11:
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatDestByte11
;
; This does a pattern to destination operation when it comes from a bitblt
; operation.  The pattern is 1,1 data and may wrap around.  Only the
; foreground mix will be required.  In order to do this we must use the
; pattern as source.  This only copes with 8 pel wide patterns (the default)
;
; Get a correctly aligned byte of pattern data
; From this get an aligned byte of source data (same as pattern byte or
;   inverse of pattern byte depending on fore and back colours)
; Get the byte from the destination
; Combine source and destination with fg mix (fg mix == bg mix)
; Then apply start or end masks if necessary and put it back into
;   destination
;
; Parmeters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       ebx.lo  - startMask (bl) and ~startMask (bh)
;       ebx.hi  - endMask (bl) and ~endMask (bh)
;       cl      - source byte
;       dx      - bytes per line counter
;       es:di   - destination position
;       fs:si   - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatDestByte11, <PUBLIC>                                ;**

        localW  linesLoop
        localD  startMixOffset          ; the offsets we need           ;**
        localD  fullMixOffset                                           ;**
        localD  endMixOffset                                            ;**
        localW  patLinesToGo            ; see below
        localB  srcInvertMask

        ; patLinesToGo -
        ;   The number of lines to go before we have to wrap around the
        ;   pattern

        ; srcInvertMask -
        ;   Either 00 or FF.  This is xor'ed with the pattern byte to
        ;   produce a source byte.

cBegin
        ; Set up masks etc. with this (returns dst start addr in eax)
        cCall   eddf_MESSSetUpDest11

        ; Get start position for pattern
        mov     esi, patPixmap.startAddr                                ;**
IFDEF _8514
        movzx   eax, Shadow8514Regs.patt_map_y                                ;**
ELSE
        movzx   eax, ShadowXGARegs.patt_map_y                                ;**
ENDIF
        add     esi, eax                                                ;**

        ; Work out whether we should invert the 'pattern' to get the
        ; 'source'.  If the fg_colour is 1 then we should invert.
IFDEF _8514
        mov     eax, Shadow8514Regs.Color_1
ELSE
        mov     ax, ShadowXGARegs.fg_colour
ENDIF
        and     al, 01h
        xor     al, 01h
        mov     ah, 00h
        sub     ah, al
        mov     srcInvertMask, ah

        ; First work out the srcToDestShift (in the same way as we work
        ; it out for a srcdest11 operation)
IFDEF _8514
        mov     cx, Shadow8514Regs.patt_map_x
        mov     dx, Shadow8514Regs.dest_map_x
ELSE
        mov     cx, ShadowXGARegs.patt_map_x
        mov     dx, ShadowXGARegs.dest_map_x
ENDIF
        and     cl, 07h
        and     dl, 07h
        sub     cl, dl
        jc      short @f

        ; Simply use this as is
        mov     _messSpad.srcToDestShift, cl
        jmp     short gotShiftPDB11

@@:
        ; Use 8 - the difference
        add     cl, 8
        mov     _messSpad.srcToDestShift, cl

gotShiftPDB11:
        ; How many lines before we wrap pattern vertically
        mov     ax, patPixmap.yLen
        inc     ax
IFDEF _8514
        sub     ax, Shadow8514Regs.patt_map_y
ELSE
        sub     ax, ShadowXGARegs.patt_map_y
ENDIF
        mov     patLinesToGo, ax

        ; Now work out all the mixing offsets which we need.  The fg mix
        ; will equal the bg mix for a BitBlt.
IFDEF _8514
        mov     ebx, Shadow8514Regs.Function_1
        and     ebx, FUNC_ALU
ELSE
        movzx   ebx, ShadowXGARegs.fg_mix
ENDIF
        mov     edx, dword ptr [mixTrashSourcePartBY+ebx*4]

        mov     eax, offset FLAT:startMixBasePDB11                      ;**
        add     eax, edx                                                ;**
        mov     startMixOffset, eax                                     ;**

        mov     eax, offset FLAT:fullMixBasePDB11                       ;**
        add     eax, edx                                                ;**
        mov     fullMixOffset, eax                                      ;**

        mov     eax, offset FLAT:endMixBasePDB11                        ;**
        add     eax, edx                                                ;**
        mov     endMixOffset, eax                                       ;**

        ; Now set up ebx with all those masks which we need
        mov     bl, _messSpad.endMask
        mov     bh, bl
        not     bh
        swap    ebx
        mov     bl, _messSpad.startMask
        mov     bh, bl
        not     bh

        ; Now we've done all that we can go into our per line loop
IFDEF _8514
        mov     ax, Shadow8514Regs.dim2
ELSE
        mov     ax, ShadowXGARegs.dim2
ENDIF
        inc     ax
        mov     linesLoop, ax

perLineLoopPDB11:

        ; dst is es:di
        ; src is fs:si

        ; Get a byte of source data from the pattern definition
        mov     al, [esi]                       ; get pattern byte      ;**
        xor     al, srcInvertMask               ; make it a source byte
        mov     cl, _messSpad.srcToDestShift
        rol     al, cl                          ; align it correctly
        mov     cl, al                          ; keep it in cl

        mov     dx, word ptr _messSpad.totalBytes

        ; source is already in al

        mov     ah, [edi]               ; get byte from destination     ;**
        mov     ch, ah                  ; save that

        jmp     startMixOffset

startMixBasePDB11:
        mixTrashSourcePart      al, ah

        and     ch, bh                  ; get pels from destination
        and     ah, bl                  ; get pels from result
        or      ah, ch                  ; stir them together
        mov     [edi], ah               ; write them back               ;**

        inc     edi                     ; bump pointer                  ;**

        dec     dx
        jz      loopDonePDB11

        dec     dx
        jz      short endMaskPDB11

        ; dx is the number of full bytes to do
pelLoopPDB11:
        mov     al, cl                  ; get source byte
        mov     ah, [edi]               ; get byte from destination     ;**
        jmp     fullMixOffset

fullMixBasePDB11:
        mixTrashSourcePart      al, ah

        mov     [edi], ah               ; write result back             ;**

        inc     edi                     ; bump pointer                  ;**

        dec     dx
        jnz     short pelLoopPDB11

endMaskPDB11:
        mov     al, cl                  ; get source byte
        mov     ah, [edi]               ; get byte from destination     ;**
        mov     ch, ah                  ; save that
        jmp     endMixOffset

endMixBasePDB11:
        mixTrashSourcePart      al, ah

        swap    ebx                     ; get end masks
        and     ch, bh                  ; get pels from destination
        and     ah, bl                  ; get pels from result
        or      ah, ch                  ; stir them together
        mov     [edi], ah               ; write them back               ;**
        swap    ebx

        inc     edi                     ; bump pointer                  ;**

loopDonePDB11:
        add     edi, _messSpad.dstLineInc     ; next line                ;**

        ; More lines ?
        dec     linesLoop
        jz      short exitPDB11

        ; More lines in pattern ?
        dec     patLinesToGo
        jz      short vertWrapPatternPDB11

        ; Bump pattern address to next line
        inc     esi                                                     ;**
        jmp     perLineLoopPDB11

vertWrapPatternPDB11:
        ; Need to apply a vertical wrap to the pattern
        movzx   eax, patPixmap.yLen                                     ;**
        sub     esi, eax                                                ;**
        inc     eax                                                     ;**
        mov     patLinesToGo, ax
        jmp     perLineLoopPDB11

exitPDB11:
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatDestMixesByte11
;
; This does a pattern to destination operation when it comes from a scanlines
; operation.  The pattern is 1,1 data and may wrap around.  Seperate
; foreground and background mixes are possible.  The operation will only be
; one pel high.  The pattern is only 8 pels (one byte) wide.
; In order to do this we must use the pattern as both a source and a pattern.
; The sequence of operations is..
;
; Get a correctly aligned byte of pattern data
; From this get an aligned byte of source data (same as pattern byte or
;   inverse of pattern byte depending on fore and back colours)
; Apply fg mix to source and destination -> fg result
; Apply bg mix to source and destination -> bg result
; pattern byte AND fg result -> fg pels
; NOT(pattern byte) AND bg result -> bg pels
; fg pels OR bg pels -> result
; Write result to destination using start or end masks if necessary
;
; Parmeters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       bl      - pattern byte
;       bh      - NOT(pattern byte)
;       cl      - source byte
;       dx      - bytes per line counter
;       es:di   - destination position
;       fs:si   - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatDestMixesByte11, <NEAR, PUBLIC>

        localW  linesLoop
        localD  fgStartMixOffset        ; the offsets we need           ;**
        localD  fgFullMixOffset                                         ;**
        localD  fgEndMixOffset                                          ;**
        localD  bgStartMixOffset                                        ;**
        localD  bgFullMixOffset                                         ;**
        localD  bgEndMixOffset                                          ;**
        localW  patLinesToGo            ; see below
        localB  srcInvertMask

        ; patLinesToGo -
        ;   The number of lines to go before we have to wrap around the
        ;   pattern

        ; srcInvertMask -
        ;   Either 00 or FF.  This is xor'ed with the pattern byte to
        ;   produce a source byte.

cBegin
        ; Set up masks etc. with this (returns dst start addr in eax)
        cCall   eddf_MESSSetUpDest11

        ; Get start position for pattern
        mov     esi, patPixmap.startAddr                                ;**
IFDEF _8514
        movzx   eax, Shadow8514Regs.patt_map_y                                ;**
ELSE
        movzx   eax, ShadowXGARegs.patt_map_y                                ;**
ENDIF
        add     esi, eax                                                ;**

        ; Work out whether we should invert the 'pattern' to get the
        ; 'source'.  If the fg_colour is 0 then we should invert.
IFDEF _8514
        mov     eax, Shadow8514Regs.Color_1
ELSE
        mov     ax, ShadowXGARegs.fg_colour
ENDIF
        and     al, 01h
        xor     al, 01h
        mov     ah, 00h
        sub     ah, al
        mov     srcInvertMask, ah

        ; First work out the srcToDestShift (in the same way as we work
        ; it out for a srcdest11 operation)
IFDEF _8514
        mov     ax, Shadow8514Regs.patt_map_x
        mov     dx, Shadow8514Regs.dest_map_x
ELSE
        mov     ax, ShadowXGARegs.patt_map_x
        mov     dx, ShadowXGARegs.dest_map_x
ENDIF
        and     al, 07h
        and     dl, 07h
        sub     al, dl
        jc      short @f

        ; Simply use this as is
        mov     _messSpad.srcToDestShift, al
        jmp     short gotShiftPDMB11

@@:
        ; Use 8 - the difference
        add     al, 8
        mov     _messSpad.srcToDestShift, al

gotShiftPDMB11:
        ; How many lines before we wrap pattern vertically
        mov     ax, patPixmap.yLen
        inc     ax
IFDEF _8514
        sub     ax, Shadow8514Regs.patt_map_y
ELSE
        sub     ax, ShadowXGARegs.patt_map_y
ENDIF
        mov     patLinesToGo, ax

        ; Now work out all the mixing offsets which we need.
IFDEF _8514
        mov     ebx, Shadow8514Regs.Function_1                          ;**
        and     ebx, FUNC_ALU
ELSE
        movzx   ebx, ShadowXGARegs.fg_mix                               ;**
ENDIF
        mov     edx, dword ptr [mixTrashSourceAllBY+ebx*4]              ;**

        mov     eax, offset FLAT:fgStartMixBasePDMB11                   ;**
        add     eax, edx                                                ;**
        mov     fgStartMixOffset, eax                                   ;**

        mov     eax, offset FLAT:fgFullMixBasePDMB11                    ;**
        add     eax, edx                                                ;**
        mov     fgFullMixOffset, eax                                    ;**

        mov     eax, offset FLAT:fgEndMixBasePDMB11                     ;**
        add     eax, edx                                                ;**
        mov     fgEndMixOffset, eax                                     ;**

IFDEF _8514
        mov     ebx, Shadow8514Regs.Function_0                                   ;**
        and     ebx, FUNC_ALU
ELSE
        movzx   ebx, ShadowXGARegs.bg_mix                                    ;**
ENDIF
        mov     edx, dword ptr [mixTrashSourceAllBY+ebx*4]              ;**

        mov     eax, offset FLAT:bgStartMixBasePDMB11                   ;**
        add     eax, edx                                                ;**
        mov     bgStartMixOffset, eax                                   ;**

        mov     eax, offset FLAT:bgFullMixBasePDMB11                    ;**
        add     eax, edx                                                ;**
        mov     bgFullMixOffset, eax                                    ;**

        mov     eax, offset FLAT:bgEndMixBasePDMB11                     ;**
        add     eax, edx                                                ;**
        mov     bgEndMixOffset, eax                                     ;**

        ; Now we've done all that we can go into our per line loop
IFDEF _8514
        mov     ax, Shadow8514Regs.dim2
ELSE
        mov     ax, ShadowXGARegs.dim2
ENDIF
        inc     ax
        mov     linesLoop, ax

perLineLoopPDMB11:

        ; dst is es:si
        ; src is fs:si

        ; Get a byte of source data from the pattern definition
        mov     al, [esi]                       ; get pattern byte      ;**
        mov     cl, _messSpad.srcToDestShift
        rol     al, cl                          ; align it correctly
        mov     bl, al                          ; save it
        mov     bh, bl
        not     bh                              ; save NOT(pattern)
        xor     al, srcInvertMask               ; make it a source byte
        mov     cl, al                          ; keep it in cl

        mov     dx, word ptr _messSpad.totalBytes

        ; source is already in al

        mov     ah, [edi]               ; get byte from destination     ;**

        push    ax                      ; save source and destination

        jmp     fgStartMixOffset

fgStartMixBasePDMB11:
        mixTrashSourceAll       al, ah

        mov     ch, ah                  ; save result of foreground mix
        pop     ax                      ; get source and destination

        jmp     bgStartMixOffset

bgStartMixBasePDMB11:
        mixTrashSourceAll       al, ah

        ; fg mix result is in ch
        ; bg mix result is in ah

        and     ch, bl                  ; get foreground pels
        and     ah, bh                  ; get background pels
        or      ah, ch

        swap    ebx
        mov     bl, _messSpad.startMask  ; work out the mask and ~mask
        mov     bh, bl
        not     bh
        mov     ch, [edi]               ; get destination again         ;**
        and     ch, bh                  ; save some pels from it
        and     ah, bl                  ; get some pels from result
        or      ah, ch                  ; cram them together
        mov     [edi], ah               ; write it out                  ;**
        swap    ebx

        inc     edi                     ; bump pointer                  ;**

        dec     dx
        jz      loopDonePDMB11

        dec     dx
        jz      endMaskPDMB11

        ; dx is the number of full bytes to do
pelLoopPDMB11:
        mov     ah, [edi]               ; get byte from destination     ;**
        mov     al, cl                  ; get source byte

        push    ax                      ; save source and destination

        jmp     fgFullMixOffset

fgFullMixBasePDMB11:
        mixTrashSourceAll       al, ah

        mov     ch, ah                  ; save result of foreground mix
        pop     ax                      ; get source and destination

        jmp     bgFullMixOffset

bgFullMixBasePDMB11:
        mixTrashSourceAll       al, ah

        ; fg mix result is in ch
        ; bg mix result is in ah

        and     ch, bl                  ; get foreground pels
        and     ah, bh                  ; get background pels
        or      ah, ch
        mov     [edi], ah               ; write it out                  ;**

        inc     edi                     ; bump pointers                 ;**

        dec     dx
        jnz     pelLoopPDMB11

endMaskPDMB11:
        mov     ah, [edi]               ; get byte from destination     ;**
        mov     al, cl                  ; get source byte

        push    ax                      ; save source and destination

        jmp     fgEndMixOffset

fgEndMixBasePDMB11:
        mixTrashSourceAll       al, ah

        mov     ch, ah                  ; save result of foreground mix
        pop     ax                      ; get source and destination

        jmp     bgEndMixOffset

bgEndMixBasePDMB11:
        mixTrashSourceAll       al, ah

        ; fg mix result is in ch
        ; bg mix result is in ah

        and     ch, bl                  ; get foreground pels
        and     ah, bh                  ; get background pels
        or      ah, ch

        mov     bl, _messSpad.endMask    ; work out the mask and ~mask
        mov     bh, bl
        not     bh
        mov     ch, [edi]               ; get destination again         ;**
        and     ch, bh                  ; save some pels from it
        and     ah, bl                  ; get some pels from result
        or      ah, ch                  ; cram them together
        mov     [edi], ah               ; write it out                  ;**

        inc     edi                     ; bump pointer                  ;**

loopDonePDMB11:
        add     edi, _messSpad.dstLineInc     ; next line                ;**

        ; More lines ?
        dec     linesLoop
        jz      short exitPDMB11

        ; More lines in pattern ?
        dec     patLinesToGo
        jz      short vertWrapPatternPDMB11

        ; Bump pattern address to next line
        inc     esi                                                     ;**
        jmp     perLineLoopPDMB11

vertWrapPatternPDMB11:
        ; Need to apply a vertical wrap to the pattern
        movzx   eax, patPixmap.yLen                                     ;**
        sub     esi, eax                                                ;**
        inc     eax                                                     ;**
        mov     patLinesToGo, ax
        jmp     perLineLoopPDMB11

exitPDMB11:
cEnd


;-------------------------------------------------------------------------
;
; Function: eddf_MESSPatCopyByte11
;
; This does a pattern to destination operation when it comes from a bitblt
; operation.  The pattern is 1,1 data and may wrap around.
; This only copes with 8 pel wide patterns (the default)
;
; Get a correctly aligned byte of pattern data
; From this get an aligned byte of source data (same as pattern byte or
;   inverse of pattern byte depending on fore and back colours)
; Get the byte from the destination
; Combine source and destination with fg mix (fg mix == bg mix)
; Then apply start or end masks if necessary and put it back into
;   destination
;
; Parmeters:
;       ShadowXGARegs, _messSpad, pixmap structures
;
; Returns:
;       None
;
; Internally:
;       ebx.lo  - startMask (bl) and ~startMask (bh)
;       ebx.hi  - endMask (bl) and ~endMask (bh)
;       cl      - source byte
;       dx      - bytes per line counter
;       es:di   - destination position
;       fs:si   - pattern position
;
;-------------------------------------------------------------------------

        align   4
cProc   eddf_MESSPatCopyByte11, <PUBLIC>                                ;**

        localW  linesLoop
        localW  patLinesToGo            ; see below
        localB  srcInvertMask

        ; patLinesToGo -
        ;   The number of lines to go before we have to wrap around the
        ;   pattern

        ; srcInvertMask -
        ;   Either 00 or FF.  This is xor'ed with the pattern byte to
        ;   produce a source byte.

cBegin
        ; Set up masks etc. with this (returns dst start addr in eax)
        cCall   eddf_MESSSetUpDest11

        ; Get start position for pattern
        mov     esi, patPixmap.startAddr                                ;**
IFDEF _8514
        movzx   eax, Shadow8514Regs.patt_map_y                                ;**
ELSE
        movzx   eax, ShadowXGARegs.patt_map_y                                ;**
ENDIF
        add     esi, eax                                                ;**

        ; Work out whether we should invert the 'pattern' to get the
        ; 'source'.  If the fg_colour is 1 then we should invert.
IFDEF _8514
        mov     eax, Shadow8514Regs.Color_1
ELSE
        mov     ax, ShadowXGARegs.fg_colour
ENDIF
        and     al, 01h
        xor     al, 01h
        mov     ah, 00h
        sub     ah, al
        mov     srcInvertMask, ah

        ; First work out the srcToDestShift (in the same way as we work
        ; it out for a srcdest11 operation)
IFDEF _8514
        mov     cx, Shadow8514Regs.patt_map_x
        mov     dx, Shadow8514Regs.dest_map_x
ELSE
        mov     cx, ShadowXGARegs.patt_map_x
        mov     dx, ShadowXGARegs.dest_map_x
ENDIF
        and     cl, 07h
        and     dl, 07h
        sub     cl, dl
        jc      short @f

        ; Simply use this as is
        mov     _messSpad.srcToDestShift, cl
        jmp     short gotShiftPCB11

@@:
        ; Use 8 - the difference
        add     cl, 8
        mov     _messSpad.srcToDestShift, cl

gotShiftPCB11:
        ; How many lines before we wrap pattern vertically
        mov     ax, patPixmap.yLen
        inc     ax
IFDEF _8514
        sub     ax, Shadow8514Regs.patt_map_y
ELSE
        sub     ax, ShadowXGARegs.patt_map_y
ENDIF
        mov     patLinesToGo, ax

        ; Now set up ebx with all those masks which we need
        mov     bl, _messSpad.endMask
        mov     bh, bl
        not     bh
        swap    ebx
        mov     bl, _messSpad.startMask
        mov     bh, bl
        not     bh

        ; Now we've done all that we can go into our per line loop
IFDEF _8514
        mov     ax, Shadow8514Regs.dim2
ELSE
        mov     ax, ShadowXGARegs.dim2
ENDIF
        inc     ax
        mov     linesLoop, ax

perLineLoopPCB11:

        ; dst is es:di
        ; src is fs:si

        ; Get a byte of source data from the pattern definition
        mov     al, [esi]                       ; get pattern byte      ;**
        xor     al, srcInvertMask               ; make it a source byte
        mov     cl, _messSpad.srcToDestShift
        rol     al, cl                          ; align it correctly
        mov     cl, al                          ; keep it in cl

        mov     dx, word ptr _messSpad.totalBytes

        ; source is already in al

        mov     ah, [edi]               ; get byte from destination     ;**

        and     ah, bh                  ; get pels from destination
        and     al, bl                  ; get pels from source
        or      ah, al                  ; stir them together
        mov     [edi], ah               ; write them back               ;**

        inc     edi                     ; bump pointer                  ;**

        dec     dx
        jz      short loopDonePCB11

        dec     dx
        jz      short endMaskPCB11

        ; dx is the number of full bytes to do
pelLoopPCB11:
        mov     [edi], cl               ; write source byte             ;**

        inc     edi                     ; bump pointer                  ;**

        dec     dx
        jnz     short pelLoopPCB11

endMaskPCB11:
        mov     ah, [edi]               ; get byte from destination     ;**

        swap    ebx                     ; get end masks
        and     ah, bh                  ; get pels from destination
        and     cl, bl                  ; get pels from source
        or      ah, cl                  ; stir them together
        mov     [edi], ah               ; write them back               ;**
        swap    ebx

        inc     edi                     ; bump pointer                  ;**

loopDonePCB11:
        add     edi, _messSpad.dstLineInc     ; next line                ;**

        ; More lines ?
        dec     linesLoop
        jz      short exitPCB11

        ; More lines in pattern ?
        dec     patLinesToGo
        jz      short vertWrapPatternPCB11

        ; Bump pattern address to next line
        inc     esi                                                     ;**
        jmp     perLineLoopPCB11

vertWrapPatternPCB11:
        ; Need to apply a vertical wrap to the pattern
        movzx   eax, patPixmap.yLen                                     ;**
        sub     esi, eax                                                ;**
        inc     eax                                                     ;**
        mov     patLinesToGo, ax
        jmp     perLineLoopPCB11

exitPCB11:
cEnd



_TEXT ends


END
