;*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.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = SCANLINE.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    PolyScanline
;*
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   02/22/87                     Written by Walt Moore [waltm] and Wes
;*                                Rupel [wesleyr]
;*   12/08/87                     Walt Moore [waltm] Added kludged test of the
;*                                COM_DRAW bit for IC support.
;*   04/13/88                     Bob Grudem [bobgru] Added MF_FGNOP_BKOPQ flag.
;*   08/01/88                     Bob Grudem [bobgru] Cursor exclusion done
;*                                outside of loops, to the bounding box of the
;*                                shortline structure. If all the clipping
;*                                rectangles are contained in the DDC, then
;*                                don't call off to get_clip_rects to get them.
;*   12/20/89                     Viroon Touranachun [viroont] Added 16
;*                                background mixmodes.
;*   05/08/89                     Lee A. Newberg [leen] Will correlate INFO DC's.
;*   09/06/92                     Tetsuro Nishimura [tetsu] Added COM_PRECLIP
;*                                handling
;*   11/26/92                     John Batty. Added DCAF changes.
;*   12/03/92              56855  David A Kerr [dkerr] Check grim reaper flag
;*                                for stress test defect switching screens.
;*
;*****************************************************************************/

        .386

        OPTION  OLDSTRUCTS

        .xlist

INCL_GRE_BITMAPS        equ     1
INCL_DDIMISC            equ     1
INCL_DDICOMFLAGS        equ     1
INCL_GPIREGIONS         equ     1
INCL_GPIBITMAPS         equ     1
INCL_GPIPRIMITIVES      equ     1
INCL_GRE_CLIP           equ     1
INCL_GRE_CLIP           equ     1
INCL_GRE_SCANS          equ     1
INCL_GPIREGIONS         equ     1
INCL_GPIERRORS          equ     1
INCL_DDIMISC            equ     1
INCL_DDICOMFLAGS        equ     1
DINCL_ROPS              equ     1
DINCL_ENABLE            equ     1
DINCL_BITMAP            equ     1
DINCL_EXTENDEDCONTROL   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
if SCAN_CNT EQ 768
        include oem_macs.inc
endif

        .list

        .MODEL FLAT,SYSCALL

        ASSUME  CS:FLAT,SS:FLAT,DS:FLAT,ES:FLAT


        .DATA


;/*
;** The next two constants define the mask and shift count for different
;** size accesses to the destination surface.  The high byte is the mask
;** to determine the pixel position within a data item.  The low byte
;** is the shift count for division, to determine which data item a pixel
;** is in.
;*/

PSL_BYTE_FETCH  equ     0703h           ;mask for modulus / shift count
PSL_WORD_FETCH  equ     0F04h


;/*
;** The following table is used to determine which drawing function
;** should be invoked for the inner loop bytes of the interval
;**
;** The table is indexed as follows:
;**
;**       000 x rrrr
;**
;**           |  |
;**           |   --------  raster op index
;**           |
;**            ----  transparent pixels if 1
;**
;**
;** The table can also be used to determine the drawing function
;** for the first and last bytes of the intervals by faking
;** transparent mode.
;**
;** All entries are the offset from the start of the raster
;** op drawing routines, which allows the table to be stored
;** as bytes instaed of words, saving 32 bytes.
;*/

proc_addr_tbl   label DWORD

        DWORD   OFFSET transp_ddx  ; - OFFSET rops_start
        DWORD   OFFSET transp_dpon ; - OFFSET rops_start
        DWORD   OFFSET transp_dpna ; - OFFSET rops_start
        DWORD   OFFSET transp_pn   ; - OFFSET rops_start
        DWORD   OFFSET transp_pdna ; - OFFSET rops_start
        DWORD   OFFSET transp_dn   ; - OFFSET rops_start
        DWORD   OFFSET transp_dpx  ; - OFFSET rops_start
        DWORD   OFFSET transp_dpan ; - OFFSET rops_start
        DWORD   OFFSET transp_dpa  ; - OFFSET rops_start
        DWORD   OFFSET transp_dpxn ; - OFFSET rops_start
        DWORD   OFFSET transp_d    ; - OFFSET rops_start
        DWORD   OFFSET transp_dpno ; - OFFSET rops_start
        DWORD   OFFSET transp_p    ; - OFFSET rops_start
        DWORD   OFFSET transp_pdno ; - OFFSET rops_start
        DWORD   OFFSET transp_dpo  ; - OFFSET rops_start
        DWORD   OFFSET transp_ddxn ; - OFFSET rops_start

;/*
;** The following table is used to map raster ops when the pattern
;** is all 1's or 0's.  All the rops can be mapped into one of
;** the following:
;**
;**       DDxn    DDx     Dn      D
;**
;**
;** based on the following results:
;**
;**
;**             Color     Result                Color     Result
;**
;**       DDx     0         0             DPa     0         0
;**               1         0                     1        dest
;**
;**       DPon    0       ~dest           DPxn    0       ~dest
;**               1         0                     1        dest
;**
;**       DPna    0        dest           D       0        dest
;**               1         0                     1        dest
;**
;**       Pn      0         1             DPno    0         1
;**               1         0                     1        dest
;**
;**       PDna    0         0             P       0         0
;**               1       ~dest                   1         1
;**
;**       Dn      0       ~dest           PDno    0       ~dest
;**               1       ~dest                   1         1
;**
;**       DPx     0        dest           DPo     0        dest
;**               1       ~dest                   1         1
;**
;**       DPan    0         1             DDxn    0         1
;**               1       ~dest                   1         1
;**
;**
;**
;** The table is indexed as follows:
;**
;**       000 rrrr c
;**
;**            |   |
;**            |   +----  color 0 = 1s, 1 = 0's
;**            |
;**            +--------  raster op index
;*/

map_1s_0s       label   byte
        db      ROP_DDX                 ;DDx    with all 0s
        db      ROP_DDX                 ;DDx    with all 1s
        db      ROP_DN                  ;DPon   with all 0s
        db      ROP_DDX                 ;DPon   with all 1s
        db      ROP_D                   ;DPna   with all 0s
        db      ROP_DDX                 ;DPna   with all 1s
        db      ROP_DDXN                ;Pn     with all 0s
        db      ROP_DDX                 ;Pn     with all 1s
        db      ROP_DDX                 ;PDna   with all 0s
        db      ROP_DN                  ;PDna   with all 1s
        db      ROP_DN                  ;Dn     with all 0s
        db      ROP_DN                  ;Dn     with all 1s
        db      ROP_D                   ;DPx    with all 0s
        db      ROP_DN                  ;DPx    with all 1s
        db      ROP_DDXN                ;DPan   with all 0s
        db      ROP_DN                  ;DPan   with all 1s
        db      ROP_DDX                 ;DPa    with all 0s
        db      ROP_D                   ;DPa    with all 1s
        db      ROP_DN                  ;DPxn   with all 0s
        db      ROP_D                   ;DPxn   with all 1s
        db      ROP_D                   ;D      with all 0s
        db      ROP_D                   ;D      with all 1s
        db      ROP_DDXN                ;DPno   with all 0s
        db      ROP_D                   ;DPno   with all 1s
        db      ROP_DDX                 ;P      with all 0s
        db      ROP_DDXN                ;P      with all 1s
        db      ROP_DN                  ;PDno   with all 0s
        db      ROP_DDXN                ;PDno   with all 1s
        db      ROP_D                   ;DPo    with all 0s
        db      ROP_DDXN                ;DPo    with all 1s
        db      ROP_DDXN                ;DDxn   with all 0s
        db      ROP_DDXN                ;DDxn   with all 1s


;/*
;** another_tbl contains various flags for the different raster ops
;**
;** MY_SINGLE_OK    rop can be performed in a single pass
;** NEG_PATTERN     pattern is to be negated before use
;** ALT_NEG_PATTERN same as above (different bit position for convenience)
;** NO_OBJECT       rop doesn't require an object (D, Dn, DDx, DDxn)
;** STOSB_OK        inner loop can use stosb
;*/

another_tbl     label   byte

        db      MY_SINGLE_OK+NO_OBJECT+STOSB_OK                         ;DDx
        db      ALT_NEG_PATTERN                                         ;DPon
        db      MY_SINGLE_OK+ALT_NEG_PATTERN                            ;DPna
        db      MY_SINGLE_OK+STOSB_OK+NEG_PATTERN+ALT_NEG_PATTERN       ;Pn
        db      0                                                       ;PDna
        db      MY_SINGLE_OK+NO_OBJECT                                  ;Dn
        db      MY_SINGLE_OK                                            ;DPx
        db      0                                                       ;DPan
        db      MY_SINGLE_OK                                            ;DPa
        db      MY_SINGLE_OK+ALT_NEG_PATTERN                            ;DPxn
        db      MY_SINGLE_OK+NO_OBJECT+STOSB_OK                         ;D
        db      MY_SINGLE_OK+ALT_NEG_PATTERN                            ;DPno
        db      MY_SINGLE_OK+STOSB_OK                                   ;P
        db      ALT_NEG_PATTERN                                         ;PDno
        db      MY_SINGLE_OK                                            ;DPo
        db      MY_SINGLE_OK+NO_OBJECT+STOSB_OK+ALT_NEG_PATTERN         ;DDxn

        .CODE
EXTERN ega_first_last :NEAR
EXTERN do_nothing     :NEAR
EXTERN do_nothing     :NEAR
EXTERN ega_first_last :NEAR
EXTERN ega_first_last :NEAR
EXTERN rops_start     :NEAR
EXTERN transp_ddx     :NEAR
EXTERN transp_dpon    :NEAR
EXTERN transp_dpna    :NEAR
EXTERN transp_pn      :NEAR
EXTERN transp_pdna    :NEAR
EXTERN transp_dn      :NEAR
EXTERN transp_dpx     :NEAR
EXTERN transp_dpan    :NEAR
EXTERN transp_dpa     :NEAR
EXTERN transp_dpxn    :NEAR
EXTERN transp_d       :NEAR
EXTERN transp_dpno    :NEAR
EXTERN transp_p       :NEAR
EXTERN transp_pdno    :NEAR
EXTERN transp_dpo     :NEAR
EXTERN transp_ddxn    :NEAR

EXTERN ega_inner_stosb     :NEAR
EXTERN ega_inner_latch          :NEAR

MF_LAST_PASS     equ    00000001b
MF_KILL_SL       equ    00000010b
MF_UNEXCLUDE     equ    00100000b
MF_USE_DDC_RECTS equ    01000000b
MF_SPECIAL_SOLID equ    10000000b

page

;/***************************************************************************
;*
;* FUNCTION NAME = PolyScanline
;*
;* DESCRIPTION   =
;*
;*        Short Line Header
;*              SHORTLINEHEADER struc
;*                  slh_usStyle     dw  ?
;*                  slh_usFormat            dw  ?
;*                  slh_ptsStart    dw  (SIZE POINTS)/2 dup (?)
;*                  slh_ptsStop     dw  (SIZE POINTS)/2 dup (?)
;*                  slh_sxLeft      dw  ?
;*                  slh_sxRight     dw  ?
;*                  slh_pslhNext    dd  ?
;*                  slh_pslhPrev    dd  ?
;*              SHORTLINEHEADER ends
;*        Short Line
;*              SHORTLINE struc
;*                  sl_slh          dw  (size SHORTLINEHEADER)/2 dup (?)
;*                  sl_ax           dw  1 dup (?)
;*              SHORTLINE ends
;*        ScanData
;*              SCANDATA struc
;*                  sd_pslFirstLeft  dd  ?
;*                  sd_pslLastLeft   dd  ?
;*                  sd_pslFirstRight dd  ?
;*                  sd_pslLastRight  dd  ?
;*                  sd_c       dd  ?
;*                  sd_rclBound      dw  (SIZE RECTL)/2 dup (?)
;*              SCANDATA ends
;*
;*
;*
;*
;*
;* INPUT         =
;*
;*
;*
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1,2 = Good,Good/Correlation
;* RETURN-ERROR  = AX = 0
;*
;**************************************************************************/

