*=======================================================*
*	BSP-Descent: latest update 27/11/95		*
*=======================================================*
*	Descend BSP tree, generating sectors & walls.	*
*=======================================================*
*     >	New 68030 replacement by Douglas Little.	*
*     >	Atari C conversion by Johan Klockars.		*
*     >	Original C++ code for the PC by Jake Hill.	*
*=======================================================*
*	Some improvements made to 68030 version:	*
*=======================================================*
*     >	Node-quadrant checks changed to octants.	*
*     >	Nodes projected & checked against viewcone. 	*
*     >	Nodes checked against wall occlusion list.	*
*     >	Program recursion removed & replaced by stack.	*
*     >	Optimised for latent-memory references.		*
*     >	Accuracy of 3D calculations improved (32 bit).	*
*     >	Local variables accessed from structure.	*
*     >	Temporary lighting effects just for fun.	*
*     >	Several 16-bit offset-addressing bug fixes.	*
*     >	Logic flow simplified around AddWall		*
*     >	Projection now peformed in realtime.		*
*=======================================================*

invisible_code	=	0
visible_code	=	1

*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	Descend Binary Space Partitioning Tree		*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
descend_bsp:
*-------------------------------------------------------*
*	Place start & terminator on heap and descend	*
*-------------------------------------------------------*
	move.l		sp,bsp_return
	lea		display_struct,a6
	push.w		#terminator
	push.w		maxnode
	bra		next_node
*-------------------------------------------------------*
*	Thread returns here when tree is exhausted	*
*-------------------------------------------------------*
finish_tree:
*-------------------------------------------------------*
	move.l		bsp_return,sp
	rts

*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	[node] = [sector] -> draw this node		*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
ssector_node:
*-------------------------------------------------------*
*	Stop drawing when [width] columns are filled	*
*-------------------------------------------------------*
	tst.w		columns
	beq.s		finish_tree
*-------------------------------------------------------*
*	Stop drawing when last node has been popped	*
*-------------------------------------------------------*
	not.w		d0
	beq.s		finish_tree
	eor.w		#$7FFF,d0

*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	Render ssector into run-buffer			*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
build_ssector:
*-------------------------------------------------------*
*	Locate [segs] for this [ssector]		*
*-------------------------------------------------------*
	move.l		display_ssectors(a6),a0
	moveq		#0,d4
	move.w		ssec_first(a0,d0.w*4),d4
	moveq		#0,d3
	move.w		ssec_segments(a0,d0.w*4),d3
*-------------------------------------------------------*
*	Locate [linedef] & [sidedef] for first [seg]	*
*-------------------------------------------------------*
	move.l		d4,d0
	move.l		display_segs(a6),a2
	add.l		d0,d0
	add.l		d4,d0
	lsl.l		#2,d0
	add.l		d0,a2				; a+(d*12)
	moveq		#0,d0
	move.w		seg_linedef(a2),d0
	moveq		#0,d2
	move.w		seg_sidedef(a2),d2
*-------------------------------------------------------*
*	Locate right [sidedef] for this [linedef]	*
*-------------------------------------------------------*
	move.l		d0,d1
	move.l		display_linedefs(a6),a0
	lsl.l		#3,d0
	sub.l		d1,d0
	add.l		d0,d0
	add.l		d0,a0				; a+(d*14)
	moveq		#0,d1
	move.w		linedef_right(a0,d2.w*2),d1 
*-------------------------------------------------------*
*	Locate [sector] for this [sidedef]		*
*-------------------------------------------------------*
	move.l		d1,d0 
	move.l		display_sidedefs(a6),a0
	lsl.l		#4,d0 
	sub.l		d1,d0				; a+(d*30)
	move.w		sidedef_sector(a0,d0.l*2),d1	
*-------------------------------------------------------*
*	Set up floor & ceiling heights for this sector	*
*-------------------------------------------------------*
	move.l		d1,d0
	add.l		d0,d0
	move.l		d0,d2
	lsl.l		#3,d0
	move.l		display_sectors(a6),a0
	sub.l		d2,d0
	sub.l		d1,d0				; a+(d*26)
	add.l		d0,d0
	add.l		d0,a0
	move.l		a0,this_sector
	move.w		sector_floorht(a0),floor_ht
	move.w		sector_ceilht(a0),ceiling_ht
