;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = 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.
;*   11/04/92              54759  Added COM_PRECLIP handling CMVC_54759
;*
;*****************************************************************************/


        .386

        .xlist

        OPTION  OLDSTRUCTS

INCL_GRE_BITMAPS        equ     1
INCL_GRE_CLIP           equ     1
INCL_GRE_SCANS          equ     1
INCL_GPIREGIONS         equ     1
INCL_GPIBITMAPS         equ     1
INCL_GPIPRIMITIVES      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


        .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
;*
;**************************************************************************/


ALIGN 4
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

MF_LAST_PASS    equ     00000001b
MF_KILL_SL      equ     00000010b
MF_OPQ_CLP_LFT  equ     00000100b
MF_OPQ_CLP_RGT  equ     00001000b
MF_FGNOP_BKOPQ  equ     00010000b       ;if fg mix is NOP, bk mix is OPAQUE
MF_UNEXCLUDE     equ     00100000b
MF_USE_DDC_RECTS equ     01000000b

        local   loc_virgin_first_mask: dword    ;these are the original clip masks
        local   loc_virgin_last_mask: dword     ;  for use in opaque-mode clipping
        local   loc_dest_adjust: dword  ;necessary for opaque-mode clipping
        local   temp_address:dword
;/*
;** 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
ALIGN 4

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
ALIGN 4

scanline_bitmap_selected:

        cmp     [esi].ddc_crcsClip,0
        jnz     scanline_visible

scanline_short_exit:

        jmp     get_rc_and_leave
ALIGN 4

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

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

        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

;/*
;** 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      exclusion_handled

        mov     loc_clean_up,CU_EXCLUDE+CU_PLANE_SEL+CU_REGS
        mov     loc_next_plane,0           ; Index to next plane == 0 for EGA

        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.
;*/

        mov     ebx,pScansData
        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
exclusion_handled:

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

        ASSUME  esi:PTR SCANDATA

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

;           Start
        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
@@:
;           End

;/*
;** 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
        ; 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                                  ;          
                                                                     ;          
                                                                     ;          
                                                                     ;          
                                                                     ;          
        ; Move to the next rectangle                                 ;          
        push    esi
        mov     ecx,(size RECTL) / 4

rect_copy_loop:

        rep     movsd

        pop     esi
        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:

;/*                                                                  ;          
;** 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.                ;          
;*/                                                                  ;          
                                                                     ;          
;/*                                                                  ;          
;** Save the contents of esi and edi.                                ;          
;*/                                                                  ;          
;/*                                                                  ;          
;** Only 2 bits of the Command word are of interest to us.           ;          
;*/                                                                  ;          
                                                                     ;          
;/*                                                                  ;          
;**                                                                  ;          
;** Make esi point to the ddc.                                       ;          
;*/                                                                  ;          
;/*                                                                  ;          
;** (eax,ebx)-(ecx,edx) = inclusive rect to accumulate               ;          
;** esi = DDC, edi = Command                                         ;          
;*/                                                                  ;          
                                                                     ;          
                                                                     ;          

;/*
;** 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
;           Start
        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
@@:
;           End

;/*
;** If this shortline-pair is completely 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

;/*
;**  insert codes
;*/

        public  next_scanline
next_scanline::
        dec     loc_saved_y             ; Set Y for next scanline

        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


;/*
;** Break the scanline drawing into the three cases.  These are scanlines into
;** monochrome bitmaps, color bitmaps, and onto the 8514/A.
;*/

        mov     esi,arg_lp_ddc
        ddc?    esi

        ASSUME  esi:PTR DDC

        mov     esi,[esi].ddc_npsd      ;get surface definition flag byte

        ASSUME  esi:PTR SURFACE

        mov     bl,loc_sd_fb            ;[esi].sd_fb
        test    bl,SD_COLOR
        jz      draw_scan_for_mono_bitmap


        public  draw_scan_for_color_bitmap
draw_scan_for_color_bitmap::

;/*
;** Draw into Color Bitmap.
;**
;** 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.
;*/

        call    draw_scan_on_clrbm
        jmp     do_scans_done

        public  draw_scan_for_mono_bitmap
draw_scan_for_mono_bitmap::

;/*
;** Draw into Monochrome Bitmap.
;**
;** 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.
;*/

        call    comp_scan_for_bitmap           ;Compute scanline, device data
draw_scan_for_device:
        call    get_fill_data          ;Get data for filling
        jc      do_scans_done           ;get_fill_data aborted for some reason

        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
        ASSUME  esi:PTR cntrl_blk

        sub     esi,size cntrl_blk      ;--> Set next plane's data
        add     edi,loc_next_plane      ;DS:DI, ES:DI --> first byte, next plane
        test    loc_processors[esi].nop_flag,NF_NOP
        jnz     do_scans_done           ;ROP is a nop, skip it

        call    draw_one_plane_of_scan
        jmp     do_scans_done

