The /tests/pc folder is now /tests/pcx86 (to be consistent with the associated emulator)
This commit is contained in:
parent
51b50382fb
commit
663343a1ad
68 changed files with 24 additions and 16 deletions
|
|
@ -1,366 +0,0 @@
|
|||
; Fast assembler implementation of Bresenham's line drawing algorithm
|
||||
; for the EGA and VGA. Works in modes 0Eh, 0Fh, 10h, and 12h.
|
||||
; C near-callable.
|
||||
; Bit mask accumulation technique when |DeltaX| >= |DeltaY|
|
||||
; suggested by Jim Mackraz.
|
||||
;
|
||||
; Assembled with MASM
|
||||
;
|
||||
; By Michael Abrash
|
||||
;
|
||||
;****************************************************************
|
||||
; C-compatible line-drawing entry point at _EVGALine. *
|
||||
; Near C-callable as: *
|
||||
; EVGALine(X0, Y0, X1, Y1, Color); *
|
||||
;****************************************************************
|
||||
;
|
||||
.model small
|
||||
.code
|
||||
;
|
||||
; Equates.
|
||||
;
|
||||
EVGA_SCREEN_WIDTH_IN_BYTES equ 80 ;memory offset from start of
|
||||
; one row to start of next
|
||||
; in display memory
|
||||
EVGA_SCREEN_SEGMENT equ 0a000h ;display memory segment
|
||||
GC_INDEX equ 3ceh ;Graphics Controller
|
||||
; Index register port
|
||||
SET_RESET_INDEX equ 0 ;indexes of needed
|
||||
ENABLE_SET_RESET_INDEX equ 1 ; Graphics Controller
|
||||
BIT_MASK_INDEX equ 8 ; registers
|
||||
|
||||
;
|
||||
; Stack frame.
|
||||
;
|
||||
EVGALineParms struc
|
||||
dw ? ;pushed BP
|
||||
dw ? ;pushed return address (make double
|
||||
; word for far call)
|
||||
X0 dw ? ;starting X coordinate of line
|
||||
Y0 dw ? ;starting Y coordinate of line
|
||||
X1 dw ? ;ending X coordinate of line
|
||||
Y1 dw ? ;ending Y coordinate of line
|
||||
Color db ? ;color of line
|
||||
db ? ;dummy to pad to word size
|
||||
EVGALineParms ends
|
||||
|
||||
;****************************************************************
|
||||
; Line drawing macros. *
|
||||
;****************************************************************
|
||||
|
||||
;
|
||||
; Macro to loop through length of line, drawing each pixel in turn.
|
||||
; Used for case of |DeltaX| >= |DeltaY|.
|
||||
; Input:
|
||||
; MOVE_LEFT: 1 if DeltaX < 0, 0 else
|
||||
; AL: pixel mask for initial pixel
|
||||
; BX: |DeltaX|
|
||||
; DX: address of GC data register, with index register set to
|
||||
; index of Bit Mask register
|
||||
; SI: DeltaY
|
||||
; ES:DI: display memory address of byte containing initial
|
||||
; pixel
|
||||
;
|
||||
LINE1 macro MOVE_LEFT
|
||||
local LineLoop, MoveXCoord, NextPixel, Line1End
|
||||
local MoveToNextByte, ResetBitMaskAccumulator
|
||||
mov cx,bx ;# of pixels in line
|
||||
jcxz Line1End ;done if there are no more pixels
|
||||
; (there's always at least the one pixel
|
||||
; at the start location)
|
||||
shl si,1 ;DeltaY * 2
|
||||
mov bp,si ;error term
|
||||
sub bp,bx ;error term starts at DeltaY * 2 - DeltaX
|
||||
shl bx,1 ;DeltaX * 2
|
||||
sub si,bx ;DeltaY * 2 - DeltaX * 2 (used in loop)
|
||||
add bx,si ;DeltaY * 2 (used in loop)
|
||||
mov ah,al ;set aside pixel mask for initial pixel
|
||||
; with AL (the pixel mask accumulator) set
|
||||
; for the initial pixel
|
||||
LineLoop:
|
||||
;
|
||||
; See if it's time to advance the Y coordinate yet.
|
||||
;
|
||||
and bp,bp ;see if error term is negative
|
||||
js MoveXCoord ;yes, stay at the same Y coordinate
|
||||
;
|
||||
; Advance the Y coordinate, first writing all pixels in the current
|
||||
; byte, then move the pixel mask either left or right, depending
|
||||
; on MOVE_LEFT.
|
||||
;
|
||||
out dx,al ;set up bit mask for pixels in this byte
|
||||
xchg byte ptr [di],al
|
||||
;load latches and write pixels, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
add di,EVGA_SCREEN_WIDTH_IN_BYTES ;increment Y coordinate
|
||||
add bp,si ;adjust error term back down
|
||||
;
|
||||
; Move pixel mask one pixel (either right or left, depending
|
||||
; on MOVE_LEFT), adjusting display memory address when pixel mask wraps.
|
||||
;
|
||||
if MOVE_LEFT
|
||||
rol ah,1 ;move pixel mask 1 pixel to the left
|
||||
else
|
||||
ror ah,1 ;move pixel mask 1 pixel to the right
|
||||
endif
|
||||
jnc ResetBitMaskAccumulator ;didn't wrap to next byte
|
||||
jmp short MoveToNextByte ;did wrap to next byte
|
||||
;
|
||||
; Move pixel mask one pixel (either right or left, depending
|
||||
; on MOVE_LEFT), adjusting display memory address and writing pixels
|
||||
; in this byte when pixel mask wraps.
|
||||
;
|
||||
MoveXCoord:
|
||||
add bp,bx ;increment error term & keep same
|
||||
if MOVE_LEFT
|
||||
rol ah,1 ;move pixel mask 1 pixel to the left
|
||||
else
|
||||
ror ah,1 ;move pixel mask 1 pixel to the right
|
||||
endif
|
||||
jnc NextPixel ;if still in same byte, no need to
|
||||
; modify display memory yet
|
||||
out dx,al ;set up bit mask for pixels in this byte.
|
||||
xchg byte ptr [di],al
|
||||
;load latches and write pixels, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
MoveToNextByte:
|
||||
if MOVE_LEFT
|
||||
dec di ;next pixel is in byte to left
|
||||
else
|
||||
inc di ;next pixel is in byte to right
|
||||
endif
|
||||
ResetBitMaskAccumulator:
|
||||
sub al,al ;reset pixel mask accumulator
|
||||
NextPixel:
|
||||
or al,ah ;add the next pixel to the pixel mask
|
||||
; accumulator
|
||||
loop LineLoop
|
||||
;
|
||||
; Write the pixels in the final byte.
|
||||
;
|
||||
Line1End:
|
||||
out dx,al ;set up bit mask for pixels in this byte.
|
||||
xchg byte ptr [di],al
|
||||
;load latches and write pixels, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
endm
|
||||
|
||||
;
|
||||
; Macro to loop through length of line, drawing each pixel in turn.
|
||||
; Used for case of DeltaX < DeltaY.
|
||||
; Input:
|
||||
; MOVE_LEFT: 1 if DeltaX < 0, 0 else
|
||||
; AL: pixel mask for initial pixel
|
||||
; BX: |DeltaX|
|
||||
; DX: address of GC data register, with index register set to
|
||||
; index of Bit Mask register
|
||||
; SI: DeltaY
|
||||
; ES:DI: display memory address of byte containing initial
|
||||
; pixel
|
||||
;
|
||||
LINE2 macro MOVE_LEFT
|
||||
local LineLoop, MoveYCoord, ETermAction, Line2End
|
||||
mov cx,si ;# of pixels in line
|
||||
jcxz Line2End ;done if there are no more pixels
|
||||
shl bx,1 ;DeltaX * 2
|
||||
mov bp,bx ;error term
|
||||
sub bp,si ;error term starts at DeltaX * 2 - DeltaY
|
||||
shl si,1 ;DeltaY * 2
|
||||
sub bx,si ;DeltaX * 2 - DeltaY * 2 (used in loop)
|
||||
add si,bx ;DeltaX * 2 (used in loop)
|
||||
;
|
||||
; Set up initial bit mask & write initial pixel.
|
||||
;
|
||||
out dx,al
|
||||
xchg byte ptr [di],ah
|
||||
;load latches and write pixel, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
LineLoop:
|
||||
;
|
||||
; See if it's time to advance the X coordinate yet.
|
||||
;
|
||||
and bp,bp ;see if error term is negative
|
||||
jns ETermAction ;no, advance X coordinate
|
||||
add bp,si ;increment error term & keep same
|
||||
jmp short MoveYCoord; X coordinate
|
||||
ETermAction:
|
||||
;
|
||||
; Move pixel mask one pixel (either right or left, depending
|
||||
; on MOVE_LEFT), adjusting display memory address when pixel mask wraps.
|
||||
;
|
||||
if MOVE_LEFT
|
||||
rol al,1
|
||||
sbb di,0
|
||||
else
|
||||
ror al,1
|
||||
adc di,0
|
||||
endif
|
||||
out dx,al ;set new bit mask
|
||||
add bp,bx ;adjust error term back down
|
||||
;
|
||||
; Advance Y coordinate.
|
||||
;
|
||||
MoveYCoord:
|
||||
add di,EVGA_SCREEN_WIDTH_IN_BYTES
|
||||
;
|
||||
; Write the next pixel.
|
||||
;
|
||||
xchg byte ptr [di],ah
|
||||
;load latches and write pixel, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
;
|
||||
loop LineLoop
|
||||
Line2End:
|
||||
endm
|
||||
|
||||
;****************************************************************
|
||||
; Line drawing routine. *
|
||||
;****************************************************************
|
||||
|
||||
public _EVGALine
|
||||
_EVGALine proc near
|
||||
push bp
|
||||
mov bp,sp
|
||||
push si ;preserve register variables
|
||||
push di
|
||||
push ds
|
||||
;
|
||||
; Point DS to display memory.
|
||||
;
|
||||
mov ax,EVGA_SCREEN_SEGMENT
|
||||
mov ds,ax
|
||||
;
|
||||
; Set the Set/Reset and Set/Reset Enable registers for
|
||||
; the selected color.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,SET_RESET_INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,[bp+Color]
|
||||
out dx,al
|
||||
dec dx
|
||||
mov al,ENABLE_SET_RESET_INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,0ffh
|
||||
out dx,al
|
||||
;
|
||||
; Get DeltaY.
|
||||
;
|
||||
mov si,[bp+Y1] ;line Y start
|
||||
mov ax,[bp+Y0] ;line Y end, used later in
|
||||
;calculating the start address
|
||||
sub si,ax ;calculate DeltaY
|
||||
jns CalcStartAddress;if positive, we're set
|
||||
;
|
||||
; DeltaY is negative -- swap coordinates so we're always working
|
||||
; with a positive DeltaY.
|
||||
;
|
||||
mov ax,[bp+Y1] ;set line start to Y1, for use
|
||||
; in calculating the start address
|
||||
mov dx,[bp+X0]
|
||||
xchg dx,[bp+X1]
|
||||
mov [bp+X0],dx ;swap X coordinates
|
||||
neg si ;convert to positive DeltaY
|
||||
;
|
||||
; Calculate the starting address in display memory of the line.
|
||||
; Hardwired for a screen width of 80 bytes.
|
||||
;
|
||||
CalcStartAddress:
|
||||
shl ax,1 ;Y0 * 2 ;Y0 is already in AX
|
||||
shl ax,1 ;Y0 * 4
|
||||
shl ax,1 ;Y0 * 8
|
||||
shl ax,1 ;Y0 * 16
|
||||
mov di,ax
|
||||
shl ax,1 ;Y0 * 32
|
||||
shl ax,1 ;Y0 * 64
|
||||
add di,ax ;Y0 * 80
|
||||
mov dx,[bp+X0]
|
||||
mov cl,dl ;set aside lower 3 bits of column for
|
||||
and cl,7 ; pixel masking
|
||||
shr dx,1
|
||||
shr dx,1
|
||||
shr dx,1 ;get byte address of column (X0/8)
|
||||
add di,dx ;offset of line start in display segment
|
||||
;
|
||||
; Set up GC Index register to point to the Bit Mask register.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,BIT_MASK_INDEX
|
||||
out dx,al
|
||||
inc dx ;leave DX pointing to the GC Data register
|
||||
;
|
||||
; Set up pixel mask (in-byte pixel address).
|
||||
;
|
||||
mov al,80h
|
||||
shr al,cl
|
||||
;
|
||||
; Calculate DeltaX.
|
||||
;
|
||||
mov bx,[bp+X1]
|
||||
sub bx,[bp+X0]
|
||||
;
|
||||
; Handle correct one of four octants.
|
||||
;
|
||||
js NegDeltaX
|
||||
cmp bx,si
|
||||
jb Octant1
|
||||
;
|
||||
; DeltaX >= DeltaY >= 0.
|
||||
;
|
||||
LINE1 0
|
||||
jmp EVGALineDone
|
||||
;
|
||||
; DeltaY > DeltaX >= 0.
|
||||
;
|
||||
Octant1:
|
||||
LINE2 0
|
||||
jmp short EVGALineDone
|
||||
;
|
||||
NegDeltaX:
|
||||
neg bx ;|DeltaX|
|
||||
cmp bx,si
|
||||
jb Octant2
|
||||
;
|
||||
; |DeltaX| >= DeltaY and DeltaX < 0.
|
||||
;
|
||||
LINE1 1
|
||||
jmp short EVGALineDone
|
||||
;
|
||||
; |DeltaX| < DeltaY and DeltaX < 0.
|
||||
;
|
||||
Octant2:
|
||||
LINE2 1
|
||||
;
|
||||
EVGALineDone:
|
||||
;
|
||||
; Restore EVGA state.
|
||||
;
|
||||
mov al,0ffh
|
||||
out dx,al ;set Bit Mask register to 0ffh
|
||||
dec dx
|
||||
mov al,ENABLE_SET_RESET_INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
sub al,al
|
||||
out dx,al ;set Enable Set/Reset register to 0
|
||||
;
|
||||
pop ds
|
||||
pop di
|
||||
pop si
|
||||
pop bp
|
||||
ret
|
||||
_EVGALine endp
|
||||
|
||||
end
|
||||
Loading…
Reference in a new issue