; LSYSAF.ASM: assembler support routines for optimized L-System code
; (floating-point version)
; Nicholas Wilt, 7/93.

.MODEL	MEDIUM,C

lsys_turtlestatef   STRUC   
counter             DB      ?
angle               DB      ?
reverse             DB      ?
stackoflow          DB      ?
maxangle            DB      ?
dmaxangle           DB      ?
curcolor            DB      ?
dummy               DB      ?
ssize               DT      ?
realangle           DT      ?
xpos                DT      ?
ypos                DT      ?
xmin                DT      ?
ymin                DT      ?
xmax                DT      ?
ymax                DT      ?
aspect              DT      ?
num		    DD      ?
lsys_turtlestatef   ENDS

EXTRN	overflow:WORD
EXTRN	draw_line:FAR
EXTRN	FPUsincos:FAR
EXTRN	cpu:WORD

EXTRN	boxy:TBYTE

sins_f	equ	boxy
coss_f	equ	boxy + 500	; 50 * 10 bytes

.CODE

DECANGLE MACRO
	LOCAL	@1
	dec	al
	jge	@1
	mov	al,[bx.dmaxangle]
@1:	mov	[bx.angle],al
	ENDM

INCANGLE MACRO
	LOCAL	@1
	inc	al
	cmp	al,[bx.maxangle]
	jne	@1
	xor	ax,ax
@1:	mov	[bx.angle],al
	ENDM

	PUBLIC	lsysf_doplus

lsysf_doplus	PROC	lsyscmd:ptr
	mov	bx,lsyscmd
	mov	al,[bx.angle]
	cmp	[bx.reverse],0
	jnz	PlusIncAngle
	DECANGLE
	ret
PlusIncAngle:
	INCANGLE
	ret
lsysf_doplus	ENDP

	PUBLIC	lsysf_dominus

lsysf_dominus	PROC	lsyscmd:ptr
	mov	bx,lsyscmd	; Get pointer
	mov	al,[bx.angle]
	cmp	[bx.reverse],0
	jnz	MinusDecAngle
	INCANGLE
	ret
MinusDecAngle:
	DECANGLE
	ret
lsysf_dominus	ENDP

	PUBLIC	lsysf_doplus_pow2

lsysf_doplus_pow2	PROC	lsyscmd:ptr
	mov	bx,lsyscmd	; Get pointer
	mov	al,[bx.angle]
	cmp	[bx.reverse],0
	jnz	Plus2IncAngle
	dec	al
	and	al,[bx.dmaxangle]
	mov	[bx.angle],al
	ret
Plus2IncAngle:
	inc	al
	and	al,[bx.dmaxangle]
	mov	[bx.angle],al
	ret
lsysf_doplus_pow2	ENDP

	PUBLIC	lsysf_dominus_pow2

lsysf_dominus_pow2	 PROC	lsyscmd:ptr
	mov	bx,lsyscmd	; Get pointer
	mov	al,[bx.angle]
	cmp	[bx.reverse],0
	jz	Minus2IncAngle
	dec	al
	and	al,[bx.dmaxangle]
	mov	[bx.angle],al
	ret
Minus2IncAngle:
	inc	al
	and	al,[bx.dmaxangle]
	mov	[bx.angle],al
	ret
lsysf_dominus_pow2	 ENDP

	PUBLIC	lsysf_dopipe_pow2

lsysf_dopipe_pow2	PROC	lsyscmd:ptr
	mov	bx,lsyscmd	; Get pointer
	xor	ax,ax
	mov	al,[bx.maxangle]
	shr	ax,1
	xor	dx,dx
	mov	dl,[bx.angle]
	add	ax,dx
	and	al,[bx.dmaxangle]
	mov	[bx.angle],al
	ret
lsysf_dopipe_pow2	ENDP

	PUBLIC	lsysf_dobang

lsysf_dobang	PROC	lsyscmd:ptr
	mov	bx,lsyscmd	; Get pointer
	mov	al,[bx.reverse]	; reverse = ! reverse;
	dec	al		; -1 if was 0; 0 if was 1
	neg	al		; 1 if was 0; 0 if was 1
	mov	[bx.reverse],al	;
	ret