PolyScanline    PROC SYSCALL USES EBX edi esi,      hdc:DWORD, pScansData:DWORD,
                                                hddc:DWORD, FunN:DWORD
                LOCAL   arg_lp_ddc:DWORD,
                        loc_right_sl:DWORD,
                        loc_left_sl:DWORD,
                        loc_right_sl_ini:DWORD,
                        loc_left_sl_ini:DWORD,
                        loc_right_sl_x:DWORD,
                        loc_left_sl_x:DWORD
                LOCAL   loc_points:POINTL,
                        loc_sl_count:DWORD,
                        loc_sl_count_ini:DWORD,
                        loc_scan_count:DWORD,
                        loc_saved_y:DWORD,
                        loc_saved_y_unfliped:DWORD
                LOCAL   loc_next_plane:DWORD,
                        loc_raster_op:DWORD,
                        loc_bk_raster_op:DWORD,
                        loc_loop_control:DWORD,
                        loc_fetch_data:DWORD,
                        loc_bm_height:DWORD,
                        loc_current_rect:DWORD
                LOCAL   loc_scan_start:DWORD,
                        loc_control:EXTENDED_CONTROL,
                        loc_proc_offset:DWORD,
                        loc_sd_fb:BYTE,
                        loc_transparency_mask:DWORD,
                        loc_bk_transparency_mask:DWORD,
                        loc_some_flags:BYTE
                LOCAL   loc_moore_flags:BYTE,
                        loc_clean_up:BYTE,
                        loc_first_mask:DWORD,
                        loc_last_mask:DWORD,
                        loc_inner_loop_count:DWORD,
                        retcode:DWORD,
                        loc_processors[ BITS_PEL ]:cntrl_blk,
                        loc_bk_processors[ BITS_PEL ]:cntrl_blk
if SCAN_CNT EQ 768
                LOCAL   start_bank:DWORD
endif


;/*
;** PolyScanline only makes sense with the device locked, check it out!
;*/


        DebugMsg <PolyScanLine SCANLINE CLIFFL>

        cld

ifdef FIREWALLS

        INVOKE  check_sem

        or      eax,eax
        jz      @F

        rip     text,<PolyScanLine called without LockDevice>
@@:
endif
        INSURE_VISREGIONNOTIFY

        mov     esi,hddc                ; DS:[SI] --> DDC

        ddc?    esi

        mov     arg_lp_ddc,esi

        ASSUME  esi:PTR DDC

        mov     eax,[esi].ddc_iSysClr
        cmp     eax,ddcInit.ddc_iSysClr
        jz      sys_colors_are_good

        INVOKE  PropagateSysClrChange

        jmp     must_rerealize_brush

sys_colors_are_good:

        test    [esi].ddc_pa.pa_ba.ba_fb,BA_REREALIZE
        jz      scanline_brush_ok

must_rerealize_brush:

        lea     ebx,[esi].ddc_pa.pa_ba
        xor     cl,cl

        INVOKE  MakeBrushValid, eax         ;unused parameter

        or      eax,eax
        js      scanline_error_exit     ;Error logged by MakeBrushValid

scanline_brush_ok:

        mov     retcode,1               ; be an optimist

        test    [esi].ddc_fb,DDC_PRESENT
        jnz     scanline_bitmap_selected
        mov     eax,PMERR_BITMAP_NOT_SELECTED

        save_error_code

scanline_error_exit:

        xor     eax,eax
        jmp     scanline_get_out

scanline_bitmap_selected:

        cmp     [esi].ddc_crcsClip,0
        jnz     scanline_visible

scanline_short_exit:

        jmp     get_rc_and_leave

scanline_visible:

        test    FunN,COM_CORRELATE
        jz      scanline_correlate_done
        mov     ecx,RECTDIR_LFRT_BOTTOP-1
        lea     edi,pScansData
        mov     eax,pScansData
        add     eax,OFFSET SCANDATA.sd_rclBound

ifdef DCAF                                                           ;          
        ; We don't write anything to ulGlobalCOMFlags in this        ;          
        ; situation as we do not want any bounds accumulation.       ;          
endif ;DCAF                                                          ;          

        INVOKE  enumerate_clip_rects, esi, eax, ADDR do_sl_corr

        cmp     ecx,0
        je      scanline_correlate_done
        mov     retcode,ecx

scanline_correlate_done:

        test    [esi].ddc_fb,DDC_VISIBLE        ; rejects info ddc's
        jz      scanline_short_exit
        test    FunN,COM_DRAW
        jz      scanline_short_exit
        cmp     fGrimReaper,WE_BE_DEAD                            ;          
        jnz     @F                                                ;          
        test    [esi].ddc_fb,DDC_DEVICE                           ;          
        jnz     scanline_short_exit                               ;          
@@:

;/*
;** I have changed the arguments.  Some of the args are really gone,
;** like the draw_mode (for which the relevant data is pulled from
;** the ddc whenever it is needed).  Other args have been moved down
;** to be locals.  The data in the poly-short-lines will be read, a
;** scan at a time and put into *loc_lp_points (arg_lp_points used to
;** be an arg).  We will then loop around at this high level for each
;** scanline.
;**
;** I've taken the process described above a bit further, in particular
;** eliminating loc_lp_points entirely.
;*/

        mov     loc_moore_flags,0       ; clear all the moore flags
;/*
;** If the DDC contains all the clipping rectangles we'll need, set
;** a flag.  Doing this here lets us test a bit later on rather than
;** load DS:SI with the DDC twice.
;*/

        mov     eax,[esi].ddc_crcsClip
        or      eax,eax
        jz      outahere                ; no clip rects --> nothing visible
        cmp     eax,NUM_CLIP_RECTS
        ja      @F
        or      loc_moore_flags,MF_USE_DDC_RECTS
@@:
        mov     esi,[esi].ddc_npsd      ; get surface definition from ddc

        ASSUME  esi:PTR SURFACE

        mov     ecx,[esi].sd_cy         ; Save for flipping Y coord
        mov     loc_bm_height,ecx
;/*
;** If we're drawing to the device, then exclude the cursor from the
;** area to receive the bits.
;*/

        mov     al,[esi].sd_fb
        mov     loc_sd_fb,al            ; save sd_fb for later
        call    predigest_data
        jc      outahere
        test    loc_sd_fb,SD_DEVICE
        jz      @F
        call    scanline_device_init    ; cursor exclusion, etc.
        call    look_for_special_cases
@@:
        mov     esi,pScansData          ; DS:SI --> ScanData structure

        ASSUME  esi:PTR SCANDATA

        mov     eax,[esi].sd_c
        mov     loc_sl_count_ini,eax

        test    FunN,COM_PRECLIP                                   ;          
        jz      @F                                                 ;          
                                                                   ;          
;/*                                                                ;          
;** Set loc_current_rect to the scanline data bounding rectangle   ;          
;*/                                                                ;          
                                                                   ;          
        mov     eax,[esi].sd_rclBound.RECTL.rcl_xLeft              ;          
        mov     loc_control.ec_buffer.RECTL.rcl_xLeft,eax          ;          
                                                                   ;          
        mov     eax,[esi].sd_rclBound.RECTL.rcl_yBottom            ;          
        mov     loc_control.ec_buffer.RECTL.rcl_yBottom,eax        ;          
                                                                   ;          
        mov     eax,[esi].sd_rclBound.RECTL.rcl_xRight             ;          
        mov     loc_control.ec_buffer.RECTL.rcl_xRight,eax         ;          
                                                                   ;          
        mov     eax,[esi].sd_rclBound.RECTL.rcl_yTop               ;          
        mov     loc_control.ec_buffer.RECTL.rcl_yTop,eax           ;          
                                                                   ;          
        lea     eax,loc_control.ec_buffer                          ;          
        mov     loc_current_rect,eax                               ;          
                                                                   ;          
; Save the location of the first shortlines.                       ;          
                                                                   ;          
        mov     edi,[esi].sd_pslFirstLeft                          ;          
        mov     esi,[esi].sd_pslFirstRight                         ;          
        mov     loc_right_sl_ini,esi                               ;          
        mov     loc_left_sl_ini,edi                                ;          
                                                                   ;          
; We don't handle clipping rectangle                               ;          
                                                                   ;          
        or      loc_moore_flags,MF_LAST_PASS                       ;          
                                                                   ;          
        mov     eax,loc_sl_count_ini                               ;          
        mov     loc_sl_count,eax                                   ;          
                                                                   ;          
        jmp     got_both_sls                                       ;          
@@:                                                                ;          

;/*
;** If we're to get clip rects from the DDC, skip the initialization
;** of the loc_control variable.
;*/

        test    loc_moore_flags,MF_USE_DDC_RECTS
        jnz     copy_bounding_rect


;/*
;** There are more clip rects than fit in the DDC, so we have to call away
;** to get them in batches.  To do this we must set up some fields in the
;** ec_control structure that aren't needed if the rects come from the DDC.
;**
;** Fill in the Control Structure needed by get_clip_rects
;**
;** The field rgnrc_ircStart is updated at the bottom of the loop before
;** calling for the next batch of rects.
;**
;** DS:SI --> ScanData structure
;*/

        mov     loc_control.ec_control.rgnrc_ircStart,1
        mov     loc_control.ec_control.rgnrc_crc,NBR_RECTS
        mov     loc_control.ec_control.rgnrc_ulDirection,RECTDIR_LFRT_BOTTOP

;/*
;** Copy the scanline data bounding rectangle into our stack frame.  We'll
;** need it later to pass to get_clip_rects, or to do our own intersections
;** with clipping rectangles.
;*/

copy_bounding_rect:

        mov     eax,[esi].sd_rclBound.RECTL.rcl_xLeft
        mov     loc_control.ec_rect_bound.rcl_xLeft,eax

        mov     eax,[esi].sd_rclBound.RECTL.rcl_yBottom
        mov     loc_control.ec_rect_bound.rcl_yBottom,eax

        mov     eax,[esi].sd_rclBound.RECTL.rcl_xRight
        mov     loc_control.ec_rect_bound.rcl_xRight,eax

        mov     eax,[esi].sd_rclBound.RECTL.rcl_yTop
        mov     loc_control.ec_rect_bound.rcl_yTop,eax


;/*
;** Save the location of the first shortlines.
;*/

        mov     edi,[esi].sd_pslFirstLeft
        mov     esi,[esi].sd_pslFirstRight
        mov     loc_right_sl_ini,esi
        mov     loc_left_sl_ini,edi

;/*
;** If we're to get clip rects from the DDC, then go get them.
;*/

        test    loc_moore_flags,MF_USE_DDC_RECTS
        jz      get_rects_from_engine


;/*
;** We have all the rectangles we'll ever need right in the DDC.
;** Check for intersection of each clip rectangle with the scan data
;** bounding box.  Each intersecting rect gets copied into the ec_buffer
;** just as the engine would do it.  Also have to fill in rgnrc_crcReturned
;** for the fake-out to work.
;**
;** This code assumes that the clip rectangles in the DDC are stored
;** in order of moving up and to the right.
;*/

;/*
;** More work to do if these constants aren't the same.  NBR_RECTS is
;** the size of the batch the engine gives back.  NUM_CLIP_RECTS is the
;** number of rects stored in the DDC.
;*/


;/*
;** Source is RECTS, destination is RECTL:
;*/

        mov     esi,arg_lp_ddc

        ddc?    esi

        ASSUME  esi:PTR DDC

        mov     eax,[esi].ddc_crcsClip

        assert  eax,NE,0

        assert  eax,BE,NUM_CLIP_RECTS

        lea     edi,loc_control.ec_buffer
        mov     esi,[esi].ddc_prddc     ;GS:SI = RDDC
        add     esi,OFFSET RDDC.rddc_arcsClip

        ASSUME  esi:PTR RECTL

        xor     ebx,ebx                 ;assume no intersections

try_intersection:

        mov     edx,[esi].rcl_xLeft
        cmp     edx,loc_control.ec_rect_bound.rcl_xRight
        jge     next_rect

        mov     edx,[esi].rcl_xRight
        cmp     edx,loc_control.ec_rect_bound.rcl_xLeft
        jle     next_rect

        mov     edx,[esi].rcl_yBottom
        cmp     edx,loc_control.ec_rect_bound.rcl_yTop
        jge     next_rect

        mov     edx,[esi].rcl_yTop
        cmp     edx,loc_control.ec_rect_bound.rcl_yBottom
        jle     next_rect

        inc     ebx                     ;we had another intersection

        push    eax
