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

864 lines
26 KiB
NASM

;---------------------------Module-Header------------------------------;
; Module Name: vgastrps.asm
;
; Routines used by line code to draw strips of pixels.
;
; Copyright (c) 1992 Microsoft Corporation
;-----------------------------------------------------------------------;
.386
.model small,c
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\lines.inc
.list
.code
_TEXT$04 SEGMENT DWORD USE32 PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;---------------------------Public-Routine------------------------------;
; vSetStrips
;
; Set the VGA into the appropriate mode for line drawing.
;
;-----------------------------------------------------------------------;
cProc vSetStrips,8,< \
clr: dword, \
mode: dword >
mov edx, VGA_BASE + GRAF_ADDR
mov al, GRAF_SET_RESET
mov ah, byte ptr clr
out dx, ax
cmp mode, DR_SET
je @F
mov al, GRAF_DATA_ROT
mov ah, byte ptr mode
out dx, ax
@@:
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)
cRet vSetStrips
endProc vSetStrips
;---------------------------Public-Routine------------------------------;
; vClearStrips
;
; Restore the VGA to its default state.
;
;-----------------------------------------------------------------------;
cProc vClearStrips,4,< \
oldmode: dword >
; Restore the EGA/VGA to its default state:
mov edx, VGA_BASE + GRAF_ADDR
cmp oldmode, DR_SET
je @F
mov eax, (DR_SET shl 8) + GRAF_DATA_ROT
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
cRet vClearStrips
endProc vClearStrips
;--------------------------Private-Routine------------------------------;
; vStripSolidDiagonalHorizontal
;
; Draw an x-major near-diagonal strip left-to-right
;
;-----------------------------------------------------------------------;
cProc vStripSolidDiagonalHorizontal,12,< \
uses esi edi ebx, \
pStrips: ptr STRIPS, \
pls: ptr LINESTATE, \
plStripEnd: ptr >
mov esi, pStrips
push ebp
mov ebp, plStripEnd
mov ecx, [esi].ST_lNextScan
mov al, [esi].ST_jBitMask
mov edi, [esi].ST_pjScreen
add esi, offset ST_alStrips
; al = bit mask
; ebx = pixel count
; ecx = delta
; edx = port #
; esi = strip pointer
; edi = memory pointer
; ebp = end of strips pointer
next_diagonal:
mov ebx, [esi]
add esi, 4
diagonal_loop:
and [edi], al
ror al, 1
adc edi, ecx
dec ebx
jnz short diagonal_loop
sub edi, ecx ; side step
cmp esi, ebp
jl short next_diagonal
pop ebp
mov esi, pStrips
mov [esi].ST_pjScreen, edi
mov [esi].ST_jBitmask, al
cRet vStripSolidDiagonalHorizontal
endProc vStripSolidDiagonalHorizontal
;--------------------------Private-Routine------------------------------;
; vStripSolidDiagonalVertical
;
; Draw a y-major near-diagonal strip left-to-right
;
;-----------------------------------------------------------------------;
cProc vStripSolidDiagonalVertical,12,< \
uses esi edi ebx, \
pStrips: ptr STRIPS, \
pls: ptr LINESTATE, \
plStripEnd: ptr >
mov esi, pStrips
push ebp
mov ebp, plStripEnd
mov ecx, [esi].ST_lNextScan
mov al, [esi].ST_jBitMask
mov edi, [esi].ST_pjScreen
add esi, offset ST_alStrips
; al = bit mask
; ebx = pixel count
; ecx = delta
; edx = port #
; esi = strip pointer
; edi = memory pointer
; ebp = end of strips pointer
next_diagonal:
mov ebx, [esi]
add esi, 4
diagonal_loop:
and [edi], al
ror al, 1
adc edi, ecx
dec ebx
jnz short diagonal_loop
rol al, 1 ; side step
sbb edi, 0
cmp esi, ebp
jl short next_diagonal
pop ebp
mov esi, pStrips
mov [esi].ST_pjScreen, edi
mov [esi].ST_jBitmask, al
cRet vStripSolidDiagonalVertical
endProc vStripSolidDiagonalVertical
;--------------------------Private-Routine------------------------------;
; vStripSolidHorizontal
;
; Draw a horizontal strip left to right
;
;-----------------------------------------------------------------------;
cProc vStripSolidHorizontal,12,< \
uses esi edi ebx, \
pStrips: ptr STRIPS, \
pls: ptr LINESTATE, \
plStripEnd: ptr >
; Do some initializing:
mov esi, pStrips
push ebp
mov ebp, plStripEnd
mov edx, [esi].ST_lNextScan
mov al, [esi].ST_jBitMask
mov edi, [esi].ST_pjScreen
add esi, offset ST_alStrips
; (al) = rotating bit
; (bl) = current mask
; (ecx) = pixel count
; (edx) = delta
; (esi) = strip pointer
; (edi) = display pointer
; (ebp) = end of strips pointer
next_horizontal:
mov ecx, [esi]
add esi, 4
lea ebx, [2 * eax - 1] ; bl = start mask
ror al, cl ; rotate bit
shr ecx, 3 ; compute # bytes to lay down
cmp bl, al ; we have to adjust for wrap
adc ecx, 0
jnz short extends_out_of_first_byte
sub bl, al ; zero out end bits
sub bl, al
inc bl
and [edi], bl ; write result
add edi, edx ; increment to next scan
cmp esi, ebp ; see if done strips
jb short next_horizontal
pop ebp ; we're done
mov esi, pStrips
mov [esi].ST_pjScreen, edi
mov [esi].ST_jBitmask, al
cRet vStripSolidHorizontal
extends_out_of_first_byte:
; This part gets called when the current strip doesn't fit entirely
; into one byte:
and [edi], bl ; output with start mask
inc edi ; go on to next byte
dec ecx ; see if there's any bytes in
jnz short output_bunch ; between start and end byte
last_byte:
lea ebx, [2 * eax - 1] ; compute end mask
not bl
and [edi], bl ; write result
add edi, edx ; increment to next scan
cmp esi, ebp ; see if done strips
jb short next_horizontal
pop ebp ; we're done
mov esi, pStrips
mov [esi].ST_pjScreen, edi
mov [esi].ST_jBitmask, al
cRet vStripSolidHorizontal
output_bunch:
; We have a bunch of complete bytes to lay down.
mov ebx, esi ; we're gonna overwrite esi
mov esi, edi
rep movsb ; Write the bytes. Mask is 0ffh because
; we're in read mode 1, reading 0ffh,
; which becomes the write mode 3 mask.
mov esi, ebx ; restore esi
jmp short last_byte ; do last byte in scan
endProc vStripSolidHorizontal
;--------------------------Private-Routine------------------------------;
; vStripSolidHorizontalSet
;
; Draw horizontal strips left to right for SRCCOPY lines.
;
;-----------------------------------------------------------------------;
cProc vStripSolidHorizontalSet,12,< \
uses esi edi ebx, \
pStrips: ptr STRIPS, \
pls: ptr LINESTATE, \
plStripEnd: ptr >
; Do some initializing:
mov esi, pStrips
push ebp
mov ebp, plStripEnd
mov edx, [esi].ST_lNextScan
mov al, [esi].ST_jBitMask
mov edi, [esi].ST_pjScreen
add esi, offset ST_alStrips
; (al) = rotating bit
; (bl) = current mask
; (ecx) = pixel count
; (edx) = delta
; (esi) = strip pointer
; (edi) = display pointer
; (ebp) = end of strips pointer
next_horizontal:
mov ecx, [esi]
add esi, 4
lea ebx, [2 * eax - 1] ; bl = start mask
ror al, cl ; rotate bit
shr ecx, 3 ; compute # bytes to lay down
cmp bl, al ; we have to adjust for wrap
adc ecx, 0
jnz short extends_out_of_first_byte
sub bl, al ; zero out end bits
sub bl, al
inc bl
and [edi], bl ; write result
add edi, edx ; increment to next scan
cmp esi, ebp ; see if done strips
jb short next_horizontal
pop ebp ; we're done
mov esi, pStrips
mov [esi].ST_pjScreen, edi
mov [esi].ST_jBitmask, al
cRet vStripSolidHorizontalSet
extends_out_of_first_byte:
; This part gets called when the current strip doesn't fit entirely
; into one byte:
and [edi], bl ; output with start mask
inc edi ; go on to next byte
dec ecx ; see if there's any bytes in
jnz short output_bunch ; between start and end byte
last_byte:
lea ebx, [2 * eax - 1] ; compute end mask
not bl
and [edi], bl ; write result
add edi, edx ; increment to next scan
cmp esi, ebp ; see if done strips
jb short next_horizontal
pop ebp ; we're done
mov esi, pStrips
mov [esi].ST_pjScreen, edi
mov [esi].ST_jBitmask, al
cRet vStripSolidHorizontalSet
output_bunch:
; We have a bunch of complete bytes to lay down. Since we're doing
; the interior of the line and we have a SRCCOPY ROP, we don't have
; to worry about loading the latches properly, so we can do this
; without reading the VGA memory. We also use 16 bit writes since
; on some devices it's faster to write a single word than to write
; two bytes -- doing so means we must be word-aligned.
test edi, 1
jz now_aligned
mov byte ptr [edi], 0ffh ; write a byte to get alignment right
inc edi
dec ecx
jz short last_byte ; maybe that was only byte we had to do
now_aligned:
shr ecx, 1 ; divide by 2 to determine the number
; of words to write
; NOTE: We check the carry later on!
jz short last_byte_in_bunch ; small optimization: skip word stuff
; if we've only got a single byte
mov ebx, eax ; save eax
mov eax, 0ffffh ; prepare ax
rep stosw ; lay those words down
mov eax, ebx ; restore eax
jnc short last_byte ; NOTE: NOW we're checking the carry!
last_byte_in_bunch:
mov byte ptr [edi], 0ffh ; write that last byte
inc edi
jmp short last_byte
endProc vStripSolidHorizontalSet
;--------------------------Private-Routine------------------------------;
; vStripSolidVertical
;
; Draw a vertical strip left to right
;
;-----------------------------------------------------------------------;
cProc vStripSolidVertical,12,< \
uses esi edi ebx, \
pStrips: ptr STRIPS, \
pls: ptr LINESTATE, \
plStripEnd: ptr >
; Do some initialization:
mov esi, pStrips
mov edx, plStripEnd
mov ecx, [esi].ST_lNextScan
mov al, [esi].ST_jBitmask
mov edi, [esi].ST_pjScreen
add esi, offset ST_alStrips
mov [edx], ebp ; save ebp
next_vertical:
mov ebx, [esi] ; ebx = # bits to set
add esi, 4
; (al) = rotating bit
; (ebx) = # of loops to do
; (ecx) = minor add
; (edx) = end of strips pointer
; (esi) = strip pointer
; (edi) = address of byte to write
; (ebp) = garbage
vertical_strip_loop:
and [edi], al ; write the byte
add edi, ecx ; go to next scan
dec ebx
jnz vertical_strip_loop
; Adjust address and rotating bit for sidestep:
ror al, 1 ; one to the right
adc edi, 0
cmp esi, edx
jl short next_vertical ; hit end of array?
; Remember where we left off, for next time:
mov ebp, [edx] ; restore ebp
mov esi, pStrips
mov [esi].ST_pjScreen, edi
mov [esi].ST_jBitmask, al
cRet vStripSolidVertical
endProc vStripSolidVertical
;--------------------------Private-Routine------------------------------;
; vStripStyledHorizontal
;
; Draws an arbitrarily styled horizontal strip left-to-right.
;
;-----------------------------------------------------------------------;
cProc vStripStyledHorizontal,12,< \
uses esi edi ebx, \
pStrips: ptr STRIPS, \
pls: ptr LINESTATE, \
plStripEnd: ptr >
local aEnd:dword ; end of length array
local minoradd:dword
local spToGo:dword
; So some initialization:
mov esi, pStrips
mov eax, plStripEnd
mov aEnd, eax
mov eax, [esi].ST_lNextScan
mov bl, [esi].ST_jBitmask
mov edi, [esi].ST_pjScreen
mov minoradd, eax
; Initialize styling:
mov eax, [esi].ST_spRemaining
mov bh, [esi].ST_jStyleMask
mov spToGo, eax
add esi, offset ST_alStrips
Strip_loop:
mov ecx, [esi] ; ecx = # bits to write
add esi, 4
; Now we're going to paste the bytes to the screen
;
; (al) = used to accumulate the mask
; (bl) = rotating bit
; (bh) = jStyleMask
; (ecx) = # of bits to write
; (edx) =
; (esi) = ptr to spot in ST_alStrips
; (edi) = address of byte to write
xor al, al ; clear style mask
Strip_count:
xor al, bh ; set bit in output mask if style bit 0
or al, bl
xor al, bh
dec spToGo
jz short Next_style_entry
Next_bit:
ror bl, 1
jc short Output_byte
dec ecx
jnz short Strip_count
; Do sidestep
Side_step:
and byte ptr [edi], al
add edi, minoradd
cmp esi, aEnd
jl short Strip_loop
mov esi, pStrips
mov [esi].ST_pjScreen, edi
mov [esi].ST_jBitmask, bl
mov [esi].ST_jStyleMask, bh
mov eax, spToGo
mov [esi].ST_spRemaining, eax
cRet vStripStyledHorizontal
Output_byte:
and byte ptr [edi], al
xor al, al
inc edi ; Moved one byte to right on screen
dec ecx
jnz short Strip_count
jz short Side_step
; We're on to a new entry in the style array:
Next_style_entry:
push eax
mov edx, pStrips
mov eax, [edx].ST_psp
add eax, 4
cmp [edx].ST_pspEnd, eax
jae short @F
mov eax, [edx].ST_pspStart ; Go back to start of array
@@:
mov [edx].ST_psp, eax
mov edx, [eax] ; Load up new style entry
add spToGo, edx
not bh ; jStyleMask = !jStyleMask
pop eax
jmp short Next_bit
endProc vStripStyledHorizontal
;--------------------------Private-Routine------------------------------;
; vStripStyledVertical
;
; Draw an arbitrarily styled vertical strip left-to-right.
;
;-----------------------------------------------------------------------;
cProc vStripStyledVertical,12,< \
uses esi edi ebx, \
pStrips: ptr STRIPS, \
pls: ptr LINESTATE, \
plStripEnd: ptr >
local aEnd:dword ; end of length array
local minoradd:dword
local spToGo:dword
; So some initialization:
mov esi, pStrips
mov eax, plStripEnd
mov aEnd, eax
mov ecx, [esi].ST_lNextScan
mov al, [esi].ST_jBitmask
mov edi, [esi].ST_pjScreen
mov minoradd, ecx
; Initialize styling:
mov ebx, [esi].ST_spRemaining
mov ah, [esi].ST_jStyleMask
mov spToGo, ebx
add esi, offset ST_alStrips
Strip_loop:
mov ebx, [esi] ; ebx = # bits to set
add esi, 4
; Now we're going to paste the bytes to the screen
;
; (al) = rotating bit
; (ah) = jStyleMask
; (ebx) = # of bits to write
; (ecx) = minor add
; (edx) =
; (esi) = ptr to spot in ST_alStrips
; (edi) = address of byte to write
Strip_count:
or ah, ah
jnz short @F ; Don't output pixel if in a gap
and [edi], al
@@:
dec spToGo
jz short Next_style_entry
Minor_add:
add edi, ecx
dec ebx
jnz short Strip_count
; Adjust address and rotating bit for sidestep
ror al, 1 ; one to the right
adc edi, 0
cmp esi, aEnd
jl short Strip_loop ; hit end of array?
mov esi, pStrips
mov [esi].ST_pjScreen, edi
mov [esi].ST_jBitmask, al
mov [esi].ST_jStyleMask, ah
mov eax, spToGo
mov [esi].ST_spRemaining, eax
cRet vStripStyledVertical
Next_style_entry:
mov edx, pStrips
mov ecx, [edx].ST_psp
add ecx, 4
cmp [edx].ST_pspEnd, ecx
jae short @F
mov ecx, [edx].ST_pspStart ; Go back to start of array
@@:
mov [edx].ST_psp, ecx ; Save our pointer
mov edx, [ecx] ; Load up new style entry
add spToGo, edx
not ah ; jStyleMask = !jStyleMask
; Restore the registers we used:
mov ecx, minoradd
jmp short Minor_add
endProc vStripStyledVertical
;--------------------------Private-Routine------------------------------;
; vStripMaskedHorizontal
;
; Draws a mask-styled horizontal strip left to right.
;
;-----------------------------------------------------------------------;
cProc vStripMaskedHorizontal,12,< \
uses esi edi ebx, \
pStrips: ptr STRIPS, \
pls: ptr LINESTATE, \
plStripEnd: ptr >
local aEnd:dword ; end of length array
local minoradd:dword
local density:dword
; So some initialization:
mov esi, pStrips
mov eax, plStripEnd
mov aEnd, eax
mov eax, [esi].ST_lNextScan
mov bl, [esi].ST_jBitmask
mov edi, [esi].ST_pjScreen
mov minoradd, eax
; Initialize styling:
mov ecx, [esi].ST_xyDensity
mov ah, byte ptr [esi].ST_spRemaining
mov bh, [esi].ST_jStyleMask
mov density, ecx
add esi, offset ST_alStrips
Strip_loop:
mov ecx, [esi] ; ecx = # bits to write
add esi, 4
; Now we're going to paste the bytes to the screen
;
; (al) = used to accumulate style mask
; (ah) = # pixels left in style
; (bl) = rotating bit
; (bh) = style mask
; (ecx) = # of bits to write
; (esi) = ptr to spot in ST_alStrips
; (edi) = address of byte to write
xor al, al ; clear output mask
Strip_count:
xor al, bh ; set bit in output mask if style bit 0
or al, bl
xor al, bh
dec ah
jnz short @F
rol bh, 1
mov ah, byte ptr density
@@: ror bh, 1
ror bl, 1
jc short Output_byte
dec ecx
jnz short Strip_count
; Do sidestep
Side_step:
and byte ptr [edi], al
add edi, minoradd
cmp esi, aEnd
jl short Strip_loop
mov esi, pStrips
mov [esi].ST_pjScreen, edi
mov [esi].ST_jBitmask, bl
mov [esi].ST_jStyleMask, bh
mov byte ptr [esi].ST_spRemaining, ah
cRet vStripMaskedHorizontal
Output_byte:
and byte ptr [edi], al
xor al, al
inc edi
dec ecx
jnz short Strip_count
jz short Side_step
endProc vStripMaskedHorizontal
;--------------------------Private-Routine------------------------------;
; vStripMaskedVertical
;
; Draw a mask-styled vertical strip left to right.
;
;-----------------------------------------------------------------------;
cProc vStripMaskedVertical,12,< \
uses esi edi ebx, \
pStrips: ptr STRIPS, \
pls: ptr LINESTATE, \
plStripEnd: ptr >
local aEnd:dword ; end of length array
local minoradd:dword
local density:dword
; So some initialization:
mov esi, pStrips
mov al, [esi].ST_jBitmask
mov edi, [esi].ST_pjScreen
mov ebx, [esi].ST_lNextScan
mov ecx, plStripEnd
mov minoradd, ebx
mov aEnd, ecx
; Initialize styling:
mov ecx, [esi].ST_xyDensity
mov ah, byte ptr [esi].ST_spRemaining
mov bh, [esi].ST_jStyleMask
mov density, ecx
add esi, offset ST_alStrips
Strip_loop:
mov ecx, [esi] ; ecx = # bits to set
add esi, 4
; Now we're going to paste the bytes to the screen
; (al) = rotating bit
; (ah) = # pixels left in style
; (bh) = style mask
; (ecx) = # bits to write
; (dx) = io address of mask register
; (esi) = ptr to spot in ST_alStrips
; (edi) = address of byte to write
Strip_count:
test bh, al
jnz short @F ; don't output pixel if style bit is 1
and [edi], al
@@:
dec ah ; we've advanced 1 pel in the style
jnz short @F
mov ah, byte ptr density
rol bh, 1
@@:
add edi, minoradd
dec ecx
jnz short Strip_count
; Adjust address, style mask and rotating bit for sidestep:
ror bh, 1 ; rotate style mask to stay in sync
ror al, 1 ; move rotating bit one to the right
adc edi, 0
cmp esi, aEnd
jl short Strip_loop ; hit end of array?
mov esi, pStrips
mov [esi].ST_pjScreen, edi
mov [esi].ST_jBitmask, al
mov [esi].ST_jStyleMask, bh
mov byte ptr [esi].ST_spRemaining, ah
cRet vStripMaskedVertical
endProc vStripMaskedVertical
_TEXT$04 ends
end