;****************************************************************************
;
; GetRoomBounds
;
;****************************************************************************

	SECTION	ASM
	opt	at-,w-,c+,m-
	INCLUDE	..\spec_psx\gp.inc
	INCLUDE	..\spec_psx\gte.inc
	INCLUDE	..\spec_psx\draw.inc
	INCLUDE	..\spec_psx\room.inc

;----------------------------------------------------------------------------
; Constants
;----------------------------------------------------------------------------

DCACHE		equ	$1f800000

;----------------------------------------------------------------------------
; Type Definitions
;----------------------------------------------------------------------------

; -------- MATRIX3D structure definition

		rsreset
m00		rh	1
m01		rh	1
m02		rh	1
m10		rh	1
m11		rh	1
m12		rh	1
m20		rh	1
m21		rh	1
m22		rh	1
mPad		rh	1
mx		rw	1
my		rw	1
mz		rw	1
SIZEOF_MATRIX	rb	0

; -------- local scratchpad usage

		rsreset
BoundList	rb	128
DoorBox		rw	12
TransX		rw	1
TransY		rw	1
TransZ		rw	1
CamX		rw	1
CamY		rw	1
CamZ		rw	1
OutsideLeft	rw	1
OutsideRight	rw	1
OutsideTop	rw	1
OutsideBottom	rw	1
regs0		rw	1
regs1		rw	1
regs2		rw	1
regs3		rw	1
regs4		rw	1
regs5		rw	1
regs6		rw	1
regs7		rw	1
regfp		rw	1

;----------------------------------------------------------------------------
; Externals
;----------------------------------------------------------------------------

	XREF	room			; ROOM *room
	XREF	Matrix			; MATRIX3D *Matrix
	XREF	CamPos			; VECTOR3D CamPos
	XREF	outside			; long outside
	XREF	draw_rooms		; sint16 draw_rooms[]
	XREF	outside_left		; LONG outside_left
	XREF	outside_right		; LONG outside_right
	XREF	outside_top		; LONG outside_top
	XREF	outside_bottom		; LONG outside_bottom
	XREF	number_draw_rooms       ; long number_draw_rooms

;----------------------------------------------------------------------------
; Public Routines
;----------------------------------------------------------------------------

	XDEF	GetRoomBoundsAsm

;----------------------------------------------------------------------------
;GetRoomBounds
;
;Purpose:	Adds all visible rooms to the draw list
;
;Inputs:	a0 = current room #
;
;Outputs:	None
;
;Usage:		a0-a3/t0-t9/v0-v1
;
;----------------------------------------------------------------------------

GetRoomBoundsAsm:
	lui	a1,DCACHE>>16		; preserve registers
	sw	s0,regs0(a1)
	sw	s1,regs1(a1)
	sw	s2,regs2(a1)
	sw	s3,regs3(a1)
	sw	s4,regs4(a1)
	sw	s5,regs5(a1)
	sw	s6,regs6(a1)
	sw	s7,regs7(a1)
	sw	fp,regfp(a1)

; -------- initialise constants

	move	s0,a1			; s0 = workspace
	GPR.lw	s1,room			; s1 = room structures
	move	s2,zero			; s2 = bound start
	ori	s3,zero,1		; s3 = bound end
	GPla	s4,draw_rooms		; s4 = list of rooms to draw
	move	s5,zero			; s5 = # rooms to draw
	GPR.lw	fp,outside		; fp = outside flag

; -------- set bounds of initial room

	sb	a0,BoundList(s0)

	sll	a0,4			; a0 = current room ptr
	sll	at,a0,2
	add	a0,at
	add	a0,s1

	lui	t0,SCREEN_WIDTH-1
	lui	t1,SCREEN_HEIGHT-1
	ori	t2,zero,2
	sw	t0,riTestL(a0)
	sw	t1,riTestT(a0)
	sb	t2,riBoundActive(a0)

; -------- load current matrix onto GTE

;	GPR.lw	t0,Matrix
	GPla	t6,CamPos