ifdef DCAF
        ASSUME  esi:PTR RECTL                                        ;          
        ASSUME  edi:PTR RECTL                                        ;          
        ; The existing code merely copied the whole of any rectangle ;          
        ; which includes any of the bounds, into the 'fake' buffer.  ;          
        ; This is not the equivalent of the engine function which    ;          
        ; only copies the intersecting part.                         ;          
        ; Thus for the DCAF SCREEN bounds to work properly we must   ;          
        ; change this code to correctly mimic the engine.            ;          
        ; mov    eax,[esi].rcl_yTop                                  ;          
        mov     eax, edx          ; edx already holds what we want   ;          
        cmp     eax,loc_control.ec_rect_bound.rcl_yTop               ;          
        jl      @F                                                   ;          
        mov     eax,loc_control.ec_rect_bound.rcl_yTop               ;          
@@:                                                                  ;          
        mov     [edi].rcl_yTop,eax                                   ;          
                                                                     ;          
        mov     eax,[esi].rcl_xLeft                                  ;          
        cmp     eax,loc_control.ec_rect_bound.rcl_xLeft              ;          
        jg      @F                                                   ;          
        mov     eax,loc_control.ec_rect_bound.rcl_xLeft              ;          
@@:                                                                  ;          
        mov     [edi].rcl_xLeft,eax                                  ;          
                                                                     ;          
        mov     eax,[esi].rcl_yBottom                                ;          
        cmp     eax,loc_control.ec_rect_bound.rcl_yBottom            ;          
        jg      @F                                                   ;          
        mov     eax,loc_control.ec_rect_bound.rcl_yBottom            ;          
@@:                                                                  ;          
        mov     [edi].rcl_yBottom,eax                                ;          
                                                                     ;          
        mov     eax,[esi].rcl_xRight                                 ;          
        cmp     eax,loc_control.ec_rect_bound.rcl_xRight             ;          
        jl      @F                                                   ;          
        mov     eax,loc_control.ec_rect_bound.rcl_xRight             ;          
@@:                                                                  ;          
        mov     [edi].rcl_xRight,eax                                 ;          
                                                                     ;          
        ; Move to the next rectangle                                 ;          
        add     edi,size RECTL                                       ;          
else ; DCAF                                                          ;          
        push    esi
        mov     ecx,(size RECTL) / 4

rect_copy_loop:

        rep     movsd

        pop     esi
endif ; DCAF                                                         ;          
        pop     eax

next_rect:

        add     esi,size RECTL
        dec     eax
        jnz     try_intersection

        or      ebx,ebx
        jz      all_done_already

        mov     loc_control.ec_control.rgnrc_crcReturned,ebx
        jmp     got_the_rects

;/*
;** send_more_clip_rects
;**
;** This is the top of the outermost loop, where we call for batches of
;** clipping rectangles.  The field rgnrc_ircStart will have been set
;** as needed.
;*/

send_more_clip_rects:

get_rects_from_engine:

        mov     esi,arg_lp_ddc

        ddc?    esi

        push    ebp
        lea     ebp,loc_control         ; SS:BP -> extended control structure

        INVOKE  get_clip_rects          ; fill ec_buffer with clip rects

        pop     ebp
;/*
;** Now check how many rects we got.  If the buffer is not full then
;** we will set a flag to say this is the last pass -- we should not
;** call for more rects again.  If it returned no rects then we are
;** already done.
;*/

        mov     ecx,loc_control.ec_control.rgnrc_crcReturned
        cmp     ecx,NBR_RECTS

ifdef FIREWALLS

        jbe     its_good_joe

        rip     text,<More rectangles were returnd from get_clip_rects than were asked for>

its_good_joe:

endif
        jz      buffer_is_full
        cmp     ecx,0
        je      all_done_already        ; no more rects


;/*
;** If all the clipping rectangles were in the DDC, then we'll get here
;** without having called the engine, and we never expect to come back here.
;** We enforce this by setting the Moore flag to indicate this is the last
;** pass over the clip rects.
;**
;** We also get here if we called the engine for clip rects and it didn't
;** fill our buffer.
;*/

got_the_rects:

        or      loc_moore_flags,MF_LAST_PASS

buffer_is_full:

        lea     eax,loc_control.ec_buffer
        mov     loc_current_rect,eax

do_scans_data:

        mov     eax,loc_sl_count_ini
        mov     loc_sl_count,eax

        mov     edi,loc_left_sl_ini     ; ES:DI --> Left ShortLine
        mov     esi,loc_right_sl_ini    ; DS:SI --> Right ShortLine
        jmp     got_both_sls


;/*
;** Another one of those ubiquitous short jump way-stations.
;*/

all_done_already:               ; no more rects

        jmp     outahere

;/*
;** Get the next shortline structures for right and left sides.
;*/

next_shortline:

        mov     esi,loc_right_sl        ; current Right ShortLine struct
        mov     edi,loc_left_sl         ; current Left  ShortLine struct

        ASSUME  esi:PTR SHORTLINE, edi:PTR SHORTLINE

        mov     esi,[esi].sl_slh.slh_pslhNext ; next      Right ShortLine struct
        mov     edi,[edi].sl_slh.slh_pslhNext ; next      Left  ShortLine struct


got_both_sls:

ifdef DCAF                                                           ;          
;/*                                                                  ;          
;** All the rectangles we are currently processing are the clip      ;          
;** rectangles intersected with the engine provided bound of         ;          
;** the scanline data.                                               ;          
;** In the common case we will have a single clip rectangle, so      ;          
;** will only pass through here once.  Thus this case is no worse    ;          
;** than accumulating the engine provided bounding rectangle         ;          
;** outside of the per rectangle loop.  However we would hope to     ;          
;** gain when there are multiple clip rects, since we will have      ;          
;** to make more accumulation calls, but will be accumulating        ;          
;** smaller areas.                                                   ;          
;*/                                                                  ;          
                                                                     ;          
;/*                                                                  ;          
;** If COM_SCR_BOUND is not set, then skip DCAF code.                ;          
;*/                                                                  ;          
        test    FunN, COM_SCR_BOUND                                  ;          
        jz      screen_bound_considered                              ;          
                                                                     ;          
;/*                                                                  ;          
;** Save the contents of esi and edi.                                ;          
;*/                                                                  ;          
        pushem  esi,edi                                              ;          
;/*                                                                  ;          
;** Only 2 bits of the Command word are of interest to us.           ;          
;*/                                                                  ;          
        mov     edi, FunN                                            ;          
        and     edi, COM_SCR_BOUND or COM_DRAW                       ;          
                                                                     ;          
        mov     ebx,loc_current_rect                                 ;          
        ASSUME  ebx:PTR RECTL                                        ;          
        mov     eax,[ebx].rcl_xLeft                                  ;          
        mov     ecx,[ebx].rcl_xRight                                 ;          
        mov     edx,[ebx].rcl_yTop                                   ;          
        mov     ebx,[ebx].rcl_yBottom                                ;          
        dec     ecx                          ; make inclusive        ;          
        dec     edx                          ; make inclusive        ;          
;/*                                                                  ;          
;**                                                                  ;          
;** Make esi point to the ddc.                                       ;          
;*/                                                                  ;          
        mov     esi,arg_lp_ddc                                       ;          
;/*                                                                  ;          
;** (eax,ebx)-(ecx,edx) = inclusive rect to accumulate               ;          
;** esi = DDC, edi = Command                                         ;          
;*/                                                                  ;          
        call    InnerAccumulateBounds                                ;          
                                                                     ;          
        popem   esi,edi                                              ;          
                                                                     ;          
screen_bound_considered:                                             ;          
endif ; DCAF                                                         ;          

;/*
;** Save the location of our new shortlines.
;*/

        mov     loc_right_sl,esi
        mov     loc_left_sl,edi

        test    loc_moore_flags,MF_KILL_SL
        jz      no_kill_to_do
;/*
;** We must blow off the previous shortline-pair, never to be referenced
;** again.  We do this by advancing the "ini" local variables.
;*/

        and     loc_moore_flags,not MF_KILL_SL
        dec     loc_sl_count_ini
        mov     loc_right_sl_ini,esi
        mov     loc_left_sl_ini,edi

no_kill_to_do:

;/*
;** - - - - - - - - Get Start/Stop Y values - - - - - - - - - - - - - -
;** The Start and Stop Y values should match on the right and left.
;** If they don't we use a FireWall to catch Engine bugs.  Then we return
;** an error.
;*/

        mov     eax,[esi].sl_slh.slh_ptlStart.ptl_y     ; Check that start and stop

        assert  eax,E,[edi].sl_slh.slh_ptlStart.ptl_y ; Y coords match

        jmp     same_start_y

skip_this_shortline_forevermore:

        or      loc_moore_flags,MF_KILL_SL

skip_this_shortline:

        dec     loc_sl_count
        jnz     next_shortline

done_with_this_clip_rect:

        jmp     done_with_scans_data

same_start_y:

        xchg    ebx,eax
        mov     eax,[esi].sl_slh.slh_ptlStop.ptl_y ; BX = StartY, AX = StopY

        assert  eax,E,[edi].sl_slh.slh_ptlStop.ptl_y

        sub     eax,ebx                 ; scan count = StopY - StartY
        mov     loc_scan_count,eax

        lea     eax,[ebx-1]             ; -1 to balance INC below.
        mov     loc_saved_y_unfliped,eax
        mov     eax,loc_bm_height
        sub     eax,ebx                 ; flip Y coord (sd_cbScan - StartY)
        mov     loc_saved_y,eax

        test    FunN,COM_PRECLIP                        ;          
        jz      @F                                      ;          
                                                        ;          
        add     esi,OFFSET SHORTLINE.sl_ax              ; --> first scan right end
        add     edi,OFFSET SHORTLINE.sl_ax              ; --> first scan left end
                                                        ;          
        jmp     first_shortline_scan_visible            ;          
@@:

;/*
;** If this shortline-pair is completely out outside the clip rect then
;** we will skip to the next shortline-pair:
;**
;** bottom of shortline > top of clip-rect    =>  finished with this clip-rect
;** bottom of clip-rect > top of shortline    =>  skip this shortline forevermore
;** left   of shortline > right of clip-rect  =>  skip this shortline
;** left   of clip-rect > right of shortline  =>  skip this shortline
;**
;** By "forevermore" I mean "now and for all future rects".  We can do
;** this because the shortlines go right-then-up, as do the rects.
;** (we chose RECTDIR_LFRT_BOTTOP for the clip-rects for this reason).
;** To accomplish this we will advance the "ini" loc_ variables past
;** this shortline-pair.
;**
;** BX                  > top of clip-rect        =>  finished with this clip-rect
;** bottom of clip-rect > [si].slh_ptsStop.pts_y  =>  skip this shortline forevermore
;** es:[di].slh_sxLeft  > right of clip-rect      =>  skip this shortline
;** left   of clip-rect > ds:[si].slh_sxRight     =>  skip this shortline
;**
;** BX still has loc_saved_y_unfliped which (at this point) is the bottom scan
;*/

        xchg    eax,ebx         ; bottom of shortline -> AX
        mov     ebx,loc_current_rect

;/*
;** bottom of shortline > top of clip-rect  =>  finished with this clip-rect
;*/

        ASSUME  ebx:PTR RECTL

        cmp     eax,[ebx].rcl_yTop              ; top of clip-rect
        jg      done_with_this_clip_rect

;/*
;** bottom of clip-rect > top of shortline  =>  skip this shortline forevermore
;*/

        mov     eax,[ebx].rcl_yBottom   ; bottom of clip-rect
        cmp     eax,[esi].sl_slh.slh_ptlStop.ptl_y
        jg      skip_this_shortline_forevermore

;/*
;** left of shortline > right of clip-rect  =>  skip this shortline
;*/

        mov     eax,[edi].sl_slh.slh_lxLeft
        cmp     eax,[ebx].rcl_xRight    ; right of clip-rect
        jg      skip_this_shortline

