;*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    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME =  SCANLIN2.ASM
;*
;* DESCRIPTIVE NAME =  Scanline sub-function of Output
;*
;*
;* VERSION      V2.0
;*
;* DATE         02/22/87
;*
;* DESCRIPTION   This module contains the scanline sub-function of Output.
;*
;*
;* FUNCTIONS    NONE
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*
;*****************************************************************************/


        .386

        .xlist

INCL_GRE_CLIP           equ     1
INCL_GRE_SCANS          equ     1
INCL_GPIREGIONS         equ     1
INCL_GPIERRORS          equ     1
INCL_DDIMISC            equ     1
INCL_DEV                equ     1
INCL_DDICOMFLAGS        equ     1
DINCL_ROPS              equ     1
DINCL_ENABLE            equ     1
DINCL_BITMAP            equ     1

        include pmgre.inc
        include driver.inc
        include egafam.inc
        include display.inc
        include scanline.inc
        include assert.mac
        include extern.inc
        include protos.inc
ifdef EGAMEM_IS_STRUCT
        include egamem.inc
endif
        .list

        .MODEL FLAT,SYSCALL

        ASSUME  CS:FLAT,SS:FLAT,DS:FLAT,ES:FLAT
.CODE
public rops_start
public ega_first_last
public ega_inner_latch
public ega_inner_stosb


