;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
;***********************************************************************
;
;   Module          = EDDHSCAN
;
;   Description     = Scanline drawing code
;
;   Function        = Does scan line drawing work
;
;
; CHANGE ACTIVITY =
;   DATE      FLAG        APAR   CHANGE DESCRIPTION
;   --------  ----------  -----  ------------------------------------
;   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;   03/19/93              62482  Pattern stripes were appearing when a
;                                solid line was desired. (8514)
;   02/23/94                     Clipping was off by a line
;
;***********************************************************************
.386p

INCL_DDIMISC            EQU     1
INCL_32                 EQU     1
INCL_GPIBITMAPS EQU     1
include os2.inc
include eddinclt.inc

include pmddi.inc    /* The 32pmddi.x file(s) are no longer used.       */  
                     /* These have being included into the pmddi.x from */  
                     /* the drf6\h386 and drf6\inc32 dir's.  CMVC 94536 */  

include eddhmacr.inc
include eddhtype.inc
include eddfmacr.inc
IFDEF _8514
include cmacros.inc
include 8514.inc
ENDIF

EXTRN _CopyMemoryToVRAM:NEAR

;***********************************************************************
; handle the soft draw/hard draw differences
;***********************************************************************
IFDEF HARD_DRAW
public  _eddh_PMSCANLINE
PMScanLine      equ     <_eddh_PMSCANLINE>
bitmap_address  equ     phys_addr
IFDEF _8514
public  _eddh_UserBmapScan
UserBmapScan     equ     <_eddh_UserBmapScan>
ifdef   BPP24
public  _PM24ScanLine
PM24ScanLine     equ     <_PM24ScanLine>
colorpatphysical equ <_colorpatphysical>
endif
ENDIF ; _8514
ENDIF ; HARD_DRAW

IFDEF SOFT_DRAW
public  _eddf_PMSCANLINE
PMScanLine      equ     <_eddf_PMSCANLINE>
bitmap_address  equ     virt_addr
extrn _eddf_MESS        :proc
ENDIF ; SOFT_DRAW

;***********************************************************************
; Cope with Microsoft's naming convention
;***********************************************************************
ifndef   _8514
pXGARegs         equ <_pXGARegs>
else
p8514Regs        equ <_p8514Regs>
endif
AIxfer           equ <_AIxfer>
SPad             equ <_SPad>
pbHWPollRegister equ <_pbHWPollRegister>

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

; External access for this module

ifndef   _8514
extrn pXGARegs          :dword
else
extrn p8514Regs         :dword
extrn _DDT              :byte
ifdef   BPP24
ifdef HARD_DRAW
extrn colorpatphysical  :dword
extrn _Copy24MonoToVRAM :NEAR
extrn _Copy24ScanMixToVRAM :NEAR
endif
endif
endif
extrn AIxfer            :dword
extrn SPad              :dword
extrn pbHWPollRegister  :dword

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

; structure for parameter block

SCANLINESPB     struc
pbmhDest                dd      ?
cDestClipRects          dw      ?
pNextDestClipRect       dd      ?
lDest0Coord             dd      ?
lDest1Coord             dd      ?
pbmhSrc                 dd      ?
lSrc0Coord              dd      ?
lSrc1Coord              dd      ?
ptsPatOrig              dd      ?
ulPixelOp               dd      ?
pSLHeaderLeft           dd      ?
pSLHeaderRight          dd      ?
SCANLINESPB     ends

; structure for scratch pad

ScanLinesSP     struc
usBMHeight      dw      ?
usSrcHeight     dw      ?
usSrcWidth      dw      ?
ptsStartCoord   dd      ?
sXEndPoint      dw      ?
sClippedStartX  dw      ?
sClippedEndX    dw      ?
pSPSLHeaderL    dd      ?
pSPSLHeaderR    dd      ?
ptsClipOffset   dd      ?
ptsClipSize     dd      ?
sSrcYPos        dw      ?
ptsSubBMBotRght dd      ?
ScanLinesSP     ends


_DATA           segment dword use32 public 'DATA'
ifdef   BPP24
BiasPattern     dw      0
endif
_DATA           ends

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

fast3x  macro   regsrc, regtmp
        mov     regtmp, regsrc
        shl     regsrc, 1
        add     regsrc, regtmp
        endm

;***********************************************************************
;
; Function: PMScanLine
;
; Called by: eddl_PolyScanLine in eddspoly.c
;
; This is the single bitmap case.  Code handles..
;       Clipping - done in software to prevent pxblt operations occuring
;       outside pixel maps which are not dword aligned at the edges -
;       XGA hardware problem.
;
; 386 only code
;***********************************************************************