lsysf_dobang	ENDP

	PUBLIC	lsysf_doat

lsysf_doat	PROC	lsyscmd:ptr
	mov	bx,lsyscmd	; Get pointer
	fld	tbyte ptr [bx.num] ; Get N.
				; FPU stk: N xpos ypos size aspect
	fmulp	st(3),st	; Multiply size by it.
	ret
lsysf_doat	ENDP

.386

LSYS_SINCOS	MACRO	OFFS
	LOCAL	UseSinCos, Done

	cmp	cpu,386		; If CPU >= 386, we can use fsincos.
	jge	UseSinCos	;

				; Otherwise we use FPUsincos.

	sub	sp,50+24	; Save enough room for entire state
				; plus parameter to sin or cos
	fstp	tbyte ptr [bp-OFFS-10] ; Save state
	fstp	tbyte ptr [bp-OFFS-20] ;
	fstp	tbyte ptr [bp-OFFS-30] ;
	fstp	tbyte ptr [bp-OFFS-40] ;
	fld	st		; realangle remains on FPU stack
	fstp	tbyte ptr [bp-OFFS-50] ;
	fstp	qword ptr [bp-OFFS-50-8] ; Store as parameter to FPUsincos

	lea	ax,[bp-OFFS-50-16]	; Push pointer to cosine
	push	ax		;
	lea	ax,[bp-OFFS-50-24]	; Push pointer to sine
	push	ax		;
	lea	ax,[bp-OFFS-50-8]	; Push pointer to parameter
	push	ax		;
	call	FPUsincos	; Call it.

	add	sp,6		; Restore stack

	fld	tbyte ptr [bp-OFFS-50] ; Restore state
	fld	tbyte ptr [bp-OFFS-40] ;
	fld	tbyte ptr [bp-OFFS-30] ;
	fld	tbyte ptr [bp-OFFS-20] ;
	fld	tbyte ptr [bp-OFFS-10] ;
	fld	qword ptr [bp-OFFS-50-24] ; Get sine
	fld	qword ptr [bp-OFFS-50-16] ; Get cosine

	add	sp,50+24	; Restore stack

	jmp	short Done	;
UseSinCos:
	fld	st(4)		; Get angle
	fsincos			; c s xpos ypos size aspect realangle
Done:
	ENDM

	PUBLIC	lsysf_dosizedm

lsysf_dosizedm	PROC	lsyscmd:ptr
	LSYS_SINCOS 0		; Get sine and cosine of angle.
	mov	bx,lsyscmd	; Get pointer to structure
	fmul	st,st(5)	; c*aspect s xpos ypos size aspect
	fmul	st,st(4)	; c*size*aspect s xpos ypos size aspect
	faddp	st(2),st	; s xpos ypos size aspect
	fmul	st,st(3)	; s*size xpos ypos size aspect
	faddp	st(2),st	; xpos ypos size aspect

	push	ax		; Allocate a local for FP status word

	fld	[bx.xmin]	; Compare xpos to xmin
	fcomp			;
	fstsw	[bp-2]		; Store status word
	mov	ax,[bp-2]	;
	sahf			;
	jb	SizeDM1		; Jump if ST > xmin
	fld	st		;
	fstp	[bx.xmin]	;
	jmp	short SizeDM2	;
SizeDM1:
	fld	[bx.xmax]	; Compare to xmax
	fcomp			;
	fstsw	[bp-2]		; Store status word
	mov	ax,[bp-2]	;
	sahf			;
	ja	SizeDM2		; Jump if ST < xmax
	fld	st		;
	fstp	[bx.xmax]	;
SizeDM2:
	fxch			; Swap xpos and ypos
	fld	[bx.ymin]	; Compare ypos to ymin
	fcomp			;
	fstsw	[bp-2]		; Store status word
	mov	ax,[bp-2]	;
	sahf			;
	jb	SizeDM3		; Jump if ST > ymin
	fld	st		;
	fstp	[bx.ymin]	;
	jmp	short SizeDM4	;
SizeDM3:
	fld	[bx.ymax]	; Compare ypos to ymax
	fcomp			;
	fstsw	[bp-2]		;
	mov	ax,[bp-2]	;
	sahf			;
	ja	SizeDM4		;
	fld	st		;
	fstp	[bx.ymax]	;