;/*
;** left of clip-rect > right of shortline  =>  skip this shortline
;*/

        mov     eax,[ebx].rcl_xLeft     ; left of clip-rect
        cmp     eax,[esi].sl_slh.slh_lxRight
        jg      skip_this_shortline

        add     esi,OFFSET SHORTLINE.sl_ax              ; --> first scan right end
        add     edi,OFFSET SHORTLINE.sl_ax              ; --> first scan left end
;/*
;**---------------------------------------------------------------------------
;** Bottom of clip-rect minus StartY gives deltaY to first visible scan.
;*/

        mov     eax,[ebx].rcl_yBottom   ; bottom of clip-rect
        dec     eax
        mov     edx,eax
        sub     eax,loc_saved_y_unfliped                ; 36h - 35h
        jle     first_shortline_scan_visible
        mov     loc_saved_y_unfliped,edx        ; update StartY to first visible scan
        sub     loc_scan_count,eax      ; AX = DeltaY
        sub     loc_saved_y,eax
        shl     eax,2

        .errnz  (TYPE SHORTLINE.sl_ax) - 4

        add     esi,eax
        add     edi,eax

first_shortline_scan_visible:

;/*
;**---------------------------------------------------------------------------
;*/

        mov     loc_right_sl_x,esi
        mov     loc_left_sl_x,edi

        CALL    do_shortline_pair

        dec     loc_sl_count
        jnz     next_shortline

        test    FunN,COM_PRECLIP                             ;          
        jnz     finished_rect_buffer                         ;          

done_with_scans_data:   ; for this clip-rect

;/*
;** Check if another clip-rect exists
;*/

        add     loc_current_rect,SIZE RECTL      ; advance for next rect
        dec     loc_control.ec_control.rgnrc_crcReturned        ; dec rect_count
        jz      finished_rect_buffer
        jmp     do_scans_data                    ; another rect exists

finished_rect_buffer:

        test    loc_moore_flags,MF_LAST_PASS
        jnz     outahere
        add     loc_control.ec_control.rgnrc_ircStart,NBR_RECTS
        jmp     send_more_clip_rects

outahere:

        call    scanline_reset_ega
        test    loc_moore_flags,MF_UNEXCLUDE
        jz      get_rc_and_leave

        INVOKE  far_unexclude

get_rc_and_leave:

        mov     eax,retcode             ; Make AX nonzero to show success

scanline_get_out:

                RET

OPTION EPILOGUE:NONE


                OPTION  PROLOGUE:None
                OPTION  EPILOGUE:None

;/***************************************************************************
;*
;* PUBLIC ROUTINE   scanline_device_init
;*
;* DESCRIPTION   =  Cursor Exclusion, setting of CleanUp flags, etc.
;*
;*                  Registers Preserved:
;*                        BP
;*                  Registers Destroyed:
;*                        AX,BX,CX,DX,SI,DI,DS,ES,FLAGS
;*
;* INPUT         = NONE
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

scanline_device_init:

;/*
;** Set the clean_up flags:
;** CU_EXCLUDE      Shows that the exclusion rectangle may have been set
;** CU_PLANE_SEL    EGA plane selection will be required in the main loop
;**                 (if we determine otherwise later, we'll clear it).
;** CU_REGS         Reset EGA to default state upon exit.
;*/

        mov     loc_clean_up,CU_EXCLUDE+CU_PLANE_SEL+CU_REGS
        mov     loc_next_plane,0           ; Index to next plane == 0 for EGA
;/*
;** Selector of our drawing surface will not change since it is the device
;** and the surface is not huge.  Therefore we can fill it in now:
;*/

        mov     esi,arg_lp_ddc

        ddc?    esi

        ASSUME  esi:PTR DDC

        mov     esi,[esi].ddc_npsd

        ASSUME  esi:PTR SURFACE

        mov     edx,[esi].sd_pBits
        mov     loc_scan_start,edx
;/*
;** Use the scandata bounding box as the exclusion rectangle.
;** !!! This code assumes that the bounding rect consists of 16-bit integers.
;*/

        mov     ebx,pScansData          ; DS:SI --> ScanData structure

        ASSUME  ebx:PTR SCANDATA

        mov     eax,[ebx].sd_rclBound.RECTL.rcl_xLeft
        mov     esi,[ebx].sd_rclBound.RECTL.rcl_xRight
        mov     edi,[ebx].sd_rclBound.RECTL.rcl_yBottom
        mov     ebx,[ebx].sd_rclBound.RECTL.rcl_yTop

;/*
;** Clip all the coordinates to 0.
;*/

        cdq
        not     edx
        and     eax,edx
        xchg    eax,ecx                 ; CX = left

        xchg    eax,ebx
        cdq
        not     edx
        and     eax,edx
        xchg    eax,ebx                 ; BX = top

        xchg    eax,esi
        cdq
        not     edx
        and     eax,edx
        xchg    eax,esi                 ; SI = right

        xchg    eax,edi
        cdq
        not     edx
        and     eax,edx
        xchg    eax,edi                 ; DI = bottom

;/*
;** Flip the y coordinates.
;*/

        neg     ebx
        add     ebx,loc_bm_height
        neg     edi
        add     edi,loc_bm_height

        mov     edx,ebx                 ; top is supposed to be here

        INVOKE  far_exclude             ; destroys all registers except BP

        or      loc_moore_flags,MF_UNEXCLUDE

        ret


page

;/***************************************************************************
;*
;* PUBLIC ROUTINE  predigest_data
;*
;* DESCRIPTION   = Get All Data Required For Filling The Scan
;*
;*                 Registers Preserved:
;*                       ES,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,SI,DI,DS,FLAGS
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 'C' Carry Flag Set if nothing to do.  Clear means continue.
;* RETURN-ERROR  = 'C' set if to abort
;*                 DS:DI = ddc
;*
;**************************************************************************/

predigest_data::

        mov     edi,arg_lp_ddc

        ddc?    edi
;/*
;** Get the foreground and background mix modes.  If they are both
;** LeaveAlone, then there is no work to do for this scanline,
;** so return with the carry flag set.
;*/


        ASSUME  edi:PTR DDC

        mov     dx,WORD PTR [edi].ddc_pa.pa_ba.ba_bmix  ;Get the foreground
        mov     al,dh                           ; and background mix mode

        .errnz  BASIC_ATTRS.ba_bkmix-BASIC_ATTRS.ba_bmix-1

        and     edx,000Fh                       ; (play it safe) ;!!!magic#
        mov     loc_raster_op,edx               ;save a copy of foregnd mixmode
        and     eax,000Fh                       ; (play it safe) ;!!!magic#
        mov     loc_bk_raster_op,eax            ;save a copy of backgnd mixmode

        cmp     dl,ROP_D                        ;is foreground LeaveAlone?
        jne     pdd_work_to_do                  ;if not, can't exit early
        cmp     al,ROP_D                        ;is background LeaveAlone?
        stc
        jz      pdd_exit                        ;if so exit early

;/*
;** Set loc_loop_control to MONO_OP or COLOR_OP to indicate number of
;** planes to draw to.  Also set INDEX_MONO in loc_some_flags.
;**
;** loc_loop_control can change on a scanline basis depending on what the
;** background bits are for that scan, etc (special casing allows us to
;** sometimes treat the EGA as a MONO device).
;** That is why we keep INDEX_MONO in loc_some_flags; it won't change.
;*/

pdd_work_to_do:

        mov     eax,MONO_OP + (INDEX_MONO shl 8)
        test    loc_sd_fb,SD_COLOR      ; Is dest color?
        jz      @F
        mov     eax,COLOR_OP + (0 shl 8)
@@:
        mov     loc_some_flags,ah       ; Save the dispatch index for later
        movzx   eax,al
        mov     loc_loop_control,eax    ; loop control flags (count)

        clc

pdd_exit:

        ret

;/***************************************************************************
;*
;* PUBLIC ROUTINE look_for_special_cases
;*
;* DESCRIPTION   = Set up the EGA/VGA regs appropriately if a special case
;*                 exists.  Currently we just do "solid color".
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

look_for_special_cases:

        mov     edi,arg_lp_ddc

        ddc?    edi

        test    [edi].ddc_pa.pa_fb,PA_SINGLE_CLR ; Solid hardware Color?
        jz      sc_exit

sc_check_forground:

        cmp     BYTE PTR loc_raster_op,ROP_P
        jnz     sc_check_background

        mov     ebx,SIZE_PATTERN - 1
@@:     cmp     BYTE PTR [edi].ddc_pa.pa_abMask[ebx],0FFh       ; TransparencyMask
        jnz     sc_check_background             ; Maybe background
        dec     ebx
        jns     @B                              ; use repz scasb?
        xor     esi,esi                         ; index to foregrnd blocks
        jmp     sc_solid_brush

sc_check_background:

        cmp     BYTE PTR loc_bk_raster_op,ROP_P
        jnz     sc_exit

        mov     ebx,SIZE_PATTERN - 1
        ASSUME EBX:NOTHING
@@:     cmp     BYTE PTR [edi].ddc_pa.pa_abMask[ebx],00h        ; TransparencyMask
        jnz     sc_exit                         ; no spec case if foregrnd bits
        dec     ebx
        jns     @B                              ; use repz scasb?
        mov     esi,-(BITS_PEL * (SIZE cntrl_blk)) ; index to backgrnd blocks


;/*
;** Set the control block parameters for both foreground and background
;*/

sc_solid_brush:

        ASSUME  esi:PTR cntrl_blk

        mov     loc_processors[MONO_DATA][esi].first_last_proc,OFFSET ega_first_last ; is stosb OK?!
        mov     loc_processors[MONO_DATA][esi].inner_loop_proc,OFFSET ega_inner_stosb
        and     loc_processors[MONO_DATA][esi].nop_flag,not NF_NOP
        add     esi,BITS_PEL * (SIZE cntrl_blk)
        neg     esi                              ; switch to the other one
        mov     loc_processors[MONO_DATA][esi].first_last_proc,OFFSET do_nothing
        mov     loc_processors[MONO_DATA][esi].inner_loop_proc,OFFSET do_nothing
        or      loc_processors[MONO_DATA][esi].nop_flag,NF_NOP

;/*
;** Set up the EGA/VGA regs here we will be painting a solid color.
;*/

        mov     edx,EGA_BASE + GRAF_ADDR
        mov     ah,BYTE PTR [edi].ddc_pa.pa_ba.ba_ipc.ipc_bClr[0]
        and     ah,MM_ALL
        mov     al,GRAF_SET_RESET
        out     dx,ax
        mov     eax,MM_ALL shl 8 + GRAF_ENAB_SR
        out     dx,ax                   ;Enable all planes for set/reset

;/*
;** Leave the Graphics Controller address register pointing to
;** the Bitmask register, show that the operation must occur,
;** that plane selection isn't needed, and that only one loop is required.
;*/

        mov     dl,GRAF_ADDR
        mov     al,GRAF_BIT_MASK
        out     dx,al
        and     loc_clean_up,not CU_PLANE_SEL
        mov     loc_loop_control,MONO_OP
        mov     loc_fetch_data,PSL_BYTE_FETCH
        or      loc_moore_flags,MF_SPECIAL_SOLID

sc_exit:

        ret


;/***************************************************************************
;*
;* PUBLIC ROUTINE  scanline_reset_ega
;*
;* DESCRIPTION   = Restores EGA to default state.  To be called after last
;*                 use of EGA.
;*
;*                 Registers Destroyed:
;*                       AX,DX
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

scanline_reset_ega:

        mov     al,loc_clean_up
        or      al,al
        jz      no_clean_up_needed

        .errnz  CU_NONE

        jns     no_clean_up_needed      ; No registers need cleaning up

        .errnz  CU_REGS - 80h

        mov     edx,EGA_BASE + SEQ_DATA
        mov     eax,MM_ALL
        out     dx,al
        mov     dl,GRAF_ADDR
        mov     al,GRAF_ENAB_SR
        out     dx,ax
        mov     al,GRAF_DATA_ROT
        out     dx,ax

        .errnz  DR_SET

        mov     eax,0FF00h+GRAF_BIT_MASK
        out     dx,ax

no_clean_up_needed:

        ret

;/***************************************************************************
;*
;* PUBLIC ROUTINE  do_shortline_pair
;*
;* DESCRIPTION   = Draws a pair of lines
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

public do_shortline_pair
do_shortline_pair::

        test    loc_sd_fb,SD_DEVICE
        jz      itsa_bitmap         ; this optimization not implem. for bitmaps

;/*
;** Compute and save the starting scan address (offset only, it's the device sel)
;*/

        mov     ecx,loc_saved_y

