;	'LINE' command for native-mode
;	run386 line
	.386p			;386ネイティブモード

CODE	segment
	assume	cs:CODE

screen	macro	page,md		;TBIOSを呼び出してscreenを
	mov	ax,0100h+page	;設定するマクロ
	mov	dx,md
	call	pword ptr fs:[20h] ;グラフィックBIOSを呼ぶ
	endm

baibai	macro	x,y		;TBIOSを呼び出してドットの
	mov	ax,0202h	;大きさを設定するマクロ
	mov	dx,x
	mov	bx,y
	call	pword ptr fs:[20h]
	endm

view	macro	x,y		;TBIOSを呼び出して表示する
	mov	ax,0203h	;画面の大きさを設定する
	mov	dx,x		;マクロ
	mov	bx,y
	call	pword ptr fs:[20h]
	endm

LOOP_CNT	equ 128

MAIN	proc			;デモプログラム部分

TBIOS	equ	110h	      ;TBIOSのセレクタ（実行用）
TBIOSw	equ	118h	      ;TBIOSのセレクタ（書き込み可）

	sub	esp,1600      ; スタック上にワ−ク領域を確保

	mov	al,5
	push	Dword ptr TBIOSw
	pop	fs
	mov	fs:[10h],al	; TBIOS[10h] <- screen-mode
	push	Dword ptr TBIOS
	pop	fs
	push	ss
	pop	gs
	mov	edi,esp		; gs:edi <- ss:[esp]
	mov	ah,00h		; 画面初期化
	mov	ecx,1536
	call	pword ptr fs:[20h]	; call tbios
	mov	ax,0500h	; 書き込みペ−ジの指定
	call	pword ptr fs:[20h]
	mov	ax,0601h	; 表示ペ−ジの指定
	mov	edx,3
call	pword ptr fs:[20h]

	screen	1,3	; page 1 = screen 3
	screen	0,5	; page 0 = screen 5
set256:	baibai	2,2
	view	256,256

	add	esp,1600

	mov	eax,0			;初期化
	mov	edi,offset LINE_BUF
	cld
	mov	ecx,loop_cnt
	rep stosd
	mov	edx,0
	mov	edi,0
	mov	esi,1

MAIN1:
	push	edx

	mov	ax,word ptr ds:[DX1]  ;ｘ１を移動させる
	add	word ptr ds:[X1],ax   ;画面の範囲を越えたら
	cmp	word ptr ds:[X1],0    ;反射するようにする
	jge	M1
	mov	word ptr ds:[X1],0
	neg	word ptr ds:[DX1]
	jmp	M2

M1:	cmp	word ptr ds:[X1],255
	jle	M2
	mov	word ptr ds:[X1],255
	neg	word ptr ds:[DX1]

M2:					;ｘ２を移動させる	
	mov	ax,word ptr ds:[DX2]	;ｘ１と同じ
	add	word ptr ds:[X2],ax
	cmp	word ptr ds:[X2],0
	jge	M3
	mov	word ptr ds:[X2],0
	neg	word ptr ds:[DX2]
	jmp	M4

M3:	cmp	word ptr ds:[X2],255
	jle	M4
	mov	word ptr ds:[X2],255
	neg	word ptr ds:[DX2]

M4:					;ｙ１を移動させる
	mov	ax,word ptr ds:[DY1]	;ｘ１と同じ
	add	word ptr ds:[Y1],ax
	cmp	word ptr ds:[Y1],0
	jge	M5
	mov	word ptr ds:[Y1],0
	neg	word ptr ds:[DY1]
	jmp	M6

M5:	cmp	word ptr ds:[Y1],255
	jle	M6
	mov	word ptr ds:[Y1],255
	neg	word ptr ds:[DY1]

M6:					;ｙ２を移動させる
	mov	ax,word ptr ds:[DY2]	;ｘ１と同じ
	add	word ptr ds:[Y2],ax
	cmp	word ptr ds:[Y2],0
	jge	M7
	mov	word ptr ds:[Y2],0
	neg	word ptr ds:[DY2]
	jmp	M8

M7:	cmp	word ptr ds:[Y2],255
	jle	M8
	mov	word ptr ds:[Y2],255
	neg	word ptr ds:[DY2]

M8:		;ラインルーチンに渡す引き数をスタックに積む
	mov	eax,0			;ページは０
	push	eax

	push	edx			;表示色

	mov	ax,word ptr ds:[Y2]	;ｙ２
	push	eax
	mov	cl,al

	mov	ax,word ptr ds:[X2]	;ｘ２
	push	eax
	mov	ch,al

	mov	ax,word ptr ds:[Y1]	;ｙ１
	push	eax
	mov	bl,al

	mov	ax,word ptr ds:[X1]	;ｘ１
	push	eax
	mov	bh,al

	mov	ax,dx

	mov	WORD PTR ds:[edi*4+LINE_BUF],bx	
	mov	WORD PTR ds:[edi*4+LINE_BUF+2],cx
	inc	edi		;この線をとっておく
	cmp	edi,LOOP_CNT
	jb	M9
	mov	edi,0