SizeDM4:
	fxch			; Swap xpos and ypos back
	pop	ax		; Deallocate local for FPU status word

	ret			; Done.
lsysf_dosizedm	ENDP

	PUBLIC	lsysf_dosizegf

lsysf_dosizegf	PROC	USES SI,lsyscmd:ptr
	mov	si,lsyscmd	;
	xor	bx,bx		; BX <- angle * sizeof(long double)
	mov	bl,[si.angle]	;
	shl	bx,1		;
	mov	ax,bx		;
	shl	ax,1		;
	shl	ax,1		;
	add	bx,ax		;
	fld	st(2)		; size xpos ypos size aspect
	fld	coss_f[bx]	; size*cmd->coss[cmd->angle]
	fmul			;
	faddp	st(1),st	; xpos ypos size aspect
	fld	st(2)		; size xpos ypos size aspect
	fld	sins_f[bx]	; size*cmd->sins[cmd->angle]
	fmul			;
	faddp	st(2),st	; xpos ypos size aspect

	push	ax		; Allocate a local for FPU status word

	fld	[si.xmin]	; Compare xpos to xmin
	fcomp			;
	fstsw	[bp-4]		; Store status word
	mov	ax,[bp-4]	;
	sahf			;
	jb	SizeGF1		; Jump if ST > xmin
	fld	st		;
	fstp	[si.xmin]	;
	jmp	short SizeGF2	;
SizeGF1:
	fld	[si.xmax]	; Compare to xmax
	fcomp			;
	fstsw	[bp-4]		; Store status word
	mov	ax,[bp-4]	;
	sahf			;
	ja	SizeGF2		; Jump if ST < xmax
	fld	st		;
	fstp	[si.xmax]	;
SizeGF2:
	fxch			; Swap xpos and ypos
	fld	[si.ymin]	; Compare ypos to ymin
	fcomp			;
	fstsw	[bp-4]		; Store status word
	mov	ax,[bp-4]	;
	sahf			;
	jb	SizeGF3		; Jump if ST > ymin
	fld	st		;
	fstp	[si.ymin]	;
	jmp	short SizeGF4	;
SizeGF3:
	fld	[si.ymax]	; Compare ypos to ymax
	fcomp			;
	fstsw	[bp-4]		;
	mov	ax,[bp-4]	;
	sahf			;
	ja	SizeGF4		;
	fld	st		;
	fstp	[si.ymax]	;
SizeGF4:
	fxch			; Swap xpos and ypos back
	pop	ax		; Deallocate local for FPU status word
	ret
lsysf_dosizegf	ENDP

	PUBLIC	lsysf_dodrawg

lsysf_dodrawg	PROC	USES SI,lsyscmd:ptr
	mov	si,lsyscmd	; Get pointer to structure
	xor	bx,bx		; Get angle offset
	mov	bl,[si.angle]	;
	mov	al,10		;
	mul	bl		;
	xchg	ax,bx		;
	fld	coss_f[bx]	; xpos += cmd->size * cmd->coss[cmd->angle]
	fmul	st,st(3)	; 
	fadd			;
	fld	sins_f[bx]	; ypos += cmd->size * cmd->sins[cmd->angle]
	fmul	st,st(3)	;
	faddp	st(2),st	;
	ret			;
lsysf_dodrawg	ENDP

	PUBLIC	lsysf_dodrawd

lsysf_dodrawd	PROC	lsyscmd:PTR
	mov	bx,lsyscmd	; Get pointer to structure
	xor	ax,ax		; Push last parm to draw_line
	mov	al,[bx.curcolor]
	push	ax		;
	sub	sp,8		; Allocate the rest of draw_line's parms
	fist	word ptr [bp-10] ; Store xpos
	fxch			; Store ypos
	fist	word ptr [bp-8] ;
	fxch			;

	LSYS_SINCOS 10		; c s xpos ypos size aspect

	fmul	st,st(5)	; c*aspect s xpos ypos size aspect
	fmul	st,st(4)	; size*c*aspect s xpos ypos size aspect
	faddp	st(2),st	; s xpos ypos size aspect
	fmul	st,st(3)	; s*size xpos ypos size aspect
	faddp	st(2),st	; xpos ypos size aspect

	fist	word ptr [bp-6]	; Store xpos
	fxch			; Store ypos
	fist	word ptr [bp-4]	;
	fxch			;

	call	far ptr draw_line	;
	add	sp,10		; Remove parameters
	ret			;
