;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; 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.;
;*****************************************************************************/
        PAGE     55,132
        TITLE    BitBlt
        SUBTITLE Header
;/*****************************************************************************
;*
;* SOURCE FILE NAME = BKMTRANS.ASM
;*
;* DESCRIPTIVE NAME = Background mix special cases of BLT's.
;*
;*
;* VERSION      V2.0
;*
;* DATE         06/01/92
;*
;* DESCRIPTION  Background mix special cases of BLT's and supporting subroutines.
;*
;*           BM_SRCTRANSPARENT will result in pels from the source bitmap matching
;*            the presentation space background color NOT to be copied to the
;*            destination bitmap. (OVERLAY)
;*           BM_DESTTRANSPARENT will result in pels from the source bitmap ONLY
;*            being copied to the destination pels that match the presentation space
;*            background color. (UNDERLAY)
;*
;*
;* FUNCTIONS  copy_scanline
;*            s_copy_scanline
;*            d_copy_scanline
;*            d_xor_scanline
;*            xor_scanline
;*            solid_scanline
;*            d_solid_scanline
;*            do_wes_mono_trick
;*            special_gray_rop
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   03/02/93              63052  Moved do_wes_mono_trick and special_gray_rop
;*                                from SPECIAL8.BLT to avoid MASM "out of near
;*                                memory" error.
;*
;*****************************************************************************/

        .386
        .MODEL FLAT,SYSCALL
        ASSUME  SS:FLAT, DS:FLAT, CS:FLAT, ES:FLAT

        .xlist
        include pmgre.inc
DINCL_BB_ROPS   equ     1
DINCL_BITMAP    equ     1
DINCL_ENABLE    equ     1
        include driver.inc
        include extern.inc
        include protos.inc
        include display.inc
        include oemblt.inc
        .list

extern bkclr             :BYTE          ;Background color

        include constant.blt

.CODE