if SCAN_CNT EQ 768
        dec     ecx
        mov     loc_saved_y,ecx
endif

        mov     eax,SCREEN_CBSCAN       ;Faster to multiply on a 286
        mul     ecx                     ;  than doing explicit shifts


if SCAN_CNT EQ 768

        shld    edx,eax,16
        mov     start_bank,edx

        mov     edi,arg_lp_ddc
        ASSUME  edi:NOTHING
        mov     edi,[edi].DDC.ddc_npsd

        and     eax,0ffffh
        add     eax,[edi].SURFACE.sd_pBits
        mov     loc_scan_start,eax      ;Save address of scan

        SetBankRW

        jmp     skip_first_time

itsa_bitmap:

next_scanline:

        dec     loc_saved_y             ; Set Y for next scanline
        test    loc_sd_fb,SD_DEVICE
        jz      @f

        mov     eax,loc_saved_y
        inc     eax
        cmp     eax,SCREEN_LPB  ;same as cmp loc_saved_y,SCREEN_LPB-1
        jne     @f
        add     loc_scan_start,010000h
        mov     edx,start_bank
        dec     edx
        SetBankRW
@@:
skip_first_time:

else

        assert  edx,E,0

        sub     eax,SCREEN_CBSCAN
        mov     edi,arg_lp_ddc

        ASSUME  edi:NOTHING

        mov     edi,[edi].DDC.ddc_npsd
        add     eax,[edi].SURFACE.sd_pBits
        mov     loc_scan_start,eax      ;Save address of scan

itsa_bitmap:

next_scanline:

        dec     loc_saved_y             ; Set Y for next scanline


endif ;768

        mov     eax,loc_saved_y_unfliped
        inc     eax
        mov     loc_saved_y_unfliped,eax

        mov     edi,loc_current_rect

        ASSUME  edi:PTR RECTL

        cmp     eax,[edi].rcl_yTop      ; top of clip-rect
        jae     this_scan_done          ;!!! actually, this whole shortline is done

        mov     esi,loc_right_sl_x              ; DS:SI --> next right edge
        cld
        lodsd
        mov     edx,eax
        mov     loc_right_sl_x,esi

        mov     esi,loc_left_sl_x               ; DS:SI --> next left edge
        lodsd
        mov     loc_left_sl_x,esi

;/*
;** Check if the right-edge is actually left of the left-edge.
;*/

        cmp     eax,edx
        jg      points_misordered
        jl      points_order_okay

this_scan_done:

        jmp     do_scans_done

points_misordered:

        xchg    eax,edx

points_order_okay:

;/*
;** left edge is MAX ( AX , clip box left edge )
;*/

        mov     ebx,[edi].rcl_xLeft
        imax    eax,ebx

;/*
;** right edge is MIN ( DX , clip box right edge )
;*/

        mov     ecx,[edi].rcl_xRight
        imin    edx,ecx

;/*
;** Was the line completely outside the clip box?
;*/

        cmp     eax,edx
        jge     this_scan_done

        mov     loc_points.ptl_x,eax
        mov     loc_points.ptl_y,edx    ; "pts_y" is really 2nd X coord
;/*
;** Draw the scanline.  If get_fill_data returns with the carry set, then
;** there is no more work to do for this scanline, so go on to the next one.
;*/

        test    loc_sd_fb,SD_DEVICE
        jnz     device_comp_scan_done

        CALL    comp_scan_for_bitmap    ;Compute scanline for bitmap

device_comp_scan_done:

;/*
;** !!NOTE!!: There are two groups of parameters which are initialized by
;**           get_fill_data and comp_interval.
;**
;**               1) Parameters which are dependent on foreground/background:
;**                   their values are distinguished by colors and mixmode, so
;**                   we need two sets of them, ie.
;**                       loc_raster_op           loc_bk_raster_op
;**                       loc_transparency_mask   loc_bk_transparency_mask
;**                       loc_processors          loc_bk_processors
;**
;**               2) Parameters which are independent of foreground/background:
;**                   their values are dependent on the environment of operation,
;**                   such as device/bitmap, size of filled scanline, etc.
;**                   Therefore, both foreground and background will share the
;**                   same set of parameters. If the 2nd get_fill_data will
;**                   ever override the values intialized by the 1st call,
;**                   their values are still consistent. These parameters are:
;**                       loc_loop_control        loc_inner_loop_count
;**                       loc_first_mask          loc_last_mask
;**                       loc_clean_up
;**
;** Set parameters for foreground mixmode
;*/

        and     loc_some_flags,NOT (INDEX_BLNK_FORGRND OR INDEX_BLNK_BKGRND OR INDEX_BKGRD)

        CALL    get_fill_data           ;Get data for filling foreground

        jnc     do_get_bk_fill_data     ;get_fill_data aborted for some reason
        or      loc_some_flags,INDEX_BLNK_FORGRND

;/*
;** Set parameters for background mixmode.
;*/

do_get_bk_fill_data:

        or      loc_some_flags,INDEX_BKGRD
        mov     eax,loc_raster_op
        xchg    eax,loc_bk_raster_op     ;Pretend the background is foreground
        mov     loc_raster_op,eax
        mov     eax,loc_transparency_mask
        mov     loc_bk_transparency_mask,eax

        CALL    get_fill_data           ;Get data for filling background

        mov     eax,loc_raster_op
        xchg    eax,loc_bk_raster_op
        mov     loc_raster_op,eax        ;Restore raster_op in the right place
        jnc     do_restore_parm         ;get_fill_data aborted for some reason
        test    loc_some_flags,INDEX_BLNK_FORGRND
        jnz     do_scans_done
        or      loc_some_flags,INDEX_BLNK_BKGRND

do_restore_parm:

        mov     eax,loc_transparency_mask
        xchg    eax,loc_bk_transparency_mask
        mov     loc_transparency_mask,eax ;Restore mask in the right place
        call    comp_interval           ;Get next interval to fill
        jc      do_scans_done           ;No more points, exit
        mov     esi,loc_loop_control    ;Set looping control (C3=>C2=>C1=>C0)
                                        ;  or C0 for mono and special EGA
scan_next_plane:

        sub     esi,size cntrl_blk      ;--> Set next plane's data
        js      do_scans_done           ;No more planes, get next interval
        add     edi,loc_next_plane      ;DS:DI, ES:DI --> first byte, next plane

        CALL  draw_one_plane_of_scan

        jmp     scan_next_plane


do_scans_done:                  ; We're done with the current scanline

        test    loc_moore_flags,MF_SPECIAL_SOLID
        jnz     go_to_next_scan
        cmp     loc_clean_up,CU_NONE
        jz      go_to_next_scan

        CALL    scanline_reset_ega

go_to_next_scan:

        sub     loc_scan_start,SCREEN_CBSCAN
        dec     loc_scan_count
        jz      done_with_sl_pair
        jmp     next_scanline

done_with_sl_pair:

        ret

;/***************************************************************************
;*
;* PUBLIC ROUTINE  draw_one_plane_of_scan
;*
;* DESCRIPTION   = draws a single plane of a scan
;*
;*                 Registers Preserved:
;*                       SI,DI,BP,DS,ES
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX
;*
;* INPUT         = BP --> PolyScanline stack frame
;*                 SI  =  index to current plane in array of processor blocks
;*                 DI --> starting address of scan
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

draw_one_plane_of_scan::

        test    loc_clean_up,CU_PLANE_SEL       ;EGA plane selection needed?
        jz      dops_do_first                   ;None needed
        mov     edx,EGA_BASE + SEQ_DATA
        assume  esi:NOTHING
        mov     al,loc_bk_processors[esi].plane_map_mask ; Assume no foregrnd
        test    loc_some_flags,INDEX_BLNK_FORGRND        ; Is it true?
        jnz     @F                                       ; yes, use bkgrnd info
        mov     al,loc_processors[esi].plane_map_mask    ; no, must use foregrnd
@@:
        out     dx,al
        shr     al,1

        cmp     al,100b                 ;Set 'C' if not C3
        adc     al,-1                   ;Sub 1 only if C3

        mov     ah,al
        mov     al,GRAF_READ_MAP
        mov     dl,GRAF_ADDR
        out     dx,ax

dops_do_first:

        test    loc_some_flags,INDEX_BLNK_FORGRND
        jnz     dops_bk_do_first
        test    loc_processors[esi].nop_flag,NF_NOP  ;it is worth checking here
        jnz     dops_bk_do_first                     ;ROP is a nop, skip it
        push    edi                                  ;Have to save starting address
        mov     bl,loc_processors[esi].pattern
        mov     bh,bl
        mov     eax,loc_first_mask
        or      eax,eax
        jz      dops_do_inner
        and     eax,loc_transparency_mask
        mov     ecx,1

        CALL    loc_processors[esi].first_last_proc

dops_do_inner:

        mov     ecx,loc_inner_loop_count              ;If no inner loop, skip it
        cmp     ecx,0
        je      dops_do_last
        mov     eax,loc_transparency_mask

        CALL    loc_processors[esi].inner_loop_proc

dops_do_last:

        mov     eax,loc_last_mask
        or      eax,eax
        jz      dops_do_foregrnd_end
        and     eax,loc_transparency_mask
        mov     ecx,1

        CALL    loc_processors[esi].first_last_proc

dops_do_foregrnd_end:

        pop     edi
;/*
;** At this point, there is no need to do the plane selection (if needed).
;** If there is no foreground job, EGA was already plane-selected.
;** Otherwise, although EGA was plane-selected with the information in
;** foreground structure, it is identical for background plane.
;*/

dops_bk_do_first:

        test    loc_some_flags,INDEX_BLNK_BKGRND
        jnz     dops_exit
        test    loc_bk_processors[esi].nop_flag,NF_NOP
        jnz     dops_exit               ;ROP is a nop, skip it
        push    edi                     ;Have to save starting address
        mov     bl,loc_bk_processors[esi].pattern
        mov     bh,bl
        mov     eax,loc_first_mask
        or      eax,eax
        jz      dops_bk_do_inner
        and     eax,loc_bk_transparency_mask
        mov     ecx,1

        CALL    loc_bk_processors[esi].first_last_proc

dops_bk_do_inner:

        mov     ecx,loc_inner_loop_count ;If no inner loop, skip it
        cmp     ecx,0
        je      dops_bk_do_last
        mov     eax,loc_bk_transparency_mask

        CALL    loc_bk_processors[esi].inner_loop_proc

dops_bk_do_last:

        mov     eax,loc_last_mask
        or      eax,eax
        jz      dops_restore_pointer
        and     eax,loc_bk_transparency_mask
        mov     ecx,1

        CALL    loc_bk_processors[esi].first_last_proc

dops_restore_pointer:

        pop     edi

dops_exit:

        ret

;/***************************************************************************
;*
;* PUBLIC ROUTINE   comp_scan_for_bitmap
;*
;* DESCRIPTION   =  the starting Y.
;*
;*                  The default looping logic and plane increment values will
;*                  be set.
;*
;*                  Registers Preserved:
;*                        BP
;*                  Registers Destroyed:
;*                        AX,BX,CX,DX,SI,DI,DS,FLAGS
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = CL = loop_control flag
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

comp_scan_for_bitmap::

        mov     loc_clean_up,CU_NONE    ;Show no clean-up needed
        mov     eax,loc_saved_y         ; I set saved_y earlier  --Wes

        mov     esi,arg_lp_ddc

        ddc?    esi

        xor     edx,edx                 ;Set segment bias to 0

        ASSUME  esi:PTR DDC

        mov     esi,[esi].ddc_npsd      ;get the surface definition from ddc

        ASSUME  esi:PTR SURFACE

        test    [esi].sd_fb,SD_HUGE
        jz      cs_for_bitmap_40

;/*
;** If this is a monochrome memory DC, set up
;** the inner loop so that it will terminate after one time through
;** and set the color to be equal to the mono bit in the physical
;** color.  If it is color, set up the inner loop for all planes.
;**
;**       Currently:
;**               AX     =  Y coordinate
;**               DX     =  Segment bias for huge bitmaps
;**               DS:SI --> display surface structure
;*/

