.286
b equ byte ptr
w equ word ptr

data segment
  extrn vpage:word              ;current video page
data ends

putpixel macro                  ;puts pixel at ax/bx
  pusha
  xchg ax,bx                    ;exchange x and y
  push ax                       ;store y for later
  mov cx,bx                     ;get x
  and cx,3                      ;mask plane
  mov ax,1                      ;and set corresp. bit
  shl ax,cl
  mov ah,2                      ;TS register 2
  xchg ah,al
  mov dx,3c4h
  out dx,ax

  pop cx                        ;get y
  mov ax,80d                    ;calculate row offset
  mul cx
  shr bx,2                      ;add column offset
  add bx,ax
  add bx,vpage                  ;write to current page
  mov b es:[bx],3               ;and set color

  popa
endm

code segment public
assume cs:code,ds:data

public bline
bline proc    near
;draws line from ax/bx to cx/dx
  push bp
  push ax                       ;store x0 and
  push bx                       ;y0
  mov bx,4340h                  ;prepare self modification
  sub cx,ax                     ;calculate deltax
  jns deltax_ok                 ;negative ?
  neg cx                        ;yes, then reverse deltax sign
  mov bl,48h                    ;and decrement ax instead of incrementing ax
deltax_ok:
  mov bp,sp                     ;addressing of y1 on the stack
  sub dx,ss:[bp]                ;calculate deltay
  jns deltay_ok                 ;negative ?
  neg dx                        ;yes, then reverse deltay sign
  mov bh,4bh                    ;and decrement bx instead of  incrementing bx
deltay_ok:
  mov si,dx                     ;deltay and
  or si,cx                      ;deltax = 0 ?
  jne ok
  add sp,6                      ;then ax, bx and bp from stack and end
  ret
ok:
  mov w cs:dist_pos,bx          ;write dec/inc ax/bx to destination
  cmp cx,dx                     ;deltax >= deltay ?
  jge deltax_great
  xchg cx,dx                    ;no, then exchange deltax and deltay
  mov bl,90h                    ;and increment ax noppen
  jmp constants
deltax_great:
  mov bh,90h                    ;otherwise increment bx noppen
constants:
  mov w cs:dist_neg,bx          ;write dec/inc ax/bx to destination
  shl dx,1                      ;define add_2
  mov di,dx                     ;store in di
  sub dx,cx                     ;define start-dist
  mov bp,dx                     ;and store in bp
  mov si,bp                     ;define add_1
  sub si,cx                     ;and store in si
  mov ax,0a000h                 ;load VGA segment
  mov es,ax
  pop bx                        ;retrieve stored values for x0 and y0
  pop ax
loop_p:
  putpixel                      ;set pixel
  or bp,bp                      ;dist positive ?
  jns dist_pos
dist_neg:
  inc ax                        ;increment x (if necessary, self modification)
  inc bx                        ;increment y (if necessary, self modification)
  add bp,di                     ;update dist
  loop loop_p                   ;next pixel
  jmp finished                  ;finished
dist_pos:
  inc ax                        ;increment x (if necessary, self modification)
  inc bx                        ;increment y (if necessary, self modification)
  add bp,si                     ;update dist
  loop loop_p                   ;next pixel
finished:
  pop bp
  ret
bline endp
code ends
end