;/***************************************************************************
;*
;* FUNCTION NAME = copy_scanline
;*
;* DESCRIPTION   = copy a number of scanline from the input source to the
;*                 input dest
;*
;* INPUT         = ESI --> source
;*                 EDI --> destination
;*                 ECX count
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

public copy_scanline
copy_scanline            PROC SYSCALL
        test    edi,1                   ;Is there any odd byte ?
        jz      @f
        movsb                           ;Move odd byte.
        dec     ecx                     ;Update count.
@@:                                     ; 
        push    ecx                     ;Save number of bytes to copy.
        shr     ecx,2                   ;Prepare to copy double word.
        rep     movsd                   ;Copy tempary buffer to screen.
        pop     ecx                     ;Recover number of bytes.
        and     ecx,3                   ;Prepare to copy remainning bytes.
        shr     cx,1                    ;Prepare to copy word.
        rep     movsw                   ;Copy tempary buffer to screen.
        jnc     @f                      ;Is there any byte left to copy ?
        movsb                           ;If so, do it.
@@:
        ret
copy_scanline            ENDP


;/***************************************************************************
;*
;* FUNCTION NAME = s_copy_scanline
;*
;* DESCRIPTION   = copy a number of scanline from the input source to the
;*                 destination, respecting the source
;*
;* INPUT         = ESI --> source
;*                 EDI --> destination
;*                 ECX count
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

public s_copy_scanline
s_copy_scanline          PROC SYSCALL
        push    eax
s_copy_loop:
        lodsb                           ;Get byte from temp buffer
        cmp     al,bkclr                ;Color == background color ?
        je      s_color_found           ;If so, point to next byte
        stosb                           ;If not, copy to screen
        loop    s_copy_loop             ;Get the next byte
        jmp     @f
s_color_found:
        inc     edi                     ;Trans color found, point to next byte
        loop    s_copy_loop             ;Get the next byte
@@:
        pop     eax
        ret
s_copy_scanline          ENDP


;/***************************************************************************
;*
;* FUNCTION NAME = d_copy_scanline
;*
;* DESCRIPTION   = copy a number of scanline from the input source to the
;*                 destination, respecting the destination
;*
;* INPUT         = ESI --> source
;*                 EDI --> destination
;*                 ECX count
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

public d_copy_scanline
d_copy_scanline          PROC SYSCALL
        push    eax
d_copy_loop:
        mov     al,byte ptr[edi]        ;Get byte from destination
        cmp     al,bkclr                ;Color == background color ?
        jne     d_color_notfound        ;If not, point to next byte
        movsb                           ;If so, copy to screen
        loop    d_copy_loop             ;Get the next byte
        jmp     @f
d_color_notfound:
        inc     edi                     ;Trans color notfound, point to next byte
        inc     esi                     ;Trans color notfound, point to next byte
        loop    d_copy_loop             ;Get the next byte
@@:
        pop     eax
        ret
d_copy_scanline          ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = d_xor_scanline
;*
;* DESCRIPTION   = XOR the destination scanline if it is equal to source.
;*
;*
;* INPUT         = ESI --> source
;*                 EDI --> destination
;*                 ECX count
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

public d_xor_scanline
d_xor_scanline           PROC SYSCALL
        push    ebx
d_xor_loop:
        mov     bl,byte ptr [edi]       ;Get byte from destination
        cmp     bl,bkclr                ;Color == background color ?
        jne     d_xor_color_notfound    ;If not, point to next byte
        xor     byte ptr [edi],al       ;If so, xor destination
        inc     edi                     ;Trans color found, point to next byte
        loop    d_xor_loop              ;Get the next byte
        jmp     @f
d_xor_color_notfound:
        inc     edi                     ;Trans color notfound, point to next byte
        loop    d_xor_loop              ;Get the next byte
@@:
        pop     ebx
        ret
d_xor_scanline           ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = xor_scanline
;*
;* DESCRIPTION   = XOR the destination scanline.
;*
;*
;* INPUT         = ESI --> source
;*                 EDI --> destination
;*                 ECX count
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

public xor_scanline
xor_scanline             PROC SYSCALL
        push    ecx                     ;Save number of bytes to copy.
        shr     ecx,2                   ;Prepare to copy double word.
        jecxz   xor_word_chk1           ;Are we done yet ?
xor_32_loop:                            ; 
        xor     dword ptr [edi],eax     ;Do xor with destination.
        add     edi,4                   ; 
        loop    xor_32_loop             ; 
xor_word_chk1:                          ; 
        pop     ecx                     ;Recover number of bytes.
        and     ecx,3                   ;Prepare to xor remainning bytes.
                                        ; 
        shr     cx,1                    ;Prepare to xor word.
        jecxz   check_byte              ;Are we done yet ?
        pushf                           ;Save flag.
xor_loop:                               ; 
        xor     word ptr [edi],ax       ;Do xor destination.
        add     edi,2                   ; 
        loop    xor_loop                ; 
        popf                            ; 
check_byte:                             ; 
        jnc     xor_scanline_done       ;Is there any byte left ?
        xor     byte ptr [edi],al       ;If so, do the last byte.
xor_scanline_done:                      ; 
        ret
xor_scanline             ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = solid_scanline
;*
;* DESCRIPTION   = copy a solid color scanline from source to dest
;*
;*
;* INPUT         = ESI --> source
;*                 EDI --> destination
;*                 ECX count
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

public solid_scanline
solid_scanline           PROC SYSCALL
        test    edi,1                   ;Is there any odd byte ?
        jz      solid_pat_aligned_byte  ; 
        stosb                           ;Move odd byte.
        dec     ecx                     ;Update count.
        jz      solid_done              ;Are we done yet ?
solid_pat_aligned_byte:                 ; 
        cmp     ecx,2                   ;Check if we can do word.
        jc      sp_chk_byte             ;If less than 2 than only byte to copy.
        test    edi,2                   ;Is destination start from word boundry ?
        jz      solid_pat_aligned_word  ; 
        stosw                           ;Move word if start from word boundry.
        dec     ecx                     ;Update count.
        dec     ecx                     ;Update count.
        jz      solid_done              ;Are we done yet ?
solid_pat_aligned_word:                 ; 
        push    ecx                     ;Save number of bytes to copy.
        shr     ecx,2                   ;Prepare to copy double word.
        rep     stosd                   ;Copy source to destination.
        pop     ecx                     ;Recover number of bytes.
        and     ecx,3                   ;Prepare to copy remainning bytes.
chk_trlr:                               ; 
        jcxz    solid_done              ;Are we done yet ?
        shr     cx,1                    ;Prepare to copy word.
        rep     stosw                   ;Copy source to destination.
sp_chk_byte:                            ; 
        jnc     solid_done              ;Is there any byte left to copy ?
        stosb                           ;If so, do it.
solid_done:
        ret
solid_scanline           ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = d_solid_scanline
;*
;* DESCRIPTION   = copy a solid color scanline from source to dest,
;*                 respecting the destination
;*
;* INPUT         = ESI --> source
;*                 EDI --> destination
;*                 ECX count
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

public d_solid_scanline
d_solid_scanline         PROC SYSCALL
        push    ebx
d_solid_loop:
        mov     bl,byte ptr [edi]       ;Get byte from destination
        cmp     bl,bkclr                ;Color == background color ?
        jne     d_solid_color_notfound  ;If not, point to next byte
        stosb                           ;If so, copy to destination
        loop    d_solid_loop            ;Get the next byte
        jmp     @f
d_solid_color_notfound:
        inc     edi                     ;Trans color notfound, point to next byte
        loop    d_solid_loop            ;Get the next byte
@@:
        pop     ebx
        ret
d_solid_scanline         ENDP

;           Start
set_d_pointer           PROTO SYSCALL
set_s_pointer_map       PROTO SYSCALL

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

mono_blt_inner_loop macro
    rept 8
local   leave_alone
local   next_dest
        rol     bh, 1                   ; rotate a bit of source into carry
        jnc     leave_alone             ; 
        test    eax, BBF_ANTI_TRANS
        jnz     next_dest
        mov     byte ptr [edi],dh
        jmp     next_dest               ;CMVC_52855 Foreground color
leave_alone:
        test    eax, BBF_TRANS
        jnz     next_dest
        mov     byte ptr [edi],dl       ;CMVC_52855 Background color
next_dest:                              ;CMVC_52855
        inc     edi
    endm
endm


;/***************************************************************************
;*
;* FUNCTION NAME = do_wes_mono_trick
;*
;* DESCRIPTION   =
;*
;*                  Registers Preserved:
;*                        BP
;*                  Registers Destroyed:
;*                        AX,BX,CX,DX,SI,DI,DS,ES,flags
;*
;* INPUT         = SS:BP --> BitBLT local variable frame
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
public do_wes_mono_trick
do_wes_mono_trick       PROC SYSCALL,
 pddcDst  :DWORD, ;Destination ddc
 xDst     :DWORD, ;Destination x origin
 yDst     :DWORD, ;Destination y origin
 psdSrc   :DWORD, ;Source surface definition
 xSrc     :DWORD, ;Source x origin
 ySrc     :DWORD, ;Source y origin
 cxExt    :DWORD, ;x extent of the BLT
 cyExt    :DWORD, ;y extent of the BLT
 usMix    :DWORD, ;Mix mode
 ipcBkgnd :DWORD, ;Color to mono background match color
 fsBlt    :DWORD

        include frame.blt
        include frame8.blt
        call    set_d_pointer                   ;Set up destination address
        call    set_bank_select                 ;Enable bank in dl.
        call    set_s_pointer_map               ;Set up source bit map.

;/*
;** set the colors to expand to
;*/

        mov     dh, byte ptr ipcImageFore       ;Fore ground color to dh
        mov     dl, byte ptr ipcImageBack       ;CMVC_52855 Background color

