; LSYSA.ASM: assembler support routines for optimized L-System code
; Nicholas Wilt, 11/13/91.
; Updated to work with integer/FP code, 7/93.

ifdef ??version
   masm51
   quirks
endif

.MODEL	MEDIUM,C

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

EXTRN	overflow:WORD
EXTRN	boxy:DWORD

sins	equ	boxy
coss	equ	boxy + 200	; 50 * 4 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	lsysi_doplus

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

	PUBLIC	lsysi_dominus

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

	PUBLIC	lsysi_doplus_pow2

lsysi_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
lsysi_doplus_pow2	ENDP

	PUBLIC	lsysi_dominus_pow2

lsysi_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
lsysi_dominus_pow2	 ENDP

	PUBLIC	lsysi_dopipe_pow2

lsysi_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
lsysi_dopipe_pow2	ENDP

	PUBLIC	lsysi_dobang

lsysi_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
lsysi_dobang	ENDP

; Some 386-specific leaf functions go here.

.386

	PUBLIC	lsysi_doslash_386

lsysi_doslash_386	PROC	lsyscmd:ptr
	mov	bx,lsyscmd	; Get pointer
	mov	eax,[bx.num]
	cmp	[bx.reverse],0
	jnz	DoSlashDec
	add	[bx.realangle],eax
	ret
DoSlashDec:
	sub	[bx.realangle],eax
	ret
lsysi_doslash_386	ENDP

	PUBLIC	lsysi_dobslash_386

lsysi_dobslash_386	 PROC	 lsyscmd:ptr
	mov	bx,lsyscmd	; Get pointer
	mov	eax,[bx.num]
	cmp	[bx.reverse],0
	jz	DoBSlashDec
	add	[bx.realangle],eax
	ret
DoBSlashDec:
	sub	[bx.realangle],eax
	ret
lsysi_dobslash_386	 ENDP

	PUBLIC	lsysi_doat_386

lsysi_doat_386	PROC	lsyscmd:ptr,N:DWORD
	mov	bx,lsyscmd	; Get pointer
	mov	eax,[bx.ssize]	; Get size
	imul	[bx.num]	; Mul by n
	shrd	eax,edx,19
	mov	[bx.ssize],eax	; Save back
	ret
lsysi_doat_386	ENDP

	PUBLIC	lsysi_dosizegf_386

lsysi_dosizegf_386	PROC	USES SI,lsyscmd:ptr
	mov	si,lsyscmd	;
	mov	ecx,[si.ssize]	; Get size; we'll need it twice
   movzx ebx,[si.angle]
ifndef ??version
	mov	eax,coss[ebx*4]	; eax <- coss[angle]
else
   ; TASM-only (this is slower but it should work)
   shl   bx,2
   add   bx,offset DGROUP:coss
	mov	eax,[ebx]	; eax <- coss[angle]
endif
	imul	ecx		; Mul by size
	shrd	eax,edx,29	; eax <- multiply(size, coss[angle], 29)
	add	eax,[si.xpos]	;
	jno	nooverfl	;   check for overflow
	mov	overflow,1	;    oops - flag the user later
nooverfl:
	cmp	eax,[si.xmax]	; If xpos <= [si.xmax,
	jle	GF1		;   jump
	mov	[si.xmax],eax	;
GF1:	cmp	eax,[si.xmin]	; If xpos >= [si.xmin
	jge	GF2		;   jump
	mov	[si.xmin],eax	;
GF2:	mov	[si.xpos],eax	; Save xpos
ifndef ??version
	mov	eax,sins[ebx*4]	; eax <- sins[angle]
else     ; sins table is 200 bytes before coss
	mov	eax,[ebx-200]	; eax <- sins[angle]
endif
	imul	ecx		;
	shrd	eax,edx,29	;
	add	eax,[si.ypos]	;
	cmp	eax,[si.ymax]	; If ypos <= [si.ymax,
	jle	GF3		;   jump
	mov	[si.ymax],eax	;
GF3:	cmp	eax,[si.ymin]	; If ypos >= [si.ymin
	jge	GF4		;   jump
	mov	[si.ymin],eax	;
GF4:	mov	[si.ypos],eax	;
	ret
lsysi_dosizegf_386	ENDP

	PUBLIC	lsysi_dodrawg_386

lsysi_dodrawg_386	PROC	USES SI,lsyscmd:ptr
	mov	si,lsyscmd	; Get pointer to structure
	mov	ecx,[si.ssize]	; Because we need it twice
   movzx ebx,[si.angle]
ifndef ??version
	mov	eax,coss[ebx*4]	; eax <- coss[angle]
else
   ; TASM-only (this is slow but it should work)
   shl   bx,2
   add   bx,offset DGROUP:coss
	mov	eax,[ebx]	; eax <- coss[angle]
endif
	imul	ecx		;
	shrd	eax,edx,29	;
	add	[si.xpos],eax	; xpos += size*coss[angle] >> 29
ifndef ??version
	mov	eax,sins[ebx*4]	; eax <- sins[angle]
else     ; sins table is 200 bytes before coss
	mov	eax,[ebx-200]	; eax <- sins[angle]
endif
	imul	ecx		; ypos += size*sins[angle] >> 29
	shrd	eax,edx,29	;
	add	[si.ypos],eax	;
	ret			;
lsysi_dodrawg_386	ENDP

	END
