{$N+,A+,G+,F+,D-,E-,L-,R-,S-,Q-,Y-,I-}

unit line;

interface
procedure line0(x1,y1,x2,y2:word; c:byte; where:word);
procedure DrawLine(ax,ay,  bx,by:longint; col:byte; where:word);



implementation

uses math2;

const
min_X=0; max_X=319;
min_Y=0; max_Y=199;

procedure line0(x1,y1,x2,y2:word; c:byte; where:word); assembler;
asm
 mov es, where
 mov al, c
 mov dx, y2
 mov cx, x2
 mov bx, y1
 mov di, x1
 mov si, 320

{ Calc dX }
 sub cx,di; jz @vertical; ja @l1
 add di,cx; neg cx; xchg dx,bx
@l1:

{ Calc dY }
 sub dx,bx; jz @horizontal; ja @l2
 neg dx; neg si
@l2:

{ Calc address }
 xchg bh,bl; add di,bx; shr bx,2; add di,bx

{ Determine slope }
 cmp cx,dx; je @diagonal; mov ax,0; mov bx,8000h; jb @high_slope

@low_slope: { |dX| > |dY| > 0 }
 div cx; xchg dx,ax; mov al,c
@ls1:
 mov es:[di],al; add bx,dx; jc @ls3
@ls2:
 inc di; dec cx; jz @last
 mov es:[di],al; add bx,dx; jnc @ls2
@ls3:
 adc di,si; dec cx; jnz @ls1; jmp @last

@high_slope: { 0 < |dX| < |dY| }
 xchg cx,dx; div cx; xchg dx,ax; inc cx; mov al,c
 shr cx,1; jnc @hs2
@hs1:
 mov es:[di],al; add bx,dx; adc di,si
@hs2:
 mov es:[di],al; add bx,dx; adc di,si
 dec cx; jnz @hs1; jmp @last

@vertical: { |dX| = 0 }
 sub dx,bx; jnb @v1
 add bx,dx; neg dx
@v1:
 xchg bh,bl; add di,bx; shr bx,2; add di,bx; inc dx
@v2:
 mov es:[di],al; add di,si; dec dx; jnz @v2; jmp @end

@horizontal: { |dY| = 0 }
 inc cx; xchg bh,bl; add di,bx; shr bx,2; add di,bx
 test di,1; jz @h1
 stosb; dec cx
@h1:
 mov ah,al; shr cx,1; rep stosw; jnc @end; jmp @last

@diagonal: { |dX| = |dY| }
 inc si
@d1:
 mov es:[di],al; add di,si; dec cx; jnz @d1

@last:
 mov es:[di],al

@end:
end;


{line with clipping}
procedure DrawLine(ax,ay,  bx,by:longint; col:byte; where:word);
var
temp, delta:longint;
begin

if ((ax<Min_x) and (bx<Min_x)) or
   ((ax>Max_x) and (bx>Max_x)) or
   ((ay<Min_y) and (by<Min_y)) or
   ((ay>Max_y) and (by>Max_y)) then exit;

if (ax>bx) then begin temp:=ay; ay:=by; by:=temp; temp:=ax; ax:=bx; bx:=temp; end;

if ax<Min_X then begin
       delta := shl_(AY-BY, 8) div (AX-BX);
       ay:=(AY - sar_(delta*(AX-Min_X) ,8));
       ax:=Min_X;
       end;
if bx>Max_X then begin
       delta := shl_(AY-BY, 8) div (BX-AX);
       by:=(BY + sar_(delta*(BX-Max_X) ,8));
       bx:=Max_X;
       end;

if   ((ay<Min_y) and (by<Min_y)) or ((ay>Max_y) and (by>Max_y)) then exit;

if (ay>by) then begin temp:=ay; ay:=by; by:=temp; temp:=ax; ax:=bx; bx:=temp; end;

if ay<Min_y then begin
       delta := shl_(AX-BX, 8) div (AY-BY);
       ax:=(AX - sar_(delta*(AY-Min_Y) ,8));
       ay:=Min_Y;
       end;
if by>Max_Y then begin
       delta := shl_(AX-BX, 8) div (BY-AY);
       bx:=(BX + sar_(delta*(BY-Max_Y) ,8));
       by:=Max_Y;
       end;

Line0(ax,ay, bx,by, col, where);

end;


end.