;/*
;** If this is the 8514, the exclusion rectangle must be cleared.
;*/

do_scans_done:                  ; We're done with the current scanline
        mov     al,loc_clean_up
        or      al,al
        jz      do_scans_exit           ;No clean up needed
        .errnz  CU_NONE

;/*
;** If we need to restore the state of the 8514/A between scanlines
;** this is the place to do it.
;*/

do_scans_exit:
        dec     loc_scan_count
        jz      done_with_sl_pair
        jmp     next_scanline

        public  done_with_sl_pair
done_with_sl_pair::


        dec     loc_sl_count
        jz      done_with_sl_pair_1
        jmp     next_scanline

done_with_sl_pair_1:
done_with_scans_data:   ; for this clip-rect

;           Start
        test    FunN,COM_PRECLIP
        jnz     finished_rect_buffer
;           End

;/*
;** 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:

        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 = carry     = transparent mode
;*                 not carry = opaque mode.
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

look_for_special_cases:
        push    edi
        push    ebx
        mov     edi,arg_lp_ddc

        ddc?    edi

sc_check_forground:

        cmp     byte ptr [edi].ddc_pa.pa_ba.ba_bmix,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 [edi].ddc_pa.pa_ba.ba_bkmix,ROP_P
        jnz     not_solid

        mov     ebx,SIZE_PATTERN - 1
@@:     cmp     BYTE PTR [edi].ddc_pa.pa_abMask[ebx],0h ; TransparencyMask
        jnz     not_solid               ; Maybe background
        dec     ebx
        jns     @B                              ; use repz scasb?
        jmp     sc_solid_brush

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

sc_solid_brush:
        clc                     ;Opaque mode
        jmp     short   sc_exit
not_solid:
        stc                     ;Transparent mode

sc_exit:
        pop     ebx
        pop     edi
        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  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::
        push    edi                     ;Have to save starting address
        mov     bl,loc_processors[esi].pattern
        mov     bh,bl
        test    loc_moore_flags,MF_OPQ_CLP_LFT
        jz      dops_really_do_first
 dops_really_do_first:
        mov     eax,loc_first_mask      ;If no first byte, skip it
        or      eax,eax
        jz      dops_do_inner
        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
        jcxz    dops_do_last
        mov     eax,loc_transparency_mask
        call    loc_processors[esi].inner_loop_proc
dops_do_last:
dops_really_do_last:
        mov     eax,loc_last_mask       ;If no inner loop, skip it
        or      eax,eax
        jz      dops_restore_pointer
        inc     ecx
        call    loc_processors[esi].first_last_proc

dops_restore_pointer:
        pop     edi
        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 - 8

@@:
        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


        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.
;**!!! loc_loop_control can be incorrectly set (below) for EGA special cases.
;*/

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
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
        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
        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
;*
;**************************************************************************/


ALIGN 4
comp_interval_null::

        stc
        ret

ALIGN 4
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
ALIGN 4


;/*
;** 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

        and     loc_moore_flags,not (MF_OPQ_CLP_LFT or MF_OPQ_CLP_RGT)
        mov     ecx,loc_transparency_mask;if no background bits visible
        inc     ecx                     ;  in pattern, we don't want opaque
        jz      comp_interval_and_masks ;  clipped backgr bits on either side
        test    loc_some_flags,INDEX_XPARENT
        jnz     comp_interval_and_masks
        or      eax,eax
        jz      comp_interval_chk_opq_clp_rgt
        or      loc_moore_flags,MF_OPQ_CLP_LFT
        mov     loc_virgin_first_mask,eax
comp_interval_chk_opq_clp_rgt:
        or      ebx,ebx
        jz      comp_interval_and_masks
        or      loc_moore_flags,MF_OPQ_CLP_RGT
        mov     loc_virgin_last_mask,ebx
comp_interval_and_masks:
        dec     cl                      ;restore transparency mask
        mov     ch,cl
        and     eax,ecx
        and     ebx,ecx
        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
        mov     loc_dest_adjust,eax     ;save adjustment in case clipped opaque
        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

;/***************************************************************************
;*
;* FUNCTION NAME = draw_scan_on_clrbm
;*
;* DESCRIPTION   = Perform scanline operation on color bitmap (packed pixel,
;*                 8bpp).
;*
;*                 Registers Preserved:
;*                       SI,DI,BP,DS,ES
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX
;*
;* INPUT         = BP --> PolyScanline stack frame
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

draw_scan_on_clrbm::

;/*
;**save some registers
;*/

        push    esi
        push    edi

        mov     eax,loc_saved_y         ; I set saved_y earlier  --Wes

        mov     esi,arg_lp_ddc
        ddc?    esi

