;by Sean Palmer--Public Domain. Please credit me if you use it.
ideal
model tpascal
p386n
extrn segA000:word
codeseg
public line
proc line near x:word,y:word,x2:word,y2:word,c:byte
mov edi,[dword y]
mov ebx,[dword y2]
cmp di,bx
jle @@TOPDOWN ;always draw top-down to normalize lines
mov [dword y],ebx ;swap coord pairs to keep from drawing bottom-up
mov [dword y2],edi ;stack is top down, left-to-right. Do pair as one dword
xchg di,bx
@@TOPDOWN:
sub bx,di ;bx=positive vertical distance
mov cx,320 ;screen width, used to step to next line down
shl di,6 ;*64*(4+1)=*320
lea di,[edi*4+edi]
add di,[x]
shl edi,16 ;dest adr out of harm's way for now
mov dx,1 ;from one pixel to the next on the right
mov ax,[x2]
sub ax,[x]
jnc @@XS
neg ax
neg dx
@@XS:
cmp ax,bx
jae @@XMAJ
xchg bx,ax
xchg cx,dx
@@XMAJ:
mov si,ax
neg si
test cx,cx
jns @@SGNOK
dec si ;adjust for consistent carry into edihi
@@SGNOK: ;this is safe because di will not overflow (line offscreen)
shl esi,16 ;esihi=decision var adjuster for minor step
mov si,cx ;si=minor step for di
mov cx,ax ;set line length to major axis distance-1
mov di,ax ;set decision var halfway in edihi
neg di
sar di,1
rol edi,16
test dx,dx
jns @@SGNOK2
dec bx ;adjust for consistent carry into edihi
@@SGNOK2: ;this is safe because di will not overflow (line offscreen)
shl ebx,16 ;ebxhi=major adjust for decision var
mov bx,dx ;bx=major adjust for dest adr
mov ah,[c] ;color
push ds
mov ds,[segA000]
; this inner loop's about as optimized as it's gonna get, and
; still have edx,ecxhi,al,and eaxhi left over. Could even use ebp...
; would work really well in a 32-bit operand segment.
; as it is, the benefits over the old version is mainly the unrolling
; of the loop, and the fact that it no longer uses memory variables.
shr cx,1
jc @@L ;unrolled 2x below, so take care of odd count case
mov [di],ah
dec cx
js @@X
add edi,ebx
jns @@MIN2
@@L:
mov [di],ah ;plot pixel
add edi,ebx ;do major step
jns @@MIN ;did decision var wrap? (do NOT test carry!)
mov [di],ah ;kinda unrolled again here. Doesn't help on a Pentium.
dec cx ;check counter every two major steps
js @@X
add edi,ebx ;do major step
js @@L
@@MIN2:
add edi,esi ;adjust decision var/adr for minor step
jmp @@L
@@X: ;clean up and exit
pop ds
ret
@@MIN: ;Minor step for first unrolled part
add edi,esi ;adjust decision var/adr for minor step
mov [di],ah ;kinda unrolled again here. Doesn't help on a Pentium.
dec cx
js @@X
add edi,ebx ;did decision var wrap? and do major step
js @@L
add edi,esi
jmp @@L
endp
ends
end