page
;/***************************************************************************
;*
;* PUBLIC ROUTINE  ega_first_last
;*
;* DESCRIPTION   = ega_first_last handles the first and last bytes of the raster
;*                 operations which can be performed in one pass, and the inner
;*                 loop of those raster operations which can be performed in one
;*                 pass that cannot use stosb.
;*
;*                 The following conditions must be met:
;*
;*                     a)  The destination is the EGA
;*                     b)  single pass rop
;*                     c)  rep stosb cannot be used if for the inner loop
;*
;*
;*                 This function can handle both opaque and transparent modes.
;*
;*                 Registers Preserved:
;*                       BX,SI,DS,ES,BP
;*                 Registers Destroyed:
;*                       AX,DX,FLAGS
;*
;* INPUT         = DS:DI    --> destination byte
;*                 ES:DI    --> destination byte
;*                    AL     =  transparency/first/last mask as appropriate
;*                    CX     =  byte count
;*                 GRAF_ADDR =  GRAF_BIT_MASK
;*
;* OUTPUT        = DS:DI    --> next destination word
;*                 ES:DI    --> next destination word
;*                    CX     =  0
;*                 GRAF_ADDR =  GRAF_BIT_MASK
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


ega_first_last::

        ret

page

;/***************************************************************************
;*
;* PUBLIC ROUTINES   Raster Operation Subroutines
;*
;* DESCRIPTION   =
;*
;*       The following subroutines implement the foreground mix modes.
;*       They all have the same register interface.
;*
;*       The code has been compressed so that the address table could
;*       be stored as bytes instead of words.  This is accomplished
;*       mainly by combining rops with their inverses. The inverse of
;*       rop A is rop B if
;*
;*             rop A  maps  0 --> x, 1 --> y
;*       whereas
;*             rop B  maps  0 --> y, 1 --> x.
;*
;*       The pattern will have been pre-inverted for all the "inverses"
;*       (look for the ALT_NEG_PATTERN flag in another_tbl to see which
;*       are the "inverses").
;*
;*       In addition, some rops were embedded in others, code-wise, in
;*       such a way that the larger could be written to fall through to
;*       the smaller (e.g. transp_dpna and transp_dpa falling through to
;*       transp_ddx).  Unfortunately this makes the code harder to read.
;*
;*       Many of the rops require a third work register, so BX is used
;*       and reloaded afterwards.
;*
;*       Entry:
;*             AX = transparency mask
;*             BX = pattern
;*             CX = loop count
;*             SI = index into table of per-plane processor blocks
;*             DS:DI --> destination
;*             ES:DI --> destination
;*             direction flag cleared
;*       Returns:
;*             CX = 0
;*             DS:DI --> next destination
;*             ES:DI --> next destination
;*             direction flag cleared
;*       Registers Preserved:
;*             BX,SI,BP,DS,ES
;*       Registers Destroyed:
;*             AX,DX,flags
;*
;*      ---------------------------------------------------------------;
;*
;*       The following table describes the boolean logic necessary for
;*       creating any desired masks from the transparency mask and pattern.
;*       To use it, determine what mask behavior you want (remember to invert
;*       AND masks), look it up, then look across to see how to set it up.
;*       The columns indicate the mask bits for foreground 1's, foreground 0's,
;*       background 1's, and background 0's, respectively.
;*
;*
;*                                          s s s s
;*                                         1 0 1 0
;*
;*                                       g g k k
;*                                      f f b b
;*
;*              transparency mask (AX)  1 1 0 0
;*                        pattern (BX)  1 0 1 0
;*                                      -------
;*                                      0 0 0 0         0
;*                                      0 0 0 1         not (AX or BX)
;*                                      0 0 1 0         not AX and BX
;*                                      0 0 1 1         not AX
;*                                      0 1 0 0         AX and not BX
;*                                      0 1 0 1         not BX
;*                                      0 1 1 0         AX xor BX
;*                                      0 1 1 1         not (AX and BX)
;*                                      1 0 0 0         AX and BX
;*                                      1 0 0 1         not (AX xor BX)
;*                                      1 0 1 0         BX
;*                                      1 0 1 1         not AX or BX
;*                                      1 1 0 0         AX
;*                                      1 1 0 1         AX or not BX
;*                                      1 1 1 0         AX or BX
;*                                      1 1 1 1         1
;*
;*
;*       For example, take the rop DPon with opaque background.  On a plane
;*       by plane basis, the rop's effect is to write 0's where the pattern
;*       is 1, and invert the destination where the pattern is 0.  This can
;*       be done with an AND mask and an XOR mask.  The AND mask clears out
;*       all the bits corresponding to foreground 1's or to background bits.
;*       The XOR mask flips bits corresponding to foreground 0's or
;*       background 1's. The AND mask must be applied first to get the
;*       correct background color.
;*
;*       DPon: inverse (source or destination), mix mode 10
;*
;*           pattern
;*          foreground  effective
;*             bit         rop
;*           -------------------
;*              0   -->   ~dest
;*              1   -->     0
;*
;*              background mix = OverPaint (P):
;*
;*              AND mask behavior: 0 1 0 0  ==> mask logic: (AX and not BX)
;*
;*                                 | | | |
;*                                 | | | +----- clear background 0's
;*                                 | | |
;*                                 | | +------- clear background 1's
;*                                 | |
;*                                 | +--------- don't touch foreground 0's
;*                                 |
;*                                 +----------- clear foreground 1's
;*
;*
;*              XOR mask behavior: 0 1 1 0  ==> mask logic: (AX xor BX)
;*
;*                                 | | | |
;*                                 | | | +----- don't touch background 0's
;*                                 | | |
;*                                 | | +------- invert (i.e. set) background 1's
;*                                 | |
;*                                 | +--------- invert foreground 0's
;*                                 |
;*                                 +----------- don't touch foreground 1's
;*
;*
;*      ---------------------------------------------------------------;
;*       The following table describes the behavior of each raster operation
;*       plane by plane, bit by bit. The mapping is from pattern bits to
;*       effective rops (DDx, Dn, D, DDxn) on the destination.  This table
;*       is a convenient reference for figuring out the necessary masks for
;*       rop subroutines, as well as a good display of the symmetry of rop
;*       behavior.
;*
;*             DDx             PDna            DPa             P
;*               0 ->  0         0 ->  0         0 ->  0         0 ->  0
;*               1 ->  0         1 -> ~dest      1 ->  dest      1 ->  1
;*
;*             DPon            Dn              DPxn            PDno
;*               0 -> ~dest      0 -> ~dest      0 -> ~dest      0 -> ~dest
;*               1 ->  0         1 -> ~dest      1 ->  dest      1 ->  1
;*
;*             DPna            DPx             D               DPo
;*               0 ->  dest      0 ->  dest      0 ->  dest      0 ->  dest
;*               1 ->  0         1 -> ~dest      1 ->  dest      1 ->  1
;*
;*             Pn              DPan            DPno            DDxn
;*               0 ->  1         0 ->  1         0 ->  1         0 ->  1
;*               1 ->  0         1 -> ~dest      1 ->  dest      1 ->  1
;*
;*
;*      ---------------------------------------------------------------;
;*       Catalog of masks for raster operations:
;*
;*             If the inverse is mentioned at the right, then the
;*             rop has been implemented by pre-inverting the pattern
;*             and executing the inverse rop's subroutine.
;*
;*             DDx
;*                 D
;*                     AND:    not AX
;*                 P
;*                     AND:    not AX and BX
;*
;*             DPon                                    inverse of PDna
;*                 D
;*                     AND:    not (AX and BX)
;*                     XOR:    AX and not BX
;*                 P
;*                     AND:    AX and not BX
;*                     XOR:    AX xor BX
;*
;*             DPna                                    inverse of DPa
;*                 D
;*                     AND:    not (AX and BX)
;*                 P
;*                     AND:    AX and not BX
;*                     XOR:    not AX and BX
;*
;*             Pn                                      inverse of P
;*                 D   no masks (uses double-xor trick)
;*                 P   no masks (uses rep stosw)
;*
;*             PDna
;*                 D
;*                     AND:    not AX or BX
;*                     XOR:    AX and BX
;*                 P
;*                     AND:    AX and BX
;*                     XOR:    BX
;*
;*             Dn
;*                 D
;*                     XOR:    AX
;*                 P
;*                     AND:    AX
;*                     XOR:    AX or BX
;*
;*             DPx
;*                 D
;*                     XOR:    AX and BX
;*                 P
;*                     AND:    AX
;*                     XOR:    BX
;*
;*             DPan
;*                 D
;*                     OR:     AX and not BX
;*                     XOR:    AX and BX
;*                 P
;*                     OR:     not (AX and BX)
;*                     XOR:    not (AX xor BX)
;*
;*             DPa
;*                 D
;*                     AND:    not AX or BX
;*                 P
;*                     AND:    AX and BX
;*                     XOR:    not AX and BX
;*
;*             DPxn                                    inverse of DPx
;*                 D
;*                     XOR:    AX and not BX
;*                 P
;*                     AND:    AX
;*                     XOR:    AX xor BX
;*
;*             D
;*                 D   no masks (just advance destination pointer)
;*                 P
;*                     AND:    AX
;*                     XOR:    not AX and BX
;*
;*             DPno                                    inverse of DPo
;*                 D
;*                     OR:     AX and not BX
;*                 P
;*                     AND:    AX and BX
;*                     XOR:    AX xor BX
;*
;*             P
;*                 D   no masks (uses double-xor trick)
;*                 P   no masks (uses rep stosw)
;*
;*
;*             PDno                                    inverse of DPan
;*                 D
;*                     AND:    not (AX and BX)
;*                     XOR:    AX
;*                 P
;*                     AND:    AX and not BX
;*                     XOR:    AX or BX
;*
;*             DPo
;*                 D
;*                     OR:     AX and BX
;*                 P
;*                     AND:    AX and not BX
;*                     XOR:    BX
;*
;*             DDxn
;*                 D
;*                     OR:     AX
;*                 P
;*                     OR:     AX or BX
;*
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

rops_start      label   byte

do_nothing      PROC

                RET

do_nothing      ENDP

transp_dpna     PROC

transp_dpa      PROC

        not     eax
        or      eax,ebx
        not     eax                               ;compensate for "not ax" in transp_ddx

transp_dpa      ENDP

transp_dpna     ENDP

transp_ddx      PROC

        not     eax
@@:
        and     WORD PTR [edi],ax
        inc     edi
        inc     edi
        dec     ecx
        jnz     @B

                RET

transp_ddx      ENDP

transp_pn       PROC

transp_p        PROC

        not     eax                               ;Need inverse for unaltered bits
        xchg    eax,edx                           ;Need to use the work register
@@:
        mov     ax,WORD PTR [edi]                ;Quicker to dest into a register
        xor     eax,ebx                           ;Invert bits which will not change
        and     eax,edx                           ;Set new bits to 0
        xor     eax,ebx                           ;Invert unchanged again, set new bits
        stosw                                     ;Store and update destination ptr
        dec     ecx
        jnz     @B

                RET

transp_p        ENDP

transp_pn       ENDP

transp_dpon     PROC

transp_pdna     PROC

        push    ebx
        mov     edx,ebx                           ;Need to use the work register
        and     ebx,eax                           ;XOR mask
        not     eax
        or      edx,eax                           ;AND mask
@@:
        mov     ax,WORD PTR [edi]                ;Quicker to have dest into a register
        xor     eax,ebx                           ;Invert bits as needed
        and     eax,edx                           ;Set bits to 0 as needed
        stosw                                     ;Store and update destination ptr
        dec     ecx
        jnz     @B
        pop     ebx

                RET

transp_pdna     ENDP

transp_dpon     ENDP

transp_dpxn     PROC

transp_dpx      PROC

        and     eax,ebx

transp_dpx      ENDP

transp_dpxn     ENDP

transp_dn       PROC

@@:
        xor     WORD PTR [edi],ax
        inc     edi
        inc     edi
        dec     ecx
        jnz     @B

                RET

transp_dn       ENDP

transp_pdno     PROC

transp_dpan     PROC

        push    ebx
        mov     edx,ebx                           ;Need to use the work register
        and     ebx,eax                           ;XOR mask
        not     edx                               ;Map 0 ==> 1 for ORing
        and     edx,eax                           ;OR mask

@@:
        mov     ax,WORD PTR [edi]                ;Quicker to have dest into a register
        xor     eax,ebx                           ;Invert bits as needed
        or      eax,edx                           ;Set bits to 1 as needed
        stosw                                     ;Store and update destination ptr
        dec     ecx
        jnz     @B
        pop     ebx

        RET

transp_dpan     ENDP

transp_pdno     ENDP

transp_dpno     PROC

transp_dpo      PROC

        and     eax,ebx

transp_dpo      ENDP

transp_dpno     ENDP

transp_ddxn     PROC

@@:
        or      WORD PTR [edi],ax
        inc     edi
        inc     edi
        dec     ecx
        jnz     @B

                RET

transp_ddxn     ENDP

;/*
;** transp_d
;**
;** This is only used when the foreground is D, the background
;** is P, and there are clipped words to output.   The pointer
;** must be updated so the inner loop code will fill in the
;** background bits correctly.
;*/