;/*
;** The device is a memory bitmap. If it is a huge bitmap, special
;** processing must be performed to compute the Y address.
;**
;** currently:    AX     =  Y start
;**               DS:SI --> DDC
;*/

        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    loc_sd_fb, SD_DEVICE    ; NewCon 5-26-89
        jnz     @f

        test    [esi].sd_fb,SD_HUGE
        jz      dsoc_for_bitmap_40

;/*
;** This is a huge bitmap.  Compute which segment the Y coordinate
;** is in.  Assuming that no huge bitmap will be bigger than two
;** or three segments, iteratively computing the value would be
;** faster than a divide, especially if Y is in the first segment
;** (which would always be the case for a huge color bitmap that
;** didn't have planes >64K).
;*/

;/*
;** Special case the screen.
;*/

@@:
        mov     ebx, 64                 ; VGA scan lines per segment
        mov     ecx, 1                  ; VGA segment increment
        test    loc_sd_fb, SD_DEVICE
        jnz     @f
        mov     ebx,[esi].sd_cySeg      ;Get # scans per segment
        mov     ecx,DOSHUGEINCR
@@:
dsoc_for_bitmap_30:
        add     edx,ecx                 ;Show in next segment
        sub     eax,ebx                 ;See if in this segment
        jnc     dsoc_for_bitmap_30      ;Not in current segment, try next
        add     eax,ebx                 ;Restore correct Y
        sub     edx,ecx                 ;Show correct segment

;/*
;** This is a memory DC.  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 packed pixel
;** processing.
;**
;** Also handle modifying Y for huge bitmaps if necessary.
;**
;**
;**       Currently:
;**               AX     =  Y coordinate
;**               DX     =  Segment bias for huge bitmaps
;**               DS:SI --> display surface structure
;**               CH     =  Huge bitmap flag
;**                         (0 = small bitmap)
;*/

dsoc_for_bitmap_40:
        mov     eax,loc_saved_y         ; I set saved_y earlier  --Wes
        mov     ebx,SCREEN_CBSCAN       ;[esi].sd_cbScan        ;Get index to next plane

        test    loc_sd_fb, SD_DEVICE    ; If it's the screen
        jnz     @F
        mov     edx, 0
        mov     ebx,[esi].sd_cbScan     ;Get index to next plane
        mul     ebx
        jmp     dfb_5
@@:
        mul     bx                      ;Compute start of scan
        call    set_bank_select         ; set the bank
dfb_5:
        add     eax,[esi].sd_pBits
        mov     edi,eax

;/*
;**Get the foreground and background mix modes
;*/

        mov     esi,arg_lp_ddc                  ;get new copy

        ASSUME  esi:PTR DDC

        mov     dx,WORD PTR [esi].ddc_pa.pa_ba.ba_bmix  ;Get the foreground
        mov     al,dh                           ; and background mix mode
        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

;/*
;** Get scanline mask
;** determine scan of brush to use
;*/

        mov     eax,loc_bm_height       ;Correct for the fact we align top left
        neg     eax                     ;  instead of bottom left
        add     al,byte ptr [esi].ddc_pa.pa_ptsOrg.ptl_y
        add     al,byte ptr loc_saved_y ;The current Y scan dictates which
        and     eax,00000111b           ;  scan of brush to use
        xchg    eax,ebx
        mov     dh,byte ptr [esi].ddc_pa.pa_abMask[ebx]

;/*
;**Get pointer to pattern bytes
;*/

        shl     ebx,3
        mov     esi,[esi].ddc_pa.pa_abColor
        add     esi,ebx
        xchg    eax,ebx

;/*
;**Get start and ending X's
;*/

        mov     eax,loc_points.ptl_x
        mov     ecx,loc_points.ptl_y
        sub     ecx,eax
        add     edi,eax                 ;update pointer to scanline for x
        and     eax,07h
        xchg    ecx,eax
        rol     dh,cl                  ;preshift mask for starting pel
        xchg    ecx,eax                ; 
                                       ; 
        cmp     dh,0                   ;Optimize if mask is all 0 or ff.
        jz      special_0              ; 
        cmp     dh,0ffh                ; 
        jnz     not_special_case       ; 
        mov     ebx,loc_raster_op      ; 
        jmp     short   do_special_case; 
special_0:                             ; 
        mov     ebx,loc_bk_raster_op   ; 
do_special_case:                       ; 
        and     bl,0fh                 ;bx = foreground or background rop.
        cmp     bl,0ah                 ;Is rop is leave alone ?
        jz      skip_line              ; 
        shl     bl,2                   ; 
        add     ebx,offset clrbm_solid_special
        mov     ebx,dword ptr [ebx]    ; 
        call    ebx                    ; 
