; this code intended to generate any missing normals 
; it works a bit slowly, because it runs on 68000
; but it won't be run very often !

Normal_generate::
	movem.l	d0-d7/a0-a3,-(sp)

	movea.l	#StrtW,a0	; get address of 3d object data blocks

.lop:	tst.w	(a0)		; check for end of list marker (-1)
	bmi.b	.exit
	move.l	4(a0),d0	; get pointer to point data (required if going to work out normals)
	beq.b	.next

	move.l	d0,a1		; put pointer to point data in useful register
	move.l	12(a0),a2	; get normal pointer
	move.l	16(a0),a3	; get face pointer
	addq.l	#4,a1		; skip point count

	bsr	check_normals

.next:	lea	20(a0),a0
	bra.b	.lop

.exit:	movem.l	(sp)+,d0-d7/a0-a3
	move.w	#$4e75,Normal_generate	; self disablement
	rts

;==============================================================
; note the modular nature here Dennis - I'm learning.
;==============================================================
; routine to run through all current normals, and fill in any which are zeros

check_normals::	

	move.l	(a2)+,d0	; get normals count
	moveq.l	#0,d1		; use for counter

.lop:	tst.w	(a2)		; check first axis part
	bne.b	.next
	tst.w	2(a2)		; check 2nd axis part
	bne.b	.next
	tst.w	4(a2)		; check 3rd axis part
	bne.b	.next

	bsr	missing_normal

.next:	addq.l	#1,d1
	lea	6(a2),a2		; point at next normal
	cmp.l	d1,d0

	bne.b	.lop

	rts

;==============================================================
; routine to find a polygon with the missing normal in use, and then pass the
; necessary data to normal generator which will write it back in place (at a2)

missing_normal::
	movem.l	d0-d1/d3/a3,-(sp)	

	move.w	#$8000,d3
	move.w	d1,d0
	asl.w	d1
	add.w	d0,d1		; mult by 3
	asl.w	#2,d1		; mult by 12 altogether

	move.l	(a3)+,d0	; get face count
	bra.b	.dbx

.lop:	move.w	(a3)+,d2	; get point count to allow quick jump over
	bpl.b	.f1
	cmp.w	d2,d3		; test for bsp_end code
	beq	.lop		; if so simply go round again
	addq.l	#6,a3		; otherwise skip normal,point,address
	bra	.lop

.f1:	addq.l	#4,a3		; skip colour code
	cmp.w	(a3)+,d1	; test for correct normal number
	bne.b	.not

	bsr	generate

.not:	asl.w	#1,d2		; skip quantity
	add.w	d2,a3		; move address along

.dbx:	dbra	d0,.lop

	movem.l	(sp)+,d0-d1/d3/a3
	rts

;================================================================
; routine to generate a normal and write it into (a2) where it is missing

generate::
	movem.l	d0-d2/a2/a3,-(sp)

	move.w	(a3)+,d0	; get a vertex number
	move.w	d0,d1
	asl.w	d0
	add.w	d1,d0		; mult by 3
	asl.w	#2,d0		; mult by 12 altogether

	move.l	(a1,d0.w),d1	; get x1
	move.l	4(a1,d0.w),d2
	move.l	8(a1,d0.w),d3

	move.l	d1,d4
	move.l	d2,d5
	move.l	d3,d6

	move.w	(a3)+,d0	; get next vertex number
	move.w	d0,d7
	asl.w	d0
	add.w	d7,d0		; mult by 3
	asl.w	#2,d0		; mult by 12 altogether

	sub.l	(a1,d0.w),d1	; give x1-x2 etc
	sub.l	4(a1,d0.w),d2
	sub.l	8(a1,d0.w),d3

	move.w	(a3)+,d0	; get next vertex number
	move.w	d0,d7
	asl.w	d0
	add.w	d7,d0		; mult by 3
	asl.w	#2,d0		; mult by 12 altogether

	sub.l	(a1,d0.w),d4	; give x1-x3 etc
	sub.l	4(a1,d0.w),d5
	sub.l	8(a1,d0.w),d6

	move.l	d2,d0		; = v2
	muls	d6,d0		; = v2 * w3
	move.l	d3,d7		; = v3
	muls	d5,d7		; = v3 * w2
	sub.l	d7,d0		; = n0

	exg.l	d3,d0		; store n0 in v3 (d3) for now
	muls	d4,d0		; = v3 * w1
	move.l	d1,d7		; = v1
	muls	d6,d7		; = v1 * w3
	sub.l	d7,d0

	exg.l	d0,d1		; store n1 in v1 (d1) for now
	muls	d5,d0		; = v1 * w2
	move.l	d2,d7		; = v2
	muls	d4,d7		; = v2 * w1
	sub.l	d7,d0

	move.l	d0,d2		; store n2 in v2 (d2) for now

	bsr	bit16		; trim d1,d2,d3 to 16 bits with equalised scaling

	move.l	d2,d0
	muls	d0,d0		; square n2
	move.l	d3,d7
	muls	d7,d7		; square n0
	add.l	d7,d0
	move.l	d1,d7
	muls	d7,d7		; square n1
	add.l	d7,d0

	bsr	quick_root
	bne.b	.ok
	illegal