;	lw	t1,m00(t0)
;	lw	t2,m02(t0)
;	lw	t3,m11(t0)
;	lw	t4,m20(t0)
;	lw	t5,m22(t0)
;	ctc2	t1,C2_R11R12
;	ctc2	t2,C2_R13R21
;	ctc2	t3,C2_R22R23
;	ctc2	t4,C2_R31R32
;	ctc2	t5,C2_R33

; -------- cache vars

;	lw	t1,mx(t0)		; cache current translation
;	lw	t2,my(t0)
;	lw	t3,mz(t0)
	cfc2	t1,C2_TRX
	cfc2	t2,C2_TRY
	cfc2	t3,C2_TRZ
	sw	t1,TransX(s0)
	sw	t2,TransY(s0)
	sw	t3,TransZ(s0)

	lw	t1,0(t6)		; cache camera pos
	lw	t2,4(t6)
	lw	t3,8(t6)
	sw	t1,CamX(s0)
	sw	t2,CamY(s0)
	sw	t3,CamZ(s0)

	GPR.lw	t0,outside_left		; cache horizon clip window
	GPR.lw	t1,outside_right
	GPR.lw	t2,outside_top
	GPR.lw	t3,outside_bottom
	sw	t0,OutsideLeft(s0)
	sw	t1,OutsideRight(s0)
	sw	t2,OutsideTop(s0)
	sw	t3,OutsideBottom(s0)

;--------------------------------------
; GetRoomBounds
;--------------------------------------

@loop:	beq	s2,s3,@end

	add	t0,s0,s2		; t0 = BoundList ptr
	lbu	s6,0(t0)		; s6 = current room #
	addi	s2,1			; BoundStart++
	andi	s2,127
	sll	a0,s6,4			; a0 = current room ptr
	sll	at,a0,2
	add	a0,at
	add	a0,s1

	lb	v0,riBoundActive(a0)
	lw	t1,riClipL(a0)
	subi	v0,2

; -------- enlarge room bounds to incorporate test bounds

	lw	t3,riClipT(a0)
	lw	t5,riTestL(a0)
	lw	t7,riTestT(a0)
	srl	t2,t1,16
	andi	t1,$ffff
	srl	t4,t3,16
	andi	t3,$ffff
	srl	t6,t5,16
	andi	t5,$ffff
	srl	t8,t7,16
	andi	t7,$ffff

	slt	at,t5,t1		; test_left < left
	beqz	at,@ren
	slt	at,t6,t2		; test_right > right
	move	t1,t5
@ren	bnez	at,@ten
	slt	at,t7,t3		; test_top < top
	move	t2,t6
@ten	beqz	at,@ben
	slt	at,t8,t4		; test_bottom > bottom
	move	t3,t7
@ben	bnez	at,@sen
	sll	t6,t2,16
	move	t4,t8
@sen	or	t5,t1,t6
	sll	t6,t4,16
	or	t6,t3
	sw	t5,riClipL(a0)
	sw	t6,riClipT(a0)

; -------- add to draw list

	andi	at,v0,1
	bnez	at,@bounded
	ori	v0,1			; activate room's bounding box
	sh	s6,0(s4)
	addi	s4,2			; advance draw list ptr
	addi	s5,1			; increase # rooms to draw
@bounded:
	lh	s6,riFlags(a0)		; update outside flag
	sb	v0,riBoundActive(a0)
	andi	s6,OUTSIDE
	beqz	s6,@inside
	or	fp,s6

; -------- update horizon clip window

	lw	t5,OutsideLeft(s0)
	lw	t6,OutsideRight(s0)
	lw	t7,OutsideTop(s0)
	lw	t8,OutsideBottom(s0)

	slt	at,t1,t5		; left < outside_left
	beqz	at,@rhor
	slt	at,t2,t6		; right > outside_right
	move	t5,t1
@rhor	bnez	at,@thor
	slt	at,t3,t7		; top < outside_top
	move	t6,t2
@thor	beqz	at,@bhor
	slt	at,t4,t8		; bottom > outside_bottom
	move	t7,t3
@bhor	bnez	at,@shor
	sw	t5,OutsideLeft(s0)
	move	t8,t4
@shor
	sw	t6,OutsideRight(s0)
	sw	t7,OutsideTop(s0)
	sw	t8,OutsideBottom(s0)