transp_d        PROC

        add     ecx,ecx
        add     edi,ecx                           ;just advance the pointer
        xor     ecx,ecx

                RET

transp_d        ENDP

page
;/***************************************************************************
;*
;* PUBLIC ROUTINE  ega_inner_latch
;*
;* DESCRIPTION   =
;*
;*        ega_inner_latch handles the inner loop bytes of a scanline when all
;*        of the following conditions are met:
;*
;*            a)  The destination is the EGA
;*            b)  The raster op is either P or Pn
;*            c)  No transparency
;*            d)  The brush is non-solid
;*
;*        The pattern which is stored at EGAMem:current_brush[0] will
;*        be loaded into the latches and stored into the destination.
;*
;*        Registers Preserved:
;*              BX,SI,DS,ES,BP
;*        Registers Destroyed:
;*              AX,DX,FLAGS
;*
;* INPUT         = DS:DI    --> destination byte
;*                 ES:DI    --> destination byte
;*                    AL     =  0FFh
;*                    CX     =  byte count
;*                 GRAF_ADDR =  GRAF_BIT_MASK
;*
;* OUTPUT        = DS:DI    --> next destination word
;*                 ES:DI    --> next destination word
;*                    CX     =  0
;*                 GRAF_ADDR =  GRAF_BIT_MASK
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ega_inner_latch::

        ret
page
;/***************************************************************************
;*
;* PUBLIC ROUTINE  ega_inner_stosb
;*
;* DESCRIPTION   = ega_inner_stosb handles the inner loop bytes of a scanline
;*                 when all of the following conditions are met:
;*
;*                 a)  The destination is the EGA
;*                 b)  No transparency
;*                 c)  rep stosb can be used
;*
;*                 Registers Preserved:
;*                       BX,SI,DS,ES,BP
;*                 Registers Destroyed:
;*                       AX,DX,FLAGS
;*
;* INPUT         = DS:DI    --> destination byte
;*                 ES:DI    --> destination byte
;*                    AL     =  0FFh
;*                    CX     =  byte count
;*                 GRAF_ADDR =  GRAF_BIT_MASK
;*
;* OUTPUT        = DS:DI    --> next destination word
;*                 ES:DI    --> next destination word
;*                    CX     =  0
;*                 GRAF_ADDR =  GRAF_BIT_MASK
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
ega_inner_stosb::


        ret
end