.ok:	moveq.l	#14,d4
	asl.l	d4,d1
	asl.l	d4,d2
	asl.l	d4,d3

	divs	d0,d1
	divs	d0,d2
	divs	d0,d3

;	ext.l	d1
;	ext.l	d2
;	ext.l	d3

	move.w	d3,(a2)+	; note order - corrected
	move.w	d1,(a2)+	
	move.w	d2,(a2)+

	movem.l	(sp)+,d0-d2/a2/a3
	rts


;===========================================================
; routine to perform square root assuming that x will be in 16 bits

quick_root::
	movem.l	d1-d6,-(sp)
	tst.l	d0
	bpl.b	ok
	message	"Negative root attempted"
ok:	move.l	#$4000,d1	; root inc
	move.l	#$10000000,d2	; square inc
	moveq.l	#0,d3		; holds x as it is generated
	moveq.l	#0,d4		; holds x^2 as it is generated
	moveq.l	#15,d5		; shift count for generating 2xy

.lop:	move.l	d4,d7
	add.l	d2,d7		; apply square incs
	move.l	d3,d6		; =x
	asl.l	d5,d6		; =2xy
	add.l	d6,d7
	cmp.l	d7,d0		; check if proposed change is still small enough
	bmi.b	.not	

	add.l	d1,d3		; if it is, make the change
	move.l	d7,d4

.not:	lsr.l	#2,d2		; anyway, scale down all increments
	subq.l	#1,d5
	lsr.l	#1,d1
	bne.b	.lop

	move.l	d3,d0		; place x in for return
	movem.l	(sp)+,d1-d6
	rts

;===============================================================
; 16 bit scale down for oversized vectors in d1,d2,d3

bit16::
	movem.l	d1-d3,-(sp)
	tst.l	d1		; make d1 absolute
	bpl.b	.nn1
	neg.l	d1
.nn1:	tst.l	d2		; make d2 absolute
	bpl.b	.nn2
	neg.l	d2
.nn2:	tst.l	d3		; make d3 absolute
	bpl.b	.nn3
	neg.l	d3
.nn3:	cmp.l	d1,d2		; make d1 = d2 if d2 bigger
	bmi.b	.nb1
	move.l	d2,d1
.nb1:	cmp.l	d1,d3		; make d1 = d3 if d3 bigger
	bmi.b	.nb2
	move.l	d3,d1
.nb2:	moveq.l	#0,d0		; shift count
	move.l	#$6882,d2	; maximum size allowed - trick value to ensure triple square never overflows

.lp:	cmp.l	d1,d2
	bpl.b	.done
	addq.l	#1,d0
	asr.l	d1
	bra.b	.lp

.done:	movem.l	(sp)+,d1-d3
	asr.l	d0,d1
	asr.l	d0,d2
	asr.l	d0,d3

	rts
;=======================================