PMScanLine      proc
        push    edi
        push    esi
        push    ebx
        push    ebp

; get access to hardware registers
        pushxga
        ifndef  _8514
        movxga  pXGARegs
        else
        movxga  p8514Regs
        endif

; set up the destination bitmap (as pixel map A)
        memregwrite     pi_map_index_A, SEL_PIX_MAP_A

        mov     ebx, AIxfer.pbmhDest

; bitmap address (could be phys_addr for h/w or virt_addr for s/w)
        mov     eax, [ebx].bitmap_address
        memregwrite     pi_map_base_ptr_A, eax

; width and height
        mov     ax, [ebx].hw_height
        shl     eax, 16                 ; move to top word
        mov     ax, [ebx].hw_width
        memregwrite     pi_map_size_A, eax

; format
        mov     ax, [ebx].hw_format
        memregwrite     pi_map_format_A, al

; other useful things..
        movzx   eax, word ptr [ebx].bm_height
        dec     eax
        mov     SPad.usBMHeight, ax

; set up the source bitmap (as pixel map B)
; note that this 'source' may either be a 1,1 pattern or an 8,1 dither
; matrix BUT we assume that the calling code will not be asking us to
; do something like an 8,1 dither to a 1,1 destination.
; this function is unaware of whether pixel map b will be specified in
; the pixel op as the source or the pattern
        mov     ebx,AIxfer.pbmhSrc
        memregwrite     pi_map_index_B, SEL_PIX_MAP_B

; bitmap address (could be phys_addr for h/w or virt_addr for s/w)
        mov     eax, [ebx].bitmap_address
        memregwrite     pi_map_base_ptr_B, eax

; width and height
        mov     ax, [ebx].hw_height
        shl     eax, 16         ; move to top word
        mov     ax, [ebx].hw_width
        memregwrite     pi_map_size_B, eax

; format
        mov     ax, [ebx].hw_format
        memregwrite     pi_map_format_B, al

; other useful things..
        mov     ax, [ebx].bm_height
        mov     SPad.usSrcHeight, ax
        mov     ax, [ebx].bm_width
        mov     SPad.usSrcWidth, ax

; copy these pointers to the SPad to make handling multiple scanlines
; easier
        mov     eax, AIxfer.pSLHeaderLeft
        mov     SPad.pSPSLHeaderL, eax
        mov     eax, AIxfer.pSLHeaderRight
        mov     SPad.pSPSLHeaderR, eax

; Determining pattern (source) coordinates for scanlines
; to work this out we have to consider the offset from the src start
; (ie the pattern origin) to the destination start and also which
; direction this offset is in.
; consider the case for x..
;
;           012345601234560123456
;           P.....|p.....|p...D.|
;           ^     ^           destination origin
;           ^     end of pattern
;           ^pattern origin
;
; if we do (abs(D-P))%PatternLength we get 4 which is the offset to D
; from the last p before D - this would be our source start position
;
; now consider the other case..
;
;          456012345601234560123456012
;          ..|p.D...|p.....|p.....|P..
;          321065432106543210654321065
;
; now if we do (abs(D-P))%PatternLength we get 5 which is the offset to D
; from the first p after D - to turn this into the source start postion
; we need to subtract it from PatternLength (7) to get 2
;
; this is the case for the x pattern origin - for the y pattern origin
; the origin is given as the bottom of the pattern pixel map but for the
; hardware we want the top of the pixel map to be the origin so we need
; to do something slightly different..
;
;     .
;   5 P 0
;   0 - 1
;   1 . 2   here we get abs(D-P)%PatternHeight gives us the offset
;   2 . 3   from the last 'pattern origin' above D using the right
;   3 . 4   hand coordinates - but what we actually want is the offset
;   4 . 5   from  the left hand coordinates where zero corresponds to
;   5 p 0   the top of the pattern map to get this we simply decrement
;   0 - 1   the offset (and make sure it does not become -1!)
;   1 . 2
;   2 D 3
;   3 . 4
;   4 . 5
;   5 p 0
;   0 - 1
;
;     .
;   5 p 0
;   0 - 5
;   1 . 4   here we get abs(D-P)%PatternHeight gives us the offset
;   2 D 3   from the bottom of the pattern (3) using the right hand
;   3 . 2   coordinates but - the offset we actually want is the one
;   4 . 1   on the left where zero corresponds to the top of the pattern
;   5 p 0   and the pattern origin would have an offset of (PatternHeight-1)
;   0 - 5   or 5 in this case - so we subtract 3 from PatternHeight-1
;   1 . 4
;   2 . 3
;   3 . 2
;   4 . 1
;   5 P 0
;   0 - 5
;
; for the y case if abs(D-P) = 0 then we special case this and translate
; it too PatternHeight-1