cs_for_bitmap_40:

        mov     edi,[esi].sd_cbScan     ;Get index to next plane
        mov     ebx,edi                 ;  (and Y multiplier)
        mov     cl,MONO_OP              ;Assume mono loop
        test    [esi].sd_fb,SD_COLOR
        jz      @F
        mov     cl,COLOR_OP             ;Show color loop
        add     eax,eax                 ;Compute Y to use for offset calculation
        add     eax,eax

        .errnz  BITS_PEL - 4

@@:
        mul     ebx                     ;Compute start of scan

        add     eax,[esi].sd_pBits      ;!!! needed until bitblt     is fixed

;/*
;** The looping logic always adds in next_scan at the start of
;** the loop.  This is countered now by biasing the scan lines
;** starting address by this amount.
;*/

        sub     eax,edi                 ;Bias offset for looping logic
        mov     loc_scan_start,eax      ;Save address of scan
        mov     loc_next_plane,edi      ;Save index to next plane

        ret

page

;/***************************************************************************
;*
;* PUBLIC ROUTINE  get_fill_data
;*
;* DESCRIPTION   = Get All Data Required For Filling The Scan
;*
;*                 Registers Preserved:
;*                       ES,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,SI,DI,DS,FLAGS
;*
;* INPUT         = INDEX_BKGRND flag set to 0 for foreground
;*                 INDEX_BKGRND flag set to 1 for background
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 'C' clear
;* RETURN-ERROR  = 'C' set if to abort
;*
;**************************************************************************/

get_fill_data::

        mov     edi,arg_lp_ddc

        ddc?    edi
;/*
;** Combine the pattern foreground color and accelerator flags (we only
;** use the PA_SINGLE_CLR flag).  Save local copy of the transparency mask
;** for the correct scan of the brush.
;*/

        xor     ecx,ecx

        ASSUME  edi:PTR DDC

        movzx   eax,BYTE PTR [edi].ddc_pa.pa_ba.ba_ipc.ipc_bClr[0]
        test    loc_some_flags,INDEX_BKGRD
        jz      gfd_brush_acc
        movzx   eax,BYTE PTR [edi].ddc_pa.pa_ba.ba_ipcBack.ipc_bClr[0]
        dec     ecx

gfd_brush_acc:

        and     al,MM_ALL or MONO_BIT or ONES_OR_ZEROS
        mov     ah,[edi].ddc_pa.pa_fb
        and     ah,PA_SINGLE_CLR
        or      ah,al

        .errnz  PA_SINGLE_CLR and (MM_ALL or MONO_BIT or ONES_OR_ZEROS)

        mov     ebx,loc_bm_height       ;Correct for the fact we align top left
        neg     ebx                     ;  instead of bottom left
        add     bl,byte ptr [edi].ddc_pa.pa_ptsOrg.ptl_y
        add     bl,byte ptr loc_saved_y ;The current Y scan dictates which
        and     ebx,00000111b           ;  scan of brush to use
        mov     al,BYTE PTR [edi].ddc_pa.pa_abMask[ebx]
        xor     al,cl                   ;Must invert mask if background
        movzx   edx,al
        mov     dh,al
        mov     loc_transparency_mask,edx

;/*
;** All the parameters are already set if it is solid brush. So exit
;*/

gfd_special_cases:

        test    loc_moore_flags,MF_SPECIAL_SOLID
        jnz     gfd_exit                ;No, not a special case

;/*
;** Since we are now in a very good occasion (CX = FFFFh if background, and
;** 0 otherwise), we can calculate the offset of the first control element
;** right here. Specifically, we need:
;**
;**       loc_proc_offset = 0                         ;for foreground mixmode
;**                       = BITS_PEL*(SIZE cntrl_blk) ;for background mixmode
;*/

gfd_calc_offset:

ifdef FIREWALLS

        push    eax
        lea     eax,loc_processors
        lea     edx,loc_bk_processors
        sub     eax,edx
        sub     eax,BITS_PEL * (SIZE cntrl_blk)
        jz      @F

        rip     text,<SCANLINE: Non adjacent processor blocks>
@@:
        pop     eax

endif;FIREWALLS

        and     ecx,-(BITS_PEL * (SIZE cntrl_blk))
        mov     loc_proc_offset,ecx

;/*
;** Two conditions allow us to exit early:
;**
;**    If the transparency mask is all 1's, and the foreground mix mode
;**    is D (i.e. NOP), then there's no work to do on this scanline.
;**
;**    If the background is LeaveAlone, but the transparency mask is all
;**    0's, then neither any foreground nor background bits are visible,
;**    so signal the caller that this scanline is done.
;**
;** Currently:
;**       AL = transparency mask
;**       AH = brush accelerators
;**       BX = current scan of brush
;*/

        or      loc_some_flags,INDEX_XPARENT    ;Assume any hole is XPARENT
        cmp     al,0FFh
        jne     gfd_check_background_mix
        and     loc_some_flags,NOT INDEX_XPARENT;But there is no hole
        cmp     byte ptr loc_raster_op,ROP_D
        je      gfd_exit_with_carry

gfd_check_background_mix:

        or      al,al
        jnz     gfd_gather_colors

gfd_exit_with_carry:

        stc
        jmp     gfd_exit


;/*
;** Gather up the color bits for the current scan of the brush.  If
;** we're writing to a mono bitmap, only bother with the mono plane's
;** bits.
;**
;** Four of the Rops do not require an object (D, Dn, DDx, DDxn).
;** If the current rop is one of these, then we want to show
;** that the pattern is solid so that special case code can
;** kick in regardless of what pattern was given.
;**
;** Currently:
;**       AL = transparency mask
;**       AH = brush accelerator flags
;**       BX = current scan of brush
;**       DI = DDC
;*/

gfd_gather_colors:



        mov     ch,al                   ;may need mask again soon
        mov     dl,BYTE PTR [edi].ddc_pa.pa_abMono[ebx]
        test    loc_some_flags,INDEX_MONO
        jnz     @F

        mov     al,ah                                   ;save brush accelerators
        mov     esi,[edi].ddc_pa.pa_abColor
        mov     dl,BYTE PTR [esi][ebx]         ; .ipb_abPlane0
        mov     dh,BYTE PTR [esi][ebx + SIZE_PATTERN]       ; .ipb_abPlane1
        mov     cl,BYTE PTR [esi][ebx + SIZE_PATTERN * 2]       ; .ipb_abPlane2
        mov     bl,BYTE PTR [esi][ebx + SIZE_PATTERN * 3]       ; .ipb_abPlane3

@@:                                     ;Test if pattern required
        mov     esi,loc_raster_op
        mov     ah,another_tbl[esi]     ;These flags will be useful
        test    ah,NO_OBJECT            ;Is an object required?
        jz      gfd_we_have_colors      ;If yes, not one of the rops

;/*
;** If we have an object-less rop, set foreground pattern bits to black.
;** The rop may cause the foreground bits to be inverted to white.
;*/

        not     ch                      ;invert transparency mask
        and     bl,ch                   ;isolate background bits in each
        and     cl,ch                   ;  color plane
        and     dl,ch                   ; 
        and     dh,ch                   ; 
        xor     al,al                   ;clear all brush accelerators
;/*
;** Determine whether or not to set the PA_SINGLE_CLR and ONES_OR_ZEROS
;** accelerator bits.  PA_SINGLE_CLR is set if all planes are either
;** 0 or FF.  ONES_OR_ZEROS is set if PA_SINGLE_CLR is set and all planes
;** are identical.
;*/

        mov     ch,0FFh
        cmp     bl,ch
        je      gfd_intense_ok
        or      bl,bl
        jnz     gfd_we_have_colors

gfd_intense_ok:

        cmp     cl,ch
        je      gfd_red_ok
        or      cl,cl
        jnz     gfd_we_have_colors

gfd_red_ok:

        cmp     dl,ch
        je      gfd_green_ok
        or      dl,dl
        jnz     gfd_we_have_colors

gfd_green_ok:

        cmp     dh,ch
        je      gfd_blue_ok
        or      dh,dh

        jnz     gfd_we_have_colors

gfd_blue_ok:

        or      al,PA_SINGLE_CLR

        cmp     bl,cl
        jnz     gfd_we_have_colors
        cmp     bl,dl
        jnz     gfd_we_have_colors
        cmp     bl,dh
        jnz     gfd_we_have_colors
        or      al,ONES_OR_ZEROS

gfd_we_have_colors:

;/*
;** As much device independent preprocessing has been done
;** as possible.  Now get into the specifics of mono/color/ega.
;**
;** Currently:
;**       AL = brush accelerator flags
;**       AH = another_tbl[SI]
;**       BL = color for C3
;**       CL = color for C2
;**       DH = color for C1
;**       DL = color for C0/mono
;**       SI = raster op
;*/

        test    loc_sd_fb,SD_DEVICE
        jnz     set_procs_ega           ; Destination is EGA/VGA
;/*
;** Set up the process addresses for either a color or a mono
;** bitmap.
;*/

gfd_acts_like_a_bitmap:

        mov     esi,COLOR_OP
        test    loc_some_flags,INDEX_MONO
        jz      @F
        mov     esi,MONO_OP
@@:
        mov     loc_loop_control,esi

        ror     ah,1                    ;Set AH = 0FFh if to invert the pattern
        sbb     ah,ah

        .errnz  ALT_NEG_PATTERN - 00000001b

        and     ah,byte ptr loc_transparency_mask;Only want to invert foreground bits

gfd_got_mask:

        mov     al,80h                  ;D7 = 1 to show nop
        lea     esi,loc_processors[MONO_DATA]
        add     esi,loc_proc_offset      ;SI-->first control block
        test    loc_some_flags,al
        jnz     set_procs_mono          ;Handle it for a mono bitmap

        .errnz  INDEX_MONO - 80h        ;Must be same as AL

set_procs_color:

        mov     ch,bl                   ;Set up for C3 color
        mov     bl,MM_C3
        call    set_procs_non_ega
        mov     ch,cl                   ;Set up for C2 color
        mov     bl,MM_C2
        call    set_procs_non_ega
        mov     ch,dh                   ;Set up for C1 color
        mov     bl,MM_C1
        call    set_procs_non_ega
        mov     bl,MM_C0                ;EGA map mask value

set_procs_mono:

        mov     ch,dl                   ;Set up for C0 or mono color
        call    set_procs_non_ega
        mov     loc_fetch_data,PSL_WORD_FETCH ;Set for word alignment
        shl     al,1                    ;Set 'C' if operation can be skipped

gfd_exit:

        ret


;/*
;** The EGA (should be said with a tone of pending doom).
;**
;** If the brush has ONES_OR_ZEROS set in the accelerator,
;** the raster op will be mapped to one of the rops which doesn't
;** require a drawing object (D, Dn, DDx, DDxn).  These Rops can
;** always be special cased.
;**
;** If the foreground raster op, after remapping, is D, return with
;** carry set so that no more time is spent on this scanline.  Note
;** that this only works for solid brushes, where the transparency
;** mask is all 1's (also has PA_SINGLE_CLR set).
;**
;** Currently:
;**       AL = brush accelerator flags
;**       AH = another_tbl[SI]
;**       BL = color for C3
;**       CL = color for C2
;**       DH = color for C1
;**       DL = color for C0
;**       SI = raster op
;**       DI = DDC
;*/