skip_line:
        jmp     short   dsoc_exit

not_special_case:
        mov     ah,dh                  ; 
        movzx   edx,al                 ; 
        mov     al,byte ptr [esi+edx]  ; 
next_pixel:                            ; 
        mov     ebx,loc_raster_op      ; 
        rol     ah,1                   ;If mask is 1 use foreground rop.
        jc      @f                     ;else use background rop.
        mov     ebx,loc_bk_raster_op   ; 
@@:                                    ; 
        and     bl,0fh                 ;bx = foreground or background rop.
        cmp     bl,0ah                 ;Is rop is leave alone ?
        jz      skip_pixel             ; 
        shl     bl,2                   ; 
        add     ebx,offset clrbm_solid_proc_addr_tbl
        mov     ebx,dword ptr [ebx]    ; 
        call    ebx                    ; 
        jmp     short   @f             ; 
skip_pixel:                            ; 
        inc     edi                    ; 
@@:                                    ; 
        inc     dl                     ; 
        and     dl,7                   ; 
        mov     al,byte ptr [esi+edx]  ; 
        loop    next_pixel             ; 
                                       ; 
dsoc_exit:                             ; 
        ;restore some regiseters       ;
        pop     edi                    ; 
        pop     esi                    ; 

        RET


;/*
;** SCANLINE - routines used to fill color bitmap scanlines.  The entry
;**   and exit conditions for combinations of foreground and background
;**   ROPS are the same.
;**
;** Entry:
;**   ax = pattern data offset: varies between 0 and 7
;**   cx = no. of pels to fill in
;**   dh = mask for the scanline
;**   es:di = ptr to scanline byte
;**   ds:si = ptr to start of pattern data
;**
;** Exit:
;**  cx = 0
;**
;** Assumptions:
;**   direction flag is cleared
;**
;*/

clrbm_proc_addr_tbl   label dword
        dd      clrbm_transp_ddx
        dd      clrbm_transp_dpon
        dd      clrbm_transp_dpna
        dd      clrbm_transp_pn
        dd      clrbm_transp_pdna
        dd      clrbm_transp_dn
        dd      clrbm_transp_dpx
        dd      clrbm_transp_dpan
        dd      clrbm_transp_dpa
        dd      clrbm_transp_dpxn
        dd      clrbm_transp_d
        dd      clrbm_transp_dpno
        dd      clrbm_transp_p
        dd      clrbm_transp_pdno
        dd      clrbm_transp_dpo
        dd      clrbm_transp_ddxn

        dd      clrbm_opaque_ddx
        dd      clrbm_opaque_dpon
        dd      clrbm_opaque_dpna
        dd      clrbm_opaque_pn
        dd      clrbm_opaque_pdna
        dd      clrbm_opaque_dn
        dd      clrbm_opaque_dpx
        dd      clrbm_opaque_dpan
        dd      clrbm_opaque_dpa
        dd      clrbm_opaque_dpxn
        dd      clrbm_opaque_d
        dd      clrbm_opaque_dpno
        dd      clrbm_opaque_p
        dd      clrbm_opaque_pdno
        dd      clrbm_opaque_dpo
        dd      clrbm_opaque_ddxn

clrbm_opaque_ddx::
        mov     ebx,eax

o_ddx_top:
        rol     dh,1                    ;move mask bit into carry flag
        sbb     al,al                   ;duplicate carry flag into all bits
        not     al                      ;flip the bits
        and     al,byte ptr [esi+ebx]           ;get pattern color
                                        ; if mask was foreground we get 00
                                        ; else we got the pattern color.
        stosb

        inc     ebx                     ;point to next pattern byte
        and     ebx,07h                 ;mod 8
        loop    o_ddx_top

        RET

clrbm_opaque_dpon::
        mov     ebx,eax

o_dpon_top:
        rol     dh,1                    ;move mask bit into carry flag
        sbb     ah,ah                   ;duplicate carry flag into all bits
        mov     al,byte ptr[edi]        ;get the destination color
        and     al,ah                   ;if background clear al to zero
        or      al,byte ptr [esi+ebx]   ;or in pattern color
        inc     ebx
        and     ebx,07h
        xor     al,ah                   ;if foreground flip all bits.
        stosb

        loop    o_dpon_top

        RET

clrbm_opaque_dpna::
        mov     ebx,eax

o_dpna_top:
        rol     dh,1                    ;move mask bit into carry flag
        sbb     ah,ah                   ;duplicate carry flag into all bits
        mov     al,byte ptr [edi]       ;get the destination color
        mov     dl,byte ptr [esi+ebx]   ;get pattern color
        inc     ebx                     ;point to next pattern color
        and     ebx,07h
        xor     dl,ah                   ;not the pattern if its in foreground
        not     ah
        or      al,ah
        and     al,dl
        stosb
        loop    o_dpna_top

        RET