;/*
;** Starting a new row
;*/

cdsc_mono_100:                          ; Scan line loop

mono_inner_loop_top:

        push    edi                     ; Start of scan of destination
        push    esi                     ; Start of scan of source

;/*
;** do the left fring first
;** check for degenerate case
;*/

        mov     ecx, mPhase             ; Is this the degenerate case?
        cmp     ecx, 0
        jz      mono_not_degenerate     ; nope...

;/*
;** this is the degenerate case.
;** the number of bits to blit are intierly contained with the first byte
;*/

        mov     bl, byte ptr mStart     ; bl = first bit to expand
        mov     ah, [esi]               ; ah = first byte to expand
mono_degen_loop:
        mov     al, dl                  ; al = background color
        test    ah, bl                  ; test forground or
        jz      @f                      ;   background expansion
        mov     al, dh                  ; al = forground color
@@:
        mov     byte ptr [edi],al
        inc     edi
        shr     bl, 1                   ; bl = next bit to test
        loop    mono_degen_loop         ; loop through the first byte
        jmp     mono_exit_inner_loop


mono_not_degenerate:

;/*
;** do the left fring
;** if the xSrc is on a byte boundry then there will be no bits
;** to expand in the first byte.
;** The faster middle byte code will handle it.
;*/

        mov     bl, byte ptr mStart     ; bl = first bit to test
        or      bl, bl                  ; are there any bits in the first
        jz      mono_lf_done            ; nope...
        mov     al,[esi]
        inc     esi
        mov     ah, al                  ; ah = source byte cache