*-------------------------------------------------------*
*	Are we in this sector?				*
*-------------------------------------------------------*
	tst.w		first_ssector
	beq.s		.skip
	clr.w		first_ssector
*-------------------------------------------------------*
*	Set viewcone to (sector_height+player_height)	*
*-------------------------------------------------------*
	move.w		floor_ht,d0
	add.w		#player_height,d0
	move.w		d0,Ph
*-------------------------------------------------------*
*	Set up segment-heap for loop			*
*-------------------------------------------------------*
.skip:	move.l		d4,d2
	move.w		d2,display_segbase(a6)
	move.w		d3,display_segnum(a6)
	ble		end_ssector
*-------------------------------------------------------*
*	Process simple lighting effects (temporary!)	*
*-------------------------------------------------------*
	ifd		lighting_effects
	bsr		process_lighting
	endc
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	Render segments surrounding this ssector	*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
segment_loop:
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	Hidden surface removal stage #1			*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	Is viewer on left or right side of this line?	*
*-------------------------------------------------------*
*	((y2-y1)*(Px-x1))) => (((x2-x1)*(Py-y1)) ?	*
*-------------------------------------------------------*
	move.l		display_vertices(a6),a0
	moveq		#0,d0
	moveq		#0,d1
	move.w		linedef_from(a2),d0
	move.w		linedef_to(a2),d1
	move.w		vtx_x(a0,d0.l*4),d5
	move.w		vtx_x(a0,d1.l*4),d6
	move.w		vtx_y(a0,d0.l*4),d0
	move.w		vtx_y(a0,d1.l*4),d1
	sub.w		d5,d6			; x2-x1
	sub.w		d0,d1			; y2-y1
	neg.w		d5
	add.w		display_px(a6),d5	; px-x1
	neg.w		d0
	add.w		display_py(a6),d0	; py-y1
	muls.w		d6,d0			; (x2-x1)*(Py-y1)
	muls.w		d5,d1			; (y2-y1)*(Px-x1)
	cmp.l		d0,d1
	bmi		invisible
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	Segment is visible				*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
	pea		(a2)
*-------------------------------------------------------*
	moveq		#0,d0
	move.w		display_segbase(a6),d0
	move.l		d0,d1
	move.l		display_segs(a6),a5
	add.l		d0,d0
	add.l		d1,d0
	lsl.l		#2,d0
	add.l		d0,a5			; a+(d*12)
*-------------------------------------------------------*
*	Locate segment vertices				*
*-------------------------------------------------------*
	move.l		display_vertices(a6),a0
	moveq		#0,d0
	move.w		seg_from(a5),d0
	move.l		a0,a1
	moveq		#0,d1
	move.w		seg_to(a5),d1 
	lsl.l		#2,d0
	lsl.l		#2,d1
	add.l		d0,a0			; a+(d*4)
	add.l		d1,a1			; a+(d*4)
*-------------------------------------------------------*
*	Fetch X1,Y1 / X2,Y2 & centre around viewpoint	*
*-------------------------------------------------------*
	move.w		display_px(a6),d1
	move.w		display_py(a6),d7
	move.w		vtx_x(a0),d4
	move.w		vtx_y(a0),d5
	move.w		vtx_x(a1),d6
	move.w		vtx_y(a1),d2
	sub.w		d1,d4		; dx1
	sub.w		d7,d5		; dy1
	sub.w		d1,d6		; dx2
	sub.w		d7,d2		; dy2
*-------------------------------------------------------*
*	Rotate X & Y into canonical VX & VZ		*
*-------------------------------------------------------*
	move.w		display_sina(a6),d0
	move.w		display_cosa(a6),d7
*-------------------------------------------------------*
*	x1 = (dx1)*sin(a) + (dy1)*cos(a)		*
*	z1 = (dx1)*cos(a) - (dy1)*sin(a)		*
*-------------------------------------------------------*
	move.w		d4,d3
	move.w		d5,d1
	muls.w		d7,d4
	muls.w		d0,d5
	muls.w		d0,d3
	muls.w		d7,d1
	sub.l		d5,d4
	add.l		d1,d3
*-------------------------------------------------------*
*	x2 = (dx2)*sin(a) + (dy2)*cos(a)		*
*	z2 = (dx2)*cos(a) - (dy2)*sin(a)		*
*-------------------------------------------------------*
	move.w		d6,d5
	move.w		d2,d1
	muls.w		d7,d6
	muls.w		d0,d2
	muls.w		d0,d5
	muls.w		d7,d1
	sub.l		d2,d6
	add.l		d1,d5
*-------------------------------------------------------*
*	Renormalize output from matrix			*
*-------------------------------------------------------*
	lsl.l		#2,d3		; x1
	lsl.l		#2,d4		; z1
	lsl.l		#2,d5		; x2
	lsl.l		#2,d6		; z2
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	Z-clipping of walls				*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
	moveq		#ZMIN,d0
	swap		d0
*-------------------------------------------------------*
*	Check for intersection with viewplane		*
*-------------------------------------------------------*
	cmp.l		d0,d4
	bgt.s		.vis1
*-------------------------------------------------------*
*	Skip segment if both points are behind viewer	*
*-------------------------------------------------------*
	cmp.l		d0,d6
	ble		end_segment
*-------------------------------------------------------*
*	Case #1 - clip X1,Z1 against ZMIN		*
*-------------------------------------------------------*
	sub.l		d4,d0		; (cz-z1)
	move.l		d5,d1
	sub.l		d3,d1		; (x2-x1)
	muls.l		d0,d2:d1	; (x2-x1)*(cz-z1)
	move.l		d6,d0
	sub.l		d4,d0		; (z2-z1)
	divs.l		d0,d2:d1	; ((x2-x1)*(cz-z1))/(z2-z1)
	add.l		d1,d3		; (((x2-x1)*(cz-z1))/(z2-z1))+x1
	moveq		#ZMIN,d4
	swap		d4		; z1 = cz
	bra.s		.vis2
*-------------------------------------------------------*
*	Draw segment if both points are in view		*
*-------------------------------------------------------*
.vis1:	cmp.l		d0,d6
	bgt.s		.vis2
*-------------------------------------------------------*
*	Case #2 - clip X2,Z2 against ZMIN		*
*-------------------------------------------------------*
	sub.l		d6,d0		; (cz-z2)
	move.l		d3,d1
	sub.l		d5,d1		; (x1-x2)
	muls.l		d0,d2:d1	; (x1-x2)*(cz-z2)
	move.l		d4,d0
	sub.l		d6,d0		; (z1-z2)
	divs.l		d0,d2:d1	; ((x1-x2)*(cz-z2))/(z1-z2)
	add.l		d1,d5		; (((x1-x2)*(cz-z2))/(z1-z2))+x2
	moveq		#ZMIN,d6
	swap		d6		; z2 = cz
*-------------------------------------------------------*
*	Project points into 2D viewspace		*
*-------------------------------------------------------*
.vis2:	moveq		#0,d1
	move.w		display_shwid(a6),d1
	swap		d1
	muls.l		d1,d0:d3
	divs.l		d4,d0:d3
	muls.l		d1,d0:d5
	divs.l		d6,d0:d5
	move.l		d1,d0
	add.l		d0,d0
*-------------------------------------------------------*
*	Centre screen coordinates & check bounds	*
*-------------------------------------------------------*
	neg.l		d5
	add.l		d1,d5
	ble		end_segment
	move.l		d5,d7
	cmp.l		d0,d7
	bmi.s		.i2in
	move.l		d0,d7	
.i2in:	neg.l		d3
	add.l		d1,d3
	move.l		d3,d1
	bpl.s		.i1in
	moveq		#0,d1
.i1in:	cmp.l		d0,d3
	bpl		end_segment
*-------------------------------------------------------*
*	Check size (i2-i1)				*
*-------------------------------------------------------*
	swap		d1
	swap		d7
	move.w		d7,d0
	sub.w		d1,d0
	ble		end_segment
*-------------------------------------------------------*
*	Discard fully occluded walls			*
*-------------------------------------------------------*
	ifd		dsp
*-------------------------------------------------------*
	dspwrite.l	#scan_command
	ext.l		d1
	dspwrite.l	d1
	ext.l		d7
	dspwrite.l	d7
	dspread.w	d0
	cmp.w		#visible_code,d0
	bne		end_segment
*-------------------------------------------------------*
	elseif
*-------------------------------------------------------*
	lea		occlusion_list,a2
	add.w		d1,a2
	moveq		#4-1,d2
	and.w		d0,d2
	lsr.w		#2,d0
	bra.s		.sbs
.sb:	tst.b		(a2)+
	bne.s		.draw
.sbs:	dbra		d2,.sb
	bra.s		.sls
.sl:	tst.l		(a2)+
	bne.s		.draw
.sls:	dbra		d0,.sl
	bra		end_segment
*-------------------------------------------------------*
	endc
*-------------------------------------------------------*
*	Write coordinates into addwall struct		*
*-------------------------------------------------------*
.draw:	lea		addwall_struct,a2
	move.l		d3,addwall_i1(a2)
	move.l		d4,addwall_z1(a2)
	move.l		d5,addwall_i2(a2)
	move.l		d6,addwall_z2(a2)
*-------------------------------------------------------*
*	Look up linedef for this seg			*
*-------------------------------------------------------*
	moveq		#0,d1
	move.w		seg_linedef(a5),d1
	move.l		d1,d0 
	move.l		display_linedefs(a6),a0
	lsl.l		#3,d0 
	sub.l		d1,d0
	add.l		d0,d0
	add.l		d0,a0
	move.l		a0,a1
*-------------------------------------------------------*
*	Determine one or two-sided linedef		*
*-------------------------------------------------------*
	moveq		#attrib_twosided,d0
	and.w		linedef_attrib(a0),d0
	move.b		d0,twosided_flag
*-------------------------------------------------------*
*	Determine which sidedef is facing us		*
*-------------------------------------------------------*
	move.w		seg_sidedef(a5),d0
	moveq		#0,d5
	move.w		linedef_right(a0,d0.l*2),d5	; visible sidedef
	bchg		#0,d0
	moveq		#0,d6
	move.w		linedef_right(a0,d0.l*2),d6	; invisible sidedef
*-------------------------------------------------------*
*	Look up sidedef for visible side of linedef	*
*-------------------------------------------------------*
	move.l		d5,d0
	move.l		d0,d1
	move.l		display_sidedefs(a6),a3
	lsl.l		#4,d0
	sub.l		d1,d0
	add.l		d0,d0
	add.l		d0,a3				; a+(d*30)
*-------------------------------------------------------*
*	(a6) pointer to addwall structure		*
*-------------------------------------------------------*
	lea		addwall_struct,a6
*-------------------------------------------------------*
*	Hack colours & lighting to something useful	*
*-------------------------------------------------------*
	move.w		a3,sector_colour
	move.w		sidedef_sector(a3),d0
	bsr		select_colours
*-------------------------------------------------------*
*	Check for main wall texture			*
*-------------------------------------------------------*
	cmpi.b		#'-',sidedef_mtns(a3) 
	beq.s		sector_window
*-------------------------------------------------------*
*	Valid texture indicates a solid sector wall	*
*-------------------------------------------------------*
sector_wall:	
*-------------------------------------------------------*
	move.b		twosided_flag,addwall_opaque(a6)
	move.w		Ph,d0
	move.w		d0,d1
	sub.w		ceiling_ht,d1
	move.w		d0,d2
	sub.w		floor_ht,d2
	cmp.w		d1,d2
	bmi		end_segment
	move.w		d1,addwall_y1(a6)
	move.w		d2,addwall_y2(a6)
	move.b		#WALL_TYPE,addwall_type(a6)
	bsr		AddWall
	bra		end_segment
*-------------------------------------------------------*
sector_window:
*-------------------------------------------------------*
	move.b		#0,addwall_opaque(a6)
*-------------------------------------------------------*
*	Locate [sector] on opposite side of [linedef]	*
*-------------------------------------------------------*
	move.l		d6,d0
	move.l		Side_Array,a4
	move.l		d0,d1
	lsl.l		#4,d0
	sub.l		d1,d0
	move.w		sidedef_sector(a4,d0.l*2),a0	; a+(d*30)
	lea		(a0,a0.l*2),a2
	move.l		Sector_Array,a1
	move.l		a2,d0 
	lsl.l		#2,d0
	add.l		a0,d0
	lea		(a1,d0.l*2),a4			; a+(d*26)
*-------------------------------------------------------*
*	Check for lower wall texture			*
*-------------------------------------------------------*
	move.w		floor_ht,d1 
	cmp.b		#'-',sidedef_ltns(a3) 
	beq.s		lower_floor
*-------------------------------------------------------*
*	Valid texture indicates a solid lower wall	*
*-------------------------------------------------------*
lower_wall:
*-------------------------------------------------------*
	move.w		sector_floorht(a4),d1
	cmp.w		ceiling_ht,d1
	bmi.s		lower_floor
	move.w		ceiling_ht,d1
*-------------------------------------------------------*
lower_floor:
*-------------------------------------------------------*
	move.w		floor_ht,d2 
	neg.w		d1
	neg.w		d2
	add.w		Ph,d1
	add.w		Ph,d2
	cmp.w		d1,d2
	bpl.s		.fix
	move.w		d2,d1
.fix:	move.w		d1,addwall_y1(a6)
	move.w		d2,addwall_y2(a6)
	move.b		#LOWER_TYPE,addwall_type(a6)
	bsr		AddWall 
	tst.w		columns
	beq.s		end_segment		 
*-------------------------------------------------------*
*	Check for upper wall texture			*
*-------------------------------------------------------*
	move.w		ceiling_ht,d2 
	cmp.b		#'-',sidedef_utns(a3) 
	beq.s		upper_ceiling
*-------------------------------------------------------*
*	Valid texture indicates a solid upper wall	*
*-------------------------------------------------------*
upper_wall:
*-------------------------------------------------------*
	move.w		sector_ceilht(a4),d2
	cmp.w		floor_ht,d2
	bpl.s		upper_ceiling
	move.w		floor_ht,d2
*-------------------------------------------------------*
upper_ceiling:
*-------------------------------------------------------*
	move.w		ceiling_ht,d1 
	neg.w		d1
	neg.w		d2
	add.w		Ph,d1
	add.w		Ph,d2
	cmp.w		d1,d2
	bpl.s		.fix
	move.w		d1,d2
.fix:	move.w		d1,addwall_y1(a6)
	move.w		d2,addwall_y2(a6)
	move.b		#UPPER_TYPE,addwall_type(a6)
	bsr		AddWall 
*-------------------------------------------------------*
end_segment:
*-------------------------------------------------------*
	pop.l		a2
*-------------------------------------------------------*
*	Proceed to next segment				*
*-------------------------------------------------------*
invisible:
*-------------------------------------------------------*
	lea		display_struct,a6
	lea		seg_len(a2),a2
	addq.w		#1,display_segbase(a6)
	subq.w		#1,display_segnum(a6)
	beq		end_ssector
	tst.w		columns
	bne		segment_loop
*-------------------------------------------------------*
end_ssector:
*-------------------------------------------------------*
*	Fetch next node from heap and descend again	*
*-------------------------------------------------------*
next_node:
*-------------------------------------------------------*
	move.w		(sp)+,d0
	bmi		ssector_node

*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	[node] /= [sector] -> descend again		*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
dividing_node:
*-------------------------------------------------------*
	move.l		display_nodes(a6),a1	
	move.l		(a1,d0.w*4),a1
*-------------------------------------------------------*
*	Inverse descent rules for left side of tree	*
*-------------------------------------------------------*
*	(dy*(x1-Px))) => ((dx*(y1-Py)) ?		*
*-------------------------------------------------------*
	move.w		node_dx(a1),d2
	move.w		node_x(a1),d0
	move.w		node_dy(a1),d3
	move.w		node_y(a1),d1
	add.w		d2,d0			; x2 = (x1+dx)
	sub.w		display_px(a6),d0	; (x2-px)
	add.w		d3,d1			; y2 = (y1+dy)
	sub.w		display_py(a6),d1	; (xy-py)
	muls.w		d2,d1			; (y2-py) * dx
	muls.w		d3,d0			; (x2-px) * dy
	cmp.l		d0,d1 
	bmi.s		node_leftside
*-------------------------------------------------------*
*	Viewer is on right side of node divider		*
*-------------------------------------------------------*
node_rightside:
*-------------------------------------------------------*
	lea		node_lvtx(a1),a0
	bsr.s		nodeincone
	beq.s		.noln
	move.w		node_left(a1),-(sp)
.noln:	lea		node_rvtx(a1),a0
	bsr.s		nodeincone
	beq.s		next_node
	move.w		node_right(a1),-(sp) 
	bra.s		next_node
*-------------------------------------------------------*
*	Viewer is on left side of node divider		*
*-------------------------------------------------------*
node_leftside:
*-------------------------------------------------------*
	lea		node_rvtx(a1),a0
	bsr.s		nodeincone
	beq.s		.noln
	move.w		node_right(a1),-(sp) 
.noln:	lea		node_lvtx(a1),a0
	bsr.s		nodeincone
	beq.s		next_node
	move.w		node_left(a1),-(sp)
	bra.s		next_node

*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	Determine visibility of a child node.		*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	Only exposed nodes are dealt with.		*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*

*-------------------------------------------------------*
*	Check #1 -> Octal node elimination		* 
*-------------------------------------------------------*
*	All nodes are checked against the 3 octal	*
*	segments immediately in front of viewcone.	*
*	Nodes from 5 of all 8 octants are discarded.	*
*-------------------------------------------------------*
*	Check #2 -> Canonical volume intersection	* 
*-------------------------------------------------------*
*	The remaining nodes are fully intersected	*
*	with the projected canonical view volume.	*
*	Any nodes outside the viewcone are discarded.	*
*-------------------------------------------------------*
*	Check #3 -> Occlusion check			* 
*-------------------------------------------------------*
*	Any nodes remaining in view are checked		*
*	against the occlusion table. Any nodes		*
*	completely occluded by walls are discarded.	*
*-------------------------------------------------------*
nodeincone:
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	Octal segment BSP node eliminator		*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	Eliminates nodes from 5 out of all 8 octants	*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
qx1	equr		d1
qy1	equr		d2
qx2	equr		d3
qy2	equr		d4
*-------------------------------------------------------*
	move.w		display_px(a6),d5
	move.w		display_py(a6),d6
	move.w		display_octant(a6),d7
	moveq		#0,d0
	jmp		octs(pc,d7.w)
*-------------------------------------------------------*
*	Octant elimination table		 	*
*-------------------------------------------------------*
*	Octants are out of phase by 1/4 turn		*
*-------------------------------------------------------*
octs:	dc.w		oct_2-octs
	dc.w		oct_3-octs
	dc.w		oct_4-octs
	dc.w		oct_5-octs
	dc.w		oct_6-octs
	dc.w		oct_7-octs
	dc.w		oct_0-octs
	dc.w		oct_1-octs
*-------------------------------------------------------*
*	Octant elimination routines		 	*
*-------------------------------------------------------*
oct_0:	move.w		nodevtx_y1(a0),qy1
	move.w		nodevtx_x2(a0),qx2
	sub.w		d6,qy1
	bpl.s		.x
	sub.w		d5,qx2
	cmp.w		qy1,qx2
	bpl		project_node
.x:	tst.l		d0
	rts
*-------------------------------------------------------*
oct_1:	move.w		nodevtx_x2(a0),qx2
	move.w		nodevtx_y1(a0),qy1
	sub.w		d5,qx2
	bmi.s		.x
	sub.w		d6,qy1
	cmp.w		qy1,qx2
	bpl		project_node
.x:	tst.l		d0
	rts
*-------------------------------------------------------*
oct_2:	move.w		nodevtx_x2(a0),qx2
	move.w		nodevtx_y2(a0),qy2
	sub.w		d5,qx2
	bmi.s		.x
	sub.w		d6,qy2
	neg.w		qy2
	cmp.w		qy2,qx2
	bpl.s		project_node
.x:	tst.l		d0
	rts
*-------------------------------------------------------*
oct_3:	move.w		nodevtx_y2(a0),qy2
	move.w		nodevtx_x2(a0),qx2
	sub.w		d6,qy2
	bmi.s		.x
	sub.w		d5,qx2
	neg.w		qy2
	cmp.w		qy2,qx2
	bpl.s		project_node
.x:	tst.l		d0
	rts
*-------------------------------------------------------*
oct_4:	move.w		nodevtx_y2(a0),qy2
	move.w		nodevtx_x1(a0),qx1
	sub.w		d6,qy2
	bmi.s		.x
	sub.w		d5,qx1
	cmp.w		qy2,qx1
	bmi.s		project_node
.x:	tst.l		d0
	rts
*-------------------------------------------------------*
oct_5:	move.w		nodevtx_x1(a0),qx1
	move.w		nodevtx_y2(a0),qy2
	sub.w		d5,qx1
	bpl.s		.x
	sub.w		d6,qy2
	cmp.w		qy2,qx1
	bmi.s		project_node
.x:	tst.l		d0
	rts
*-------------------------------------------------------*
oct_6:	move.w		nodevtx_x1(a0),qx1
	move.w		nodevtx_y1(a0),qy1
	sub.w		d5,qx1
	bpl.s		.x
	sub.w		d6,qy1
	neg.w		qy1
	cmp.w		qy1,qx1
	bmi.s		project_node	
.x:	tst.l		d0
	rts
*-------------------------------------------------------*
oct_7:	move.w		nodevtx_y1(a0),qy1
	move.w		nodevtx_x1(a0),qx1
	sub.w		d6,qy1
	bpl.s		.x
	sub.w		d5,qx1
	neg.w		qy1
	cmp.w		qy1,qx1
	bmi.s		project_node
.x:	tst.l		d0
	rts
	
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	Intersect node with viewcone in 2D		*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
project_node:	
*-------------------------------------------------------*
	pea		(a1)
*-------------------------------------------------------*
	move.w		#$1000,d0
	move.l		d0,display_imin(a6)
	neg.l		d0
	move.l		d0,display_imax(a6)
*=======================================================*
*	Prefetch X2,Y2 for polygon loop			*
*=======================================================*
	move.w		nodevtx_x1(a0),d4
	move.w		nodevtx_y2(a0),d6
	sub.w		display_px(a6),d4
	sub.w		display_py(a6),d6
*-------------------------------------------------------*
*	Rotate NY & NZ into canonical VZ & VX		*
*-------------------------------------------------------*
*	x = (dx)*sin(a) + (dy)*cos(a)			*
*	z = (dx)*cos(a) - (dy)*sin(a)			*
*-------------------------------------------------------*
	move.w		display_sina(a6),d1
	move.w		display_cosa(a6),d2
	move.w		d4,d3
	move.w		d6,d5
	muls.w		d2,d4
	muls.w		d1,d6
	muls.w		d1,d3
	muls.w		d2,d5
	sub.l		d6,d4
	add.l		d5,d3
	lsl.l		#2,d3
	lsl.l		#2,d4
*-------------------------------------------------------*
*	Limit & hold as X2,Y2				*
*-------------------------------------------------------*
	move.l		d3,a2
	move.l		d4,a3
*=======================================================*
*	2D polygon cone-intersection 			*
*=======================================================*
	lea		nodev_indices,a1
	moveq		#4-1,d7
*-------------------------------------------------------*
*	Fetch new X1,Y1 & centre at origin		*
*-------------------------------------------------------*
.rect:	move.w		(a1)+,d6
	move.w		(a1)+,d2
	move.w		(a0,d6.w),d6
	move.w		(a0,d2.w),d2
	sub.w		display_px(a6),d6
	sub.w		display_py(a6),d2
*-------------------------------------------------------*
*	Rotate NY & NZ into canonical VZ & VX		*
*-------------------------------------------------------*
*	x = (dx)*sin(a) + (dy)*cos(a)			*
*	z = (dx)*cos(a) - (dy)*sin(a)			*
*-------------------------------------------------------*
	move.w		display_sina(a6),d3
	move.w		display_cosa(a6),d4
	move.w		d6,d5
	move.w		d2,d1
	muls.w		d4,d6
	muls.w		d3,d2
	muls.w		d3,d5
	muls.w		d4,d1
	sub.l		d2,d6
	add.l		d1,d5
	lsl.l		#2,d5
	lsl.l		#2,d6
*-------------------------------------------------------*
*	Clip X1,Y1 / store next X2,Y2 / get this X2,Y2	*
*-------------------------------------------------------*
	move.l		a2,d3
	move.l		a3,d4
	move.l		d5,a2
	move.l		d6,a3
*-------------------------------------------------------*
*	Reorient line and check against viewplane	*
*-------------------------------------------------------*
	cmp.l		d4,d6
	bpl.s		.swap
	exg.l		d3,d5
	exg.l		d4,d6
.swap:	moveq		#ZMIN,d1
	swap		d1
	cmp.l		d1,d6
	ble.s		.next	
*-------------------------------------------------------*
*	z-clip line if it intersects with viewplane	*	
*-------------------------------------------------------*
	moveq		#ZMIN,d0
	swap		d0
	sub.l		d4,d0		; (cz-z1)
	ble.s		.nzcl	
	move.l		d5,d1
	sub.l		d3,d1		; (x2-x1)
	muls.l		d0,d2:d1	; (x2-x1)*(cz-z1)
	move.l		d6,d0
	sub.l		d4,d0		; (z2-z1)
	divs.l		d0,d2:d1	; ((x2-x1)*(cz-z1))/(z2-z1)
	add.l		d1,d3		; (((x2-x1)*(cz-z1))/(z2-z1))+x1
	moveq		#ZMIN,d4
	swap		d4		; z1 = cz
*-------------------------------------------------------*
*	Project points into 2D viewspace		*
*-------------------------------------------------------*
.nzcl:	moveq		#0,d1
	move.w		display_shwid(a6),d1
	muls.l		d1,d0:d3
	divs.l		d4,d0:d3
	muls.l		d1,d0:d5
	divs.l		d6,d0:d5
*-------------------------------------------------------*
*	Adjust bounds					*
*-------------------------------------------------------*
	move.l		display_imin(a6),d1
	neg.l		d3
	neg.l		d5
	move.l		display_imax(a6),d2
	cmp.l		d1,d3
	bpl.s		.n1
	move.l		d3,d1
.n1:	cmp.l		d2,d3
	ble.s		.n2
	move.l		d3,d2
.n2	cmp.l		d1,d5
	bpl.s		.n3
	move.l		d5,d1
.n3:	cmp.l		d2,d5
	ble.s		.n4
	move.l		d5,d2
.n4:	move.l		d1,display_imin(a6)
	move.l		d2,display_imax(a6)
.next:	dbra		d7,.rect
*-------------------------------------------------------*
*	Inside / outside viewport check			*
*-------------------------------------------------------*
	move.l		display_imin(a6),d3
	moveq		#0,d0
	move.l		display_imax(a6),d5
	subq.l		#1,d3
	addq.l		#1,d5
	moveq		#0,d2
	move.w		display_width(a6),d2
	move.l		d2,d1
	lsr.l		d1
	add.l		d1,d5
	bmi.s		.end
	add.l		d1,d3
	bpl.s		.x1in
	moveq		#0,d3
.x1in:	cmp.l		d2,d3
	bpl.s		.end
	cmp.l		d2,d5
	bmi.s		.x2in
	move.l		d2,d5
.x2in:	sub.l		d3,d5
	ble.s		.end
*-------------------------------------------------------*
*	Occlusion check					*
*-------------------------------------------------------*
	ifd		dsp
*-------------------------------------------------------*
	add.l		d3,d5
	dspwrite.l	#scan_command
	dspwrite.l	d3
	dspwrite.l	d5
	dspread.w	d0
	ext.l		d0
*-------------------------------------------------------*
	elseif
*-------------------------------------------------------*
	moveq		#1,d0
	lea		occlusion_list,a2
	add.w		d3,a2
	moveq		#4-1,d2
	and.w		d5,d2
	lsr.w		#2,d5
	bra.s		.sbs
.sb:	tst.b		(a2)+
	bne.s		.end
.sbs:	dbra		d2,.sb
	bra.s		.sls
.sl:	tst.l		(a2)+
	bne.s		.end
.sls:	dbra		d5,.sl
	moveq		#0,d0
*-------------------------------------------------------*
	endc
*-------------------------------------------------------*
.end:	pop.l		a1
*-------------------------------------------------------*
*	Return exitcode					*
*-------------------------------------------------------*
end_nodecheck:
*-------------------------------------------------------*
	tst.l		d0
	rts 

*-------------------------------------------------------*
			data
*-------------------------------------------------------*

*-------------------------------------------------------*
*	Ordered list of node->polygon vertex defs	*
*-------------------------------------------------------*
nodev_indices:		dc.w	nodevtx_x1,nodevtx_y1
			dc.w	nodevtx_x2,nodevtx_y1
			dc.w	nodevtx_x2,nodevtx_y2
			dc.w	nodevtx_x1,nodevtx_y2

*-------------------------------------------------------*
			bss
*-------------------------------------------------------*

maxnode:		ds.l	1	
floor_ht:		ds.l	1	
ceiling_ht:		ds.l	1	
first_ssector:		ds.w	1	
sector_colour:		ds.w	1
this_sector:		ds.l	1
bsp_return:		ds.l	1
twosided_flag:		ds.b	1
			even

*-------------------------------------------------------*
			text
*-------------------------------------------------------*