clrbm_opaque_pn::
        mov     ebx,eax

o_pn_top:
        rol     dh,1                    ;move mask bit into carry flag
        sbb     al,al                   ;duplicate carry flag into all bits
        xor     al,byte ptr [esi+ebx]
        inc     ebx
        and     ebx,07h
        stosb                           ;return to scanline
        loop    o_pn_top

        RET

clrbm_opaque_pdna::
        mov     ebx,eax

o_pdna_top:
        rol     dh,1                    ;move mask bit into carry flag
        sbb     eax,eax
        xor     al,byte ptr[edi]                ;get destination color
        not     ah                      ;make dest white if in background
        or      al,ah
        and     al,byte ptr [esi+ebx]
        inc     ebx
        and     ebx,07h
        stosb                           ;return color to scanline
        loop    o_pdna_top

        RET

clrbm_opaque_dn::
        mov     ebx,eax

o_dn_top:
        rol     dh,1                    ;move mask bit into carry flag
        sbb     eax,eax                 ;duplicate carry flag into all bits
        and     al,byte ptr[edi]        ;get destination color
        or      ah,byte ptr [esi+ebx]   ;white if foreground, else pattern clr
        inc     ebx
        and     ebx,07h
        xor     al,ah
        stosb
        loop    o_dn_top

        RET

clrbm_opaque_dpx::
        mov     ebx,eax

o_dpx_top:
        rol     dh,1                    ;move mask bit into carry flag
        sbb     al,al                   ;duplicate carry flag into all bits
        and     al,byte ptr [edi]       ;get destination color
        xor     al,byte ptr [esi+ebx]
        inc     ebx
        and     ebx,07h
        stosb
        loop    o_dpx_top

        RET

clrbm_opaque_dpan::
        mov     ebx,eax

o_dpan_top:
        rol     dh,1
        sbb     eax,eax                 ;duplicate carry into all bits
        not     eax
        xor     ah,byte ptr[esi+ebx]    ;flip pattern if its in background
                                        ; else leave it alone
        inc     ebx                     ;point to next pattern color
        and     ebx,07h
        or      al,byte ptr [edi]
        and     al,ah
        not     al
        stosb
        loop    o_dpan_top

        RET

clrbm_opaque_dpa::
        mov     ebx,eax

o_dpa_top:
        rol     dh,1
        sbb     al,al                   ;duplicate carry into all bits
        not     al
        or      al,byte ptr [edi]
        and     al,byte ptr [esi+ebx]
        inc     ebx
        and     ebx,07h
        stosb
        loop    o_dpa_top

        RET

clrbm_opaque_dpxn::
        mov     ebx,eax

o_dpxn_top:
        rol     dh,1                    ;place mask bit into carry
        sbb     eax,eax
        not     ah                      ;not pattern if in background
        xor     ah,byte ptr [esi+ebx]
        inc     ebx
        and     ebx,07h
        and     al,byte ptr [edi]       ;zero destination if in background
        xor     al,ah                   ;combine pattern and dest.
        not     al                      ;do final not
        stosb                           ;and save the bits
        loop    o_dpxn_top

        RET

clrbm_opaque_d::
        RET

clrbm_opaque_dpno::
        mov     ebx,eax

o_dpno_top:
        rol     dh,1
        sbb     eax,eax
        and     al,byte ptr [edi]
        xor     ah,byte ptr [esi+ebx]
        inc     ebx
        and     ebx,07h
        or      al,ah
        stosb
        loop    o_dpno_top

        RET

clrbm_opaque_p::
        mov     ebx,eax

o_p_top:
        mov     al,byte ptr [esi+ebx]
        inc     ebx
        and     ebx,07h
        stosb
        loop    o_p_top

        RET

clrbm_opaque_pdno::
        mov     ebx,eax

o_pdno_top:
        rol     dh,1
        sbb     al,al
        or      al,byte ptr [edi]
        not     al
        or      al,byte ptr [esi+ebx]
        inc     ebx
        and     ebx,07h
        stosb
        loop    o_pdno_top

        RET

clrbm_opaque_dpo::
        mov     ebx,eax

o_dpo_top:
        rol     dh,1
        sbb     al,al
        and     al,byte ptr [edi]
        or      al,byte ptr [esi+ebx]
        inc     ebx
        and     ebx,07h
        stosb
        loop    o_dpo_top

        RET

clrbm_opaque_ddxn::
        mov     ebx,eax