slines_loop:
; set up the start position of the first shortlines
; all scanlines will be drawn left to right
; the left and right shortlines will be the same height and run from
; bottom to top
        mov     edi, SPad.pSPSLHeaderL
        mov     ebp, SPad.pSPSLHeaderR

; get the pointers to the next shortlines now when we have edi & ebp
; set up to the start of the shortline structure
        mov     eax, [edi].slh_pslhNext
        mov     SPad.pSPSLHeaderL, eax
        mov     eax, [ebp].slh_pslhNext
        mov     SPad.pSPSLHeaderR, eax

; get the coordinate of the first scanline
; we want to end up with the y coordinate in the top word of eax and
; the x coordinate in the low word of eax

; get the low word of y coord into the low word of eax and convert to h/w coords
        movzx   eax, SPad.usBMHeight
        sub     eax, [edi].slh_ptlStart.ptl_y
        shl     eax, 16                 ; place y coord in high word

; get the low-word of x coordinate into the high word of eax
        mov     ax, word ptr [edi].slh_ptlStart.ptl_x

; store in the scratch pad
        mov     SPad.ptsStartCoord, eax

; the right (x) coordinate of the first scanline
        mov     ax, word ptr [ebp].slh_ptlStart.ptl_x
        mov     SPad.sXEndPoint, ax

; work out the first y pattern (source) coordinate
; get the y difference
        mov     ax, SPad.ptsStartCoord.y
        sub     ax, AIxfer.lSrc0Coord.y

; is it negative ?
        js      short neg_diff_y

