2025-04-27 07:49:33 -04:00

1806 lines
67 KiB
NASM

;---------------------------Module-Header------------------------------;
; Module Name: vgablts.asm
;
; Copyright (c) 1992 Microsoft Corporation
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; VOID vTrgBlt(PDEVSURF pdsurf, ULONG culRcl, RECTL * prcl, MIX ulMix,
; ULONG ulClr);
; Input:
; pdsurf - surface to which to draw
; culRcl - # of rectangles to fill
; prcl - pointer to list of rectangles to fill
; ulMix - mix rop with which to fill
; ulClr - color with which to fill
;
; Performs accelarated solid area fills for all mixes.
;
;-----------------------------------------------------------------------;
;
; Note: Assumes all rectangles have positive heights and widths. Will not
; work properly if this is not the case.
;
;-----------------------------------------------------------------------;
;
; Note: Cases where the width of the whole bytes fill is equal to the
; width of the bitmap could be sped up by using a single REP MOVS or REP
; STOS, but how often does WIN32 do a fill that's the width of the screen?
; Not very.
;
;-----------------------------------------------------------------------;
comment $
The overall approach of this module is to accept a list of rectangles to
fill, set up the VGA hardware for the desired fill, and then fill the
rectangles one at a time. Each rectangle fill is set up for everything
but vertical parameters, and then decomposed into the sections that
intersect each VGA bank; each section is drawn in turn. Vectors are set
up so that the drawing code appropriate for the desired fill is
essentially threaded together.
commend $
;-----------------------------------------------------------------------;
.386
ifndef DOS_PLATFORM
.model small,c
else
ifdef STD_CALL
.model small,c
else
.model small,pascal
endif; STD_CALL
endif; DOS_PLATFORM
assume ds:FLAT,es:FLAT,ss:FLAT
assume fs:nothing,gs:nothing
.xlist
include stdcall.inc ;calling convention cmacros
include i386\egavga.inc
include i386\strucs.inc
include i386\ropdefs.inc
.list
;-----------------------------------------------------------------------;
.data
;-----------------------------------------------------------------------;
; Left edge clip masks for intrabyte start addresses 0 through 7.
; Whole byte cases are flagged as 0ffh.
public jLeftMask
jLeftMask label byte
db 0ffh,07fh,03fh,01fh,00fh,007h,003h,001h
;-----------------------------------------------------------------------;
; Right edge clip masks for intrabyte end addresses (non-inclusive)
; 0 through 7. Whole byte cases are flagged as 0ffh.
public jRightMask
jRightMask label byte
db 0ffh,080h,0c0h,0e0h,0f0h,0f8h,0fch,0feh
;-----------------------------------------------------------------------;
; Tables used to set up for the desired raster op. Note that entries for raster
; ops that aren't handled here are generally correct, except that they ignore
; need for inversion of the destination, which those rops require.
; Table used to force off the drawing color for R2_BLACK (0).
; The first entry is ignored; there is no mix 0.
public jForceOffTable
jForceOffTable db 0
db 0,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh
db 0ffh,0ffh, 0,0ffh,0ffh,0ffh,0ffh,0ffh
;-----------------------------------------------------------------------;
; Table used to force on the drawing color for R2_NOT (Dn) and R2_WHITE (1).
; The first entry is ignored; there is no mix 0.
public jForceOnTable
jForceOnTable db 0, 0,0,0,0,0,0ffh,0,0,0,0,0,0,0,0,0,0ffh
;-----------------------------------------------------------------------;
; Table used to invert the passed-in drawing color for Pn mixes.
; The first entry is ignored; there is no mix 0.
public jNotTable
jNotTable db 0, 0,0ffh,0ffh,0ffh,0,0,0,0ffh,0,0ffh,0,0ffh,0,0,0,0
;-----------------------------------------------------------------------;
; Table of VGA ALU logical functions corresponding to mixes. Note that Dn is
; handled as a separate preceding inversion pass when part of a more complex
; mix.
; The first entry is ignored; there is no mix 0.
public jALUFuncTable
jALUFuncTable db 0
db DR_SET,DR_AND,DR_AND,DR_SET
db DR_AND,DR_XOR,DR_XOR,DR_OR
db DR_AND,DR_XOR, 0,DR_OR
db DR_SET,DR_OR ,DR_OR ,DR_SET
;-----------------------------------------------------------------------;
; 1 entries mark rops that require two passes, one to invert the destination
; and then another to finish the rop.
; The first entry is ignored; there is no mix 0.
public jInvertDest
jInvertDest db 0, 0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0
;-----------------------------------------------------------------------;
; Table of routines to be called to draw edges, according to which edges are
; partial and which edges are whole bytes.
align 4
pfnEdgeDrawing label dword
dd do_right_edge_bytes
dd do_both_edge_bytes
dd check_next_bank
dd do_left_edge_bytes
;-----------------------------------------------------------------------;
; Table of pointers to tables used to find entry points in wide
; whole byte code.
align 4
pfnWideWholeRep label dword
dd draw_wide_w_00_loop
dd draw_wide_w_01_loop
dd draw_wide_w_02_loop
dd draw_wide_w_03_loop
dd draw_wide_w_10_loop
dd draw_wide_w_11_loop
dd draw_wide_w_12_loop
dd draw_wide_w_13_loop
dd draw_wide_w_20_loop
dd draw_wide_w_21_loop
dd draw_wide_w_22_loop
dd draw_wide_w_23_loop
dd draw_wide_w_30_loop
dd draw_wide_w_31_loop
dd draw_wide_w_32_loop
dd draw_wide_w_33_loop
;-----------------------------------------------------------------------;
; Table of pointers to tables used to find entries points in narrow, special-
; cased non-replace whole byte code.
; Note: The breakpoint where one should switch from special-casing to
; REP MOVSB is purely a guess on my part. 5 seemed reasonable.
align 4
pfnWholeBytesNonReplaceEntries label dword
dd 0 ;we never get a 0-wide case
dd draw_1_wide_rw_loop
dd draw_2_wide_rw_loop
dd draw_3_wide_rw_loop
dd draw_4_wide_rw_loop
MAX_NON_REPLACE_SPECIAL equ ($-pfnWholeBytesNonReplaceEntries)/4
;-----------------------------------------------------------------------;
; Table of pointers to tables used to find entry points in narrow, special-
; cased replace whole byte code.
; Note: The breakpoint where one should switch from special-casing to
; REP STOS is purely a guess on my part. 8 seemed reasonable.
; Start address MOD 3 is 0.
align 4
pfnWholeBytesMod0ReplaceEntries label dword
dd 0 ;we never get a 0-wide case
dd draw_1_wide_w_loop
dd draw_2_wide_w_loop
dd draw_3_wide_w_even_loop
dd draw_4_wide_w_loop
dd draw_5_wide_w_even_loop
dd draw_6_wide_w_mod3_0_loop
dd draw_7_wide_w_mod3_0_loop
dd draw_8_wide_w_mod3_0_loop
MAX_REPLACE_SPECIAL equ ($-pfnWholeBytesMod0ReplaceEntries)/4
; Start address MOD 3 is 1.
align 4
pfnWholeBytesMod1ReplaceEntries label dword
dd 0 ;we never get a 0-wide case
dd draw_1_wide_w_loop
dd draw_2_wide_w_loop
dd draw_3_wide_w_odd_loop
dd draw_4_wide_w_loop
dd draw_5_wide_w_odd_loop
dd draw_6_wide_w_mod3_1_loop
dd draw_7_wide_w_mod3_1_loop
dd draw_8_wide_w_mod3_1_loop
; Start address MOD 3 is 2.
align 4
pfnWholeBytesMod2ReplaceEntries label dword
dd 0 ;we never get a 0-wide case
dd draw_1_wide_w_loop
dd draw_2_wide_w_loop
dd draw_3_wide_w_even_loop
dd draw_4_wide_w_loop
dd draw_5_wide_w_even_loop
dd draw_6_wide_w_mod3_2_loop
dd draw_7_wide_w_mod3_2_loop
dd draw_8_wide_w_mod3_2_loop
; Start address MOD 3 is 3.
align 4
pfnWholeBytesMod3ReplaceEntries label dword
dd 0 ;we never get a 0-wide case
dd draw_1_wide_w_loop
dd draw_2_wide_w_loop
dd draw_3_wide_w_odd_loop
dd draw_4_wide_w_loop
dd draw_5_wide_w_odd_loop
dd draw_6_wide_w_mod3_1_loop
dd draw_7_wide_w_mod3_3_loop
dd draw_8_wide_w_mod3_3_loop
; Master MOD 3 alignment look-up table for entry tables for four possible
; alignments for narrow, special-cased replace whole byte code.
align 4
pfnWholeBytesReplaceMaster label dword
dd pfnWholeBytesMod0ReplaceEntries
dd pfnWholeBytesMod1ReplaceEntries
dd pfnWholeBytesMod2ReplaceEntries
dd pfnWholeBytesMod3ReplaceEntries
;-----------------------------------------------------------------------;
.code
_TEXT$01 SEGMENT DWORD USE32 PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;-----------------------------------------------------------------------;
cProc vTrgBlt,20,< \
uses esi edi ebx, \
pdsurf: ptr DEVSURF, \
culRcl: dword, \
prcl: ptr RECTL, \
ulMix: dword, \
ulColor:dword >
local ulRowOffset :dword ;Offset from start of scan line of
; first byte to fill
local ulWholeBytes :dword ;# of whole bytes to fill
local ulWholeDwords :dword ;# of whole dwords to fill
local pfnWholeFn :dword ;pointer to routine used to draw
; whole bytes
local ulScanWidth :dword ;offset from start of one scan to start
; of next
local ulNextScan :dword ;offset from end of one scan line's
; fill to start of next
local ulCurrentTopScan :dword ;top scan line to fill in current bank
local ulMasks :dword ;low byte = right mask, high byte =
; left mask
local ulBottomScan :dword ;bottom scan line of fill rectangle
local jALUFunc :dword ;VGA ALU logical operation (SET, AND,
; OR, or XOR)
local pfnStartDrawing :dword ;pointer to function to call to start
; drawing
local pfnContinueDrawing :dword ;pointer to function to call to
; continue drawing after doing whole
; bytes
local ulLeftEdgeAdjust :dword ;used to bump the whole bytes start
; address past the left edge when the
; left edge is partial
local pfnWholeBytes :dword ;pointer to table of entry points
; into loops for whole byte filling
local jInvertDestFirst :dword ;1 if the rop requires a pass to invert
; the destination before the normal
; pass
local jDrawingColor :dword ;color with which we're drawing
; dword to finish out fill
;-----------------------------------------------------------------------;
cld
;-----------------------------------------------------------------------;
; Make sure there's something to draw; clip enumerations can be empty.
;-----------------------------------------------------------------------;
cmp culRcl,0 ;any rects to fill?
jz vTrgBlts_done ;no, we're done
;-----------------------------------------------------------------------;
; Set up variables that are constant for the entire time we're in this
; module.
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; Set up for the desired raster op.
;-----------------------------------------------------------------------;
sub ebx,ebx ;ignore any background mix; we're only
mov bl,byte ptr ulMix ; concerned with the foreground in this
; module
cmp ebx,R2_NOP ;is this NOP?
jz vTrgBlts_done ;yes, we're done
mov al,jInvertDest[ebx] ;remember whether we need to
mov byte ptr jInvertDestFirst,al ; invert the destination before
; finishing the rop
mov ah,byte ptr ulColor ;get the drawing color
and ah,jForceOffTable[ebx] ;force color to 0 if necessary
; (R2_BLACK)
or ah,jForceOnTable[ebx] ;force color to 0ffh if necessary
; (R2_WHITE, R2_NOT)
xor ah,jNotTable[ebx] ;invert color if necessary (any Pn mix)
;at this point, CH has the color we
; want to draw with; set up the VGA
; hardware to draw with that color
mov byte ptr jDrawingColor,ah ;remember drawing color for restoring
; after inversion
mov edx,VGA_BASE + GRAF_ADDR
mov al,GRAF_SET_RESET ;set/reset = color to write
out dx,ax
mov eax,0F00h + GRAF_ENAB_SR ;enable set/reset for all planes, so
out dx,ax ; set/reset color we just set becomes
; the drawing color, regardless of the
; value written by the CPU
mov ah,jALUFuncTable[ebx] ;get the ALU logical function
and ah,ah ;is the logical function DR_SET?
.errnz DR_SET
jz short skip_ALU_set ;yes, don't have to set because that's
; the VGA's default state
mov al,GRAF_DATA_ROT
out dx,ax ;set the ALU logical function
skip_ALU_set:
mov byte ptr jALUFunc,ah ;remember the ALU logical function
mov eax,GRAF_MODE + ((M_AND_WRITE + M_COLOR_READ) SHL 8)
out dx,ax ;write mode 3 so we can do the masking
; without OUTs, read mode 1 so we can
; read 0xFF from memory always, for
; ANDing (because Color Don't Care is
; all zeros)
;-----------------------------------------------------------------------;
; Fill the current rectangle with the specified raster op and color.
;-----------------------------------------------------------------------;
fill_rect_loop:
;-----------------------------------------------------------------------;
; Set up variables that are constant from bank to bank during a single
; fill.
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; Set up masks and widths.
;-----------------------------------------------------------------------;
mov edi,prcl ;point to rectangle to fill
mov eax,[edi].yBottom
mov ulBottomScan,eax ;remember the bottom scan line of fill
mov ebx,[edi].xRight ;right edge of fill (non-inclusive)
mov ecx,ebx
and ecx,0111b ;intrabyte address of right edge
mov ah,jRightMask[ecx] ;right edge mask
mov esi,[edi].xLeft ;left edge of fill (inclusive)
mov ecx,esi
shr ecx,3 ;/8 for start offset from left edge
; of scan line
mov ulRowOffset,ecx ;remember offset from start of scan
; line
sub ebx,esi ;width in pixels of fill
and esi,0111b ;intrabyte address of left edge
mov al,jLeftMask[esi] ;left edge mask
dec ebx ;make inclusive on right
add ebx,esi ;inclusive width, starting counting at
; the beginning of the left edge byte
shr ebx,3 ;width of fill in bytes touched - 1
jnz short more_than_1_byte ;more than 1 byte is involved
; Only one byte will be affected. Combine first/last masks.
and al,ah ;we'll use first byte mask only
xor ah,ah ;want last byte mask to be 0
inc ebx ;so there's one count to subtract below
; if this isn't a whole edge byte
more_than_1_byte:
; If all pixels in the left edge are altered, combine the first byte into the
; whole byte count and clear the first byte mask, because we can handle solid
; edge bytes faster as part of the whole bytes. Ditto for the right edge.
sub ecx,ecx ;edge whole-status accumulator
cmp al,-1 ;is left edge a whole byte or partial?
adc ecx,ecx ;ECX=1 if left edge partial, 0 if whole
sub ebx,ecx ;if left edge partial, deduct it from
; the whole bytes count
mov ulLeftEdgeAdjust,ecx ;for skipping over the left edge if
; it's partial when pointing to the
; whole bytes
and ah,ah ;is right edge mask 0, meaning this
; fill is only 1 byte wide?
jz short save_masks ;yes, no need to do anything
cmp ah,-1 ;is right edge a whole byte or partial?
jnz short save_masks ;partial
add ecx,2 ;bit 1 of ECX=0 if right edge partial,
; 1 if whole;
;bit 1=0 if left edge partial, 1 whole
inc ebx ;if right edge whole, include it in the
; whole bytes count
save_masks:
mov ulMasks,eax ;save left and right clip masks
mov ulWholeBytes,ebx ;save # of whole bytes
mov ecx,pfnEdgeDrawing[ecx*4] ;set address of routine to draw
mov pfnContinueDrawing,ecx ; all partial (non-whole) edges
and ebx,ebx ;any whole bytes?
jz short start_vec_set ;no
;yes, so draw the whole bytes before
; the edge bytes
; The whole bytes loop depends on the type of operation being done. If the
; operation is one which uses DR_SET, then we can use a STOS-type operation,
; else we have to use a MOVSB-type operation (to load the latches with the
; existing contents of display memory to allow the ALUs to work).
cmp byte ptr jALUFunc,DR_SET ;is it a replace-type rop?
jz short is_replace_type ;yes
;no, set up for non-replace whole bytes
mov ecx,offset whole_bytes_non_replace_wide
;assume too wide to special-case
cmp ebx,MAX_NON_REPLACE_SPECIAL ;too wide to special case?
jnb short start_vec_set ;yes
mov ecx,pfnWholeBytesNonReplaceEntries[ebx*4] ;no, point to entry
mov pfnWholeBytes,ecx ; table for width
mov ecx,offset whole_bytes_special
;set up to call special routine to fill
; whole bytes
jmp short start_vec_set
is_replace_type: ;set up for replace-type rop
cmp ebx,MAX_REPLACE_SPECIAL ;too wide to special case?
jnb short is_wide_replace ;yes
;narrow enough to special case. Look up
; the entry table for the special case
; base on the start alignment
mov ecx,ulRowOffset
add ecx,ulLeftEdgeAdjust ;left edge whole bytes start offset
and ecx,011b ;left edge whole bytes start alignment
; MOD 3
mov ecx,pfnWholeBytesReplaceMaster[ecx*4] ;look up table of entry
; tables for alignment
mov ecx,[ecx+ebx*4] ;look up entry table for width
mov pfnWholeBytes,ecx ; table for width
mov ecx,offset whole_bytes_special
;set up to call special routine to fill
; whole bytes
jmp short start_vec_set
is_wide_replace: ;set up for wide replace-type op
;Note: assumes there is at least one
; full dword involved!
mov ecx,ulRowOffset
add ecx,ulLeftEdgeAdjust ;left edge whole bytes start offset
neg ecx
and ecx,011b
mov edx,ebx
sub edx,ecx ;ignore odd leading bytes
mov eax,edx
shr edx,2 ;# of whole dwords across (not counting
; odd leading & trailing bytes)
mov ulWholeDwords,edx
and eax,011b ;# of odd (fractional) trailing bytes
shl ecx,2
or ecx,eax ;build a look-up index from the number
; of leading and trailing bytes
mov ecx,pfnWideWholeRep[ecx*4] ;proper drawing handler for front/
mov pfnWholeBytes,ecx ; back alignment
mov ecx,offset whole_bytes_rep_wide
;set up to call routine to perform wide
; whole bytes fill
start_vec_set:
mov pfnStartDrawing,ecx ; all partial (non-whole) edges
mov ecx,pdsurf
mov eax,[ecx].dsurf_lNextScan
mov ulScanWidth,eax ;local copy of scan line width
sub eax,ebx ;EAX = delta to next scan
mov ulNextScan,eax
;-----------------------------------------------------------------------;
; Fill this rectangle.
;-----------------------------------------------------------------------;
cmp byte ptr jInvertDestFirst,1
;is this an invert-dest-plus-something-
; else rop that requires two passes?
jz short do_invert_dest_rop ;yes, special case with two passes
do_single_pass:
call draw_banks
;-----------------------------------------------------------------------;
; See if there are any more rectangles to fill.
;-----------------------------------------------------------------------;
add prcl,(size RECTL) ;point to the next rectangle, if there is one
dec culRcl ;count down the rectangles to fill
jnz fill_rect_loop
;-----------------------------------------------------------------------;
; We have filled all rectangles. Restore the VGA to its default state.
;-----------------------------------------------------------------------;
mov edx,VGA_BASE + GRAF_ADDR
mov eax,0000h + GRAF_ENAB_SR ;disable set/reset
out dx,ax
mov eax,GRAF_MODE + ((M_PROC_WRITE + M_DATA_READ) SHL 8)
out dx,ax ;restore read mode 0 and write mode 0
cmp byte ptr jALUfunc,DR_SET ;is the logical function already SET?
jz short vTrgBlts_done ;yes, no need to reset it
mov eax,(DR_SET shl 8) + GRAF_DATA_ROT ;set the logical function to
out dx,ax ; SET
vTrgBlts_done:
cRet vTrgBlt
;-----------------------------------------------------------------------;
; Handles rops that require two passes, the first being a destination
; inversion pass.
;-----------------------------------------------------------------------;
do_invert_dest_rop:
; Set up the VGA's hardware for inversion
mov edx,VGA_BASE + GRAF_ADDR
mov eax,0ff00h + GRAF_SET_RESET ;set/reset = 0ffh to invert in
out dx,ax ; conjunction with XOR
mov eax,(DR_XOR shl 8) + GRAF_DATA_ROT
out dx,ax ;logical function = XOR to invert
; Invert the destination
call draw_banks
; Restore the VGA's hardware to the state required for the second pass.
mov edx,VGA_BASE + GRAF_ADDR
mov ah,byte ptr jDrawingColor
mov al,GRAF_SET_RESET ;set/reset = color to write
out dx,ax
mov ah,byte ptr jALUFunc
mov al,GRAF_DATA_ROT
out dx,ax ;set the ALU logical function
; Perform the second pass to finish the rop.
jmp do_single_pass
;-----------------------------------------------------------------------;
; Fills all banks in the current fill rectangle. Called once per fill
; rectangle, except for destination-inversion-plus-something-else rops.
;-----------------------------------------------------------------------;
draw_banks:
;-----------------------------------------------------------------------;
; Map in the bank containing the top scan to fill, if it's not mapped in
; already.
;-----------------------------------------------------------------------;
mov edi,prcl ;point to rectangle to fill
mov ecx,pdsurf ;point to surface
mov eax,[edi].yTop ;top scan line of fill
mov ulCurrentTopScan,eax ;this will be the fill top in 1st bank
cmp eax,[ecx].dsurf_rcl1WindowClip.yTop ;is fill top less than
; current bank?
jl short map_init_bank ;yes, map in proper bank
cmp eax,[ecx].dsurf_rcl1WindowClip.yBottom ;fill top greater than
; current bank?
jl short init_bank_mapped ;no, proper bank already mapped
map_init_bank:
; Map in the bank containing the top scan line of the fill.
ptrCall <dword ptr [ecx].dsurf_pfnBankControl>,<ecx,eax,JustifyTop>
init_bank_mapped:
;-----------------------------------------------------------------------;
; Main loop for processing fill in each bank.
;-----------------------------------------------------------------------;
; Compute the starting address and scan line count for the initial bank.
mov eax,pdsurf ;EAX->target surface
mov ebx,ulBottomScan ;bottom of destination rectangle
cmp ebx,[eax].dsurf_rcl1WindowClip.yBottom
;which comes first, the bottom of the
; dest rect or the bottom of the
; current bank?
jl short BottomScanSet ;fill bottom comes first, so draw to
; that; this is the last bank in fill
mov ebx,[eax].dsurf_rcl1WindowClip.yBottom
;bank bottom comes first; draw to
; bottom of bank
BottomScanSet:
mov edi,ulCurrentTopScan ;top scan line to fill in current bank
sub ebx,edi ;# of scans to fill in bank
imul edi,ulScanWidth ;offset of starting scan line
; Note that the start of the bitmap will change each time through the
; bank loop, because the start of the bitmap is varied to map the
; desired scan line to the banking window.
add edi,[eax].dsurf_pvBitmapStart ;start of scan in bitmap
add edi,ulRowOffset ;EDI = start offset of fill in bitmap
; We have computed the starting address and scan count. Time to start drawing
; in the initial bank.
jmp pfnStartDrawing
;-----------------------------------------------------------------------;
; Whole byte fills.
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; Handles non-replace whole byte fills wider than the maximum special
; case width.
;
; The destination is not involved, so a STOS (or equivalent) can be used
; (no read needed before write).
;-----------------------------------------------------------------------;
whole_bytes_rep_wide:
push ebx ;save scan count
push edi ;save starting address
add edi,ulLeftEdgeAdjust ;point to first whole byte to fill
mov esi,ulWholeDwords ;whole dwords width
mov eax,-1 ;this will become the Bit Mask,
; enabling drawing to all bits
mov edx,ulNextScan ;offset from end of one scan line to
; start of next
call pfnWholeBytes ;draw the wide whole bytes
pop edi ;restore screen pointer
pop ebx ;restore fill scan count
jmp pfnContinueDrawing ;either keep drawing or we're done
;-----------------------------------------------------------------------;
; Handles both replace and non-replace whole byte fills narrow enough to
; special case.
;-----------------------------------------------------------------------;
whole_bytes_special:
push ebx ;save scan count
push edi ;save starting address
add edi,ulLeftEdgeAdjust ;point to first whole byte to fill
mov ecx,ulScanWidth ;offset to next scan line
mov eax,-1 ;this will become the Bit Mask,
; enabling drawing to all bits
call pfnWholeBytes ;draw the whole bytes
pop edi ;restore screen pointer
pop ebx ;restore fill scan count
jmp pfnContinueDrawing ;either keep drawing or we're done
;-----------------------------------------------------------------------;
; Handles non-replace whole byte fills wider than the maximum special case
; width.
;
; The destination is involved, so a MOVSB (or equivalent) must be
; performed in order to do a read before write to give the ALUs something
; to work with.
;-----------------------------------------------------------------------;
whole_bytes_non_replace_wide:
push ebx ;save scan count
push edi ;save starting address
add edi,ulLeftEdgeAdjust ;point to first whole byte to fill
mov eax,ulWholeBytes ;whole bytes width
mov edx,ulNextScan ;offset from end of one scan line to
; start of next
call draw_wide_rw_loop ;draw the wide whole bytes
pop edi ;restore screen pointer
pop ebx ;restore fill scan count
jmp pfnContinueDrawing ;either keep drawing or we're done
;-----------------------------------------------------------------------;
; Process any left/right columns that that have to be done.
;
; Currently:
; EBX = height to fill, in scans
; EDI --> first byte of left edge
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; Handle case where both edges are partial (non-whole) bytes.
;-----------------------------------------------------------------------;
public do_both_edge_bytes
do_both_edge_bytes::
; Set up variables for entering loop.
mov ecx,ulScanWidth ;offset from one scan to next
mov esi,ulWholeBytes ;ESI = # of whole bytes
lea esi,[esi+edi+1] ;--> start for right edge
mov al,byte ptr ulMasks ;this will become the Bit Mask for the
; left edge
push ebx ;preserve scan line count
call draw_1_wide_rw_loop ;jump into the loop to draw
pop ebx ;restore scan line count
mov edi,esi ;point to first right edge byte
mov al,byte ptr ulMasks+1 ;this will become the Bit Mask for the
; right edge
push offset edges_done ;return here
jmp draw_1_wide_rw_loop ;jump into the loop to draw
;-----------------------------------------------------------------------;
; Handle case where only the left edge is partial (non-whole).
;-----------------------------------------------------------------------;
do_left_edge_bytes::
; Set up variables for entering loop.
mov ecx,ulScanWidth ;offset from one scan to next
mov al,byte ptr ulMasks ;this will become the Bit Mask for the
; left edge
push offset edges_done ;return here
jmp draw_1_wide_rw_loop ;jump into the loop to draw
;-----------------------------------------------------------------------;
; Handle case where only the right edge is partial (non-whole).
;-----------------------------------------------------------------------;
do_right_edge_bytes::
; Set up variables for entering loop.
mov ecx,ulScanWidth ;offset from one scan to next
add edi,ulWholeBytes ;--> start for right edge (remember,
; left edge is whole, so the left edge
; byte is included in the whole byte
; count)
mov al,byte ptr ulMasks+1 ;this will become the Bit Mask for the
; right edge
call draw_1_wide_rw_loop ;jump into the loop to draw
;-----------------------------------------------------------------------;
; We have done all partial edges.
;-----------------------------------------------------------------------;
edges_done:
;-----------------------------------------------------------------------;
; See if there are any more banks to process.
;-----------------------------------------------------------------------;
check_next_bank::
mov edi,pdsurf
mov eax,[edi].dsurf_rcl1WindowClip.yBottom ;is the fill bottom in
cmp ulBottomScan,eax ; the current bank?
jle short banks_done ;yes, so we're done
;no, map in the next bank and fill it
mov ulCurrentTopScan,eax ;remember where the top of the bank
; we're about to map in is (same as
; bottom of bank we just did)
ptrCall <dword ptr [edi].dsurf_pfnBankControl>,<edi,eax,JustifyTop>
;map in the bank
; Compute the starting address and scan line count in this bank.
mov eax,pdsurf ;EAX->target surface
mov ebx,ulBottomScan ;bottom of destination rectangle
cmp ebx,[eax].dsurf_rcl1WindowClip.yBottom
;which comes first, the bottom of the
; dest rect or the bottom of the
; current bank?
jl short BottomScanSet2 ;fill bottom comes first, so draw to
; that; this is the last bank in fill
mov ebx,[eax].dsurf_rcl1WindowClip.yBottom
;bank bottom comes first; draw to
; bottom of bank
BottomScanSet2:
mov edi,ulCurrentTopScan ;top scan line to fill in current bank
sub ebx,edi ;# of scans to fill in bank
imul edi,ulScanWidth ;offset of starting scan line
; Note that the start of the bitmap will change each time through the
; bank loop, because the start of the bitmap is varied to map the
; desired scan line to the banking window.
add edi,[eax].dsurf_pvBitmapStart ;start of scan in bitmap
add edi,ulRowOffset ;EDI = start offset of fill in bitmap
; Draw in the new bank.
jmp pfnStartDrawing
;-----------------------------------------------------------------------;
; Done with all banks in this fill.
banks_done:
PLAIN_RET
endProc vTrgBlt
;-----------------------------------------------------------------------;
; Drawing loops.
; There are two kinds of loops: read-before-write (to load the
; latches), and write-only (for replace-type rops).
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; Drawing stuff for cases where read before write is required,
; to load the latches.
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; 1-, 2-, 3-, and 4-wide read before write drawing loops.
;
; Entry:
; AL = pixel mask
; EBX = loop count
; ECX = scan line width in bytes
; EDI = start offset
;
; EBX, EDI modified. All other registers preserved.
;-----------------------------------------------------------------------;
; 1-wide read/write.
draw_1_wide_rw_loop proc near
and [edi],al ;we always read 0xFF, so AL is written
; as-is; because we're in write mode 3,
; AL becomes the Bit Mask
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_1_wide_rw_loop
ret
draw_1_wide_rw_loop endp
;-----------------------------------------------------------------------;
; 2-wide read/write.
draw_2_wide_rw_loop proc near
and [edi],al
and [edi+1],al
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_2_wide_rw_loop
ret
draw_2_wide_rw_loop endp
;-----------------------------------------------------------------------;
; 3-wide read/write.
draw_3_wide_rw_loop proc near
and [edi],al
and [edi+1],al
and [edi+2],al
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_3_wide_rw_loop
ret
draw_3_wide_rw_loop endp
;-----------------------------------------------------------------------;
; 4-wide read/write.
draw_4_wide_rw_loop proc near
and [edi],al
and [edi+1],al
and [edi+2],al
and [edi+3],al
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_4_wide_rw_loop
ret
draw_4_wide_rw_loop endp
;-----------------------------------------------------------------------;
; 5-or-wider read before write loop.
;
; Entry:
; EAX = # of bytes to fill across scan line (needed only by 5-or-wider
; handler)
; EBX = loop count
; EDX = offset from end of one scan line to the start of the next next
; EDI = start offset
;
; EBX, ECX, ESI, EDI modified. All other registers preserved.
;-----------------------------------------------------------------------;
; 5-or-wider read/write. Draws five or more read before write bytes, then
; advances to next scan line. (Actually, will handle any number of bytes,
; including 0, but there are special-case handlers for narrow cases.)
; Works because reads of display memory return 0ffh, which then becomes the
; Bit Mask as it's written in write mode 3.
draw_wide_rw_loop proc near
mov esi,edi
mov ecx,eax
rep movsb
add edi,edx
dec ebx
jnz draw_wide_rw_loop
ret
draw_wide_rw_loop endp
;-----------------------------------------------------------------------;
; Drawing stuff for cases where read before write is NOT required.
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; [BUGFIX] - dword writes mess up the cirrus 542x chips so change them
; to word writes.
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; 1-, 2-, 3-, and 4-wide write-only edge-drawing loops.
;
; Entry:
; AL/AX/EAX = pixel mask (if AX or EAX, then 0xFFFF or 0xFFFFFFFF)
; EBX = loop count
; ECX = scan line width in bytes
; EDI = start offset
;
; EBX, EDI modified. All other registers preserved.
;-----------------------------------------------------------------------;
; 1-wide write-only.
draw_1_wide_w_loop proc near
mov [edi],al ;we always read 0xFF, so AL is written
; as-is; because we're in write mode 3,
; AL becomes the Bit Mask
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_1_wide_w_loop
ret
draw_1_wide_w_loop endp
;-----------------------------------------------------------------------;
; 2-wide write-only.
draw_2_wide_w_loop proc near
mov [edi],ax
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_2_wide_w_loop
ret
draw_2_wide_w_loop endp
;-----------------------------------------------------------------------;
; 3-wide write-only, starting at an even address.
draw_3_wide_w_even_loop proc near
mov [edi],ax
mov [edi+2],al
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_3_wide_w_even_loop
ret
draw_3_wide_w_even_loop endp
;-----------------------------------------------------------------------;
; 3-wide write-only, starting at an odd address.
draw_3_wide_w_odd_loop proc near
mov [edi],al
mov [edi+1],ax
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_3_wide_w_odd_loop
ret
draw_3_wide_w_odd_loop endp
;-----------------------------------------------------------------------;
; 4-wide write-only.
draw_4_wide_w_loop proc near
mov [edi],ax
mov [edi+2],ax
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_4_wide_w_loop
ret
draw_4_wide_w_loop endp
;-----------------------------------------------------------------------;
; 5-wide write-only, starting at an even address.
draw_5_wide_w_even_loop proc near
mov [edi],ax
mov [edi+2],ax
mov [edi+4],al
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_5_wide_w_even_loop
ret
draw_5_wide_w_even_loop endp
;-----------------------------------------------------------------------;
; 5-wide write-only, starting at an odd address.
draw_5_wide_w_odd_loop proc near
mov [edi],al
mov [edi+1],ax
mov [edi+3],ax
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_5_wide_w_odd_loop
ret
draw_5_wide_w_odd_loop endp
;-----------------------------------------------------------------------;
; 6-wide write-only, starting at MOD 3 == 0.
draw_6_wide_w_mod3_0_loop proc near
mov [edi],ax
mov [edi+2],ax
mov [edi+4],ax
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_6_wide_w_mod3_0_loop
ret
draw_6_wide_w_mod3_0_loop endp
;-----------------------------------------------------------------------;
; 6-wide write-only, starting at MOD 3 == 1 or 3.
draw_6_wide_w_mod3_1_loop proc near
mov [edi],al
mov [edi+1],ax
mov [edi+3],ax
mov [edi+5],al
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_6_wide_w_mod3_1_loop
ret
draw_6_wide_w_mod3_1_loop endp
;-----------------------------------------------------------------------;
; 6-wide write-only, starting at MOD 3 == 2.
draw_6_wide_w_mod3_2_loop proc near
mov [edi],ax
mov [edi+2],ax
mov [edi+4],ax
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_6_wide_w_mod3_2_loop
ret
draw_6_wide_w_mod3_2_loop endp
;-----------------------------------------------------------------------;
; 7-wide write-only, starting at MOD 3 == 0.
draw_7_wide_w_mod3_0_loop proc near
mov [edi],ax
mov [edi+2],ax
mov [edi+4],ax
mov [edi+6],al
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_7_wide_w_mod3_0_loop
ret
draw_7_wide_w_mod3_0_loop endp
;-----------------------------------------------------------------------;
; 7-wide write-only, starting at MOD 3 == 0.
draw_7_wide_w_mod3_1_loop proc near
mov [edi],al
mov [edi+1],ax
mov [edi+3],ax
mov [edi+5],ax
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_7_wide_w_mod3_1_loop
ret
draw_7_wide_w_mod3_1_loop endp
;-----------------------------------------------------------------------;
; 7-wide write-only, starting at MOD 3 == 2.
draw_7_wide_w_mod3_2_loop proc near
mov [edi],ax
mov [edi+2],ax
mov [edi+4],ax
mov [edi+6],al
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_7_wide_w_mod3_2_loop
ret
draw_7_wide_w_mod3_2_loop endp
;-----------------------------------------------------------------------;
; 7-wide write-only, starting at MOD 3 == 3.
draw_7_wide_w_mod3_3_loop proc near
mov [edi],al
mov [edi+1],ax
mov [edi+3],ax
mov [edi+5],ax
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_7_wide_w_mod3_3_loop
ret
draw_7_wide_w_mod3_3_loop endp
;-----------------------------------------------------------------------;
; 8-wide write-only, starting at MOD 3 == 0.
draw_8_wide_w_mod3_0_loop proc near
mov [edi],ax
mov [edi+2],ax
mov [edi+4],ax
mov [edi+6],ax
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_8_wide_w_mod3_0_loop
ret
draw_8_wide_w_mod3_0_loop endp
;-----------------------------------------------------------------------;
; 8-wide write-only, starting at MOD 3 == 1.
draw_8_wide_w_mod3_1_loop proc near
mov [edi],al
mov [edi+1],ax
mov [edi+3],ax
mov [edi+5],ax
mov [edi+7],al
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_8_wide_w_mod3_1_loop
ret
draw_8_wide_w_mod3_1_loop endp
;-----------------------------------------------------------------------;
; 8-wide write-only, starting at MOD 3 == 2.
draw_8_wide_w_mod3_2_loop proc near
mov [edi],ax
mov [edi+2],ax
mov [edi+4],ax
mov [edi+6],ax
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_8_wide_w_mod3_2_loop
ret
draw_8_wide_w_mod3_2_loop endp
;-----------------------------------------------------------------------;
; 8-wide write-only, starting at MOD 3 == 3.
draw_8_wide_w_mod3_3_loop proc near
mov [edi],al
mov [edi+1],ax
mov [edi+3],ax
mov [edi+5],ax
mov [edi+7],al
add edi,ecx ;point to the next scan line
dec ebx
jnz draw_8_wide_w_mod3_3_loop
ret
draw_8_wide_w_mod3_3_loop endp
;-----------------------------------------------------------------------;
; Drawing loops for wide replace-type rops (arbitrary width).
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; N-wide write-only, 0 leading bytes, 0 trailing bytes.
; EAX = 0ffffh
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_00_loop proc near
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_00_loop
ret
draw_wide_w_00_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 0 leading bytes, 1 trailing byte.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_01_loop proc near
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
stosb ;fill the trailing byte
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_01_loop
ret
draw_wide_w_01_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 0 leading bytes, 2 trailing byte.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_02_loop proc near
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
stosw ;fill the trailing word
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_02_loop
ret
draw_wide_w_02_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 0 leading bytes, 3 trailing bytes.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_03_loop proc near
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
stosw ;fill the trailing word
stosb ;fill the trailing byte
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_03_loop
ret
draw_wide_w_03_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 1 leading byte, 0 trailing bytes.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_10_loop proc near
stosb ;fill the leading byte
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_10_loop
ret
draw_wide_w_10_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 1 leading bytes, 1 trailing byte.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_11_loop proc near
stosb ;fill the leading byte
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
stosb ;fill the trailing byte
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_11_loop
ret
draw_wide_w_11_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 1 leading bytes, 2 trailing byte.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_12_loop proc near
stosb ;fill the leading byte
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
stosw ;fill the trailing word
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_12_loop
ret
draw_wide_w_12_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 0 leading bytes, 3 trailing bytes.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_13_loop proc near
stosb ;fill the leading byte
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
stosw ;fill the trailing word
stosb ;fill the trailing byte
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_13_loop
ret
draw_wide_w_13_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 2 leading bytes, 0 trailing bytes.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_20_loop proc near
stosw ;fill the leading word
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_20_loop
ret
draw_wide_w_20_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 2 leading bytess, 1 trailing byte.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_21_loop proc near
stosw ;fill the leading word
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
stosb ;fill the trailing byte
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_21_loop
ret
draw_wide_w_21_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 2 leading bytess, 2 trailing byte.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_22_loop proc near
stosw ;fill the leading word
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
stosw ;fill the trailing word
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_22_loop
ret
draw_wide_w_22_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 0 leading bytes, 3 trailing bytes.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_23_loop proc near
stosw ;fill the leading word
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
stosw ;fill the trailing word
stosb ;fill the trailing byte
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_23_loop
ret
draw_wide_w_23_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 3 leading bytes, 0 trailing bytes.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_30_loop proc near
stosb ;fill the leading byte
stosw ;fill the leading word
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_30_loop
ret
draw_wide_w_30_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 3 leading bytess, 1 trailing byte.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_31_loop proc near
stosb ;fill the leading byte
stosw ;fill the leading word
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
stosb ;fill the trailing byte
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_31_loop
ret
draw_wide_w_31_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 3 leading bytess, 2 trailing byte.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_32_loop proc near
stosb ;fill the leading byte
stosw ;fill the leading word
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
stosw ;fill the trailing word
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_32_loop
ret
draw_wide_w_32_loop endp
;-----------------------------------------------------------------------;
; N-wide write-only, 0 leading bytes, 3 trailing bytes.
; EAX = # of dwords to fill
; EBX = count of scans to fill
; EDX = offset from end of one scan's fill to start of next
; ESI = # of dwords to fill
; EDI = target address to fill
draw_wide_w_33_loop proc near
stosb ;fill the leading byte
stosw ;fill the leading word
mov ecx,esi ;# of whole dwords
shl ecx,1
rep stosw ;fill all whole bytes as words
stosw ;fill the trailing word
stosb ;fill the trailing byte
add edi,edx ;point to the next scan line
dec ebx
jnz draw_wide_w_33_loop
ret
draw_wide_w_33_loop endp
;--------------------------Private-Routine------------------------------;
; comp_byte_interval
;
; A interval will be computed for byte boundaries.
;
; 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 to adjust for it.
;
; Entry:
; EBX = right coordinate (exclusive)
; EDX = left coordinate (inclusive)
; Returns:
; EDI = offset to first byte to be altered in the scan
; ESI = inner loop count
; AL = first byte mask (possibly 0)
; AH = last byte mask (possibly 0)
; Error Returns:
; None
; Registers Preserved:
; ES,BP
; Registers Destroyed:
; AX,BX,CX,DX,SI,DI,FLAGS
; Calls:
; None
; History:
; Sat 11-Apr-1987 20:39:10 -by- Walt Moore [waltm]
; Created.
;-----------------------------------------------------------------------;
cProc comp_byte_interval
sub ebx,edx ;Compute extent of interval
dec ebx ;Make interval inclusive
mov edi,edx ;Don't destroy starting X
shr edi,3 ;/8 for byte address
and edx,00000111b ;Compute bit index for left side
add ebx,edx ;Compute bit index for right side
mov esi,ebx ;(save for inner loop count)
and ebx,00000111b
mov cl,dl ;Compute left side altered bits mask
mov eax,0FFFFFFFFh
mov edx,eax ;Need this here later
shr al,cl ;AL = left side altered bytes mask
mov cl,bl ;Compute right side altered bits mask
mov ah,80h
sar ah,cl ;AH = right side altered bits mask
shr esi,3 ;Compute inner byte count
jnz short comp_byte_dont_combine ;loop count + 1 > 0, check it out
; Only one byte will be affected. Combine first/last masks, set loop count = 0
and al,ah ;Will use first byte mask only
xor ah,ah ;Want last byte mask to be 0
inc esi ;Fall through to set 0
comp_byte_dont_combine:
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 mask.
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 ah,dl ;Set 'C' if not all pixels 1
sbb esi,edx ;If no 'C', sub -1 (add 1), else sub 0
cmp ah,dl ;Set 'C' if not all pixels 1
sbb ah,dl ;If no 'C', sub -1 (add 1), else sub 0
cRet comp_byte_interval
endProc comp_byte_interval
_TEXT$01 ends
end