set_procs_ega:

        or      loc_clean_up,CU_PLANE_SEL
        mov     ch,bl                   ;put C3 color in safe place
        or      al,al                   ;PA_SINGLE_CLR must be set for
        jns     gfd_chk_one_pass_rop    ;  ONES_OR_ZEROS to be valid

        .errnz  PA_SINGLE_CLR - 10000000b

        test    al,ONES_OR_ZEROS        ;If ONES_OR_ZEROS isn't set, then
        jz      gfd_chk_one_pass_rop    ;  the rop cannot be mapped
        ror     dl,1                    ;Must be all 0's or all 1's
        rcl     esi,1                   ;Add color into the rop
        mov     ebx,esi
        mov     bl,map_1s_0s[ebx]       ;Get new rop
        cmp     bl,ROP_D                ;If the rop is D
        stc                             ;  set the carry to say that
        je      gfd_exit                ;  we're all done
        mov     ah,another_tbl[ebx]     ;Need to reload these
        mov     esi,ebx                 ;save remapped rop

gfd_chk_one_pass_rop:

        mov     loc_fetch_data,PSL_BYTE_FETCH   ;Show byte alignment
        mov     bl,ch                           ;bitmap code expects C3 here
        cmp     loc_transparency_mask,00000FFFFh        ;Any background bits visible?
        jne     gfd_acts_like_a_bitmap          ;if yes, treat as a bitmap
        test    ah,MY_SINGLE_OK         ;Can the ROP occur in one operation?
        jz      set_procs_color_vect    ;  No, treat as a bitmap


;/*
;** The ROP can be performed in one pass on the EGA for solid brushes.
;** If the brush really is solid, then set up the EGA and the looping
;** logic as necessary for a one pass operation.  If the brush isn't
;** solid, both P and Pn may still be able to be accelerated.
;**
;** If there are no transparent pixels, and the raster operation
;** can use STOSB in it's inner loop, then set BX to 0FFFFh to
;** flag that STOSB is ok.  Otherwise, set BX = 0.
;*/

        mov     ebx,STOSB_OK shl 8 + INDEX_XPARENT
        xor     bh,ah                   ;Invert STOSB_OK flag
        or      bh,loc_some_flags       ;OR in INDEX_XPARENT
        and     bh,bl                   ;BH = 0 if we can use STOSB
        cmp     bh,bl                   ;Set 'C' if STOSB can be used
        sbb     ebx,ebx                 ;FFFF if STOSB ok, 0000 otherwise

        .errnz  INDEX_XPARENT - STOSB_OK;Must be the same bits

        or      al,al                   ;Solid brush?
        jns     set_procs_ega_50        ;  No, but might still handle P and Pn

        .errnz  PA_SINGLE_CLR - 10000000b

scanline_solid_brush:
;/*
;** The first and last bytes will use ega_first_last.  The inner loop
;** generally will also use ega_first_last, but may be able to use
;** ega_inner_stosb.   It will be able to do this if there are no
;** transparent bits and the STOSB_OK flag is set for the rop.
;*/

        mov     edi,loc_proc_offset                  ;DI-->first element

        ASSUME  edi:PTR cntrl_blk

        mov     edx,OFFSET ega_first_last
        mov     loc_processors[MONO_DATA][edi].first_last_proc,edx
        and     ebx,ega_inner_stosb-ega_first_last
        add     edx,ebx                                 ;Add 0 or delta to ega_inner_stosb if stosb ok
        mov     loc_processors[MONO_DATA][edi].inner_loop_proc,edx
;/*
;** Program the EGA for the correct mode of operation as defined
;** by the raster operation.
;*/

        mov     edx,EGA_BASE + GRAF_ADDR
        and     al,Code_rop_pen_and[esi]      ;Set correct color for the ROP
        xor     al,Code_rop_pen_xor[esi]
        and     al,MM_ALL               ;Only leave bits of interest
        mov     ah,al
        mov     al,GRAF_SET_RESET
        out     dx,ax
        mov     eax,MM_ALL shl 8 + GRAF_ENAB_SR
        out     dx,ax                   ;Enable all planes for set/reset
        mov     al,GRAF_DATA_ROT        ;Set Data Rotate reg value
        mov     ah,Code_rop_data_r[esi]
        out     dx,ax


;/*
;** Just about done setting up the EGA for whatever.  Leave
;** the Graphics Controller address register pointing to
;** the Bitmask register, show that the operation must occur,
;** that plane selection isn't needed, and that only one loop
;** is required.
;** Currently:
;**       DI = index to first control block element
;*/

set_procs_ega_40:

        and     loc_clean_up,not CU_PLANE_SEL
        mov     loc_loop_control,MONO_OP
        and     loc_processors[MONO_DATA][edi].nop_flag,not NF_NOP
        mov     edx,EGA_BASE + GRAF_ADDR
        mov     al,GRAF_BIT_MASK
        out     dx,al
        clc                             ;'C' clear to show success
        ret


set_procs_color_vect:

        jmp     gfd_acts_like_a_bitmap


;/*
;** The operation was one which could be performed in one pass
;** on the EGA, but the pattern wasn't solid.  If the ROP is
;** either P or Pn and opaque mode is set, then the inner loop
;** can use STOSB with the latches loaded from EGA memory which
;** contains the pattern.  The first and last bytes will have to
;** be done one plane at a time.
;*/

set_procs_ega_50:

        or      bx,bx                   ;BX will be 0 if either
        mov     bl,ch                   ;put C3 color in place, just in case
        jz      set_procs_color_vect    ;  transparent bits or no STOSB_OK
        mov     al,ah                   ;Negate pattern if needed
        cbw

        .errnz  NEG_PATTERN - 10000000b

        xor     dl,ah                   ; Invert C0 pattern
        xor     dh,ah                   ; Invert C1 pattern
        xor     cl,ah                   ; Invert C2 pattern
        xor     ch,ah                   ; Invert C3 pattern

        mov     esi,loc_proc_offset

        ASSUME  esi:PTR cntrl_blk

        mov     loc_processors[C0_DATA][esi].pattern,dl
        mov     loc_processors[C1_DATA][esi].pattern,dh
        mov     loc_processors[C2_DATA][esi].pattern,cl
        mov     loc_processors[C3_DATA][esi].pattern,ch
        mov     loc_processors[MONO_DATA][esi].inner_loop_proc,OFFSET ega_inner_latch
        xor     edi,edi
        cmp     edi,esi
        sbb     edi,edi                   ; DI=FFFF if backgrnd, 0 otherwise
        and     edi,OFFSET ega_all_partial_back-OFFSET ega_all_partial
        add     edi,OFFSET ega_all_partial
        mov     loc_processors[MONO_DATA][esi].first_last_proc,edi

        mov     edi,arg_lp_ddc                   ;Place the pattern into EGA memory

        ASSUME  edi:PTR DDC

        mov     edi,[edi].ddc_npsd                ;  at current_brush
        ASSUME  edi:NOTHING
        mov     edi,[edi].SURFACE.sd_pBits
        mov     ebx,edx                           ;Don't destroy C0 and C1 colors
        OVAccess        ;access offscreen VRAM
ifdef EGAMEM_IS_STRUCT
        lea     edi,[edi].EGAMem.current_brush[0] ;Use the first location of the brush
else
        lea     edi,[edi+current_brush]           ;Use the first location of the brush
endif
        mov     edx,EGA_BASE + SEQ_DATA          ;Set the pattern into ega memory
        mov     al,MM_C0
        out     dx,al
        mov     BYTE PTR [edi],bl
        mov     al,MM_C1
        out     dx,al
        mov     BYTE PTR [edi],bh
        mov     al,MM_C2
        out     dx,al
        mov     BYTE PTR [edi],cl
        mov     al,MM_C3
        out     dx,al
        mov     BYTE PTR [edi],ch
        OVRestore                                ;Restore VGA to previouse state
        mov     edi,esi
        jmp     set_procs_ega_40                 ;Finish here

        ret

page

;/***************************************************************************
;*
;* PUBLIC ROUTINE  set_procs_non_ega
;*
;* DESCRIPTION   = The processor addresses for performing the raster operation
;*                 with the current pattern and transparent pixels (if any)
;*                 are set in the given structure
;*
;*                 Registers Preserved:
;*                       CL,DX,DS,ES
;*                 Registers Destroyed:
;*                       CH,BX,DI,FLAGS
;*
;* INPUT         = BL     =  SEG_MAP_MASK value for this plane if EGA
;*                 CH     =  pattern for this plane
;*                 AL:D7  =  NOP flag
;*                 AH     =  0FF if to invert pattern, 00 otherwise
;*                 SS:SI --> proc_blk structure where info is to be stored
;* OUTPUT        = AL     =  0 if function isn't ROP_D, else unaltered
;*                 AH     =  0FF if to invert pattern, 00 otherwise
;*                 SS:SI --> next proc_blk structure
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

set_procs_non_ega:

        ASSUME  esi:PTR cntrl_blk

        xor     ch,ah                   ;Invert pattern if needed
        mov     [esi].pattern,ch
        xor     ch,ah
        mov     [esi].plane_map_mask,bl
        mov     ebx,loc_raster_op       ;Need raster op index
        inc     ch                      ;Colors of all 1s or 0s can be
        cmp     ch,1                    ;  special cased
        ja      set_procs_no_map        ;Not 00 or FF
        sub     ch,1                    ;Set 'C' = color (1 or 0)
        rcl     ebx,1
        mov     bl,map_1s_0s[ebx]       ;BL = mapped rop

set_procs_no_map:

        mov     [esi].nop_flag,NF_NOP ;assume nop
        cmp     bl,ROP_D                ;If rop is ROP_D
        jne     set_procs_not_nop       ;  and no background bits are visible
        cmp     loc_transparency_mask,00000FFFFh  ;  then we're done
        je      set_procs_non_ega_exit

set_procs_not_nop:

        xchg    eax,edi                         ;Must save AH
        mov     eax,proc_addr_tbl[ebx*4]        ;Compute rop's address and save it
;       add     eax,OFFSET rops_start
        mov     [esi].inner_loop_proc,eax
        mov     [esi].first_last_proc,eax
        xchg    eax,edi
        xor     al,al                      ;Clear D7 to show operation occured
        and     [esi].nop_flag,not NF_NOP  ;assumption was wrong

set_procs_non_ega_exit:

        add     esi,size cntrl_blk         ;--> next control block structure

        ret

page

;/*
;** The following two bit mask tables are used for fetching
;** the first and last byte used-bits bitmask.
;**
;** So I lied.  I no longer use the tables, I create the
;** masks on the fly.  I'll leave them here so you can
;** get the idea of what I'm trying to do later in the code.
;*/

bit_mask_tbl_left label word
                                        ;Masks for leftmost byte
;       dw      1111111111111111B
;       dw      0111111111111111b
;       dw      0011111111111111b
;       dw      0001111111111111b
;       dw      0000111111111111b
;       dw      0000011111111111b
;       dw      0000001111111111b
;       dw      0000000111111111b
;       dw      0000000011111111b
;       dw      0000000001111111b
;       dw      0000000000111111b
;       dw      0000000000011111b
;       dw      0000000000001111b
;       dw      0000000000000111b
;       dw      0000000000000011b
;       dw      0000000000000001b


bit_mask_tbl_right label word

;       dw      1000000000000000B       ;Masks for rightmost byte
;       dw      1100000000000000B
;       dw      1110000000000000B
;       dw      1111000000000000B
;       dw      1111100000000000B
;       dw      1111110000000000B
;       dw      1111111000000000B
;       dw      1111111100000000B
;       dw      1111111110000000B
;       dw      1111111111000000B
;       dw      1111111111100000B
;       dw      1111111111110000B
;       dw      1111111111111000B
;       dw      1111111111111100B
;       dw      1111111111111110B
;       dw      1111111111111111B
page

;/***************************************************************************
;*
;* PUBLIC ROUTINE  comp_interval
;*
;* DESCRIPTION   = The next interval to be filled will be computed.
;*
;*                 A first mask and a last mask will be calculated, and possibly
;*                 combined into the inner loop count.  If no first byte exists,
;*                 the start address will be incremented by the size (byte/word)
;*                 to adjust for it.
;*
;*                 Registers Preserved:
;*                       ES,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,SI,DI,FLAGS
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = 'C' clear
;*                 DS:DI --> first point
;* RETURN-ERROR  = 'C' if no more intervals
;*
;**************************************************************************/

comp_interval_null::

        stc
        ret