mono_lf_lp:                             ; mono left fring loop
        mov     al, dl                  ; CMVC_52855 background color
        test    ah, bl                  ; test forground or
        jz      @f                      ;   background expansion
        mov     al, dh                  ; al = forground color
@@:                                     ; CMVC_52855
        mov     byte ptr [edi],al

        inc     edi
        shr     bl, 1                   ; bl = next pixel to test
        jnz     mono_lf_lp              ; end when we run out of bits in the byte

mono_lf_done:

;/*
;** do the middle bytes
;*/

        mov     ecx, cInnerByte         ; cx = number of bytes to expand
        cmp     cx,0
        jz      mono_inner_bytes_done
        ;jcxz    mono_inner_bytes_done   ; skip it if there are no bytes
        mov     eax,fsBlt
mono_byte_lp:                           ; mono byte loop
        mov     bh,[esi]                ; bh = source byte cache 
        inc     esi

        mono_blt_inner_loop             ; In line expansion macro for a byte
        dec     cx
        cmp     cx,0
        jnz     mono_byte_lp
        ;loop    mono_byte_lp            ; loop through all the bytes
mono_inner_bytes_done:

;/*
;** do the right fring
;*/

        mov     cx, mLast               ; cx = number of bits in the right fring
        movzx   ecx,cx
        jcxz    mono_rf_done            ; are there any?
        mov     al,[esi]
        inc     esi
        mov     ah, al                  ; ah = source byte cache
        mov     bl, 80h                 ; bl = init expansion test bit
mono_rf_lp:                             ; mono left fring loop
        mov     al, dl                  ; CMVC_52855 background color
        test    ah, bl                  ; test forground or
        jz      @f                      ;   background expansion
        mov     al, dh                  ; al = forground color
@@:                                     ; CMVC_52855
        mov     byte ptr [edi],al

        inc     edi
        shr     bl, 1                   ; bl = next pixel to test
        loop    mono_rf_lp              ; loop through the last bits...
mono_rf_done:

mono_exit_inner_loop:

        pop     esi                     ; restore the left edges of the blits
        pop     edi

        add     esi,devSrc.width_b      ; Look at next source scan line

        add     edi,SCREEN_CBSCAN       ; Look at next screen scan line
        dec     dst_scan_line_left      ; Updata line remainning in current bank.
        jnz     cdsc_mono_300           ; Check if time to switch bank.
        push    scan_per_bank           ; Get total scan lines in one bank.
        pop     dst_scan_line_left      ; Save total scan lines left.
        ; Switch banking detected in destination
cdsc_mono_400:                          ; 
        push    dx                      ; Save dx we used in bank switching.
        mov     dl,d_page               ; Get current bank.
        inc     dx                      ; Prepare to switch to next bank.
        mov     d_page,dl               ; 
        call    set_bank_select         ; Set new bank.
        sub     edi,BANK_SIZE              ; Reset current bank address.
        pop     dx                      ; Recover dx.
                                        ; 
cdsc_mono_300:                          ; 
        dec     cyExt                   ; Another line done.
        jz      cdsc_mono_done          ; Are we done yet ?
        jmp     mono_inner_loop_top     ; Nope, go do another line.
cdsc_mono_done:                         ; 
                                        ; 
        ret                             ; 

do_wes_mono_trick       ENDP

gray_rop_inner_loop_double macro
        push    ecx
        rept    4
           mov  dh, byte ptr [edi]  ; dh = source byte
           inc  edi
           rol  bl, 1                   ; left bit of pattern into carry
           sbb  ax, ax                  ; if CY then ax = 0FFFFh, else ax = 0
           not  ah                      ; create mask
           and  ax, dx                  ; AND in the colors
           or   al, ah                  ; al = the un-mask color
           mov  cl,al                   ; 
           ror  ecx,8                   ; Get 4 bytes before storing to video buffer
        endm                            ; 
        sub     edi,4                   ; 
        mov     eax,ecx                 ; 
        stosd                           ; set the byte, bump to next pixel
        pop     ecx
        sub     cx,4                    ; bump the line count
        jz      gray_rop_245            ; exit if end of line
endm

