Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2972 lines
124 KiB

;---------------------------Module-Header------------------------------;
; Module Name: fasttext.asm
;
; Copyright (c) 1992 Microsoft Corporation
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; BOOL vFastText(PDEV * ppdev, GLYPHPOS * pGlyphPos, ULONG ulGlyphCount,
; PBYTE pTempBuffer, ULONG ulBufDelta, ULONG ulCharInc,
; RECTL * prclText, RECTL * prclOpaque, INT iFgColor,
; INT iBgColor, ULONG fDrawFlags);
; ppdev -
; pGlyphPos -
; ulGlyphCount - # of glyphs to draw. Must never be 0.
; pTempBuffer -
; ulBufDelta - logical width of temp buffer in bytes. This value *must* be the
; same number of bytes spanned by prclText; it is assumed that
; scans in the temp buffer are contiguous
; ulCharInc -
; prclText -
; prclOpaque -
; iFgColor -
; iBgColor -
; fDrawFlags -
;
; Performs accelerated proportional text drawing.
;
;-----------------------------------------------------------------------;
;
; Note: The general opaque text back-end currently assumes that it will
; never receive a text string with a bounding box that does not span at
; least one quadpixel (the four pixels at a VGA screen address).
;
;-----------------------------------------------------------------------;
;
; Note: The term "quadpixel" means a four-pixel set stored across all
; four planes of VGA memory in planar high-color mode. Quadpixels map to
; nibbles in the temp buffer in which text is assembled, where nibbles
; are always bits 4-7 or 0-3.
;
;-----------------------------------------------------------------------;
;
; Note: The direction flag is *not* explicitly set or cleared.
;
;-----------------------------------------------------------------------;
;
; Note: Assumes the text rectangle has a positive height and width. Will
; not work properly if this is not the case.
;
;-----------------------------------------------------------------------;
comment $
The overall approach of this module is to draw the text into a system
memory buffer, then copy the buffer to the screen a word at a time
using write mode 2 and clever use of the VGA hardware so that no OUTs
and a minimum of display memory reads are required. The clever use is
setting the ALUs to XOR, the latches to the background color, and the
write mode to 2, so each nibble in bits 0-3 written by the CPU turns
into 0 or 0ffh for that plane. Then the Bit Mask is set to fg ^ bg,
so that common bits between the fg and bg are preserved, while non-
common bits are either preserved (=bg color) by a 0->000h bit for
that plane, or flipped (=fg color) by a 1->0ffh bit for that plane. The
Map Mask is used to clip edges; no read before write is required. Note
that bits 0-3 must be reversed to match the order of pixels in planes
0-3. Note also that we write a whole word, containing two nibbles in
bits 0-3 of each byte, at once, to draw 8 pixels per write.
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 cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
assume fs:nothing,gs:nothing
.xlist
include stdcall.inc ;calling convention cmacros
include i386\strucs.inc
include i386\driver.inc
include i386\egavga.inc
.list
;-----------------------------------------------------------------------;
.data
;-----------------------------------------------------------------------;
; Tables used to branch into glyph-drawing optimizations.
;
; Handles narrow (1-4 bytes wide) glyph drawing, for case where initial byte
; should be MOVed even if it's not aligned (intended for use in drawing the
; first glyph in a string). Table format is:
; Bits 3-2: dest width
; Bit 1 : 1 if don't need last source byte, 0 if do need last source byte
; Bit 0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
align 4
MovInitialTableNarrow label dword
dd draw_prop_done ;0 wide
dd draw_prop_done ;0 wide
dd draw_prop_done ;0 wide
dd draw_prop_done ;0 wide
dd mov_first_1_wide_rotated_need_last ;nonalign, 1 wide, need last
dd mov_first_1_wide_unrotated ;aligned, 1 wide
dd mov_first_1_wide_rotated_no_last ;nonalign, 1 wide, no last
dd mov_first_1_wide_unrotated ;aligned, 1 wide
dd mov_first_2_wide_rotated_need_last ;nonalign, 2 wide, need last
dd mov_first_2_wide_unrotated ;aligned, 2 wide
dd mov_first_2_wide_rotated_no_last ;nonalign, 2 wide, no last
dd mov_first_2_wide_unrotated ;aligned, 2 wide
dd mov_first_3_wide_rotated_need_last ;nonalign, 3 wide, need last
dd mov_first_3_wide_unrotated ;aligned, 3 wide
dd mov_first_3_wide_rotated_no_last ;nonalign, 3 wide, no last
dd mov_first_3_wide_unrotated ;aligned, 3 wide
dd mov_first_4_wide_rotated_need_last ;nonalign, 4 wide, need last
dd mov_first_4_wide_unrotated ;aligned, 4 wide
dd mov_first_4_wide_rotated_no_last ;nonalign, 4 wide, no last
dd mov_first_4_wide_unrotated ;aligned, 4 wide
; Handles narrow (1-4 bytes wide) glyph drawing, for case where initial byte
; ORed if it's not aligned (intended for use in drawing all but the first glyph
; in a string). Table format is:
; Bits 3-2: dest width
; Bit 1 : 1 if don't need last source byte, 0 if do need last source byte
; Bit 0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
align 4
OrInitialTableNarrow label dword
dd draw_prop_done ;0 wide
dd draw_prop_done ;0 wide
dd draw_prop_done ;0 wide
dd draw_prop_done ;0 wide
dd or_first_1_wide_rotated_need_last ;nonalign, 1 wide, need last
dd mov_first_1_wide_unrotated ;aligned, 1 wide
dd or_first_1_wide_rotated_no_last ;nonalign, 1 wide, no last
dd mov_first_1_wide_unrotated ;aligned, 1 wide
dd or_first_2_wide_rotated_need_last ;nonalign, 2 wide, need last
dd mov_first_2_wide_unrotated ;aligned, 2 wide
dd or_first_2_wide_rotated_no_last ;nonalign, 2 wide, no last
dd mov_first_2_wide_unrotated ;aligned, 2 wide
dd or_first_3_wide_rotated_need_last ;nonalign, 3 wide, need last
dd mov_first_3_wide_unrotated ;aligned, 3 wide
dd or_first_3_wide_rotated_no_last ;nonalign, 3 wide, no last
dd mov_first_3_wide_unrotated ;aligned, 3 wide
dd or_first_4_wide_rotated_need_last ;nonalign, 4 wide, need last
dd mov_first_4_wide_unrotated ;aligned, 4 wide
dd or_first_4_wide_rotated_no_last ;nonalign, 4 wide, no last
dd mov_first_4_wide_unrotated ;aligned, 4 wide
; Handles narrow (1-4 bytes wide) glyph drawing, for case where all bytes
; should be ORed (intended for use in drawing potentially overlapping glyphs).
; Table format is:
; Bits 3-2: dest width
; Bit 1 : 1 if don't need last source byte, 0 if do need last source byte
; Bit 0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
align 4
OrAllTableNarrow label dword
dd draw_prop_done ;0 wide
dd draw_prop_done ;0 wide
dd draw_prop_done ;0 wide
dd draw_prop_done ;0 wide
dd or_all_1_wide_rotated_need_last ;nonalign, 1 wide, need last
dd or_all_1_wide_unrotated ;aligned, 1 wide
dd or_all_1_wide_rotated_no_last ;nonalign, 1 wide, no last
dd or_all_1_wide_unrotated ;aligned, 1 wide
dd or_all_2_wide_rotated_need_last ;nonalign, 2 wide, need last
dd or_all_2_wide_unrotated ;aligned, 2 wide
dd or_all_2_wide_rotated_no_last ;nonalign, 2 wide, no last
dd or_all_2_wide_unrotated ;aligned, 2 wide
dd or_all_3_wide_rotated_need_last ;nonalign, 3 wide, need last
dd or_all_3_wide_unrotated ;aligned, 3 wide
dd or_all_3_wide_rotated_no_last ;nonalign, 3 wide, no last
dd or_all_3_wide_unrotated ;aligned, 3 wide
dd or_all_4_wide_rotated_need_last ;nonalign, 4 wide, need last
dd or_all_4_wide_unrotated ;aligned, 4 wide
dd or_all_4_wide_rotated_no_last ;nonalign, 4 wide, no last
dd or_all_4_wide_unrotated ;aligned, 4 wide
; Handles arbitrarily wide glyph drawing, for case where initial byte should be
; MOVed even if it's not aligned (intended for use in drawing the first glyph
; in a string). Table format is:
; Bit 1 : 1 if don't need last source byte, 0 if do need last source byte
; Bit 0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
align 4
MovInitialTableWide label dword
dd mov_first_N_wide_rotated_need_last ;nonalign, need last
dd mov_first_N_wide_unrotated ;aligned
dd mov_first_N_wide_rotated_no_last ;nonalign, no last
dd mov_first_N_wide_unrotated ;aligned
; Handles arbitrarily wide glyph drawing, for case where initial byte should be
; ORed if it's not aligned (intended for use in drawing all but the first glyph
; in a string). Table format is:
; Bit 1 : 1 if don't need last source byte, 0 if do need last source byte
; Bit 0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
align 4
OrInitialTableWide label dword
dd or_first_N_wide_rotated_need_last ;nonalign, need last
dd mov_first_N_wide_unrotated ;aligned
dd or_first_N_wide_rotated_no_last ;nonalign, no last
dd mov_first_N_wide_unrotated ;aligned
; Handles arbitrarily wide glyph drawing, for case where all bytes should
; be ORed (intended for use in drawing potentially overlapping glyphs).
; Table format is:
; Bit 1 : 1 if don't need last source byte, 0 if do need last source byte
; Bit 0 : 1 if no rotation (aligned), 0 if rotation (non-aligned)
align 4
OrAllTableWide label dword
dd or_all_N_wide_rotated_need_last ;nonalign, need last
dd or_all_N_wide_unrotated ;aligned
dd or_all_N_wide_rotated_no_last ;nonalign, no last
dd or_all_N_wide_unrotated ;aligned
; Vectors to entry points for drawing various types of text. '*' means works as
; is but could be acclerated with a custom scanning loop.
align 4
MasterTextTypeTable label dword ;tops aligned overlap fixed pitch
dd draw_nf_ntb_o_to_temp_start ; N N N *
dd draw_f_ntb_o_to_temp_start ; N N Y *
dd draw_nf_ntb_o_to_temp_start ; N Y N
dd draw_f_ntb_o_to_temp_start ; N Y Y
dd draw_nf_tb_no_to_temp_start ; Y N N
dd draw_f_tb_no_to_temp_start ; Y N Y
dd draw_nf_ntb_o_to_temp_start ; Y Y N *
dd draw_f_ntb_o_to_temp_start ; Y Y Y *
;-----------------------------------------------------------------------
; Tables of pointers to optimizations for drawing up to four pixels
; of transparent text based on the upper or lower nibble of a byte.
align 4
xpar_high_nibble_table label dword
dd xpar_high_nibble_0
dd xpar_high_nibble_1
dd xpar_high_nibble_2
dd xpar_high_nibble_3
dd xpar_high_nibble_4
dd xpar_high_nibble_5
dd xpar_high_nibble_6
dd xpar_high_nibble_7
dd xpar_high_nibble_8
dd xpar_high_nibble_9
dd xpar_high_nibble_A
dd xpar_high_nibble_B
dd xpar_high_nibble_C
dd xpar_high_nibble_D
dd xpar_high_nibble_E
dd xpar_high_nibble_F
align 4
xpar_low_nibble_table label dword
dd xpar_low_nibble_0
dd xpar_low_nibble_1
dd xpar_low_nibble_2
dd xpar_low_nibble_3
dd xpar_low_nibble_4
dd xpar_low_nibble_5
dd xpar_low_nibble_6
dd xpar_low_nibble_7
dd xpar_low_nibble_8
dd xpar_low_nibble_9
dd xpar_low_nibble_A
dd xpar_low_nibble_B
dd xpar_low_nibble_C
dd xpar_low_nibble_D
dd xpar_low_nibble_E
dd xpar_low_nibble_F
; Masks for clipping for the four possible left and right edge alignments
jOpaqueLeftMasks label byte
db 0ffh,00eh,00ch,008h
jOpaqueRightMasks label byte
db 0ffh,001h,003h,007h
;-----------------------------------------------------------------------;
.code
;-----------------------------------------------------------------------;
cProc vFastText,44,<\
uses esi edi ebx,\
ppdev:ptr,\
pGlyphPos:ptr,\
ulGlyphCount:dword,\
pTempBuffer:ptr,\
ulBufDelta:dword,\
ulCharInc:dword,\
prclText:ptr,\
prclOpaque:ptr,\
iFgColor:dword,\
iBgColor:dword,\
fDrawFlags:dword>
local ulGlyDelta:dword ;width per scan of source glyph, in bytes
local ulWidthInBytes:dword ;width of glyph, in bytes
local ulTmpWidthInBytes:dword ;working byte-width count
local ulGlyphX:dword ;for fixed-pitch text, maintains the current
; glyph's left-edge X coordinate
local pGlyphLoop:dword ;pointer to glyph-processing loop
local ulTempLeft:dword ;X coordinate on screen of left edge of temp
; buffer
local ulXparBytes:dword ;general loop count storage
local ulTmpSrcDelta:dword ;distance from end of one buffer text scan to
; start of next
local ulTmpDstDelta:dword ;distance from end of one screen text scan to
; start of next
local ulTopScan:dword ;top scan of dest text rect in current bank
local ulBottomScan:dword ;bottom scan of dest text rect
local ulNumScans:dword ;# of scans to draw
local ulScreenDelta:dword ;scan-to-scan offset in screen
local ulScreenDeltaLinear:dword ;scan-to-scan offset in screen when in
; nice, neat linear packed-pixel mode
local ulTextWidthInBytesMinus1:dword ;# of bytes across spanned by
; text, minus 1
local pScreen:dword ;pointer to first screen byte to which to draw
local pfnEdgeVector:dword ;pointer to routine to draw any needed edges
local pfnFirstOpaqVector:dword ;pointer to initial drawing routine
; called for opaque (either whole
; bytes, or edge(s) if no whole bytes)
local ulWholeWidthInQuadpixelPairs:dword ;# of quadpixel pairs to copy
local ulWholeWidthInQuadpixelPairsMinus1:dword ;# of whole bytes to
; copy - 1
local ulOddQuadpixel:dword ;1 if odd quadpixel in quadpixel-pair
; copy
local ulTextLeft:dword ;left edge of leftmost glyph
local ulLeftMask:dword ;for opaque text, left edge mask for string
local ulRightMask:dword ;for opaque text, right edge mask for string
local ulScans:dword ;# of scans in glyph
local ulYOrigin:dword ;Y origin of text in string (all glyphs are at
; the same Y origin)
local pGlyphFlipTable:dword ;pointer to look-up table used to reverse
; the order of bits 0-3 and 4-7
local ulLeftEdgeShift:dword ;amount by which to right-shift left-edge
; nibbles during opaque expansion to
; right-justify them (0 or 4)
local ulRightEdgeShift:dword ;amount by which to right-shift right-edge
; nibbles during opaque expansion to
; right-justify them (0 or 4)
local ulVGAWidthInBytesMinus1:dword ;# of VGA addresses from left edge
; to right edge of destination
;-----------------------------------------------------------------------;
; Set the pointer to the table used to flip glyph bits 0-3 and 4-7. This
; table is guaranteed to be on a 256-byte boundary, so look-up can be
; performed simply by loading the low byte of a pointer register.
;-----------------------------------------------------------------------;
mov esi,ppdev
mov ebx,prclText ;point to bounding text rect during 486
; interlock slot
mov eax,[esi].pdev_pjGlyphFlipTable
mov pGlyphFlipTable,eax
;-----------------------------------------------------------------------;
; If 8 wide, byte aligned, and opaque, handle with very fast special-case
; code.
;-----------------------------------------------------------------------;
cmp ulCharInc,8 ;8 wide?
jnz short @F ;no
cmp fDrawFlags,5 ;fixed pitch?
jnz short @F ;no
cmp prclOpaque,0 ;opaque?
jz short @F ;no
test [ebx].xLeft,111b ;byte aligned?
jz special_8_wide_aligned_opaque ;yes, special-case
@@:
general_handler::
mov esi,ppdev
mov eax,[ebx].yTop
mov ulTopScan,eax ;Y screen coordinate of top edge of temp buf
mov eax,[ebx].xLeft
and eax,not 7
mov ulTempLeft,eax ;X screen coordinate of left edge of temp buf
mov eax,fDrawFlags
mov edx,[ebx].yBottom
mov ulBottomScan,edx ;bottom scan of text area
jmp MasterTextTypeTable[eax*4]
;-----------------------------------------------------------------------;
; Entry point for fixed-pitch | tops and bottoms aligned | no overlap.
; Sets up to draw first glyph.
;-----------------------------------------------------------------------;
draw_f_tb_no_to_temp_start::
mov ebx,pGlyphPos ;point to the first glyph to draw
mov esi,[ebx].gp_pgdf ;point to glyph def
mov edi,[ebx].gp_x ;dest X coordinate
sub edi,ulTempLeft ;adjust relative to the left of the
; temp buffer (we assume the text is
; right at the top of the text rect
; and hence the buffer)
mov ulGlyphX,edi ;remember where this glyph started
mov esi,[esi].gdf_pgb ;point to glyph bits
mov pGlyphLoop,offset draw_f_tb_no_to_temp_loop
;draw additional characters with this
; loop
jmp short draw_to_temp_start_entry
;-----------------------------------------------------------------------;
; Entry point for non-fixed-pitch | tops and bottoms aligned | no overlap.
; Sets up to draw first glyph.
;-----------------------------------------------------------------------;
draw_nf_tb_no_to_temp_start::
mov ebx,pGlyphPos ;point to the first glyph to draw
mov esi,[ebx].gp_pgdf ;point to glyph def
mov edi,[ebx].gp_x ;dest X coordinate
sub edi,ulTempLeft ;adjust relative to the left of the
; temp buffer
mov esi,[esi].gdf_pgb ;point to glyph bits
mov pGlyphLoop,offset draw_nf_tb_no_to_temp_loop
;draw additional characters with this
; loop
draw_to_temp_start_entry::
add edi,[esi].gb_x ;adjust to position of upper left glyph
; corner in dest
mov ecx,edi
shr edi,3 ;byte offset of first column of glyph
; offset of upper left of glyph in temp
; buffer
add edi,pTempBuffer ;initial dest byte in temp buffer
and ecx,111b ;bit alignment of upper left in temp
;calculate scan-to-scan glyph width
mov ebx,[esi].gb_cx ;glyph width in pixels
lea eax,[ebx+ecx+7]
shr eax,3 ;# of dest bytes per scan
add ebx,7
shr ebx,3 ;# of source bytes per scan
mov edx,ulBufDelta ;width of destination buffer in bytes
cmp eax,4 ;do we have special case code for this
; dest width?
ja short @F ;no, handle as general case
;yes, handle as special case
cmp ebx,eax ;carry if more dest than source bytes
; (last source byte not needed)
rcl eax,1 ;factor last source byte status in
cmp cl,1 ;carry if aligned
rcl eax,1 ;factor in alignment (aligned or not)
mov ebx,[esi].gb_cy ;# of scans in glyph
add esi,gb_aj ;point to the first glyph byte
jmp MovInitialTableNarrow[eax*4]
;branch to draw the first glyph; never
; need to OR first glyph, because
; there's nothing there yet
@@: ;too wide to special case
mov ulWidthInBytes,eax ;# of bytes across dest
cmp ebx,eax ;carry if more dest than source bytes
; (last source byte not needed)
mov eax,0
rcl eax,1 ;factor last source byte status in
cmp cl,1 ;carry if aligned
rcl eax,1 ;factor in alignment (aligned or not)
mov ebx,[esi].gb_cx ;glyph width in pixels
add ebx,7
shr ebx,3 ;glyph width in bytes
mov ulGlyDelta,ebx
mov ebx,[esi].gb_cy ;# of scans in glyph
add esi,gb_aj ;point to the first glyph byte
jmp MovInitialTableWide[eax*4]
;branch to draw the first glyph; never
; need to OR first glyph, because
; there's nothing there yet
;-----------------------------------------------------------------------;
; Entry point for fixed-pitch | tops and bottoms not aligned | overlap.
; Sets up to draw first glyph.
;-----------------------------------------------------------------------;
draw_f_ntb_o_to_temp_start::
mov ebx,pGlyphPos ;point to the first glyph to draw
mov pGlyphLoop,offset draw_f_ntb_o_to_temp_loop
;draw additional characters with this
; loop
mov edi,[ebx].gp_x ;dest X coordinate
mov esi,[ebx].gp_pgdf ;point to glyph def
sub edi,ulTempLeft ;adjust relative to the left of the
; temp buffer
mov ulGlyphX,edi ;remember where this glyph started
mov esi,[esi].gdf_pgb ;point to glyph bits
add edi,[esi].gb_x ;adjust to position of upper left glyph
; corner in dest
mov ecx,edi
shr edi,3 ;byte offset of first column of glyph
; offset of upper left of glyph in temp
; buffer
jmp short draw_to_temp_start_entry2
;-----------------------------------------------------------------------;
; Entry point for non-fixed-pitch | tops and bottoms not aligned | overlap.
; Sets up to draw first glyph.
;-----------------------------------------------------------------------;
draw_nf_ntb_o_to_temp_start::
mov ebx,pGlyphPos ;point to the first glyph to draw
mov pGlyphLoop,offset draw_nf_ntb_o_to_temp_loop
;draw additional characters with this
; loop
mov edi,[ebx].gp_x ;dest X coordinate
mov esi,[ebx].gp_pgdf ;point to glyph def
sub edi,ulTempLeft ;adjust relative to the left of the
; temp buffer
mov esi,[esi].gdf_pgb ;point to glyph bits
add edi,[esi].gb_x ;adjust to position of upper left glyph
; corner in dest
mov ecx,edi
shr edi,3 ;byte offset of first column of glyph
; offset of upper left of glyph in temp
; buffer
draw_to_temp_start_entry2::
mov eax,[ebx].gp_y ;dest origin Y coordinate
sub eax,ulTopScan ;coord of glyph origin in temp buffer
mov ulYOrigin,eax ;remember the Y origin of all glyphs
; (necessary because glyph positions
; after first aren't set for fixed-
; pitch strings)
add eax,[esi].gb_y ;adjust to position of upper left glyph
; corner in dest
mul ulBufDelta ;offset in buffer of top glyph scan
add eax,pTempBuffer ;initial dest byte
add edi,eax
and ecx,111b ;bit alignment of upper left in temp
;calculate scan-to-scan glyph width
mov ebx,[esi].gb_cx ;glyph width in pixels
lea eax,[ebx+ecx+7]
shr eax,3 ;# of dest bytes per scan
add ebx,7
shr ebx,3 ;# of source bytes per scan
mov edx,ulBufDelta ;width of destination buffer in bytes
cmp eax,4 ;do we have special case code for this
; dest width?
ja short @F ;no, handle as general case
;yes, handle as special case
cmp ebx,eax ;carry if more dest than source bytes
; (last source byte not needed)
rcl eax,1 ;factor last source byte status in
cmp cl,1 ;carry if aligned
rcl eax,1 ;factor in alignment (aligned or not)
mov ebx,[esi].gb_cy ;# of scans in glyph
add esi,gb_aj ;point to the first glyph byte
jmp OrAllTableNarrow[eax*4] ;branch to draw the first glyph; OR all
; glyphs, because text may overlap
@@: ;too wide to special case
mov ulWidthInBytes,eax ;# of bytes across dest
cmp ebx,eax ;carry if more dest than source bytes
; (last source byte not needed)
mov eax,0
rcl eax,1 ;factor last source byte status in
cmp cl,1 ;carry if aligned
rcl eax,1 ;factor in alignment (aligned or not)
mov ebx,[esi].gb_cx ;glyph width in pixels
add ebx,7
shr ebx,3 ;glyph width in bytes
mov ulGlyDelta,ebx
mov ebx,[esi].gb_cy ;# of scans in glyph
add esi,gb_aj ;point to the first glyph byte
jmp OrAllTableWide[eax*4] ;branch to draw the first glyph; OR all ; glyphs, because text may overlap never
; glyphs, because text may overlap
;-----------------------------------------------------------------------;
; Loop to draw all fixed-pitch | tops and bottoms aligned | no overlap
; glyphs after first.
;-----------------------------------------------------------------------;
draw_f_tb_no_to_temp_loop::
dec ulGlyphCount ;any more glyphs to draw?
jz draw_to_screen ;no, done
mov ebx,pGlyphPos
add ebx,size GLYPHPOS ;point to the next glyph (the one
mov pGlyphPos,ebx ; we're going to draw this time)
mov esi,[ebx].gp_pgdf ;point to glyph def
mov edi,ulGlyphX ;last glyph's dest X start in temp buf
add edi,ulCharInc ;this glyph's dest X start in temp buf
mov ulGlyphX,edi ;remember for next glyph
mov esi,[esi].gdf_pgb ;point to glyph bits
jmp short draw_to_temp_loop_entry
;-----------------------------------------------------------------------;
; Loop to draw all non-fixed-pitch | tops and bottoms aligned | no overlap
; glyphs after first.
;-----------------------------------------------------------------------;
draw_nf_tb_no_to_temp_loop::
dec ulGlyphCount ;any more glyphs to draw?
jz draw_to_screen ;no, done
mov ebx,pGlyphPos
add ebx,size GLYPHPOS ;point to the next glyph (the one we're
mov pGlyphPos,ebx ; going to draw this time)
mov esi,[ebx].gp_pgdf ;point to glyph def
mov edi,[ebx].gp_x ;dest X coordinate
mov esi,[esi].gdf_pgb ;point to glyph bits
sub edi,ulTempLeft ;adjust relative to the left edge of
; the temp buffer
draw_to_temp_loop_entry::
add edi,[esi].gb_x ;adjust to position of upper left glyph
; corner in dest
mov ecx,edi ;pixel X coordinate in temp buffer
shr edi,3 ;byte offset of first column = dest
; offset of upper left of glyph in temp
; buffer
add edi,pTempBuffer ;initial dest byte
and ecx,111b ;bit alignment of upper left in temp
;calculate scan-to-scan glyph width
mov ebx,[esi].gb_cx ;glyph width in pixels
lea eax,[ebx+ecx+7]
shr eax,3 ;# of dest bytes to copy to per scan
add ebx,7
shr ebx,3 ;# of source bytes to copy from per
; scan
mov edx,ulBufDelta ;width of destination buffer in bytes
cmp eax,4 ;do we have special case code for this
; dest width?
ja short @F ;no, handle as general case
;yes, handle as special case
cmp ebx,eax ;carry if more dest than source bytes
; (last source byte not needed)
rcl eax,1 ;factor last source byte status in
cmp cl,1 ;carry if aligned
rcl eax,1 ;factor in alignment (aligned or not)
mov ebx,[esi].gb_cy ;# of scans in glyph
add esi,gb_aj ;point to the first glyph byte
jmp OrInitialTableNarrow[eax*4] ;branch to draw the first glyph;
; need to OR the 1st byte if
; non-aligned to avoid overwriting
; what's already there
@@: ;too wide to special case
mov ulWidthInBytes,eax ;# of bytes across dest
cmp ebx,eax ;carry if more dest than source bytes
; (last source byte not needed)
mov eax,0
rcl eax,1 ;factor last source byte status in
cmp cl,1 ;carry if aligned
rcl eax,1 ;factor in alignment (aligned or not)
mov ebx,[esi].gb_cx ;glyph width in pixels
add ebx,7
shr ebx,3 ;glyph width in bytes
mov ulGlyDelta,ebx
mov ebx,[esi].gb_cy ;# of scans in glyph
add esi,gb_aj ;point to the first glyph byte
jmp OrInitialTableWide[eax*4] ;branch to draw the next glyph;
; need to OR the 1st byte if
; non-aligned to avoid overwriting
; what's already there
;-----------------------------------------------------------------------;
; Loop to draw all fixed-pitch | tops and bottoms not aligned | overlap
; glyphs after first.
;-----------------------------------------------------------------------;
draw_f_ntb_o_to_temp_loop::
dec ulGlyphCount ;any more glyphs to draw?
jz draw_to_screen ;no, done
mov ebx,pGlyphPos
add ebx,size GLYPHPOS ;point to the next glyph (the one we're
mov pGlyphPos,ebx ; going to draw this time)
mov esi,[ebx].gp_pgdf ;point to glyph def
mov edi,ulGlyphX ;last glyph's dest X start in temp buf
add edi,ulCharInc ;this glyph's dest X start in temp buf
mov ulGlyphX,edi ;remember for next glyph
mov esi,[esi].gdf_pgb ;point to glyph bits
jmp short draw_to_temp_loop_entry2
;-----------------------------------------------------------------------;
; Loop to draw all non-fixed-pitch | tops and bottoms not aligned | overlap
; glyphs after first.
;-----------------------------------------------------------------------;
draw_nf_ntb_o_to_temp_loop::
dec ulGlyphCount ;any more glyphs to draw?
jz draw_to_screen ;no, done
mov ebx,pGlyphPos
add ebx,size GLYPHPOS ;point to the next glyph (the one we're
mov pGlyphPos,ebx ; going to draw this time)
mov esi,[ebx].gp_pgdf ;point to glyph def
mov edi,[ebx].gp_x ;dest X coordinate
mov esi,[esi].gdf_pgb ;point to glyph bits
sub edi,ulTempLeft ;adjust relative to the left edge of
; the temp buffer
draw_to_temp_loop_entry2::
add edi,[esi].gb_x ;adjust to position of upper left glyph
; corner in dest
mov ecx,edi ;pixel X coordinate in temp buffer
shr edi,3 ;byte offset of first column = dest
; offset of upper left of glyph in temp
; buffer
mov eax,ulYOrigin ;dest Y coordinate
add eax,[esi].gb_y ;adjust to position of upper left glyph
; corner in dest
mul ulBufDelta ;offset in buffer of top glyph scan
add eax,pTempBuffer ;initial dest byte
add edi,eax
and ecx,111b ;bit alignment of upper left in temp
;calculate scan-to-scan glyph width
mov ebx,[esi].gb_cx ;glyph width in pixels
lea eax,[ebx+ecx+7]
shr eax,3 ;# of dest bytes to copy to per scan
add ebx,7
shr ebx,3 ;# of source bytes to copy from per
; scan
mov edx,ulBufDelta ;width of destination buffer in bytes
cmp eax,4 ;do we have special case code for this
; dest width?
ja short @F ;no, handle as general case
;yes, handle as special case
cmp ebx,eax ;carry if more dest than source bytes
; (last source byte not needed)
rcl eax,1 ;factor last source byte status in
cmp cl,1 ;carry if aligned
rcl eax,1 ;factor in alignment (aligned or not)
mov ebx,[esi].gb_cy ;# of scans in glyph
add esi,gb_aj ;point to the first glyph byte
jmp OrAllTableNarrow[eax*4] ;branch to draw the next glyph
@@: ;too wide to special case
mov ulWidthInBytes,eax ;# of bytes across dest
cmp ebx,eax ;carry if more dest than source bytes
; (last source byte not needed)
mov eax,0
rcl eax,1 ;factor last source byte status in
cmp cl,1 ;carry if aligned
rcl eax,1 ;factor in alignment (aligned or not)
mov ebx,[esi].gb_cx ;glyph width in pixels
add ebx,7
shr ebx,3 ;glyph width in bytes
mov ulGlyDelta,ebx
mov ebx,[esi].gb_cy ;# of scans in glyph
add esi,gb_aj ;point to the first glyph byte
jmp OrAllTableWide[eax*4] ;branch to draw the next glyph
;-----------------------------------------------------------------------;
; Routines to draw all scans of a single glyph into the temp buffer,
; optimized for the following cases:
;
; 1 to 4 byte-wide destination rectangles for each of:
; No rotation needed
; Rotation needed, same # of source as dest bytes needed
; Rotation needed, one less source than dest bytes needed
;
; Additionally, the three cases are handled for 5 and wider cases by a
; general routine for each case.
;
; If rotation is needed, there are three sorts of routines:
;
; 1) The leftmost byte is MOVed, to initialize the byte. Succeeding bytes are
; MOVed. This is generally used for the leftmost glyph of a string.
; 2) The leftmost byte is ORed into the existing byte. Succeeding bytes are
; MOVed. This is generally used after the leftmost glyph, because this may
; not be the first data written to that byte.
; 3) All bytes are ORed. This is for drawing when characters might overlap.
;
; If rotation is not needed, there are two sorts of routines:
;
; 1) The leftmost byte is MOVed, to initialize the byte. Succeeding bytes are
; MOVed. This is generally used for the leftmost glyph of a string.
; 2) All bytes are ORed. This is for drawing when characters might overlap.
;
; On entry:
; EBX = # of scans to copy
; CL = right rotation
; EDX = ulBufDelta = width per scan of destination buffer, in bytes
; ESI = pointer to first glyph byte
; EDI = pointer to first dest buffer byte
; DF = cleared
; ulGlyDelta = width per scan of source glyph, in bytes (wide case only)
; ulWidthInBytes = width of glyph, in bytes (required only for 5 and
; wider cases)
;
; On exit:
; Any or all of EAX, EBX, ECX, EDX, ESI, and EDI may be trashed.
;-----------------------------------------------------------------------;
; OR first byte, 1 byte wide dest, rotated.
;-----------------------------------------------------------------------;
or_all_1_wide_rotated_need_last::
or_all_1_wide_rotated_no_last::
or_first_1_wide_rotated_need_last::
or_first_1_wide_rotated_no_last::
or_first_1_wide_rotated_loop::
mov ch,[esi]
inc esi
shr ch,cl
or [edi],ch
add edi,edx
dec ebx
jnz or_first_1_wide_rotated_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, 1 byte wide dest, rotated.
;-----------------------------------------------------------------------;
mov_first_1_wide_rotated_need_last::
mov_first_1_wide_rotated_no_last::
mov_first_1_wide_rotated_loop::
mov ch,[esi]
inc esi
shr ch,cl
mov [edi],ch
add edi,edx
dec ebx
jnz mov_first_1_wide_rotated_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, 1 byte wide dest, unrotated.
;-----------------------------------------------------------------------;
mov_first_1_wide_unrotated::
mov_first_1_wide_unrotated_loop::
mov al,[esi]
inc esi
mov [edi],al
add edi,edx
dec ebx
jnz mov_first_1_wide_unrotated_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR all bytes, 1 byte wide dest, unrotated.
;-----------------------------------------------------------------------;
or_all_1_wide_unrotated::
or_all_1_wide_unrotated_loop::
mov al,[esi]
inc esi
or [edi],al
add edi,edx
dec ebx
jnz or_all_1_wide_unrotated_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR first byte, 2 bytes wide dest, rotated, need final source byte.
;-----------------------------------------------------------------------;
or_first_2_wide_rotated_need_last::
or_first_2_wide_rotated_need_loop::
mov ax,[esi]
add esi,2
ror ax,cl
or [edi],al
mov [edi+1],ah
add edi,edx
dec ebx
jnz or_first_2_wide_rotated_need_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR all bytes, 2 bytes wide dest, rotated, need final source byte.
;-----------------------------------------------------------------------;
or_all_2_wide_rotated_need_last::
or_all_2_wide_rotated_need_loop::
mov ax,[esi]
add esi,2
ror ax,cl
or [edi],ax
add edi,edx
dec ebx
jnz or_all_2_wide_rotated_need_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, 2 bytes wide dest, rotated, need final source byte.
;-----------------------------------------------------------------------;
mov_first_2_wide_rotated_need_last::
mov_first_2_wide_rotated_need_loop::
mov ax,[esi]
add esi,2
ror ax,cl
mov [edi],ax
add edi,edx
dec ebx
jnz mov_first_2_wide_rotated_need_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR first byte, 2 bytes wide dest, rotated, don't need final source byte.
;-----------------------------------------------------------------------;
or_first_2_wide_rotated_no_last::
or_first_2_wide_rotated_loop::
sub eax,eax
mov ah,[esi]
inc esi
shr eax,cl
or [edi],ah
mov [edi+1],al
add edi,edx
dec ebx
jnz or_first_2_wide_rotated_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR all bytes, 2 bytes wide dest, rotated, don't need final source byte.
;-----------------------------------------------------------------------;
or_all_2_wide_rotated_no_last::
or_all_2_wide_rotated_loop::
sub eax,eax
mov al,[esi]
inc esi
ror ax,cl
or [edi],ax
add edi,edx
dec ebx
jnz or_all_2_wide_rotated_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, 2 bytes wide dest, rotated, don't need final source byte.
;-----------------------------------------------------------------------;
mov_first_2_wide_rotated_no_last::
mov_first_2_wide_rotated_loop::
sub eax,eax
mov al,[esi]
inc esi
ror ax,cl
mov [edi],ax
add edi,edx
dec ebx
jnz mov_first_2_wide_rotated_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, 2 bytes wide dest, unrotated.
;-----------------------------------------------------------------------;
mov_first_2_wide_unrotated::
mov_first_2_wide_unrotated_loop::
mov ax,[esi]
add esi,2
mov [edi],ax
add edi,edx
dec ebx
jnz mov_first_2_wide_unrotated_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR all bytes, 2 bytes wide dest, unrotated.
;-----------------------------------------------------------------------;
or_all_2_wide_unrotated::
or_all_2_wide_unrotated_loop::
mov ax,[esi]
add esi,2
or [edi],ax
add edi,edx
dec ebx
jnz or_all_2_wide_unrotated_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR first byte, 3 bytes wide dest, rotated, need final source byte.
;-----------------------------------------------------------------------;
or_first_3_wide_rotated_need_last::
@@:
mov al,[esi]
shr al,cl
or [edi],al
mov ax,[esi]
ror ax,cl
mov [edi+1],ah
mov ax,[esi+1]
add esi,3
ror ax,cl
mov [edi+2],ah
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR first byte, 3 bytes wide dest, rotated, need final source byte.
;-----------------------------------------------------------------------;
or_all_3_wide_rotated_need_last::
@@:
mov al,[esi]
shr al,cl
or [edi],al
mov ax,[esi]
ror ax,cl
or [edi+1],ah
mov ax,[esi+1]
add esi,3
ror ax,cl
or [edi+2],ah
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, 3 bytes wide dest, rotated, need final source byte.
;-----------------------------------------------------------------------;
mov_first_3_wide_rotated_need_last::
@@:
mov al,[esi]
shr al,cl
mov [edi],al
mov ax,[esi]
ror ax,cl
mov [edi+1],ah
mov ax,[esi+1]
add esi,3
ror ax,cl
mov [edi+2],ah
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR first byte, 3 bytes wide dest, rotated, don't need final source byte.
;-----------------------------------------------------------------------;
or_first_3_wide_rotated_no_last::
neg cl
and cl,111b ;convert from right shift to left shift
@@:
sub eax,eax
mov ax,[esi]
add esi,2
xchg ah,al
shl eax,cl
mov [edi+1],ah
mov [edi+2],al
shr eax,16
or [edi],al
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR all bytes, 3 bytes wide dest, rotated, don't need final source byte.
;-----------------------------------------------------------------------;
or_all_3_wide_rotated_no_last::
neg cl
and cl,111b ;convert from right shift to left shift
@@:
sub eax,eax
mov ax,[esi]
add esi,2
xchg ah,al
shl eax,cl
xchg ah,al
or [edi+1],ax
shr eax,16
or [edi],al
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, 3 bytes wide dest, rotated, don't need final source byte.
;-----------------------------------------------------------------------;
mov_first_3_wide_rotated_no_last::
neg cl
and cl,111b ;convert from right shift to left shift
@@:
sub eax,eax
mov ax,[esi]
add esi,2
xchg ah,al
shl eax,cl
mov [edi+1],ah
mov [edi+2],al
shr eax,16
mov [edi],al
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, 3 bytes wide dest, unrotated.
;-----------------------------------------------------------------------;
mov_first_3_wide_unrotated::
@@:
mov ax,[esi]
mov [edi],ax
mov al,[esi+2]
add esi,3
mov [edi+2],al
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR all bytes, 3 bytes wide dest, unrotated.
;-----------------------------------------------------------------------;
or_all_3_wide_unrotated::
@@:
mov ax,[esi]
or [edi],ax
mov al,[esi+2]
add esi,3
or [edi+2],al
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR first byte, 4 bytes wide dest, rotated, need final source byte.
;-----------------------------------------------------------------------;
or_first_4_wide_rotated_need_last::
@@:
mov eax,[esi]
add esi,4
xchg ah,al
ror eax,16
xchg ah,al
shr eax,cl
xchg ah,al
mov [edi+2],ax
shr eax,16
mov [edi+1],al
or [edi],ah
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR all bytes, 4 bytes wide dest, rotated, need final source byte.
;-----------------------------------------------------------------------;
or_all_4_wide_rotated_need_last::
@@:
mov eax,[esi]
add esi,4
xchg ah,al
ror eax,16
xchg ah,al
shr eax,cl
xchg ah,al
ror eax,16
xchg al,ah
or [edi],eax
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, 4 bytes wide dest, rotated, need final source byte.
;-----------------------------------------------------------------------;
mov_first_4_wide_rotated_need_last::
@@:
mov eax,[esi]
add esi,4
xchg ah,al
ror eax,16
xchg ah,al
shr eax,cl
xchg ah,al
ror eax,16
xchg ah,al
mov [edi],eax
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR first byte, 4 bytes wide dest, rotated, don't need final source byte.
;-----------------------------------------------------------------------;
or_first_4_wide_rotated_no_last::
@@:
mov ax,[esi]
xchg ah,al
shl eax,16
mov ah,[esi+2]
add esi,3
shr eax,cl
xchg ah,al
mov [edi+2],ax
shr eax,16
mov [edi+1],al
or [edi],ah
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR all bytes, 4 bytes wide dest, rotated, don't need final source byte.
;-----------------------------------------------------------------------;
or_all_4_wide_rotated_no_last::
@@:
mov ax,[esi]
xchg ah,al
shl eax,16
mov ah,[esi+2]
add esi,3
shr eax,cl
xchg ah,al
ror eax,16
xchg ah,al
or [edi],eax
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, 4 bytes wide dest, rotated, don't need final source byte.
;-----------------------------------------------------------------------;
mov_first_4_wide_rotated_no_last::
@@:
mov ax,[esi]
xchg ah,al
shl eax,16
mov ah,[esi+2]
add esi,3
shr eax,cl
xchg ah,al
ror eax,16
xchg ah,al
mov [edi],eax
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, 4 bytes wide dest, unrotated.
;-----------------------------------------------------------------------;
mov_first_4_wide_unrotated::
@@:
mov eax,[esi]
add esi,4
mov [edi],eax
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR all bytes, 4 bytes wide dest, unrotated.
;-----------------------------------------------------------------------;
or_all_4_wide_unrotated::
@@:
mov eax,[esi]
add esi,4
or [edi],eax
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR first byte, n bytes wide dest, rotated, need final source byte.
;-----------------------------------------------------------------------;
or_first_N_wide_rotated_need_last::
mov eax,ulWidthInBytes
mov edx,ulBufDelta
sub edx,eax
mov ulTmpDstDelta,edx
dec eax ;source doesn't advance after first byte, and
; we do the first byte outside the loop
mov edx,ulGlyDelta
sub edx,eax
mov ulTmpSrcDelta,edx
mov ulTmpWidthInBytes,eax
ofNwrnl_scan_loop:
mov al,[esi] ;do the initial, ORed byte separately
shr al,cl
or [edi],al
inc edi
mov edx,ulTmpWidthInBytes
@@:
mov ax,[esi]
inc esi
ror ax,cl
mov [edi],ah
inc edi
dec edx
jnz @B
add esi,ulTmpSrcDelta
add edi,ulTmpDstDelta
dec ebx
jnz ofNwrnl_scan_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR all bytes, n bytes wide dest, rotated, need final source byte.
;-----------------------------------------------------------------------;
or_all_N_wide_rotated_need_last::
mov eax,ulWidthInBytes
mov edx,ulBufDelta
sub edx,eax
mov ulTmpDstDelta,edx
dec eax ;source doesn't advance after first byte, and
; we do the first byte outside the loop
mov edx,ulGlyDelta
sub edx,eax
mov ulTmpSrcDelta,edx
mov ulTmpWidthInBytes,eax
oaNwrnl_scan_loop:
mov al,[esi] ;do the initial, ORed byte separately
shr al,cl
or [edi],al
inc edi
mov edx,ulTmpWidthInBytes
@@:
mov ax,[esi]
inc esi
ror ax,cl
or [edi],ah
inc edi
dec edx
jnz @B
add esi,ulTmpSrcDelta
add edi,ulTmpDstDelta
dec ebx
jnz oaNwrnl_scan_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, n bytes wide dest, rotated, need final source byte.
;-----------------------------------------------------------------------;
mov_first_N_wide_rotated_need_last::
mov eax,ulWidthInBytes
mov edx,ulBufDelta
sub edx,eax
mov ulTmpDstDelta,edx
mov eax,ulWidthInBytes
dec eax ;source doesn't advance after first byte, and
; we do the first byte outside the loop
mov edx,ulGlyDelta
sub edx,eax
mov ulTmpSrcDelta,edx
mov ulTmpWidthInBytes,eax
mfNwrnl_scan_loop:
mov al,[esi] ;do the initial byte separately
shr al,cl
mov [edi],al
inc edi
mov edx,ulTmpWidthInBytes
@@:
mov ax,[esi]
inc esi
ror ax,cl
mov [edi],ah
inc edi
dec edx
jnz @B
add esi,ulTmpSrcDelta
add edi,ulTmpDstDelta
dec ebx
jnz mfNwrnl_scan_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR first byte, N bytes wide dest, rotated, don't need final source byte.
;-----------------------------------------------------------------------;
or_first_N_wide_rotated_no_last::
mov eax,ulWidthInBytes
dec eax ;one less because we don't advance after the
; last byte
mov edx,ulBufDelta
sub edx,eax
mov ulTmpDstDelta,edx
dec eax ;source doesn't advance after first byte, and
; we do the first & last bytes outside the
; loop; already subtracted 1 above
mov edx,ulGlyDelta
sub edx,eax
mov ulTmpSrcDelta,edx
mov ulTmpWidthInBytes,eax
ofNwr_scan_loop:
mov al,[esi] ;do the initial, ORed byte separately
shr al,cl
or [edi],al
inc edi
mov edx,ulTmpWidthInBytes
@@:
mov ax,[esi]
inc esi
ror ax,cl
mov [edi],ah
inc edi
dec edx
jnz @B
mov ah,[esi] ;do the final byte separately
sub al,al
shr eax,cl
mov [edi],al
add esi,ulTmpSrcDelta
add edi,ulTmpDstDelta
dec ebx
jnz ofNwr_scan_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR all bytes, N bytes wide dest, rotated, don't need final source byte.
;-----------------------------------------------------------------------;
or_all_N_wide_rotated_no_last::
mov eax,ulWidthInBytes
dec eax ;one less because we don't advance after the
; last byte
mov edx,ulBufDelta
sub edx,eax
mov ulTmpDstDelta,edx
dec eax ;source doesn't advance after first byte, and
; we do the first & last bytes outside the
; loop; already subtracted 1 above
mov edx,ulGlyDelta
sub edx,eax
mov ulTmpSrcDelta,edx
mov ulTmpWidthInBytes,eax
oaNwr_scan_loop:
mov al,[esi] ;do the initial, ORed byte separately
shr al,cl
or [edi],al
inc edi
mov edx,ulTmpWidthInBytes
@@:
mov ax,[esi]
inc esi
ror ax,cl
or [edi],ah
inc edi
dec edx
jnz @B
mov ah,[esi] ;do the final byte separately
sub al,al
shr eax,cl
or [edi],al
add esi,ulTmpSrcDelta
add edi,ulTmpDstDelta
dec ebx
jnz oaNwr_scan_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, N bytes wide dest, rotated, don't need final source byte.
;-----------------------------------------------------------------------;
mov_first_N_wide_rotated_no_last::
mov eax,ulWidthInBytes
dec eax ;one less because we don't advance after the
; last byte
mov edx,ulBufDelta
sub edx,eax
mov ulTmpDstDelta,edx
dec eax ;source doesn't advance after first byte, and
; we do the first & last bytes outside the
; loop; already subtracted 1 above
mov edx,ulGlyDelta
sub edx,eax
mov ulTmpSrcDelta,edx
mov ulTmpWidthInBytes,eax
mfNwr_scan_loop:
mov al,[esi] ;do the initial byte separately
shr al,cl
mov [edi],al
inc edi
mov edx,ulTmpWidthInBytes
@@:
mov ax,[esi]
inc esi
ror ax,cl
mov [edi],ah
inc edi
dec edx
jnz @B
mov ah,[esi] ;do the final byte separately
sub al,al
shr eax,cl
mov [edi],al
add esi,ulTmpSrcDelta
add edi,ulTmpDstDelta
dec ebx
jnz mfNwr_scan_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; MOV first byte, N bytes wide dest, unrotated.
;-----------------------------------------------------------------------;
mov_first_N_wide_unrotated::
mov edx,ulBufDelta
mov eax,ulWidthInBytes
sub edx,eax
shr eax,1 ;width in words
jc short odd_width ;there's at least one odd byte
shr eax,1 ;width in dwords
jc short two_odd_bytes ;there's an odd word
;copy width is a dword multiple
@@:
mov ecx,eax
rep movsd ;copy as many dwords as possible
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
odd_width::
shr eax,1 ;width in dwords
jc short three_odd_bytes ;there's an odd word and an odd byte
;there's just an odd byte
inc edx ;because we won't advance after last byte
@@:
mov ecx,eax
rep movsd ;copy as many dwords as possible
mov cl,[esi]
inc esi
mov [edi],cl
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
two_odd_bytes::
add edx,2 ;because we won't advance after last word
@@:
mov ecx,eax
rep movsd ;copy as many dwords as possible
mov cx,[esi]
add esi,2
mov [edi],cx
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
three_odd_bytes::
add edx,3 ;because we won't advance after last word/byte
@@:
mov ecx,eax
rep movsd ;copy as many dwords as possible
mov cx,[esi]
mov [edi],cx
mov cl,[esi+2]
add esi,3
mov [edi+2],cl
add edi,edx
dec ebx
jnz @B
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; OR all bytes, N bytes wide dest, unrotated.
;-----------------------------------------------------------------------;
or_all_N_wide_unrotated::
mov edx,ulBufDelta
mov eax,ulWidthInBytes
sub edx,eax
shr eax,1 ;width in words
jc short or_odd_width ;there's at least one odd byte
shr eax,1 ;width in dwords
jc short or_two_odd_bytes ;there's an odd word
;copy width is a dword multiple
or_no_odd_bytes_loop::
push ebx ;preserve scan count
mov ebx,eax
@@:
mov ecx,[esi]
add esi,4
or [edi],ecx
add edi,4 ;copy as many dwords as possible
dec ebx
jnz @B
add edi,edx
pop ebx ;restore scan count
dec ebx
jnz or_no_odd_bytes_loop
jmp pGlyphLoop
or_odd_width::
shr eax,1 ;width in dwords
jc short or_three_odd_bytes ;there's an odd word and an odd byte
;there's just an odd byte
inc edx ;skip over last byte too
or_one_odd_bytes_loop::
push ebx ;preserve scan count
mov ebx,eax
@@:
mov ecx,[esi]
add esi,4
or [edi],ecx
add edi,4 ;copy as many dwords as possible
dec ebx
jnz @B
mov cl,[esi]
or [edi],cl
inc esi
add edi,edx
pop ebx ;restore scan count
dec ebx
jnz or_one_odd_bytes_loop
jmp pGlyphLoop
or_two_odd_bytes::
add edx,2 ;skip over last 2 bytes too
or_two_odd_bytes_loop::
push ebx ;preserve scan count
mov ebx,eax
@@:
mov ecx,[esi]
add esi,4
or [edi],ecx
add edi,4 ;copy as many dwords as possible
dec ebx
jnz @B
mov cx,[esi]
or [edi],cx
add esi,2
add edi,edx
pop ebx ;restore scan count
dec ebx
jnz or_two_odd_bytes_loop
jmp pGlyphLoop
or_three_odd_bytes::
add edx,3 ;skip over last 3 bytes too
or_three_odd_bytes_loop::
push ebx ;preserve scan count
mov ebx,eax
@@:
mov ecx,[esi]
add esi,4
or [edi],ecx
add edi,4 ;copy as many dwords as possible
dec ebx
jnz @B
mov cx,[esi]
or [edi],cx
mov cl,[esi+2]
or [edi+2],cl
add esi,3
add edi,edx
pop ebx ;restore scan count
dec ebx
jnz or_three_odd_bytes_loop
jmp pGlyphLoop
;-----------------------------------------------------------------------;
; At this point, the text is drawn to the temp buffer.
; Now, color-expand the temp buffer to the screen.
;
; Input:
; ppdev = pointer to target surface's PDEV (screen)
; prclText = pointer to text bounding rectangle
; prclOpaque = pointer to opaquing rectangle, if there is one
; iFgColor = text color
; iBgColor = opaquing rectangle color, if there is one
; ulTempLeft = X coordinate on dest of left edge of temp buffer pointed
; to by pTempBuffer
; pTempBuffer = pointer to first byte (upper left corner) of
; temp buffer into which we're drawing. This should be
; word-aligned with the destination
; ulBufDelta = destination scan-to-scan offset
; Text drawn to temp buffer
;
;-----------------------------------------------------------------------;
draw_to_screen::
;-----------------------------------------------------------------------;
; Is this transparent or opaque text?
;-----------------------------------------------------------------------;
cmp prclOpaque,0
jnz opaque_text
;-----------------------------------------------------------------------;
; Transparent text.
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; Calculate drawing parameters.
;-----------------------------------------------------------------------;
mov esi,prclText
mov ebx,ppdev
mov eax,[esi].xRight
mov edx,[esi].xLeft
and edx,not 7
add eax,7
sub eax,edx
shr eax,3 ;width of text in temp buffer in bytes, rounded
mov ulXparBytes,eax ; up. Also number of quadpixels to draw
mov ecx,[ebx].pdev_lNextScan
mov ulScreenDelta,ecx
shl eax,3 ;each temp buffer byte maps to eight VGA
; addresses (two quadpixels in linear mode)
sub ecx,eax ;offset to next scan in screen
mov ulTmpDstDelta,ecx
;-----------------------------------------------------------------------;
; Calculate the offset of the initial destination quadpixel.
;-----------------------------------------------------------------------;
mov eax,[esi].yTop
mul ulScreenDelta
mov edi,ulTempLeft
add edi,eax ;offset in bitmap of first quadpixel's byte
; (remember, this is linear mode)
;-----------------------------------------------------------------------;
; Map in the bank containing the top scan of the text, if it's not
; mapped in already.
;-----------------------------------------------------------------------;
mov eax,[esi].yTop ;top scan line of text
mov ulTopScan,eax
mov esi,pTempBuffer ;initial source address
cmp eax,[ebx].pdev_rcl1WindowClip.yTop ;is text top less than
; current bank?
jl short xpar_map_init_bank ;yes, map in proper bank
cmp eax,[ebx].pdev_rcl1WindowClip.yBottom ;text top greater than
; current bank?
jl short xpar_init_bank_mapped ;no, proper bank already mapped
xpar_map_init_bank::
; Map in the bank containing the top scan line of the fill.
; Preserves EBX, ESI, and EDI.
ptrCall <dword ptr [ebx].pdev_pfnBankControl>,<ebx,eax,JustifyTop>
xpar_init_bank_mapped::
add edi,[ebx].pdev_pvBitmapStart ;initial destination address
;-----------------------------------------------------------------------;
; Main loop for processing fill in each bank.
;
; At start of loop, EBX->pdsurf
;-----------------------------------------------------------------------;
xpar_bank_loop::
mov edx,ulBottomScan ;bottom of destination rectangle
cmp edx,[ebx].pdev_rcl1WindowClip.yBottom
;which comes first, the bottom of the
; text rect or the bottom of the
; current bank?
jl short @F ;text bottom comes first, so draw to
; that; this is the last bank in text
mov edx,[ebx].pdev_rcl1WindowClip.yBottom
;bank bottom comes first; draw to
; bottom of bank
@@:
sub edx,ulTopScan ;# of scans to draw in bank
mov al,byte ptr iFgColor
mov ah,al
mov ebx,eax
shl eax,16
mov ax,bx ;put drawing color in all bytes of EAX
sub ebx,ebx ;prepare for look-up in loop
xpar_scan_loop::
mov ecx,ulXparBytes ;number of quadpixel pairs to draw
mov bl,[esi] ;get next glyph byte
and bl,bl ;are all 8 pixels transparent?
jz xpar_low_nibble_0 ;yes, just skip everything in this byte
shr bl,4 ;shift the high nibble into the low
; nibble
jmp xpar_high_nibble_table[ebx*4] ;branch to draw up to four
; pixels, followed by a branch to
; draw the the other nibble (up
; to four more pixels)
xpar_scan_done::
add edi,ulTmpDstDelta ;point to next screen scan
dec edx ;count down scans
jnz xpar_scan_loop
;-----------------------------------------------------------------------;
; See if there are more banks to draw.
;-----------------------------------------------------------------------;
mov ebx,ppdev
mov eax,[ebx].pdev_rcl1WindowClip.yBottom ;is the text bottom in
cmp ulBottomScan,eax ; the current bank?
jnle short do_next_xpar_bank ;no, map in the next bank and draw
cRet vFastText ;yes, so we're done
do_next_xpar_bank::
mov ulTopScan,eax
sub edi,[ebx].pdev_pvBitmapStart ;convert from address to offset
; within bitmap
ptrCall <dword ptr [ebx].pdev_pfnBankControl>,<ebx,eax,JustifyTop>
;map in the bank (call preserves
; EBX, ESI, and EDI)
add edi,[ebx].pdev_pvBitmapStart ;convert from offset within bitmap
; to address (bitmap start just
; moved)
jmp xpar_bank_loop ;we're ready to draw to the new
; bank
;-----------------------------------------------------------------------
; Routines to draw 0-4 pixels with the color in each byte of EAX, depending
; on the value of the nibble describing the four pixels to draw. "high_nibble"
; routines draw based on the upper nibble of the byte pointed to by ESI;
; "low_nibble" routines draw based on the lower nibble of that byte.
;
; EAX = color with which to draw, repeated four times
; EBX = zero (0)
; ECX = the number of nibble pairs (source bytes = pixels*8) to draw
; EDX = not used (preserved)
; ESI = pointer to first nibble pair to draw
; EDI = pointer to first destination byte to which to draw
;
; Must always be entered on the high nibble and extended for an even number of
; nibbles.
;-----------------------------------------------------------------------
; Macro to draw the four pixels represented by the high nibble of the byte at
; [ESI].
DO_HIGH_NIBBLE macro
inc esi ;point to the next glyph byte
add edi,8 ;point to the next destination 8-pixel set
dec ecx ;count down nibble pairs (8-pixel sets)
jz xpar_scan_done ;done with this scan
mov bl,[esi] ;not done; get next glyph byte
and bl,bl ;are all 8 pixels transparent?
jz xpar_low_nibble_0 ;yes, just skip everything in this byte
shr bl,4 ;shift the high nibble into the low nibble
jmp xpar_high_nibble_table[ebx*4] ;branch to draw up to four pixels
endm
;-----------------------------------------------------------------------
; Macro to draw the four pixels represented by the low nibble of the byte at
; [ESI].
DO_LOW_NIBBLE macro
mov bl,[esi] ;get glyph byte again, for the low nibble this
; time
and ebx,0fh ;isolate the low nibble
jmp xpar_low_nibble_table[ebx*4] ;branch to draw up to four pixels
endm
;-----------------------------------------------------------------------
xpar_high_nibble_F::
mov [edi],eax
xpar_high_nibble_0::
DO_LOW_NIBBLE
xpar_high_nibble_E::
mov [edi],ax
mov [edi+2],al
DO_LOW_NIBBLE
xpar_high_nibble_D::
mov [edi],ax
mov [edi+3],al
DO_LOW_NIBBLE
xpar_high_nibble_C::
mov [edi],ax
DO_LOW_NIBBLE
xpar_high_nibble_B::
mov [edi],al
mov [edi+2],ax
DO_LOW_NIBBLE
xpar_high_nibble_8::
mov [edi],al
DO_LOW_NIBBLE
xpar_high_nibble_6::
mov [edi+1],ax
DO_LOW_NIBBLE
xpar_high_nibble_5::
mov [edi+1],al
mov [edi+3],al
DO_LOW_NIBBLE
xpar_high_nibble_4::
mov [edi+1],al
DO_LOW_NIBBLE
xpar_high_nibble_7::
mov [edi+1],al
xpar_high_nibble_3::
mov [edi+2],ax
DO_LOW_NIBBLE
xpar_high_nibble_A::
mov [edi],al
xpar_high_nibble_2::
mov [edi+2],al
DO_LOW_NIBBLE
xpar_high_nibble_9::
mov [edi],al
xpar_high_nibble_1::
mov [edi+3],al
DO_LOW_NIBBLE
xpar_low_nibble_0::
DO_HIGH_NIBBLE
xpar_low_nibble_F::
mov [edi+4],eax
DO_HIGH_NIBBLE
xpar_low_nibble_E::
mov [edi+4],ax
mov [edi+6],al
DO_HIGH_NIBBLE
xpar_low_nibble_D::
mov [edi+4],ax
mov [edi+7],al
DO_HIGH_NIBBLE
xpar_low_nibble_C::
mov [edi+4],ax
DO_HIGH_NIBBLE
xpar_low_nibble_B::
mov [edi+4],al
mov [edi+6],ax
DO_HIGH_NIBBLE
xpar_low_nibble_8::
mov [edi+4],al
DO_HIGH_NIBBLE
xpar_low_nibble_6::
mov [edi+5],ax
DO_HIGH_NIBBLE
xpar_low_nibble_5::
mov [edi+5],al
mov [edi+7],al
DO_HIGH_NIBBLE
xpar_low_nibble_4::
mov [edi+5],al
DO_HIGH_NIBBLE
xpar_low_nibble_7::
mov [edi+5],al
xpar_low_nibble_3::
mov [edi+6],ax
DO_HIGH_NIBBLE
xpar_low_nibble_A::
mov [edi+4],al
xpar_low_nibble_2::
mov [edi+6],al
DO_HIGH_NIBBLE
xpar_low_nibble_9::
mov [edi+4],al
xpar_low_nibble_1::
mov [edi+7],al
DO_HIGH_NIBBLE
;-----------------------------------------------------------------------;
; Opaque text.
;-----------------------------------------------------------------------;
opaque_text::
;-----------------------------------------------------------------------;
; Calculate drawing parameters.
;-----------------------------------------------------------------------;
mov ebx,ppdev
mov esi,prclText ;point to bounding rectangle for text
mov eax,[ebx].pdev_lPlanarNextScan ;set the screen width in
mov ulScreenDelta,eax ; quadpixels
sub eax,eax ;assume clipped edge bytes won't need
mov ulLeftEdgeShift,eax ; to be shifted into position
mov ulRightEdgeShift,eax
mov eax,[esi].xRight
mov ebx,eax
and ebx,11b ;dest right edge % 4
mov edx,[esi].xLeft
mov ulTextLeft,edx ;remember dest left edge
mov cl,jOpaqueRightMasks[ebx] ;set right edge clip mask
mov ebx,edx
and ebx,11b ;dest left edge % 4
mov ulRightMask,ecx
mov cl,jOpaqueLeftMasks[ebx] ;set left edge clip mask
mov ulLeftMask,ecx
and edx,not 7 ;left edge, rounded down to nearest byte
dec eax ;right edge - 1
sub eax,edx
shr eax,3 ;width of the text in the temp buffer in bytes,
; rounded up, minus 1. This is used to point to
; the partial right edge, if there is one
mov ulTextWidthInBytesMinus1,eax
;-----------------------------------------------------------------------;
; Figure out what edges we need to handle, and calculate some info for
; doing whole bytes.
;-----------------------------------------------------------------------;
mov edx,[esi].xLeft
mov eax,[esi].xRight
and edx,not 3
add eax,3
sub eax,edx
shr eax,2 ;width of the text in the temp buffer in
; quadpixels, rounded up (counting all whole
; and partial quadpixels)
cmp eax,1 ;only one quadpixels total?
jnz short @F ;no
;yes, special case a single quadpixel
mov ecx,offset opaq_check_more_banks ;assume it's a solid
; quadpixel
mov ebx,ulLeftMask
and ebx,ulRightMask
cmp bl,0ffh ;solid quadpixel?
jz short opaq_set_deltas_and_edge_vector ;yes, all set
mov ulLeftMask,ebx ;no, draw as a left edge
dec eax ;there are no whole quadpixels
mov ecx,offset opaq_draw_left_edge_only
test [esi].xLeft,100b ;is partial quadpixel in bits 0-3?
jnz opaq_set_edge_vector ;yes, no shift required, already set
mov ulLeftEdgeShift,4 ;no, must shift right 4 to get into
; bits 0-3
jmp short opaq_set_edge_vector ;yes, all set
@@:
lea edx,[eax-1]
mov ulVGAWidthInBytesMinus1,edx ;offset from leftmost VGA dest byte
; to rightmost
test [esi].xLeft,11b ;is left edge a solid quadpixel?
jz short opaq_left_edge_solid ;yes
dec eax ;one less whole quadpixel
mov ecx,offset opaq_draw_left_edge_only ;assume right edge is solid
test [esi].xLeft,100b ;is partial quadpixel in bits 0-3?
jnz short @F ;yes, no shift required, already set
mov ulLeftEdgeShift,4 ;no, must shift right 4 to get into
; bits 0-3
@@:
test [esi].xRight,11b ;is right edge a solid quadpixel?
jz short opaq_set_deltas_and_edge_vector ;yes, all set
dec eax ;one less whole quadpixel
mov ecx,offset opaq_draw_both_edges ;both edges are non-solid
jmp short opaq_set_right_edge_shift
opaq_left_edge_solid::
mov ecx,offset opaq_check_more_banks ;assume right edge is solid
test [esi].xRight,11b ;is right edge a solid quadpixel?
jz short opaq_set_deltas_and_edge_vector ;yes, all set
dec eax ;one less whole quadpixel
mov ecx,offset opaq_draw_right_edge_only ;no, do non-solid right
; edge
opaq_set_right_edge_shift:
test [esi].xRight,100b ;is partial quadpixel in bits 0-3?
jnz short opaq_set_deltas_and_edge_vector
;yes, no shift required, already set
mov ulRightEdgeShift,4 ;no, must shift right 4 to get into
; bits 0-3
; At this point, EAX = # of whole quadpixels across source = # of whole bytes
; (addresses) across destination
opaq_set_deltas_and_edge_vector:
mov edi,ulScreenDelta
sub edi,eax ;whole bytes offset to next scan in screen
; (there are four pixels--one quadpixel--
; at each VGA address)
mov ulTmpDstDelta,edi
mov edx,[esi].xLeft
mov edi,[esi].xRight
add edx,3
and edx,not 7
add edi,4
sub edi,edx
shr edi,3 ;width of the text in the temp buffer in bytes,
; counting bytes containing whole quadpixels
; but not bytes containing only partial
; quadpixels. (Remember, text bytes map to
; quadpixel pairs; text nibbles map to
; quadpixels)
sub edi,ulBufDelta
neg edi
mov ulTmpSrcDelta,edi ;offset to next scan in source buffer when
; doing whole quadpixels
opaq_set_edge_vector::
mov pfnEdgeVector,ecx ;save address of partial-quadpixel-
; drawing code, or end of loop if no
; partial edge
mov edx,eax ;# of whole quadpixels
mov pfnFirstOpaqVector,offset opaq_whole_quadpixels
;assume there are whole quadpixels
; to copy, in which case we'll draw
; them first, then the partial edge
; quadpixels
sub edi,edi
shr edx,1 ;# of quadpixels / 2
mov ulWholeWidthInQuadpixelPairs,edx ;# of quadpixel pairs to copy
adc edi,edi ;odd quadpixel status
mov ulOddQuadpixel,edi ;1 if there is an odd quadpixel, 0 else
dec edx
mov ulWholeWidthInQuadpixelPairsMinus1,edx
;# of whole quadpixel pairs to copy,
; minus 1 (for case with both leading
; and trailing quadpixels)
cmp eax,0 ;are there any whole quadpixels at all?
jg short @F ;yes, we're all set
;no, set up for edge(s) only
mov pfnFirstOpaqVector,ecx ;the edges are first and only, because
; there are no whole quadpixels
@@:
;-----------------------------------------------------------------------;
; Determine the screen offset of the first destination byte.
;-----------------------------------------------------------------------;
mov ebx,ppdev
mov eax,ulTopScan
mov ecx,eax
mul ulScreenDelta
mov edi,[esi].xLeft
shr edi,2 ;left edge screen offset in quadpixels
add edi,eax
;-----------------------------------------------------------------------;
; Map in the bank containing the top scan of the text, if it's not
; mapped in already.
;-----------------------------------------------------------------------;
cmp ecx,[ebx].pdev_rcl1PlanarClip.yTop ;is text top less than
; current bank?
jl short opaq_map_init_bank ;yes, map in proper bank
cmp ecx,[ebx].pdev_rcl1PlanarClip.yBottom ;text top greater than
; current bank?
jl short opaq_init_bank_mapped ;no, proper bank already mapped
opaq_map_init_bank::
; Map in the bank containing the top scan line of the fill.
; Preserves EBX, ESI, and EDI.
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>,<ebx,ecx,JustifyTop>
opaq_init_bank_mapped::
add edi,[ebx].pdev_pvBitmapStart ;initial destination address
;-----------------------------------------------------------------------;
; Load the latches with the background color.
;-----------------------------------------------------------------------;
sub eax,eax
mov edx,[esi].xLeft
and edx,011b
cmp eax,edx ;is the first quadpixel a full
; quadpixel?
adc eax,eax ;if so, EAX = 1, else EAX = 0
mov edx,iBgColor
mov [edi+eax],dl ;write the bg color to the first full
; quadpixel, in each of the four planes
mov dl,[edi+eax] ;read back the quadpixel to load the
; latches with the bg color
;-----------------------------------------------------------------------;
; Set up the VGA's hardware for read mode 0 and write mode 2, the ALUs
; for XOR, and the Bit Mask to 1 for bits that differ between the fg and
; bg, 0 for bits that are the same.
;-----------------------------------------------------------------------;
mov edx,VGA_BASE + GRAF_ADDR
mov ah,byte ptr [ebx].pdev_ulrm0_wmX[2]
;write mode 2 setting for Graphics Mode
mov al,GRAF_MODE
out dx,ax ;write mode 2 to expand glyph bits to
; 0 or 0ffh per plane
mov eax,GRAF_DATA_ROT + (DR_XOR SHL 8)
out dx,ax ;XOR to flip latched data to make ~bg
mov ah,byte ptr iBgColor
xor ah,byte ptr iFgColor
mov al,GRAF_BIT_MASK
out dx,ax ;pass through common fg & bg bits
; unchanged from bg color in latches;
; non-common bits come from XOR in the
; ALUs, flipped from the bg to the fg
; state if the glyph bit for the pixel
; in that plane is 1, still in bg state
; if the glyph bit for that plane is 0
;-----------------------------------------------------------------------;
; Main loop for processing fill in each bank.
;
; At start of loop and on each loop, EBX->ppdev and EDI->first destination
; byte.
;-----------------------------------------------------------------------;
opaq_bank_loop::
mov pScreen,edi ;remember initial copy destination
mov edx,ulBottomScan ;bottom of destination rectangle
cmp edx,[ebx].pdev_rcl1PlanarClip.yBottom
;which comes first, the bottom of the
; text rect or the bottom of the
; current bank?
jl short @F ;text bottom comes first, so draw to
; that; this is the last bank in text
mov edx,[ebx].pdev_rcl1PlanarClip.yBottom
;bank bottom comes first; draw to
; bottom of bank
@@:
sub edx,ulTopScan ;# of scans to draw in bank
mov ulNumScans,edx
jmp pfnFirstOpaqVector ;do first sort of drawing (whole
; bytes, or edge(s) if no whole
; bytes)
;-----------------------------------------------------------------------;
; Draw the whole quadpixels, handling as many as possible paired into
; bytes so we can draw 8 pixels at a time.
;
; On entry:
; EDI = first destination byte
;-----------------------------------------------------------------------;
opaq_whole_quadpixels::
mov esi,pTempBuffer ;point to first source byte
mov eax,ulTextLeft ;left edge
test eax,011b ;is there a partial (masked) edge?
jz short @f ;no, start addresses are correct
inc edi ;yes, skip over one dest byte for the
; four pixels in the partial edge
test eax,100b ;do we have a partial left edge in the
; second quadpixel?
jz short @f ;no, source start address is correct
inc esi ;yes, skip over a source byte because
; the partial edge is all that's in
; this byte
@@:
mov ebx,pGlyphFlipTable ;point to the look-up table we'll use
; to flip the glyph bits into the form
; required by planar mode
mov edx,ulNumScans ;# of scans to draw
;decide which copy loop to use, based
; on the word-alignment of the dest
; rectangle with the screen
;the following tests rely on VGA even
; addresses being aligned to the start
; of corresponding source buffer bytes
; (4-pixel sets at even VGA addresses
; match up to the upper quadpixels of
; source buffer bytes)
test edi,1 ;is dest word-aligned?
jnz short opaq_need_leading ;no, need leading quadpixel
;yes, no leading quadpixel
cmp ulOddQuadpixel,1 ;odd width in quadpixels?
jnz short opaq_scan_loop ;no, no trailing quadpixel
jmp opaq_scan_loop_t ;yes, trailing quadpixel
opaq_need_leading: ;there's a leading quadpixel
cmp ulOddQuadpixel,1 ;odd width in quadpixels?
jnz opaq_scan_loop_lt ;no, trailing quadpixel
jmp opaq_scan_loop_l ;yes, no trailing quadpixel
;-----------------------------------------------------------------------;
; Loops for copying whole quadpixels to the screen, as much as possible a
; quadpixel pair at a time.
; On entry:
; EBX = pointer to flip table
; EDX = # of scans to draw
; ESI = pointer to first buffer byte from which to copy
; EDI = pointer to first screen byte to which to copy
; ulTmpSrcDelta = offset to next buffer scan
; ulTmpDstDelta = offset to next destination (VGA) scan
; ulWholeWidthInQuadpixelPairs = # of whole bytes to copy
; ulWholeWidthInQuadpixelPairsMinus1 = # of whole bytes to copy, minus 1
; LATER could break out and optimize short runs, such as 1, 2, 3, 4 wide.
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; Loop for doing whole opaque words: no leading quadpixel, no trailing
; quadpixel.
;-----------------------------------------------------------------------;
opaq_scan_loop::
opaq_sl_row_loop:
mov ecx,ulWholeWidthInQuadpixelPairs
opaq_sl_byte_loop:
mov bl,[esi] ;get the next temp buffer byte
mov al,[ebx] ;reverse the order of bits 0-3 and 4-7
inc esi ;point to the next temp buffer byte
mov ah,al
shr al,4 ;first quadpixel to draw in AL, next in AH
mov [edi],ax ;draw the glyph
add edi,2 ;point to the next destination address
dec ecx
jnz opaq_sl_byte_loop
opaq_sl_whole_done:
add esi,ulTmpSrcDelta ;point to next buffer scan
add edi,ulTmpDstDelta ;point to next screen scan
dec edx ;count down scans
jnz opaq_sl_row_loop
jmp pfnEdgeVector ;do the edge(s)
;-----------------------------------------------------------------------;
; Loop for doing whole opaque words: leading quadpixel, no trailing
; quadpixel.
;-----------------------------------------------------------------------;
opaq_scan_loop_l::
opaq_sll_row_loop:
mov bl,[esi] ;get the first temp buffer byte
inc esi ;point to the next temp buffer byte
mov al,[ebx] ;reverse the order of bits 0-3
mov [edi],al ;draw the first 4 pixels (the leading quadpixel)
inc edi ;point to the next destination address
mov ecx,ulWholeWidthInQuadpixelPairs
test ecx,ecx ;see if there's anything else to draw
jz short opaq_sll_whole_done
opaq_sll_byte_loop:
mov bl,[esi] ;get the next temp buffer byte
mov al,[ebx] ;reverse the order of bits 0-3 and 4-7
inc esi ;point to the next temp buffer byte
mov ah,al
shr al,4 ;first quadpixel to draw in AL, next in AH
mov [edi],ax ;draw the glyph
add edi,2 ;point to the next destination address
dec ecx
jnz opaq_sll_byte_loop
opaq_sll_whole_done:
add esi,ulTmpSrcDelta ;point to next buffer scan
add edi,ulTmpDstDelta ;point to next screen scan
dec edx ;count down scans
jnz opaq_sll_row_loop
jmp pfnEdgeVector ;do the edge(s)
;-----------------------------------------------------------------------;
; Loop for doing whole opaque words: leading byte, trailing byte.
;-----------------------------------------------------------------------;
opaq_scan_loop_lt::
opaq_sllt_row_loop:
mov bl,[esi] ;get the first temp buffer byte
inc esi ;point to the next temp buffer byte
mov al,[ebx] ;reverse the order of bits 0-3
mov [edi],al ;draw the first 4 pixels (the leading quadpixel)
inc edi ;point to the next destination address
mov ecx,ulWholeWidthInQuadpixelPairsMinus1
test ecx,ecx ;see if there's anything else to draw
jz short opaq_sllt_whole_done
opaq_sllt_byte_loop:
mov bl,[esi] ;get the next temp buffer byte
mov al,[ebx] ;reverse the order of bits 0-3 and 4-7
inc esi ;point to the next temp buffer byte
mov ah,al
shr al,4 ;first quadpixel to draw in AL, next in AH
mov [edi],ax ;draw the glyph
add edi,2 ;point to the next destination address
dec ecx
jnz opaq_sllt_byte_loop
opaq_sllt_whole_done:
mov bl,[esi] ;get the last temp buffer byte
inc esi ;point to the next temp buffer byte
mov al,[ebx] ;reverse the order of bits 4-7
shr eax,4 ;put the quadpixel in bits 0-3
mov [edi],al ;draw the last 4 pixels (the trailing quadpixel)
inc edi ;point to the next destination address
add esi,ulTmpSrcDelta ;point to next buffer scan
add edi,ulTmpDstDelta ;point to next screen scan
dec edx ;count down scans
jnz opaq_sllt_row_loop
jmp pfnEdgeVector ;do the edge(s)
;-----------------------------------------------------------------------;
; Loop for doing whole opaque words: no leading byte, trailing byte.
;-----------------------------------------------------------------------;
opaq_scan_loop_t::
opaq_slt_row_loop:
mov ecx,ulWholeWidthInQuadpixelPairs
test ecx,ecx ;see if there's anything else to draw
jz short opaq_slt_whole_done
opaq_slt_byte_loop:
mov bl,[esi] ;get the next temp buffer byte
mov al,[ebx] ;reverse the order of bits 0-3 and 4-7
inc esi ;point to the next temp buffer byte
mov ah,al
shr al,4 ;first quadpixel to draw in AL, next in AH
mov [edi],ax ;draw the glyph
add edi,2 ;point to the next destination address
dec ecx
jnz opaq_slt_byte_loop
opaq_slt_whole_done:
mov bl,[esi] ;get the last temp buffer byte
inc esi ;point to the next temp buffer byte
mov al,[ebx] ;reverse the order of bits 4-7
shr eax,4 ;put the quadpixel in bits 0-3
mov [edi],al ;draw the last 4 pixels (the trailing quadpixel)
inc edi ;point to the next destination address
add esi,ulTmpSrcDelta ;point to next buffer scan
add edi,ulTmpDstDelta ;point to next screen scan
dec edx ;count down scans
jnz opaq_slt_row_loop
jmp pfnEdgeVector ;do the edge(s)
;-----------------------------------------------------------------------;
; Draw a partial left edge.
;-----------------------------------------------------------------------;
opaq_draw_left_edge_only::
push offset opaq_edges_done ;return here when done with edge
opaq_draw_left_edge_only_entry::
mov esi,pTempBuffer ;source start
mov edi,pScreen ;destination (VGA) start
mov ecx,ulLeftEdgeShift ;CL=amount by which to shift byte to
; right-justify desired quadpixel (0 or
; 4)
mov eax,ulLeftMask ;clip mask for edge
; Enter here to copy a partial edge, with the Map Mask set to clip, ESI
; pointing to the first source byte to copy, EDI pointing to the first dest
; byte to copy to, CL the amount by which to right-shift to get the quadpixel
; of interest into bits 0-3, and AL the Map Mask setting to clip the edge
opaq_draw_edge_entry:
push ebp ;preserve stack frame pointer
mov edx,VGA_BASE + SEQ_DATA ;SEQ_INDEX already points to Map Mask
out dx,al ;set Map Mask for left edge
mov edx,ulScreenDelta ;width of a screen scan in addresses
mov eax,ulNumScans ;height of text
mov ebx,pGlyphFlipTable ;point to the look-up table we'll use
; to flip the glyph bits into the form
; required by planar mode
mov ebp,ulBufDelta ;width of a source scan in bytes
;***stack frame unavailable***
opaq_edge_loop::
mov bl,[esi] ;get the next text buffer byte
shr bl,cl ;move the desired quadpixel into bits 0-3
add esi,ebp ;point to the next destination byte
mov bl,[ebx] ;reverse the order of bits 0-3
mov [edi],bl ;draw up to four pixels, with the Map Mask
; clipping, if necessary
add edi,edx ;point to the next destination byte
dec eax
jnz opaq_edge_loop
pop ebp ;restore stack frame pointer
;***stack frame available***
retn
;-----------------------------------------------------------------------;
; Draw a partial right edge only. Once we've set up the pointers, this
; is done with exactly the same code as the left edge.
;-----------------------------------------------------------------------;
opaq_draw_right_edge_only::
push offset opaq_edges_done ;return here when done with edge
opaq_draw_right_edge_only_entry::
mov esi,ulTextWidthInBytesMinus1
add esi,pTempBuffer ;point to right edge start in buffer
mov edi,ulVGAWidthInBytesMinus1
add edi,pScreen ;point to right edge start in screen
mov ecx,ulRightEdgeShift ;CL=amount by which to shift byte to
; right-justify desired quadpixel (0 or
; 4)
mov eax,ulRightMask ;clip mask for edge
jmp opaq_draw_edge_entry
;-----------------------------------------------------------------------;
; Draw both left and right partial edges. We do this by calling first
; the left and then the right edge drawing code.
;-----------------------------------------------------------------------;
opaq_draw_both_edges::
call opaq_draw_left_edge_only_entry
call opaq_draw_right_edge_only_entry
;-----------------------------------------------------------------------;
; Restore Map Mask to enable all planes, now that we're done drawing
; partial edges.
;-----------------------------------------------------------------------;
opaq_edges_done:
mov al,MM_ALL
mov edx,VGA_BASE + SEQ_DATA ;SEQ_INDEX already points to Map Mask
out dx,al ;set Map Mask for left edge
;-----------------------------------------------------------------------;
; See if there are more banks to draw.
;-----------------------------------------------------------------------;
opaq_check_more_banks::
mov ebx,ppdev
mov eax,[ebx].pdev_rcl1PlanarClip.yBottom ;is the text bottom in
cmp ulBottomScan,eax ; the current bank?
jnle short opaq_do_next_bank ;no, do the next bank
;yes, so we're done
;-----------------------------------------------------------------------;
; Restore the VGA's hardware to the default state.
; The Graphics Controller Index still points to the Bit Mask at this
; point.
;-----------------------------------------------------------------------;
mov edx,VGA_BASE + GRAF_DATA
mov al,0ffh
out dx,al ;enable all bits through the Bit Mask
mov esi,ppdev
dec edx ;point back to the Graphics Index reg
mov ah,byte ptr [esi].pdev_ulrm0_wmX[0]
;write mode 0 setting for Graphics Mode
mov al,GRAF_MODE
out dx,ax ;write mode 0, read mode 0
mov eax,GRAF_DATA_ROT + (DR_SET SHL 8)
out dx,ax ;replace mode, no rotate
cRet vFastText
opaq_do_next_bank::
mov esi,prclText
mov ulTopScan,eax ;this will be the top of the next bank
mov ecx,eax
mul ulScreenDelta
mov edi,[esi].xLeft
shr edi,2 ;convert from pixels to quadpixels
add edi,eax ;next screen byte to which to copy
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>,<ebx,ecx,JustifyTop>
;map in the bank (call preserves EBX,
; ESI, and EDI)
add edi,[ebx].pdev_pvBitmapStart ;initial destination address
mov eax,ulBufDelta
mul ulNumScans
add pTempBuffer,eax ;advance to next temp buffer scan to
; copy
jmp opaq_bank_loop ;we're ready to draw in the new bank
;-----------------------------------------------------------------------;
; Special 8-wide aligned opaque drawing code. Loads the latches with the
; background color, sets the Bit Mask to 1 for bits that differ between
; the foreground and background, sets the ALUs to XOR, then uses write
; mode 3 to draw the glyphs. Joyously, there are no partial bytes to
; worry about, so we can really crank up the code.
;
; On entry:
; EBX = prclText
;-----------------------------------------------------------------------;
special_8_wide_aligned_opaque::
mov esi,ppdev
mov edi,[ebx].yBottom
mov eax,[ebx].yTop
sub edi,eax ;height of glyphs
;-----------------------------------------------------------------------;
; Map in the bank containing the top scan of the text, if it's not
; mapped in already.
;-----------------------------------------------------------------------;
cmp eax,[esi].pdev_rcl1PlanarClip.yTop ;is text top less than
; current bank?
jl short s8wao_map_init_bank ;yes, map in proper bank
cmp eax,[esi].pdev_rcl1PlanarClip.yBottom ;text top greater than
; current bank?
jl short s8wa0_init_bank_mapped ;no, proper bank already mapped
s8wao_map_init_bank::
; Map in the bank containing the top scan line of the text, making sure we're
; in planar mode at the same time.
; Preserves EBX, ESI, and EDI.
ptrCall <dword ptr [esi].pdev_pfnPlanarControl>,<esi,eax,JustifyTop>
s8wa0_init_bank_mapped::
;-----------------------------------------------------------------------;
; We handle only cases where the text lies entirely in one bank.
; LATER handle broken rasters and/or bank-spanning cases?
;-----------------------------------------------------------------------;
mov eax,[esi].pdev_rcl1PlanarClip.yBottom
sub eax,[ebx].yTop ;maximum run in bank
cmp edi,eax ;does all the text fit in the bank?
jg general_handler ;no, let general code handle it
;-----------------------------------------------------------------------;
; Set up variables.
;-----------------------------------------------------------------------;
mov ulScans,edi ;# of scans
;-----------------------------------------------------------------------;
; Point to the first screen byte at which to draw.
;-----------------------------------------------------------------------;
mov eax,[ebx].yTop
mul [esi].pdev_lPlanarNextScan
mov edi,[ebx].xLeft
shr edi,2
add edi,eax ;next screen byte to which to copy
add edi,[esi].pdev_pvBitmapStart ;initial destination address
mov pScreen,edi
;-----------------------------------------------------------------------;
; Load the latches with the background color.
;-----------------------------------------------------------------------;
mov eax,iBgColor
mov byte ptr [edi],al ;write the bg color to the first byte
mov al,[edi] ;read back the byte to load the
; latches with the bg color
;-----------------------------------------------------------------------;
; Set up the VGA's hardware for read mode 0 and write mode 2, the ALUs
; for XOR, and the Bit Mask to 1 for bits that differ between the fg and
; bg, 0 for bits that are the same.
;-----------------------------------------------------------------------;
mov edx,VGA_BASE + GRAF_ADDR
mov ah,byte ptr [esi].pdev_ulrm0_wmX[2]
;write mode 2 setting for Graphics Mode
mov al,GRAF_MODE
out dx,ax ;write mode 2 to expand glyph bits to
; 0 or 0ffh per plane
mov eax,GRAF_DATA_ROT + (DR_XOR SHL 8)
out dx,ax ;XOR to flip latched data to make ~bg
mov ah,byte ptr iBgColor
xor ah,byte ptr iFgColor
mov al,GRAF_BIT_MASK
out dx,ax ;pass through common fg & bg bits
; unchanged from bg color in latches;
; non-common bits come from XOR in the
; ALUs, flipped from the bg to the fg
; state if the glyph bit for the pixel
; in that plane is 1, still in bg state
; if the glyph bit for that plane is 0
;-----------------------------------------------------------------------;
; Set up the screen scan offset in EDX.
;-----------------------------------------------------------------------;
mov edx,[esi].pdev_lPlanarNextScan ;offset from one scan to next
mov ecx,ulGlyphCount
s8wao_glyph_loop:
mov ebx,pGlyphPos ;point to the current glyph to draw
add pGlyphPos,(size GLYPHPOS) ;point to the next glyph
mov edi,pScreen ;point to current glyph's screen
; location
mov esi,[ebx].gp_pgdf ;point to current glyph def
add pScreen,2 ;point to the next glyph's screen
; location
mov ecx,ulScans ;# of scans
mov esi,[esi].gdf_pgb ;point to current glyph
mov ebx,pGlyphFlipTable ;point to the look-up table we'll use
; to flip the glyph bits into the form
; required by planar mode
add esi,gb_aj ;point to the current glyph's bits
s8wao_byte_loop::
mov bl,[esi] ;get the next glyph byte
inc esi ;point to the next glyph byte
mov al,[ebx] ;reverse the order of bits 0-3 and 4-7
mov ah,al
shr al,4 ;first quadpixel to draw in AL, next in AH
mov [edi],ax ;draw the glyph
add edi,edx ;point to the next destination byte
dec ecx ;count down glyph scans
jnz s8wao_byte_loop
dec ulGlyphCount ;count down glyphs
jnz s8wao_glyph_loop
;-----------------------------------------------------------------------;
; Restore the VGA's hardware to the default state.
; The Graphics Controller Index still points to the Bit Mask at this
; point.
;-----------------------------------------------------------------------;
mov edx,VGA_BASE + GRAF_DATA
mov al,0ffh
out dx,al ;enable all bits through the Bit Mask
mov esi,ppdev
dec edx ;point back to the Graphics Index reg
mov ah,byte ptr [esi].pdev_ulrm0_wmX[0]
;write mode 0 setting for Graphics Mode
mov al,GRAF_MODE
out dx,ax ;write mode 0, read mode 0
mov eax,GRAF_DATA_ROT + (DR_SET SHL 8)
out dx,ax ;replace mode, no rotate
draw_prop_done::
cRet vFastText
endProc vFastText
;-----------------------------------------------------------------------;
; VOID vSetWriteModes(ULONG * pulWriteModes);
;
; Sets the four bytes at *pulWriteModes to the values to be written to
; the Graphics Mode register to select read mode 0 and:
; write mode 0, write mode 1, write mode 2, and write mode 3,
; respectively.
;
; Must already be in graphics mode when this is called.
;-----------------------------------------------------------------------;
cProc vSetWriteModes,4,< \
pulWriteModes:ptr >
mov edx,VGA_BASE + GRAF_ADDR
mov al,GRAF_MODE
out dx,al ;point the GC Index to the Graphics Mode reg
inc edx ;point to the GC Data reg
in al,dx ;get the current setting of the Graphics Mode
and eax,0fch ;mask off the write mode fields
mov ah,al
mov edx,eax
shl edx,16
or eax,edx ;put the Graphics Mode setting in all 4 bytes
mov edx,pulWriteModes ;the mode values go here
or eax,03020100h ;insert the write mode fields
mov [edx],eax ;store the Graphics Mode settings
cRet vSetWriteModes
endProc vSetWriteModes
;-----------------------------------------------------------------------;
; VOID vClearMemDword(PULONG * pulBuffer, ULONG ulDwordCount);
;
; Clears ulCount dwords starting at pjBuffer.
;-----------------------------------------------------------------------;
pulBuffer equ [esp+8]
ulDwordCount equ [esp+12]
cProc vClearMemDword,8,<>
push edi
mov edi,pulBuffer
mov ecx,ulDwordCount
sub eax,eax
rep stosd
pop edi
cRet vClearMemDword
endProc vClearMemDword
public general_handler
public draw_f_tb_no_to_temp_start
public draw_nf_tb_no_to_temp_start
public draw_to_temp_start_entry
public draw_f_ntb_o_to_temp_start
public draw_nf_ntb_o_to_temp_start
public draw_to_temp_start_entry2
public draw_f_tb_no_to_temp_loop
public draw_nf_tb_no_to_temp_loop
public draw_to_temp_loop_entry
public draw_f_ntb_o_to_temp_loop
public draw_nf_ntb_o_to_temp_loop
public draw_to_temp_loop_entry2
public or_all_1_wide_rotated_need_last
public or_all_1_wide_rotated_no_last
public or_first_1_wide_rotated_need_last
public or_first_1_wide_rotated_no_last
public or_first_1_wide_rotated_loop
public mov_first_1_wide_rotated_need_last
public mov_first_1_wide_rotated_no_last
public mov_first_1_wide_rotated_loop
public mov_first_1_wide_unrotated
public mov_first_1_wide_unrotated_loop
public or_all_1_wide_unrotated
public or_all_1_wide_unrotated_loop
public or_first_2_wide_rotated_need_last
public or_first_2_wide_rotated_need_loop
public or_all_2_wide_rotated_need_last
public or_all_2_wide_rotated_need_loop
public mov_first_2_wide_rotated_need_last
public mov_first_2_wide_rotated_need_loop
public or_first_2_wide_rotated_no_last
public or_first_2_wide_rotated_loop
public or_all_2_wide_rotated_no_last
public or_all_2_wide_rotated_loop
public mov_first_2_wide_rotated_no_last
public mov_first_2_wide_rotated_loop
public mov_first_2_wide_unrotated
public mov_first_2_wide_unrotated_loop
public or_all_2_wide_unrotated
public or_all_2_wide_unrotated_loop
public or_first_3_wide_rotated_need_last
public or_all_3_wide_rotated_need_last
public mov_first_3_wide_rotated_need_last
public or_first_3_wide_rotated_no_last
public or_all_3_wide_rotated_no_last
public mov_first_3_wide_rotated_no_last
public mov_first_3_wide_unrotated
public or_all_3_wide_unrotated
public or_first_4_wide_rotated_need_last
public or_all_4_wide_rotated_need_last
public mov_first_4_wide_rotated_need_last
public or_first_4_wide_rotated_no_last
public or_all_4_wide_rotated_no_last
public mov_first_4_wide_rotated_no_last
public mov_first_4_wide_unrotated
public or_all_4_wide_unrotated
public or_first_N_wide_rotated_need_last
public or_all_N_wide_rotated_need_last
public mov_first_N_wide_rotated_need_last
public or_first_N_wide_rotated_no_last
public or_all_N_wide_rotated_no_last
public mov_first_N_wide_rotated_no_last
public mov_first_N_wide_unrotated
public odd_width
public two_odd_bytes
public three_odd_bytes
public or_all_N_wide_unrotated
public or_no_odd_bytes_loop
public or_odd_width
public or_one_odd_bytes_loop
public or_two_odd_bytes
public or_two_odd_bytes_loop
public or_three_odd_bytes
public or_three_odd_bytes_loop
public draw_to_screen
public opaque_text
public opaq_left_edge_solid
public opaq_set_edge_vector
public opaq_map_init_bank
public opaq_init_bank_mapped
public opaq_bank_loop
public opaq_whole_quadpixels
public opaq_scan_loop
public opaq_scan_loop_l
public opaq_scan_loop_lt
public opaq_scan_loop_t
public opaq_draw_left_edge_only
public opaq_draw_left_edge_only_entry
public opaq_edge_loop
public opaq_draw_right_edge_only
public opaq_draw_right_edge_only_entry
public opaq_draw_both_edges
public opaq_check_more_banks
public opaq_do_next_bank
public special_8_wide_aligned_opaque
public s8wa0_init_bank_mapped
public s8wao_byte_loop
public s8wao_map_init_bank
public xpar_map_init_bank
public xpar_init_bank_mapped
public xpar_bank_loop
public xpar_scan_loop
public xpar_scan_done
public do_next_xpar_bank
public xpar_high_nibble_F
public xpar_high_nibble_E
public xpar_high_nibble_D
public xpar_high_nibble_C
public xpar_high_nibble_B
public xpar_high_nibble_8
public xpar_high_nibble_6
public xpar_high_nibble_5
public xpar_high_nibble_4
public xpar_high_nibble_7
public xpar_high_nibble_3
public xpar_high_nibble_A
public xpar_high_nibble_2
public xpar_high_nibble_9
public xpar_high_nibble_1
public xpar_high_nibble_0
public xpar_low_nibble_F
public xpar_low_nibble_E
public xpar_low_nibble_D
public xpar_low_nibble_C
public xpar_low_nibble_B
public xpar_low_nibble_8
public xpar_low_nibble_6
public xpar_low_nibble_5
public xpar_low_nibble_4
public xpar_low_nibble_7
public xpar_low_nibble_3
public xpar_low_nibble_A
public xpar_low_nibble_2
public xpar_low_nibble_9
public xpar_low_nibble_1
public xpar_low_nibble_0
end