comp_interval::

        lea     esi,loc_points          ;--> the scanline pairs

        ASSUME  esi:PTR POINTL

        mov     edx,[esi].ptl_x         ;Get start & end coordinates
        mov     eax,[esi].ptl_y

        mov     ebx,eax                 ;Compute extent of interval
        sub     ebx,edx
        jle     comp_interval_null      ;Null interval, skip it
        dec     ebx                     ;Make interval inclusive


;/*
;** Compute the starting byte/word address of this interval.
;** fetch_data contains the shift count required for either
;** bytes or words.
;*/

        mov     ecx,loc_fetch_data      ;Get mask/shift counts
        mov     edi,edx                 ;Don't destroy starting x
        shr     edi,cl                  ; 



;/*
;** We now have to determine how many bits will be affected,
;** and how they are aligned within the bytes.
;**
;** (left_x MOD word_size) will give us the starting pixel
;** within the left byte/word.  Adding the inclusive extent
;** of the interval to left_x MOD word_size) and taking the
;** result MOD word_size will give us the last pixel affected
;** in the last byte/word.        These pixel indexes (0:7 for bytes,
;** 0:15 for words), can be used to create the first and last
;** altered bits mask.
;**
;**
;** To compute the number of bytes/words in the inner loop,
;** use the second calculation above
;**
;**       (left_x MOD word_size) + inclusive_extent
;**
;** and divide it by the word size (8/16).  This gives you
;** the following:
;**
;**
;**           1)  If the result is 0, then only one destination
;**               byte/word is being altered.  In this case, the
;**               start & ending masks should be ANDed together,
;**               the innerloop count set to zero, and last_mask
;**               set to to all 0's (don't alter any bits).
;**
;**                       |      x x x x x|               |
;**                       |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
;**                        0 1 2 3 4 5 6 7
;**
;**                       start MOD 8 = 3,  extent-1 = 4
;**                       3+7 DIV 8 = 0, only altering one byte
;**
;**
;**
;**           2)  If the result is 1, then only two bytes/words
;**               will be altered.  In this case, the start and
;**               ending masks are valid, and all that needs to
;**               be done is set the innerloop count to 0.
;**
;**                       |  x x x x x x x|x x x x x x x|
;**                       |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
;**                        0 1 2 3 4 5 6 7
;**
;**                       start MOD 8 = 1,  extent-1 = 14
;**                       3+14 DIV 8 = 1.  There is a first and last
;**                       byte but no innerloop count
;**
;**
;**
;**           3)  If the result is > 1, then some number of entire
;**               bytes/words will be altered by the innerloop.  In
;**               this case the number of innerloop bytes/words will
;**               be the result - 1.
;**
;**                       |              x|x x x x x x x x|x
;**                       |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
;**                        0 1 2 3 4 5 6 7
;**
;**                       start MOD 8 = 7,  extent-1 = 9
;**                       7+9  DIV 8 = 2.  There is a first and last
;**                       byte and an innerloop count of 1 (result - 1)
;**
;*/

;/*
;** Compute the starting bit position on the left and the ending
;** bit position on the right
;*/


        and     dl,ch                   ;Compute bit index for left side
        movzx   edx,dl
        add     ebx,edx                 ;Compute bit index for right side
        mov     esi,ebx                 ;(save for inner loop count)
        and     bl,ch

;/*
;** Turn the bit index within the word (or byte) into a mask.
;** We are basically performing a table lookup into the two
;** tables bit_mask_tbl_right and bit_mask_tbl_left.  However,
;** by doing either arithmetic shifts or logical shifts, we
;** can create the masks and save a lot of table space.
;*/


        mov     ch,cl                   ;Save  byte/word shift count
        mov     cl,dl                   ;Compute left side altered bits mask
        mov     eax,0FFFFFFFFh
        mov     edx,eax
        shr     ax,cl                   ;Compute right side altered bits mask
        mov     cl,bl
        mov     ebx,8000h
        sar     bx,cl
        mov     cl,ch                   ;Restore byte/word shift count
        cmp     cl,3                    ;Must handle word/byte intervals
        je      cmp_byte_interval       ;  seperately from this point
        jmp     cmp_word_interval


;/*
;** This is for byte intervals.  The left side mask was not
;** created correctly.  It is off by one entire byte, or 8
;** bit positions.  The right side mask is also incorrect.
;** It must be placed into BL so the 8-bit partial byte code
;** can find it.
;*/

cmp_byte_interval:

        add     edi,loc_scan_start      ;DS:DI --> first byte
        movzx   eax,ah
        xchg    bl,bh                   ;Place these in the correct order
        shr     esi,cl                  ;Compute inner byte count
        jnz     cmp_byte_interval_10   ;loop count + 1 > 0, check it out

;/*
;** Only one byte will be affected.  Combine the first and
;** last byte masks, and set the loop count to 0.
;*/


        and     al,bl                   ;AL = left, BL = right, AH = 0
        xor     ebx,ebx                 ;Want the entire mask to be 0
        inc     esi                     ;Fall through to set 0

cmp_byte_interval_10:

        dec     esi                     ;Dec inner loop count (might become 0)

;/*
;** If all pixels in the first byte are altered, combine the
;** first byte into the inner loop and clear the first byte
;** mask.  Ditto for the last byte
;*/

        cmp     al,dl                   ;Set 'C' if not all pixels 1
        sbb     esi,edx                 ;If no 'C', sub -1 (add 1), else sub 0
        cmp     al,dl                   ;Set 'C' if not all pixels 1
        sbb     al,dl                   ;If no 'C', sub -1 (add 1), else sub 0

        cmp     bl,dl                   ;Set 'C' if not all pixels 1
        sbb     esi,edx                 ;If no 'C', sub -1 (add 1), else sub 0
        cmp     bl,dl                   ;Set 'C' if not all pixels 1
        sbb     bl,dl                   ;If no 'C', sub -1 (add 1), else sub 0

;/*
;** Save the first and last byte masks and the loop count.
;** If the background mix mode is LeaveAlone, AND the masks
;** with the transparency mask now to save a little time in
;** the loop for multiple passes.  If the background mode is
;** OverPaint, then we need the original clip masks as well
;** as the transparency mask, in case the clipped bytes contain
;** only background pixels to output.
;**
;** If the first byte/word mask is not zero before ANDing
;** in the transparency mask, and becomes zero after ANDing
;** in the transparency mask, then the starting address needs
;** to be updated by the size (byte/word)
;*/

comp_interval_save:

        mov     loc_inner_loop_count,esi ;Save the inner loop count
        dec     ecx                     ;Map 3==>1, 4==>2 for increment size
        dec     ecx
        neg     edx                     ;Set DX = 0001 (was FFFF)
        cmp     eax,edx                 ;'C' only if mask is all zeros
        sbb     dl,dl                   ;DX = 00FF if it was all zeros
        not     dl                      ;DX = 0000 if it was all zeros
        and     edx,ecx                 ;Now place size or 0 into DX
        mov     loc_first_mask,eax
        mov     loc_last_mask,ebx

;/*
;** If we just created a first byte/word mask of all zero's, then
;** we have to increment the starting address appropriately.
;*/


        cmp     eax,1                   ;Set 'C' if mask is zeros
        sbb     eax,eax                 ;AX = FF if mask is zeros
        and     eax,edx                 ;Only leave increment if mask is zeros
        add     edi,eax                 ;Offset start if needed
        clc
        ret

;/*
;** Everything said for bytes will just be repeated for
;** words.
;*/


cmp_word_interval:

        shl     edi,1                   ;Turn word offset into byte offset
        add     edi,loc_scan_start      ;DS:DI --> first word
        shr     esi,cl                  ;Compute inner byte count
        jnz     cmp_word_interval_10   ;loop count + 1 > 0, check it out

;/*
;** Only one word will be affected.  Combine the first and
;** last word masks, and set the loop count to 0.
;*/

        and     eax,ebx
        xor     ebx,ebx
        inc     esi                     ;Fall through to set to 0

cmp_word_interval_10:

        dec     esi                     ;Dec innerloop count (might become 0)
;/*
;** Words fetched from memory come out with the high order and low
;** order bytes swapped.  This will be handled by swapping the two
;** halves of each mask.
;*/

        xchg    al,ah
        xchg    bl,bh

;/*
;** If all pixels in the first word are altered, combine the
;** first word into the inner loop and clear the first word
;** mask.  Ditto for the last word
;*/

        cmp     eax,edx                 ;Set 'C' if not all pixels 1
        sbb     esi,edx                 ;If no 'C', sub -1 (add 1), else sub 0
        cmp     eax,edx                 ;Set 'C' if not all pixels 1
        sbb     eax,edx                 ;If no 'C', sub -1 (add 1), else sub 0

        cmp     ebx,edx                 ;Set 'C' if not all pixels 1
        sbb     esi,edx                 ;If no 'C', sub -1 (add 1), else sub 0
        cmp     ebx,edx                 ;Set 'C' if not all pixels 1
        sbb     ebx,edx                 ;If no 'C', sub -1 (add 1), else sub 0
        jmp     comp_interval_save      ;Finish here

page

;/***************************************************************************
;*
;* PUBLIC ROUTINE  ega_all_partial
;*
;* DESCRIPTION   = ega_all_partial handles the partial byte 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
;*
;*                 All planes will be processed according to the given mask.  If
;*                 the rop is Pn, the pattern will have been inverted prior to
;*                 calling this routine.
;*
;*                 Registers Preserved:
;*                       BX,SI,DS,ES,BP
;*                 Registers Destroyed:
;*                       AX,DX,FLAGS
;*
;* INPUT         = DS:DI    --> destination byte
;*                 ES:DI    --> destination byte
;*                    AL     =  mask of altered bits
;*                    BX     =  pattern to use (color) for C3
;*                 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_all_partial:

        mov     dx,EGA_BASE+GRAF_DATA   ;Set the bitmask register
        out     dx,al                   ;  to those bits which can be altered
        mov     dl,SEQ_DATA

        mov     al,MM_C3
        out     dx,al
        mov     al,BYTE PTR [edi]
        mov     BYTE PTR [edi],bl
        mov     al,MM_C2
        out     dx,al
        mov     al,loc_processors[C2_DATA].pattern
        xchg    BYTE PTR [edi],al
        mov     al,MM_C1
        out     dx,al
        mov     al,loc_processors[C1_DATA].pattern
        xchg    BYTE PTR [edi],al
        mov     al,MM_C0
        out     dx,al
        mov     al,BYTE PTR [edi]
        mov     al,loc_processors[C0_DATA].pattern
        stosb
        xor     ecx,ecx                 ;Must return with cx zero

        ret

;/***************************************************************************
;*
;* PUBLIC ROUTINE  ega_all_partial_back
;*
;* DESCRIPTION   =
;*      ega_all_partial_back handles the partial byte 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
;*
;*      All planes will be processed according to the given mask.  If the
;*      rop is Pn, the pattern will have been inverted prior to calling
;*      this routine.
;*
;*      Registers Preserved:
;*            BX,SI,DS,ES,BP
;*      Registers Destroyed:
;*            AX,DX,FLAGS
;*
;* INPUT         = DS:DI    --> destination byte
;*                 ES:DI    --> destination byte
;*                    AL     =  mask of altered bits
;*                    BX     =  pattern to use (color) for C3
;*                 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_all_partial_back:

        mov     dx,EGA_BASE+GRAF_DATA   ;Set the bitmask register
        out     dx,al                   ;  to those bits which can be altered
        mov     dl,SEQ_DATA

        mov     al,MM_C3
        out     dx,al
        mov     al,BYTE PTR [edi]
        mov     BYTE PTR [edi],bl
        mov     al,MM_C2
        out     dx,al
        mov     al,loc_bk_processors[C2_DATA].pattern
        xchg    BYTE PTR [edi],al
        mov     al,MM_C1
        out     dx,al
        mov     al,loc_bk_processors[C1_DATA].pattern
        xchg    BYTE PTR [edi],al
        mov     al,MM_C0
        out     dx,al
        mov     al,BYTE PTR [edi]
        mov     al,loc_bk_processors[C0_DATA].pattern
        stosb
        xor     ecx,ecx                 ;Must return with cx zero

        ret

PolyScanline    ENDP
END