; -------- any doors to check in this room ?

@inside	lw	s7,riDoor(a0)
	lw	t0,riX(a0)
	beqz	s7,@loop
	lw	t1,riY(a0)
	lw	t2,riZ(a0)

; -------- mTranslateXYZ

	bgez    t0,@posx
	sra     t3,t0,15
	subu    t0,zero,t0
	sra     t3,t0,15
	andi    t0,$7fff
	subu    t3,zero,t3
	j	@y
	subu    t0,zero,t0
@posx	andi    t0,$7fff

@y	bgez    t1,@posy
	sra     t4,t1,15
	subu    t1,zero,t1
	sra     t4,t1,15
	andi    t1,$7fff
	subu    t4,zero,t4
	j	@z
	subu    t1,zero,t1
@posy	andi    t1,t1,$7fff

@z	bgez    t2,@posz
	sra     t5,t2,15
	subu    t2,zero,t2
	sra     t5,t2,15
	andi    t2,t2,$7fff
	subu    t5,zero,t5
	j	@doit
	subu    t2,zero,t2
@posz	andi    t2,t2,$7fff

@doit	mtc2    t3,C2_IR1
	mtc2    t4,C2_IR2
	mtc2    t5,C2_IR3
	nop
	MVMVA	0,0,3,3,0		; [rt] * [ir]

	lw	t3,TransX(s0)		; load current translation into GTE
	lw	t4,TransY(s0)
	lw	t5,TransZ(s0)
	ctc2	t3,C2_TRX
	ctc2	t4,C2_TRY
	ctc2	t5,C2_TRZ

	mfc2    t3,C2_MAC1
	mfc2    t4,C2_MAC2
	mtc2    t0,C2_IR1
	mtc2    t1,C2_IR2
	mtc2    t2,C2_IR3
	mfc2    t5,C2_MAC3
	MVMVA	1,0,3,0,0		; ([rt] * [ir]) >> 12) + [tr]

	bgez    t3,@lab8
	sll     t0,t3,3
	subu    t3,zero,t3
	sll     t3,3
	subu    t0,zero,t3
@lab8
	bgez    t4,@lab9
	sll     t1,t4,3
	subu    t4,zero,t4
	sll     t4,3
	subu    t1,zero,t4
@lab9
	bgez    t5,@lab10
	sll     t2,t5,3
	subu    t5,zero,t5
	sll     t5,3
	subu    t2,zero,t5
@lab10
	mfc2	t3,C2_MAC1
	mfc2	t4,C2_MAC2
	mfc2	t5,C2_MAC3
	addu	t0,t3
	addu	t1,t4
	addu	t2,t5

	ctc2	t0,C2_TRX		; load compound translation onto GTE
	ctc2	t1,C2_TRY
	ctc2	t2,C2_TRZ

; -------- check all doors within this room

	lh	v0,0(s7)		; v0 = # doors
	addi	s7,2
@doorloop:
	lh	a1,0(s7)		; a1 = room #
	addi	s7,2

; -------- use door normal to determine whether to check this doorway

	lh	t0,0(s7)
	lw	t1,riX(a0)
	beqz	t0,@dy
	lh	t2,6(s7)
	lw	t3,CamX(s0)
	add	t1,t2			; roomx + doorx - camx
	sub	t1,t3
	beqz	t1,@nextdoor
	xor	t0,t1
	bltz	t0,@setroom
	move	a2,s7
	j	@nextdoor
@dy:
	lh	t0,2(s7)
	lw	t1,riY(a0)
	beqz	t0,@dz
	lh	t2,8(s7)
	lw	t3,CamY(s0)
	add	t1,t2			; roomy + doory - camy
	sub	t1,t3
	beqz	t1,@nextdoor
	xor	t0,t1
	bltz	t0,@setroom
	move	a2,s7
	j	@nextdoor
@dz:
	lh	t0,4(s7)
	lw	t1,riZ(a0)
	lh	t2,10(s7)
	lw	t3,CamZ(s0)
	add	t1,t2			; roomz + doorz - camz
	sub	t1,t3
	beqz	t1,@nextdoor
	xor	t0,t1
	bgez	t0,@nextdoor
	move	a2,s7

