;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