M9:
	call	line		;ラインルーチンを呼ぶ

	add	esp,24		;スタックレベルを戻す

	mov	bx,WORD PTR ds:[esi*4+LINE_BUF]
	mov	cx,WORD PTR ds:[esi*4+LINE_BUF+2]
		;バッファから128本前のデータをとってくる

	mov	eax,0	;引き数をセット
	push	eax

	push	DWORD PTR 0	;色を黒にして消す

	movzx	ax,cl
	push	eax

	movzx	ax,ch
	push	eax

	movzx	ax,bl
	push	eax

	movzx	ax,bh
	push	eax

	inc	esi
	cmp	esi,LOOP_CNT
	jb	M10
	mov	esi,0
M10:
	call	line		;ラインルーチンを呼ぶ

	add	esp,24
	pop	edx
	add	edx,1
	cmp	edx,7fffh
	jb	MAIN1

	mov	ah,4Ch
	int	21h
MAIN	endp

;	ラインルーチン本体

;void line(int x1,int y1,int x2,int y2,int col,int page);
;	for 256*512*32K colors (GRAPHIC MODE 5) only

	public	line	;このへんはおまじないと思ってください
	db	'line',4	;for stackdump
line	proc
	push	ebp
	push	esi
	push	edi
	push	ebx

	mov	bp,ss:[esp+20+16]	;色を読み込む
	mov	edi,ss:[esp+20+20]	;ページを読み込む
	shl	edi,9
	mov	bh,ss:[esp+20+0]	;x1を読み込む
	mov	bl,ss:[esp+20+4]	;y1　　〃
	mov	ch,ss:[esp+20+8]	;x2　　〃
	mov	cl,ss:[esp+20+12]	;y2　　〃
	mov	dh,bl
	mov	dl,bh
	movzx	edx,dx
	lea	esi,[edi+edx*2]		;(x1,y1)のアドレス
					;を求める
	push	ds		;dsをVRAMのセレクタに
	mov	dx,120h		;にする
	mov	ds,dx

	mov	edx,2		;edxが横方向の増加量
	sub	ch,bh
	jnb	short #liney	;ｘが増える方向に線を引く？
	neg	edx	;減る方向だとedxをマイナスにする
	neg	ch
#liney:	mov	edi,512		;ediが縦方向の増加量
	sub	cl,bl
	jnb	short #liner	;ｙが増える方向に線を引く？
	neg	edi	;減る方向だとediをマイナスにする
	neg	cl

#liner:	cmp	ch,cl		;ｘとｙのどちらの変化量が
	je	short #lines	;大きいか調べて，chが
	ja	short #lineg	;大きいようにする
	xchg	ch,cl		;同じ時はlinesに飛ぶ
	xchg	edi,edx		;縦横の変化量も取り替える

#lineg:	mov	ah,cl		;割り算をして，
	mov	al,0		;傾きを求める。
	div	ch
	mov	ah,128

        movzx   cx,ch           ;ループカウンタに
        movzx   ecx,cx          ;横方向のドット数を
        inc     cx              ;いれる。

	align	4
#lineg1:
	mov	ds:[esi],bp	;１ドット点をかく
	add	esi,edx		;横に座標を動かす
	add	ah,al		;傾きを足す
	jnb	short #lineg2	;あふれたら縦に
	add	esi,edi		;点を動かす
#lineg2:
	loop	#lineg1		;ループ
	jmp	#exit

	align 4
#lines: movzx   cx,ch           ;ループカウンタに
        movzx   ecx,cx          ;横方向のドット数を
        inc     cx              ;いれる

	align	4
#lines1:			;傾きが１のときの
	mov	ds:[esi],bp	;ルーチン
	add	esi,edx		;縦横に１回ずつ
	add	esi,edi		;動かしてドットをかく
	loop	#lines1

#exit:
	pop	ds		;スタックを元に
	pop	ebx		;戻す
	pop	edi
	pop	esi
	pop	ebp
	ret

line	endp

CODE	ends

DATA	segment
	assume	ds:DATA

X1	dw	38	;メインプログラムで使っているワーク
Y1	dw	56
X2	dw	34
Y2	dw	100
DX1	dw	1
DY1	dw	2
DX2	dw	3
DY2	dw	4

LINE_BUF dd	128 dup(0) ;128本分のバッファを用意している

DATA	ends

STACK	segment stack
	assume	ss:STACK
	db	2000 dup(?)
STACK	ends

	end	MAIN