gray_rop_inner_loop macro
    rept 3
        mov     dh, byte ptr [edi]      ; dh = source byte
        rol     bl, 1                   ; left bit of pattern into carry
        sbb     ax, ax                  ; if CY then ax = 0FFFFh, else ax = 0
        not     ah                      ; create mask
        and     ax, dx                  ; AND in the colors
        or      al, ah                  ; al = the un-mask color
        stosb                           ; set the byte, bump to next pixel
        dec     cx                      ; bump the line count
        jz      gray_rop_245            ; exit if end of line
    endm
endm


;/***************************************************************************
;*
;* FUNCTION NAME = special_gray_rop
;*
;* DESCRIPTION   =
;*
;* INPUT         = pddcDst  :DWORD, ;Destination ddc
;*                 xDst     :DWORD, ;Destination x origin
;*                 yDst     :DWORD, ;Destination y origin
;*                 psdSrc   :DWORD, ;Source surface definition
;*                 xSrc     :DWORD, ;Source x origin
;*                 ySrc     :DWORD, ;Source y origin
;*                 cxExt    :DWORD, ;x extent of the BLT
;*                 cyExt    :DWORD, ;y extent of the BLT
;*                 usMix    :DWORD, ;Mix mode
;*                 ipcBkgnd :DWORD, ;Color to mono background match color
;*                 fsBlt    :DWORD
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

special_gray_rop proc SYSCALL,
 pddcDst  :DWORD, ;Destination ddc
 xDst     :DWORD, ;Destination x origin
 yDst     :DWORD, ;Destination y origin
 psdSrc   :DWORD, ;Source surface definition
 xSrc     :DWORD, ;Source x origin
 ySrc     :DWORD, ;Source y origin
 cxExt    :DWORD, ;x extent of the BLT
 cyExt    :DWORD, ;y extent of the BLT
 usMix    :DWORD, ;Mix mode
 ipcBkgnd :DWORD, ;Color to mono background match color
 fsBlt    :DWORD

        include frame.blt
        include frame8.blt
        cld                             ; Direction flag going UP
        call    set_d_pointer           ; edi destination pointer, dl = bank.
        call    set_bank_select         ; 

        mov     esi, pBrush             ; esi = brush source


        mov     bl, yPatRow
        and     ebx, 0007h              ; bx = brush row offset

        mov     dl,byte ptr ipcBrushBack; dl = background color

;/*
;** Starting a new row
;*/


gray_rop_100:                           ; Scan line loop
        push    edi                     ; Start of scan of destination
        push    ebx                     ; pattern Y

        mov     bh, byte ptr [esi+ebx]  ; bh = pattern byte

;/*
;** rotate the pattern so it's aligned with the raster.
;*/

        mov     ecx, edi                ; 
        and     ecx, 07                 ; 
        rol     bh, cl                  ; 
                                        ; 
        mov     ecx,cxExt               ; Number of bytes on this scan line
                                        ; 
                                        ; 
gray_rop_200:                           ; Byte loop
        mov     bl, bh                  ; set the pattern byte
        cmp     cx,4                    ; Can we do double word output ?
        jl      do_byte                 ; If not, do one byte at a time.
        gray_rop_inner_loop_double      ; Do double word.
        jmp     gray_rop_200            ; 
do_byte:                                ; 
        gray_rop_inner_loop             ; Do remainning byte.
                                        ; 
gray_rop_245:                           ; 
        pop     ebx                     ; 
        inc     ebx                     ; Next byte in pattern mask
        and     ebx,07h                 ; Wrap around if greater than 7.
                                        ; 
        pop     edi                     ; 
        add     edi,devDst.width_b      ; Look at next screen scan line
        dec     dst_scan_line_left      ; Update line remainning in current bank.

        jnz     gray_rop_300            ; Need to switch bank yet ?
        push    scan_per_bank           ; Time to switch to next bank.
        pop     dst_scan_line_left      ; 
        inc     d_page                  ; 
        push    dx                      ; Save background color in dl.
        mov     dl,d_page               ; Get current destination bank.
        call    set_bank_select         ; Set destination bank.
        pop     dx                      ; Recover background color in dl.
        sub     edi,BANK_SIZE              ; Reset Dev to beginning of page.
                                        ; 
gray_rop_300:                           ; 
        dec     cyExt                   ; Another line done.
                                        ; 
        jz      gray_rop_done           ; Are'we done yet ?
        jmp     gray_rop_100            ; If not, go do another line.
                                        ; 
gray_rop_done:                          ; 
                                        ; 
        ret                             ; 
special_gray_rop        ENDP

;           end

END