;--------------------------------------
; SetRoomBounds
;--------------------------------------

; a0 = parent room structure
; a1 = dest room #
; a2 = door data

@setroom:
	sll	a3,a1,4			; a3 = current room ptr
	sll	at,a3,2
	add	a3,at
	add	a3,s1

; -------- determine if parent room's bounds encompass the current room's bounds

	lw	t0,riClipL(a3)
	lw	t2,riTestL(a0)
	lw	t4,riClipT(a3)
	lw	t6,riTestT(a0)
	srl	t1,t0,16
	andi	t0,$ffff
	srl	t3,t2,16
	andi	t2,$ffff
	srl	t5,t4,16
	andi	t4,$ffff
	srl	t7,t6,16
	andi	t6,$ffff
	slt	at,t0,t2		; r->left <= parent->test_left
	beqz	at,@scalc
	slt	at,t1,t3		; r->right >= parent->test_right
	bnez	at,@scalc
	slt	at,t4,t6		; r->top <= parent->test_top
	beqz	at,@scalc
	slt	at,t5,t7		; r->bottom >= parent->test_bottom
	beqz	at,@RETURN

; -------- determine door bounds

@scalc:	move	t0,t3			; initialise bounds to their extremes
	move	t1,t2
	move	t2,t7
	move	t3,t6
	addi	t4,s0,DoorBox		; t4 = vectors
	move	t5,zero			; t5 = z near clip count
	move	t6,zero			; t6 = z far clip count
	ori	v1,zero,3
@sloop:
	lhu	t7,6(a2)		; read door xyz
	lhu	t9,8(a2)
	lhu	t8,10(a2)
	sll	t9,16
	or	t7,t9
	mtc2	t7,C2_VXY0
	mtc2	t8,C2_VZ0
	addi	a2,6
	MVMVA	1,0,0,0,0		; ([rt] * [v0]) >> 12 + [tr]

	mfc2	t7,C2_IR1
	mfc2	t8,C2_IR2
	mfc2	t9,C2_IR3
	RTPS				; RotTransPers (14)
	sw	t7,0(t4)
	sw	t8,4(t4)
	sw	t9,8(t4)

	bgtz	t9,@son			; z < 0 ?
	addi	t4,12
	j	@snext
	addi	t5,1			; yes, update near clip count
@son:
	slti	at,t9,CLIPZ		; z too far ?
	mfc2	t7,C2_SXY2
	bnez	at,@szok
	sra	t8,t7,16
	addi	t6,1			; yes, update far clip count
@szok:
	sll	t7,16
	sra	t7,16
	slt	at,t7,t0		; x < left
	beqz	at,@sr
	slt	at,t7,t1		; x > right
	move	t0,t7
@sr	bnez	at,@st
	slt	at,t8,t2		; y < top
	move	t1,t7
@st	beqz	at,@sb
	slt	at,t8,t3		; y > bottom
	move	t2,t8
@sb	bnez	at,@snext
	nop				; ## grr
	move	t3,t8
@snext:
	bnez	v1,@sloop
	subi	v1,1

; -------- exit if all points were clipped

	ori	at,zero,4
	beq	t5,at,@RETURN
	addi	t4,s0,DoorBox		; t4 = vectors
	beq	t6,at,@RETURN
	ori	v1,zero,3

; -------- clip if doorway crosses z=0 plane

	beqz	t5,@sclip
	addi	t5,t4,36		; t5 = vector twin
@szloop:
	lw	t6,8(t4)		; fetch two z's
	lw	t7,8(t5)
	slti	t8,t6,33		;zero
	slti	t9,t7,33		;zero
	xor	t8,t9
	beqz	t8,@sznext		; clip only if z's straddle z plane

	lw	t6,0(t4)		; xclip
	lw	t7,0(t5)
	slt	t8,t6,zero		; if x1<0 && x2<0
	slt	t9,t7,zero
	and	t8,t9
	beqz	t8,@szr
	slt	t8,zero,t6		; if x1>0 && x2>0
	j	@szy
	move	t0,zero			; extreme left