lsysf_dodrawd	ENDP

	PUBLIC	lsysf_dodrawm

lsysf_dodrawm	PROC	lsyscmd:ptr
	LSYS_SINCOS 0		;
	fmul	st,st(5)	; c*aspect s xpos ypos size aspect
	fmul	st,st(4)	; size*c*aspect s xpos ypos size aspect
	faddp	st(2),st	; s xpos ypos size aspect
	fmul	st,st(3)	; s*size xpos ypos size aspect
	faddp	st(2),st	; xpos ypos size aspect
	ret			;
lsysf_dodrawm	ENDP

	PUBLIC	lsysf_dodrawf

lsysf_dodrawf	PROC	USES SI, lsyscmd:ptr
	mov	si,lsyscmd		; Get pointer to structure
	xor	ax,ax			; Push curcolor for draw_line
	mov	al,[si.curcolor]	;
	push	ax			;
	sub	sp,8			; Allocate the rest of the draw_line call
	fist	word ptr [bp-12]	; Store xpos in draw_line parms
	fxch				; Store ypos in draw_line parms
	fist	word ptr [bp-10]	;
	fxch				;

	xor	bx,bx			; BX <- offset into cos/sin arrays
	mov	bl,[si.angle]		;
	mov	al,10			;
	mul	bl			;
	xchg	ax,bx			;

	fld	st(2)		; xpos += size*cmd->coss[cmd->angle]
	fld	coss_f[bx]	;
	fmul
	fadd			;
	fist	word ptr [bp-8] ; Store new xpos in draw_line parms

	fld	st(2)		; ypos += size*cmd->sins[cmd->angle]
	fld	sins_f[bx]	;
	fmul			;
	faddp	st(2),st	;
	fxch			; Store new ypos in draw_line parms
	fist	word ptr [bp-6]	;
	fxch			;
	call	far ptr draw_line	; Call the line-drawing routine
	add	sp,10		; Deallocate the stuff we pushed
	ret			;
lsysf_dodrawf	ENDP

	PUBLIC	lsysf_doslash

lsysf_doslash	PROC	lsyscmd:ptr
	mov	bx,lsyscmd	; Get pointer
	fld	tbyte ptr [bx.num]
	cmp	[bx.reverse],0
	jnz	DoSlashDec
	faddp	st(5),st
	ret
DoSlashDec:
	fsubp	st(5),st
	ret
lsysf_doslash	ENDP

	PUBLIC	lsysf_dobslash

lsysf_dobslash	 PROC	 lsyscmd:ptr
	mov	bx,lsyscmd	; Get pointer
	fld	tbyte ptr [bx.num]
	cmp	[bx.reverse],0
	jz	DoBSlashDec
	faddp	st(5),st
	ret
DoBSlashDec:
	fsubp	st(5),st
	ret
lsysf_dobslash	 ENDP

	PUBLIC	lsys_prepfpu

lsys_prepfpu	PROC	lsyscmd:ptr
	mov	bx,lsyscmd	; Get pointer to structure
	fld	[bx.realangle]	; Load: xpos ypos size aspect realangle
	fld	[bx.aspect]	;
	fld	[bx.ssize]	;
	fld	[bx.ypos]	;
	fld	[bx.xpos]	;
	ret			; Return.
lsys_prepfpu	ENDP

	PUBLIC	lsys_donefpu

lsys_donefpu	PROC	lsyscmd:ptr
	mov	bx,lsyscmd	; Get pointer to structure
	fstp	[bx.xpos]	; Save: xpos ypos size aspect realangle
	fstp	[bx.ypos]	;
	fstp	[bx.ssize]	;
	fstp	[bx.aspect]	;
	fstp	[bx.realangle]	;
	ret
lsys_donefpu	ENDP

	END