o_ddxn_top:
        ;The basic method
        rol     dh,1
        sbb     al,al
        or      al,byte ptr [esi+ebx]
        inc     ebx
        and     ebx,07h
        stosb
        loop    o_ddxn_top

        RET


clrbm_transp_ddx::
        xor     al,al                   ;set up result color, outside loop

        jmp     @F
t_ddx_top:
        inc     edi
@@:     rol     dh,1
        jnc     @F
        mov     byte ptr [edi],al
@@:     loop    t_ddx_top

        RET

clrbm_transp_dpon::
        mov     ebx,eax

        jmp     @F
t_dpon_top:
        inc     edi
        inc     ebx
        and     ebx,07h
@@:     rol     dh,1
        jnc     @F
        mov     al,byte ptr [edi]
        or      al,byte ptr [esi+ebx]   ;get destination color
        not     al
        mov     byte ptr [edi],al       ;place it back in destination
@@:     loop    t_dpon_top

        RET

clrbm_transp_dpna::
        mov     ebx,eax

        jmp     @F
t_dpna_top:
        inc     edi
        inc     ebx
        and     ebx,07h
@@:     rol     dh,1
        jnc     @F
        mov     al,byte ptr [esi+ebx]   ;get pattern color
        not     al                      ;not pattern
        and     byte ptr [edi],al       ;and into scanline
@@:     loop    t_dpna_top

        RET

clrbm_transp_pn::
        mov     ebx,eax

        jmp     @F
t_pn_top:
        inc     edi
        inc     ebx
        and     ebx,07h
@@:     rol     dh,1
        jnc     @F
        mov     al,byte ptr [esi+ebx]
        not     al
        mov     byte ptr [edi],al
@@:     loop    t_pn_top

        RET

clrbm_transp_pdna::
        mov     ebx,eax

        jmp     @F
t_pdna_top:
        inc     edi
        inc     ebx
        and     ebx,07h
@@:     rol     dh,1                    ;get pattern color
        jnc     @F
        mov     al,byte ptr [esi+ebx]
        mov     ah,byte ptr [edi]               ;get destination color
        not     ah
        and     al,ah                   ;and with pattern color
        mov     byte ptr [edi],al
@@:     loop    t_pdna_top

        RET

clrbm_transp_dn::
        mov     ebx,eax

t_dn_top:
        rol     dh,1                    ;get pattern color
        sbb     al,al                   ;copy carry flag into al's bits
        xor     byte ptr [edi],al       ;if foreground not destination
        inc     edi                     ;point to next destination
        loop    t_dn_top

        RET

clrbm_transp_dpx::
        mov     ebx,eax

t_dpx_top:
        rol     dh,1                    ;get pattern color
        sbb     al,al                   ;copy carry into ah's bits
        and     al,byte ptr [esi+ebx]   ;if background make pattern zero
        xor     byte ptr [edi],al       ;xor pattern into destination
        inc     edi                     ;point to next destination
        inc     ebx
        and     ebx,07h
        loop    t_dpx_top

        RET

clrbm_transp_dpan::
        mov     ebx,eax

        jmp     @F
t_dpan_top:
        inc     edi
        inc     ebx
        and     ebx,07h
@@:     rol     dh,1                    ;get pattern color
        jnc     @F
        mov     al,byte ptr [esi+ebx]
        and     al,byte ptr [edi]       ;get destination color
        not     al                      ;invert bits
        mov     byte ptr [edi],al       ;place result in scan
@@:     loop    t_dpan_top

        RET

clrbm_transp_dpa::
        mov     ebx,eax

        jmp     @F
t_dpa_top:
        inc     edi
        inc     ebx
        and     ebx,07h
@@:     rol     dh,1
        jnc     @F
        mov     al,byte ptr [esi+ebx]
        and     byte ptr [edi],al
@@:     loop    t_dpa_top

        RET

clrbm_transp_dpxn::
        mov     ebx,eax

        jmp     @F
t_dpxn_top:
        inc     edi
        inc     ebx
        and     ebx,07h
        rol     dh,1
        jnc     @F
        mov     al,byte ptr [esi+ebx]   ;get pattern color
        xor     al,byte ptr [edi]       ;xor in destination
        not     al                      ;not result
        mov     byte ptr [edi],al       ;return result
@@:     loop    t_dpxn_top

        RET

clrbm_transp_d::

        ;The basic method
        ;This is a do nothing rop.

        RET

clrbm_transp_dpno::
        mov     ebx,eax

t_dpno_top:
        mov     al,byte ptr [esi+ebx]   ;get pattern color
        rol     dh,1
        not     al                      ;not the pattern
        sbb     ah,ah                   ;clear the color if its the background
        and     al,ah
        or      byte ptr [edi],al
        inc     edi
        inc     ebx
        and     ebx,07h
        loop    t_dpno_top

        RET