@szr:
	slt	t9,zero,t7
	and	t8,t9
	bnez	t8,@szy
	ori	t1,zero,CLIPX		; extreme right
	move	t0,zero
@szy:
	lw	t6,4(t4)		; yclip
	lw	t7,4(t5)
	slt	t8,t6,zero		; if y1<0 && y2<0
	slt	t9,t7,zero
	and	t8,t9
	beqz	t8,@szb
	slt	t8,zero,t6		; if y1>0 && y2>0
	j	@sznext
	move	t2,zero
@szb:
	slt	t9,zero,t7
	and	t8,t9
	bnez	t8,@sznext
	ori	t3,zero,CLIPY		; extreme bottom
	move	t2,zero			; extreme top
@sznext:
	move	t5,t4
	addi	t4,12
	bnez	v1,@szloop
	subi	v1,1

; -------- clip bounds to parent window

@sclip	lw	t4,riTestL(a0)
	lw	t6,riTestT(a0)
	srl	t5,t4,16
	andi	t4,$ffff
	srl	t7,t6,16
	andi	t6,$ffff
	slt	at,t0,t4		; left < parent->test_left
	beqz	at,@scr
	slt	at,t5,t1		; right > parent->test_right
	move	t0,t4
@scr	beqz	at,@sct
	slt	at,t2,t6		; top < parent->test_top
	move	t1,t5
@sct	beqz	at,@scb
	slt	at,t7,t3		; bottom > parent->test_bottom
	move	t2,t6
@scb	beqz	at,@sco
	sub	at,t0,t1		; left >= right
	move	t3,t7
@sco	bgez	at,@RETURN
	sub	at,t2,t3		; top >= bottom
	bgez	at,@RETURN

; -------- add room to bound list

	lb	v1,riBoundActive(a3)
	add	t4,s0,s3		; t4 = &BoundList[BoundEnd]
	andi	at,v1,2
	bnez	at,@sredo
	ori	v1,2

	sb	a1,0(t4)
	addi	s3,1
	andi	s3,127

	sll	t1,16
	or	t0,t1
	sll	t3,16
	or	t2,t3
	sw	t0,riTestL(a3)
	sw	t2,riTestT(a3)
	j	@RETURN
	sb	v1,riBoundActive(a3)

; -------- update existing bounds

@sredo	lw	t4,riTestL(a3)
	lw	t6,riTestT(a3)
	srl	t5,t4,16
	andi	t4,$ffff
	srl	t7,t6,16
	andi	t6,$ffff
	slt	at,t0,t4		; left < test_left
	beqz	at,@sur
	slt	at,t5,t1		; right > test_right
	move	t4,t0
@sur	beqz	at,@sut
	slt	at,t2,t6		; top < test_top
	move	t5,t1
@sut	beqz	at,@sub
	slt	at,t7,t3		; bottom > test_bottom
	move	t6,t2
@sub	beqz	at,@suend
	sll	t5,16
	move	t7,t3
@suend	or	t4,t5
	sll	t7,16
	or	t6,t7
	sw	t4,riTestL(a3)
	sw	t6,riTestT(a3)
@RETURN

;--------------------------------------
; SetRoomBounds End
;--------------------------------------

@nextdoor:
	subi	v0,1
	bgtz	v0,@doorloop
	addi	s7,30
	j	@loop
	nop
@end:
	GPR.sw	s5,number_draw_rooms
	GPR.sw	fp,outside

	lw	t0,OutsideLeft(s0)	; set horizon clip window
	lw	t1,OutsideRight(s0)
	lw	t2,OutsideTop(s0)
	lw	t3,OutsideBottom(s0)
	GPR.sw	t0,outside_left
	GPR.sw	t1,outside_right
	GPR.sw	t2,outside_top
	GPR.sw	t3,outside_bottom

	lui	a0,DCACHE>>16		; restore registers
	lw	s0,regs0(a0)
	lw	s1,regs1(a0)
	lw	s2,regs2(a0)
	lw	s3,regs3(a0)
	lw	s4,regs4(a0)
	lw	s5,regs5(a0)
	lw	s6,regs6(a0)
	lw	s7,regs7(a0)
	jr	ra
	lw	fp,regfp(a0)