; is it zero ? (special case because we don't want to divide by zero)
        jz      short zero_y

; it is a positive y difference - first take the modulus
        cwd
        idiv    SPad.usSrcHeight

; now if modulus != 0 decrement modulus otherwise use special case
; code for zero
        cmp     dx, 0
        jz      short zero_y

        dec     dx
        jmp     short got_y_pos

neg_diff_y:
; for the negative difference we need to subtract the modulus from
; usSrcHeight-1
        neg     ax
        cwd
        idiv    SPad.usSrcHeight
        mov     ax, SPad.usSrcHeight
        dec     ax
        sub     ax, dx
        mov     dx, ax
        jmp     short got_y_pos

zero_y:
        mov     dx, SPad.usSrcHeight
        dec     dx

got_y_pos:
; the source y position for the first scan line is in dx - save it
        mov     SPad.sSrcYPos, dx

; get the number of scanlines to draw
        mov     cx, word ptr [edi].slh_ptlStop.ptl_y
        sub     cx, word ptr [edi].slh_ptlStart.ptl_y

; set edi & ebp to the next coordinate
; N.B. '+ 4' to get past 1st co-ordinate in the buffer following the header info
        add     edi, size SHORTLINEHEADER + 4
        add     ebp, size SHORTLINEHEADER + 4

; and start a loop to draw them..

scan_line_draw:
        swap    ecx

; FOR each scan line FOR each clip rectangle...
        mov     cx, AIxfer.cDestClipRects
        mov     ebx, AIxfer.pNextDestClipRect

more_clips:
; test the y coordinate against this clip rectangle
        mov     ax, SPad.ptsStartCoord.y
        cmp     ax, [ebx].clip_y0
        jl      omit_clip               ; above
        cmp     ax, [ebx].clip_y1
        jg      omit_clip               ; below

; now test/clip the start/end x coordinates
        mov     ax, SPad.ptsStartCoord.x
        cmp     ax, [ebx].clip_x1
        jg      omit_clip               ; to the right
        cmp     ax, [ebx].clip_x0
        jge     short @f
        mov     ax, [ebx].clip_x0       ; clip the start point
@@:
        mov     SPad.sClippedStartX, ax

        mov     ax, SPad.sXEndPoint
        cmp     ax, [ebx].clip_x0
        jl      omit_clip               ; to the left
        cmp     ax, [ebx].clip_x1
        jle     short @f                ;            changed to jle from jl
        mov     ax, [ebx].clip_x1       ; clip the end point
; need the dec ax because scan line end point is the first pel NOT drawn
        inc     ax
@@:
        mov     SPad.sClippedEndX, ax

; now assemble a stack full of data for the hardware..
; we want -
;       source coords (not on the stack because they are calculated last)
;       destination coords
;       operating dimensions
;  - in that order when we pop so push them in reverse

; work out the operating dimensions
; y dimension is 1-1 = 0
; check there is a scanline to draw when working out the x direction
        xor     edx, edx        ; ensure zero as y dimension (top word in edx)
        mov     dx, SPad.sClippedEndX
        sub     dx, SPad.sClippedStartX
;71380 @DMS
        jle     no_pels         ; dont allow negative value I would like to return an error
;71380 @DMS
        jz      no_pels
        dec     edx             ; convert no of pels into dimension of blt
                                ; (dec of edx is OK, because top word is zero!)
        push    edx

; get the destination start position
        mov     ax, SPad.ptsStartCoord.y
        shl     eax, 16                         ; move y coord to top word
        mov     ax, SPad.sClippedStartX
        push    eax

; the source y coordinate is in SPad.sSrcYPos
        mov     dx, SPad.sSrcYPos

; dx holds the y postion so hide it
        swap    edx

; work out the source x coordinate

; get the x difference
        mov     ax, SPad.sClippedStartX
        sub     ax, AIxfer.lSrc0Coord.x

; is it negative ?
        js      short neg_diff_x

; is it zero ? (special case because we don't want to divide by zero)
        jz      short zero_x

; it is positive - just take the modulus
        cwd
        idiv    SPad.usSrcWidth
        jmp     short got_x_pos

neg_diff_x:
; it is negative - take the modulus and invert it
        neg     ax
        cwd
        idiv    SPad.usSrcWidth
        mov     ax, SPad.usSrcWidth
        dec     ax
        sub     ax, dx

zero_x:
        mov     dx, ax

got_x_pos:
; edx is now the source start position

; now our stack is all prepared so wait for the hardware
        waitshort

; first write the 'source' coordinates to both the source and pattern map
; position since this code handles patterns & dithering together.
        memregwrite     src_map, edx
        memregwrite     patt_map, edx

; now pop the dest_map and dimensions into the hardware registers
        pop     eax
        memregwrite     dest_map, eax
        pop     eax
        memregwrite     dimensions, eax
; now do the pixel_op
        mov     eax, AIxfer.ulPixelOp
        memregwrite     pixel_op, eax

IFDEF HARD_DRAW
IFDEF _8514

        push    ebx
        push    ecx

        WaitQIdle

        WaitQ   5
        memregread      eax,Function_1
        and     ax,FUNC_ALU                    ; isolate mix mode
        or      ax,FUNC_2OP_COL1
        outwQ   FUNCTION_1,ax

        memregread      eax,Function_0
        and     ax,FUNC_ALU                    ; isolate mix mode
        or      ax,FUNC_2OP_COL0
        outwQ   FUNCTION_0,ax

        ;;************************************************************
        ;; If we have a user defined color bitmap then we need a different
        ;; algorithm.  Now we will call a dfferent routine to do this
        ;; work, and the algorithm will be documented there.
        ;; The current code will handle the case of BitCount = 1, any
        ;; BitCount > 1 we will use another routine.
        ;;
        ;; In addition we now handle large mono bitmaps 32 x 64K
        ;; The same code could also handle all bitmap cases if later
        ;; we wanted to use a single src base.  For now I am keeping
        ;; mono bitmaps less than 8 bytes using the hardware assist
        ;; code for performance.
        ;;
        ;; Michael R. Cooper  3/22/93
        ;;************************************************************

        mov     ebx, AIxfer.pbmhSrc
        mov     eax, [ebx].bm_size

        ifdef   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        call    PM24ScanLine
        jmp     scan_done
@@:
        endif

        cmp     ax, 08
        jle     short pmsl_not_spcl_case
        call    UserBmapScan
        jmp     scan_done

pmsl_not_spcl_case:

        mov     eax,[ebx]                      ; get pointer to virtual memory

        ;;============== Begin of new code -            =================
        movzx   edx, byte ptr [ebx].hw_format
        and     dl, NOT MOTOROLA
        or      dl,dl
        jz      pmsl_mono_source

pmsl_color_source:
        memregread      ecx,patt_map
        swap    ecx
        and     cx,1
        jz      @F
        add     eax,2
@@:
        ifndef BPP24
        mov     ax,word ptr [eax]
        outwQ   COLOR_0,ax
        shr     ax,8
        outwQ   COLOR_1,ax
        else
        ; @DMS need to load these colors from dwords not words.
        ; where does the color info come from when looking at the virtual addr
        ; I dont think this is correct to begin with. !!!
        mov     ax,word ptr [eax]
        outwQ   COLOR_0,ax
        shr     ax,8
        outwQ   COLOR_1,ax
        endif

        mov     ax,00AAh
        swap    ecx
        and     cx,1
        ror     ax,cl
IFDEF S3
        mov     ah,al
        mov     bx,ax                          ;Save our biased 16-bit pattern.
ELSE
        LoadPattern ax
ENDIF
        jmp     pmsl_setdest
        ;;============== End of new code -            =================

pmsl_mono_source:
        memregread      edx,patt_map
        swap    edx
        add     ax,dx
IFDEF S3
        swap    edx
        mov     cx,dx
        movzx   ax,BYTE PTR [eax]              ;Get the 8-bit pattern byte.
        mov     ah,al                          ;Double it.
        rol     ax,cl                          ;Rotate for the X-Bias of our pattern.
        mov     bx,ax                          ;Save our biased 16-bit pattern.
ELSE
        LoadPattern <[eax]>                    ; get virtual bitmap
ENDIF

pmsl_setdest:
        ;;************************************************************
        ;; convert destination bitmap address to x and y for 8514 hardware
        ;;************************************************************
        WaitQ   6
        mov     eax,SPad.ptsStartCoord
        swap    eax
        outwQ   Y0,ax                       ; set destination x-y address
        mov     ax,SPad.sClippedStartX
        outwQ   X0,ax

        ;;************************************************************
        ;; set up the destination width and height
        ;;************************************************************
        memregread      eax,dimensions
        outwQ   LX,ax
IFDEF S3
        ;;************************************************************
        ;; Determine the number of words need to be written.
        ;; NOTE: LX is zero based.  Therefore, we must add 16 rather
        ;;       than 15 before dividing to calculate the correct
        ;;       number of words.  Otherwise, the LOOP statement below
        ;;       will see a zero on the first iteration and decrement
        ;;       to FFFFFFFF, and so on....
        ;;************************************************************
        add     ax,16
        shr     ax,4
        movzx   ecx,ax                         ;Save the width (in words) of scanline.
ENDIF
        swap    eax
        outwQ   LY,ax

IFNDEF S3
        outwQ   MODE,(MODE_2DECODE+MD_PS_PATT) ; use pattern registers
        outwQ   CMD_FLAGS,CMDSOLID             ; blt the pattern
ELSE
        outwQ   MODE,(MODE_2DECODE+MD_PS_VAR)
        outwQ   CMD_FLAGS,CMD_WCUR

        ;;************************************************************
        ;; Since the S3 chip doesn't support a pattern register, we
        ;; will blast our 16 bit pattern (8 bits doubled) across the
        ;; scanline for as many words as necessary.  NOTE: CX was
        ;; calculated above to contain the number of words to write.
        ;;************************************************************
        WaitQOUT
        mov     dx,COLOR_0_WAIT
        mov     ax,bx                          ;Restore 16-bit pattern.
@@:
        out     dx,ax
        loop    @B

ENDIF

scan_done:
        pop     ecx
        pop     ebx

ENDIF ; _8514
ELSE  ; SOFT_DRAW

        saveregs
        call    _eddf_MESS
        restoreregs

ENDIF ; SOFT_DRAW

; done it into that clip rectangle..
; come here when we reject a clip rectangle or we find a scan line with
; no pels (post clipping)
no_pels:
omit_clip:
        add     ebx, SIZE clip_rect     ; step to next clip rect

        dec     cx
        jnz     more_clips

; there are no more clips to draw into so go back and do another scanline
; first find out if there are any more
        swap    ecx
        dec     cx
        jz      short next_shline

; first we need to update the pattern position.
        mov     ax, SPad.sSrcYPos
        dec     ax
        jns     short @f
        mov     ax, SPad.usSrcHeight
        dec     ax
@@:
        mov     SPad.sSrcYPos, ax

; move to the next line
; change the y coordinate
        mov     ax, SPad.ptsStartCoord.y
        dec     ax
        swap    eax

; get the next x start coordinate
        mov     ax, [edi]
        add     edi, 4          ; each point is a long
        mov     SPad.ptsStartCoord, eax

; and the next x end coordinate
        mov     ax, [ebp]
        add     ebp, 4          ; each point is a long
        mov     SPad.sXEndPoint, ax

        jmp     scan_line_draw

next_shline:
; now determine if there any more shortline pairs to be done in this call
        mov     eax, SPad.pSPSLHeaderL
        and     eax, eax
        jz      short no_more_slines

; there are more shortlines (there must be a left and a right shortline
; so don't bother to check pSLHeaderRight)
        jmp     slines_loop

no_more_slines:
        popxga
        pop     ebp
        pop     ebx
        pop     esi
        pop     edi
        retn

PMScanLine      endp

IFDEF HARD_DRAW
IFDEF _8514
;;**************************************************************************
;;
;; UserBmapScan - routine draws scanlines with user supplied patterns
;; larger than 8 bytes.
;;
;; INPUT  ebx -> pBmhSrc
;; OUPUT  none
;;
;; Optimization still needs to be done.
;;**************************************************************************

UserBmapScan  Proc

;; MRC - NOTE 6P - EDDHSCAN.ASM - PolyScanLine using user supplied color bitmaps
;; After Several thoughts and discusions I have decided to write directly from
;; memory to the screen.  The reason being , since we are already in polyscanline
;; code the performance gain from drawing into offscreen vram first and then
;; blitting to the screen would be minimal.  If performance is needed then we
;; should also optmize the polyscanline code.

;; for the large mono bmap contdition we will adjust the monobits into a new
;; address and then pass in that address - for simplicity we will limit the
;; mono bitmap to 32 x 32.

        push    edi
        movzx   eax,SPad.sClippedStartX
        push    eax
        sub     eax,eax
        push    eax                    ; Color Storage
        push    eax                    ; Mono bimap adjusted src

        mov     ax,[ebx].bm_format
        cmp     ax, 01
        jz      short ubs_mono

        mov     edi,[ebx]              ; edi = pointer to bmap bits

        memregread      eax,patt_map   ; Get pattern origin

        ifdef BPP24
        mov     dx, byte ptr [ebx].hw_format
        and     dx, NOT MOTOROLA
        cmp     dx, TWENTYFOUR_BPP
        jnz     try16
        fast3x  ax,dx
        jmp     @f
try16:  cmp     dx, SIXTEEN_BPP
        jnz     @f
        shl     ax,1
@@:
        endif

        add     di,ax                  ; add in x offset
        shr     eax,16

        ifdef BPP24
        mov     dx, byte ptr [ebx].hw_format
        and     dx, NOT MOTOROLA
        cmp     dx, TWENTYFOUR_BPP
        jnz     try16a
        fast3x  ax,dx
        jmp     @f
try16a: cmp     dx, SIXTEEN_BPP
        jnz     @f
        shl     ax,1
@@:
        endif

        mul     [ebx].bm_width
        add     edi,eax                ; Have starting Src pos

        xchg    ebx,ecx                ; ecx = pointer to bitmap header

        memregread      ebx,dimensions
        movzx   ebx,bx                 ; ebx = scan length

        memregread      edx,patt_map   ; Get x offset again for 1st tile
        jmp     short ubs_tile_loop

ubs_mono:

        WaitQ   2
        ifndef  BPP24
        memregread      ax,Color_0
        outwQ   COLOR_0,ax
        shl     eax,16
        memregread      ax,Color_1
        outwQ   COLOR_1,ax
        else
        ;@DMS this scheme needs work for 24bpp accelerated version!!!
        memregread      ax,Color_0
        outwQ   COLOR_0,ax
        shl     eax,16
        memregread      ax,Color_1
        outwQ   COLOR_1,ax
        endif

        mov     [esp+4],eax

        mov     edi,[ebx]              ; edi = pointer to bmap bits

        memregread      eax,patt_map   ; 
        swap    eax
        movzx   eax,ax
        mul     [ebx].bm_width
        shr     eax,3                  ; Divide by 8 - bits per pel
        add     edi,eax                ; Have starting Src pos

        mov     ah, [edi]              ; Get 32Bits of Bitmap
        mov     al, [edi+1]
        shl     eax,16
        mov     ah, [edi+2]
        mov     al, [edi+3]

        memregread      ecx,patt_map   ; 

        rol     eax,cl                 ; add in x offset
        mov     edi,esp

        ifndef  S3
        mov     ecx, [esp+8]           ; nugget align
        and     cl,3
        ror     eax,cl
        endif

        mov     [edi+3],al
        mov     [edi+2],ah
        shr     eax,16
        mov     [edi+1],al
        mov     [edi],ah

        memregread      edx,patt_map   ; Get x offset again for 1st tile
        xchg    ebx,ecx                ; ecx = pointer to bitmap header

        memregread      ebx,dimensions
        movzx   ebx,bx                 ; ebx = scan length


ubs_tile_loop:

        movzx   eax,[ecx].bm_width
        dec     eax
        sub     ax,dx

        cmp     ebx,eax                ; eax = tile width
        jle     ubs_last_scan

;; Do a Tile for this scan

ubs_last_scan_cont:

        push eax                       ; save lenght output
        push ecx                       ; save pBmhSrc

        movzx   edx,[ecx].hw_format
        push    edx                    ; BPFormat
        sub     edx,edx
        push    edx                    ; Height
        push    eax                    ; Width
        mov     edx,SPad.ptsStartCoord
        ;ror     edx,16                ; X and Y have swapped words!
        mov     dx,SPad.sClippedStartX
        ror     edx,16
        or      edx,0F0000000h
        push    edx                    ; Pvrammem
        push    edi                    ; Psysmem

        call    _CopyMemoryToVRAM
        add     esp,20
        pop     ecx
        pop     eax
        inc     eax

        cmp     ebx,eax
        jle     ubs_end

        sub     ebx,eax

        movzx   edx,SPad.sClippedStartX
        add     edx,eax
        mov     SPad.sClippedStartX,dx

        movzx   dx,byte ptr [ecx].bm_format
        cmp     dx, 01
        jz      short ubs_mono2

        movzx   edx,[ecx].bm_width
        sub     edx,eax

        ifdef BPP24
        push    ax
        mov     ax, byte ptr [ecx].hw_format
        and     ax, NOT MOTOROLA
        cmp     ax, TWENTYFOUR_BPP
        jnz     try16b
        fast3x  dx,ax
        jmp     @f
try16b: cmp     ax, SIXTEEN_BPP
        jnz     @f
        shl     dx,1
@@:     pop     ax
        endif

        sub     edi,edx                ; reset tile to beginning of bitmap scan

ubs_mono2_cont:

        sub     edx,edx                ; set bitmap origin to 0

        jmp     ubs_tile_loop

ubs_mono2:


        mov     dx,[ecx].bm_width
        cmp     ax,dx
        jz      short @F               ; Only adjust the bits on first pass

        mov     edx,ecx
        memregread      ecx,patt_map   ; 

        mov     ah, [edi]
        mov     al, [edi+1]
        shl     eax,16
        mov     ah, [edi+2]
        mov     al, [edi+3]

        ror     eax,cl                 ; sub out x offset

        ifndef  S3
        mov     ecx, [esp+8]           ; nugget align
        and     cl,3
        rol     eax,cl
        endif

        mov     [edi+3],al
        mov     [edi+2],ah
        shr     eax,16
        mov     [edi+1],al
        mov     [edi],ah

        mov     ecx,edx
@@:
        WaitQ   2
        mov     eax,[esp+4]
        outwQ   COLOR_1,ax
        shr     eax,16
        outwQ   COLOR_0,ax

        jmp     short ubs_mono2_cont

ubs_last_scan:

        mov     eax,ebx
        jmp     ubs_last_scan_cont

ubs_end:

        sub     eax,eax
        pop     eax
        pop     eax
        pop     eax
        mov     SPad.sClippedStartX,ax
        pop     edi
        retn

UserBmapScan  endp

ifdef   BPP24
ifdef   S3
;***********************************************************************
;
; Function: PM24ScanLine
;
; Called by: PMScanLine
;
; This is the single bitmap case.  Code handles..
;       Clipping - done in software to prevent pxblt operations occuring
;       outside pixel maps which are not dword aligned at the edges -
;       XGA hardware problem.
;
; 386 only code
;***********************************************************************

PM24ScanLine      proc
        push    edi
        push    esi
        push    ebx
        push    ebp
        push    ebx
        push    ecx

        mov     ebx, AIxfer.pbmhSrc
        mov     eax, [ebx].bm_size
        cmp     ax, 08
        jle     @f

        call    UserBmapScan
        jmp     scan24_done
@@:

        WaitQIdle
        WaitQ   2

        memregread      eax,Function_0
        and     ax,FUNC_ALU                    ; isolate mix mode
        cmp     ax,FUNC_S
        jnz     bkm_scan24
        or      ax,FUNC_2OP_COPY
        outwQ   FUNCTION_0,ax

        memregread      eax,Function_1
        and     ax,FUNC_ALU                    ; isolate mix mode
        or      ax,FUNC_2OP_COPY
        outwQ   FUNCTION_1,ax

        mov     ebx, AIxfer.pbmhSrc
        mov     eax,[ebx]                      ; get pointer to virtual memory

        movzx   edx, byte ptr [ebx].hw_format
        and     dl, NOT MOTOROLA
        or      dl,dl
        jz      pmsl_24mono_source

pmsl_24color_source:
        memregread      ecx,patt_map
        mov     ax,00AAh
        and     cx,1
        ror     ax,cl
        mov     ah,al
        mov     bx,ax                          ;Save our biased 16-bit pattern.
        jmp     pmsl_24setdest

pmsl_24mono_source:
        memregread      edx,patt_map
        swap    edx
        add     ax,dx
        swap    edx
        mov     cx,dx
        movzx   ax,BYTE PTR [eax]              ;Get the 8-bit pattern byte.
        mov     ah,al                          ;Double it.
        rol     ax,cl                          ;Rotate for the X-Bias of our pattern.
        mov     bx,ax                          ;Save our biased 16-bit pattern.

pmsl_24setdest:
        ;;************************************************************
        ;; convert destination bitmap address to x and y for 8514 hardware
        ;;************************************************************
        mov     BiasPattern,bx

        mov     ebx, AIxfer.pbmhSrc
        ;expand the pattern to the screen at color pat
        xor     ax,ax
        push    ax                      ; start bits
        push    ONE_BPP
        mov     ax,[ebx].hw_height
        movzx   edx,ax
        push    edx
        mov     ax,[ebx].hw_width
        movzx   eax,ax
        push    eax                         ; width of bmap
        push    eax                         ; width of blt

        mov     eax,colorpatphysical
        and     eax,0fffffffh
        push    eax
        swap    eax
        mov     dx,ax
        shl     ax,1
        add     ax,dx
        swap    eax
        mov     edi,eax
        lea     eax,BiasPattern
        push    eax
        call    _Copy24MonoToVRAM
        add     esp,26

        WaitQIdle
        WaitQ   6
        outwQ   Y0,di                       ; set src x-y addr
        swap    edi
        outwQ   X0,di
        mov     eax,SPad.ptsStartCoord
        swap    eax
        outwQ   Y1,ax                       ; set destination x-y address
        mov     cx,ax
        mov     ax,SPad.sClippedStartX
        mov     dx,3
        mul     dx
        outwQ   X1,ax
        mov     di,ax

        ;;************************************************************
        ;; set up the destination width and height
        ;;************************************************************
        memregread      eax,dimensions
        inc     ax
        mov     dx,3
        mul     dx

        mov     si,cx
        movzx   ecx,ax                         ;Save the width (in words) of scanline.
        swap    eax
        outwQ   LY,ax

        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES)

        mov     ax,word ptr [ebx].hw_width
        inc     ax
        mov     dx,3
        mul     dx
        mov     bx,di
        mov     di,ax

        ; blit the pattern across the width of the destination bitmap
pmsl_lp24:

        WaitQ   4
        outwQ   Y1,si
        mov     ax,di                           ; get 1 based width in ax
        usmin_ax   cx                           ; pattern width or remainder
        dec     ax                              ; get zero based width
        outwQ   LX,ax                           ; set width of blt
        sub     cx,ax                           ; alter remaining width to blt (less 1)

        outwQ   CMD_FLAGS,CMDPATTERN            ; blt the pattern
        add     bx,di                           ; dest + one based offset
        outwQ   X1,bx                           ; set destination x addr
        loop    pmsl_lp24                       ; copy pattern across destination
        jmp     scan24_done

bkm_scan24:
        mov     ebx, AIxfer.pbmhSrc
        mov     eax,[ebx]                      ; get pointer to virtual memory

        movzx   edx, byte ptr [ebx].hw_format
        and     dl, NOT MOTOROLA
        or      dl,dl
        jz      bkm_24mono_source

        memregread      ecx,patt_map
        mov     ax,00AAh
        and     cx,1
        ror     ax,cl
        mov     ah,al
        mov     bx,ax                          ;Save our biased 16-bit pattern.
        jmp     bkm_24setdest

bkm_24mono_source:
        memregread      edx,patt_map
        swap    edx
        add     ax,dx
        swap    edx
        mov     cx,dx
        movzx   ax,BYTE PTR [eax]              ;Get the 8-bit pattern byte.
        mov     ah,al                          ;Double it.
        rol     ax,cl                          ;Rotate for the X-Bias of our pattern.
        mov     bx,ax                          ;Save our biased 16-bit pattern.

        ;;************************************************************
        ;; convert destination bitmap address to x and y for 8514 hardware
        ;;************************************************************
bkm_24setdest:
        mov     BiasPattern,bx

        mov     ebx, AIxfer.pbmhSrc
        ;expand the pattern to the screen at color pat
        mov     ax,[ebx].hw_width
        movzx   eax,ax
        push    eax                         ; width of bmap
        memregread      eax,dimensions
        movzx   eax,ax
        push    eax                         ; width of blt

        mov     eax,SPad.ptsStartCoord
        mov     ax,SPad.sClippedStartX
        swap    eax
        push    eax
        lea     eax,BiasPattern
        push    eax
        call    _Copy24ScanMixToVRAM
        add     esp,16

scan24_done:
        pop     ecx
        pop     ebx
        pop     ebp
        pop     ebx
        pop     esi
        pop     edi
        retn

PM24ScanLine      endp
endif   ;S3
endif   ;BPP24

ENDIF
ENDIF

_TEXT           ends

END