clrbm_transp_p::
        mov     ebx,eax

        jmp     @F
t_p_top:
        inc     edi
        inc     ebx
        and     ebx,07h
@@:     rol     dh,1
        jnc     @F
        mov     al,byte ptr [esi+ebx]
        mov     byte ptr [edi],al
@@:     loop    t_p_top

        RET

clrbm_transp_pdno::
        mov     ebx,eax

        ;The basic method
        jmp     @F
t_pdno_top:
        inc     edi
        inc     ebx
        and     ebx,07h
@@:     rol     dh,1                    ;get pattern color
        jnc     @F
        mov     al,byte ptr [edi]       ;get destination color
        not     al
        or      al,byte ptr [esi+ebx]
        mov     byte ptr [edi],al
@@:     loop    t_pdno_top

        RET

clrbm_transp_dpo::
        mov     ebx,eax

t_dpo_top:
        rol     dh,1
        sbb     al,al
        and     al,byte ptr [esi+ebx]
        or      byte ptr [edi],al
        inc     edi
        inc     ebx
        and     ebx,07h
        loop    t_dpo_top

        RET

clrbm_transp_ddxn::
        mov     ebx,eax

t_ddxn_top:
        rol     dh,1                    ;get pattern color
        sbb     al,al
        or      byte ptr [edi],al       ;or in ff if foreground, and 00 if back
        inc     edi                     ;point to next destination byte
        loop    t_ddxn_top

        RET


;/*
;** SCANLINE - routines used to fill color bitmap scanlines.  The pattern
;**   has been determined to be solid.  Therefore we need only lay the
;**   color in without to much difficulty.
;**
;** Entry:
;**   al = foreground color
;**   cx = no. of pels to fill in
;**   es:di = ptr to scanline byte
;**
;** Exit:
;**   cx = 0
;**
;** Assumptions:
;**   direction flag is cleared
;**
;*/

clrbm_solid_proc_addr_tbl   label dword
        dd      clrbm_tsolid_ddx
        dd      clrbm_tsolid_dpon
        dd      clrbm_tsolid_dpna
        dd      clrbm_tsolid_pn
        dd      clrbm_tsolid_pdna
        dd      clrbm_tsolid_dn
        dd      clrbm_tsolid_dpx
        dd      clrbm_tsolid_dpan
        dd      clrbm_tsolid_dpa
        dd      clrbm_tsolid_dpxn
        dd      clrbm_tsolid_d
        dd      clrbm_tsolid_dpno
        dd      clrbm_tsolid_p
        dd      clrbm_tsolid_pdno
        dd      clrbm_tsolid_dpo
        dd      clrbm_tsolid_ddxn


clrbm_tsolid_ddx::
        xor     al,al
        stosb
        RET

clrbm_tsolid_dpon::
        push    ax
        xchg    ah,al
        mov     al,byte ptr [edi]       ;get destination
        or      al,ah
        not     al
        stosb                           ;replace destination
        pop     ax
        RET

clrbm_tsolid_dpna::

        not     al
        and     byte ptr [edi],al
        inc     edi

        RET

clrbm_tsolid_pn::

        not     al
        stosb

        RET

clrbm_tsolid_pdna::
        push    ax
        mov     ah,al
        mov     al,byte ptr [edi]
        not     al
        and     al,ah
        stosb
        pop     ax
        RET

clrbm_tsolid_dn::

        not     byte ptr [edi]
        inc     edi

        RET

clrbm_tsolid_dpx::
        xor     byte ptr [edi],al
        inc     edi

        RET

clrbm_tsolid_dpan::
        push    ax
        mov     ah,al
        mov     al,byte ptr [edi]
        and     al,ah
        not     al
        stosb
        pop     ax
        RET

clrbm_tsolid_dpa::

        and     byte ptr [edi],al
        inc     edi

        RET

clrbm_tsolid_dpxn::
        push    ax
        mov     ah,al
        mov     al,byte ptr [edi]
        xor     al,ah
        not     al
        stosb
        pop     ax

        RET

clrbm_tsolid_d::

        RET

clrbm_tsolid_dpno::

        not     al
        or      byte ptr [edi],al
        inc     edi

        RET

clrbm_tsolid_p::
        stosb
        RET

clrbm_tsolid_pdno::
        push    ax
        mov     ah,al
        mov     al,byte ptr [edi]
        not     al
        or      al,ah
        stosb
        pop     ax
        RET

clrbm_tsolid_dpo::

        or      byte ptr [edi],al
        inc     edi

        RET

clrbm_tsolid_ddxn::

        mov     al,0ffh
        stosb

        RET


clrbm_solid_special   label dword
        dd      clrbm_special_ddx
        dd      clrbm_special_dpon
        dd      clrbm_special_dpna
        dd      clrbm_special_pn
        dd      clrbm_special_pdna
        dd      clrbm_special_dn
        dd      clrbm_special_dpx
        dd      clrbm_special_dpan
        dd      clrbm_special_dpa
        dd      clrbm_special_dpxn
        dd      clrbm_special_d
        dd      clrbm_special_dpno
        dd      clrbm_special_p
        dd      clrbm_special_pdno
        dd      clrbm_special_dpo
        dd      clrbm_special_ddxn

clrbm_special_ddx::
        xor     al,al
        rep     stosb

        RET

clrbm_special_dpon::
        mov     ebx,eax

dpon_top:
        mov     al,byte ptr[edi]        ;get the destination color
        or      al,byte ptr [esi+ebx]   ;or in pattern color
        not     al
        stosb
        inc     ebx
        and     ebx,07h

        loop    dpon_top

        RET

clrbm_special_dpna::
        mov     ebx,eax

dpna_top:
        mov     al,byte ptr [edi]       ;get the destination color
        mov     ah,byte ptr [esi+ebx]   ;get pattern color
        not     ah
        and     al,ah
        stosb
        inc     ebx                     ;point to next pattern color
        and     ebx,07h
        loop    dpna_top

        RET

clrbm_special_pn::
        mov     ebx,eax

pn_top:
        mov     al,byte ptr [esi+ebx]
        not     al
        stosb                           ;return to scanline
        inc     ebx
        and     ebx,07h
        loop    pn_top

        RET

clrbm_special_pdna::
        mov     ebx,eax

pdna_top:
        mov     ah,byte ptr [esi+ebx]
        mov     al,byte ptr[edi]                ;get destination color
        not     al                      ;make dest white if in background
        and     al,ah
        stosb                           ;return color to scanline
        inc     ebx
        and     ebx,07h
        loop    pdna_top

        RET

clrbm_special_dn::
        mov     ebx,eax

dn_top:
        mov     al,byte ptr[edi]        ;get destination color

        not     al
        stosb
        inc     ebx
        and     ebx,07h
        loop    dn_top

        RET

clrbm_special_dpx::
        mov     ebx,eax

dpx_top:
        mov     al,byte ptr [esi+ebx]
        mov     ah,[edi]
        xor     al,ah
        stosb
        inc     ebx
        and     ebx,07h
        loop    dpx_top

        RET

clrbm_special_dpan::
        mov     ebx,eax

dpan_top:
        mov     ah,byte ptr[esi+ebx]    ;flip pattern if its in background
        mov     al,byte ptr [edi]
        and     al,ah
        not     al
        stosb
        inc     ebx                     ;point to next pattern color
        and     ebx,07h
        loop    dpan_top

        RET

clrbm_special_dpa::
        mov     ebx,eax

dpa_top:
        mov     al,byte ptr [edi]
        mov     ah,byte ptr [esi+ebx]
        and     al,ah
        stosb
        inc     ebx
        and     ebx,07h
        loop    dpa_top

        RET

clrbm_special_dpxn::
        mov     ebx,eax

dpxn_top:
        mov     ah,byte ptr [esi+ebx]
        mov     al,byte ptr [edi]       ;zero destination if in background
        xor     al,ah                   ;combine pattern and dest.
        not     al                      ;do final not
        stosb                           ;and save the bits
        inc     ebx
        and     ebx,07h
        loop    dpxn_top

        RET

clrbm_special_d::
        RET

clrbm_special_dpno::
        mov     ebx,eax

dpno_top:
        mov     al,byte ptr [edi]
        mov     ah,byte ptr [esi+ebx]
        not     ah
        or      al,ah
        stosb
        inc     ebx
        and     ebx,07h
        loop    dpno_top

        RET

clrbm_special_p::
        mov     ebx,eax

p_top:
        mov     al,byte ptr [esi+ebx]
        inc     ebx
        and     ebx,07h
        stosb
        loop    p_top

        RET

clrbm_special_pdno::
        mov     ebx,eax

pdno_top:
        mov     al,byte ptr [edi]
        not     al
        or      al,byte ptr [esi+ebx]
        stosb
        inc     ebx
        and     ebx,07h
        loop    pdno_top

        RET

clrbm_special_dpo::
        mov     ebx,eax

dpo_top:
        mov     al,byte ptr [edi]
        mov     ah,byte ptr [esi+ebx]
        or      al,ah
        stosb
        inc     ebx
        and     ebx,07h
        loop    dpo_top

        RET

clrbm_special_ddxn::
        mov     al,0ffh
        rep     stosb

        RET

PolyScanline    ENDP
END
