;*******************************************************************************
;* TITLE	: CRYMAIN.S						       *
;* Function	: Complete 3D Turtle Demo				       *
;*                                                                             *
;* Project #	: Jaguar 3D pack					       *
;* Programmer	: Rob Zdybel						       *
;*                                                                             *
;* COPYRIGHT 1992,1993 Atari U.S. Corporation				       *
;* UNATHORIZED REPRODUCTION, ADAPTATION, DISTRIBUTION, PERFORMANCE OR DISPLAY  *
;* OF THIS COMPUTER PROGRAM OR THE ASSOCIATED AUDIOVISUAL WORK IS STRICTLY     *
;* PROHIBITED.  ALL RIGHTS RESERVED.					       *
;*******************************************************************************

	.title	"CRYMAIN.S - MAIN GAME PLAY HANDLER"

;*=============================================================================*
;* INCLUDE FILES							       *
;*=============================================================================*

	include "jaguar.inc"
	include "blit.inc"
	include "joypad.inc"
	include "objlist.inc"

;*=============================================================================*
;* EXTERNAL ROUTINES							       *
;*=============================================================================*

	.extern	gpuload
	.extern	gpurun
	.extern	gpuwait

	.extern TXTCRY_S
	.extern TXTCRY_E
	.extern	text3D

	.extern	SORT_S
	.extern	SORT_E
	.extern	bsort

	.extern	TURTLE_S
	.extern	TURTLE_E
	.extern turtpak

	.extern	vblank
	.extern	vidinit

	.extern BuildObjList

	.extern	readpad

;*=============================================================================*
;* EXTERNAL DATA							       *
;*=============================================================================*

	.extern	DISPBUF0
	.extern DISPBUF1
	.extern ZBUF

	.extern	framecnt

	.extern	lastObj
	.extern objData

	.extern	pad_now
	.extern	pad_shot

	.extern	cubesize		; hand-made cube
	.extern cubedata

;*=============================================================================*
;* PUBLIC ROUTINES							       *
;*=============================================================================*

	.globl	_main

;*=============================================================================*
;* PUBLIC DATA								       *
;*=============================================================================*

;*=============================================================================*
;* LOCAL EQUATES							       *
;*=============================================================================*

RAMSIZE		EQU	$1000		; 4K bytes
INPUT6		EQU	G_ENDRAM-$4	; pointer to parameter 6 for GPU
INPUT5		EQU	INPUT6-$4	; pointer to parameter 5 for GPU
INPUT4		EQU	INPUT5-$4	; pointer to parameter 4 for GPU
INPUT3		EQU	INPUT4-$4	; pointer to parameter 3 for GPU
INPUT2		EQU	INPUT3-$4	; pointer to parameter 2 for GPU
INPUT1		EQU	INPUT2-$4	; pointer to parameter 1 for GPU

;*******************************************************************************
;* SUBROUTINE AREA							       *
;*******************************************************************************

	.text

;*=============================================================================*
;* MAIN		- main game play handler loop				       *
;*=============================================================================*

_main:
	move.l	#DISPBUF0+15,d0		; set up screen buffers with
	and.l	#~15,d0			; draw_ptr on a 256 byte boundary
	move.l	d0,draw_ptr
	addq.l	#8,d0
	move.l	d0,disp_ptr

	jsr	initurtl		; initialize turtles

	moveq.l	#0,d0
	moveq.l	#-1,d1

	move.w	d0,gameover		; game not over yet
	move.l	d1,pad_now		; clear the joypad
	move.w	d0,ncubes		; initially 1 number of cubes

	move.w	d0,rotate_flg
	move.w	d1,amb_flg
	move.w	d1,sun_flg
	move.w	d1,bulb_flg

	move.w	d0,scrublist		; scrublist = Nil
	move.w	#1,drawlist		; one object

framelp:
	move.l	#$FFFFFFFF,PIT0		; initialise the programmable timer 0

	jsr	clrscreen		; clear the draw buffer
	jsr	do_sort			; sort the face list

	lea	TXTCRY_S,a0		; load Polyhedron Draw Routine into GPU RAM
	lea	text3D,a1
	move.l	#TXTCRY_E,d0
	sub.l	#TXTCRY_S,d0
	jsr	gpuload

	move.l	PIT0,time1		; get the timer 0 position

	move.w	drawlist,newlist
drawlp:	move.w	newlist,d0		; while (drawlist <> nil) do draw object
	beq.s	.drawxit

	move.w	d0,d1
	mulu	#turtlsiz,d0
	add.l	#turtle,d0		; D0 = pointer to turtle
	move.l	d0,a0
	move.w	turtlnk(a0),newlist
	cmp.w	#0,zposn(a0)		; check the z of the turtle
	blt.s	drawlp

	lea	turtle+turtlsiz,a1
	move.l	(a1)+,(a0)+		; cheat rotation by copying from one cube
	move.l	(a1)+,(a0)+
	move.l	(a1)+,(a0)+
	move.l	(a1)+,(a0)+
	move.w	(a1)+,(a0)+

	move.l	#cubedata,model_ptr	; point to the appropriate model

	jsr	gpuwait			; wait for GPU Idle
	jsr	do_fastdraw		; start GPU/BLTTER Polyhedron Draw
	bra.s	drawlp

.drawxit:
	jsr	readpad			; read the Joypad
	jsr	gpuwait			; wait for GPU Idle
	
	move.l	PIT0,time2		; get the timer 0 position

	move.l	disp_ptr,d0		; swap screen buffers
	move.l	draw_ptr,disp_ptr
	move.l	d0,draw_ptr

	lea	objData,a1		; and modify the screen object
	move.l	disp_ptr,O_DATA(a1)
	clr.l	d6
	move.w	lastObj,d6
	add.w	#1,d6
	jsr	BuildObjList		; build the new object list

	jsr	input			; interpret the joypad input

	move.l	framecnt,d7		; d7 = current frame for sync later
.wsync:	cmp.l	framecnt,d7
	beq	.wsync			; wait for video sync

timecheck:
	move.l	PIT0,time3		; get the timer 0 position

.gameovr:
	move	gameover,d0		; check if game over flag set
	beq	framelp			; no, continue screen refresh

stop:	illegal				; exit to rdb
	rts

;*=============================================================================*
;* INPUT	- Interpret Joypad results and act accordingly		       *
;*									       *
;* Given:								       *
;*	PAD_NOW  = Current Joypad reading				       *
;*	PAD_SHOT = One-Shot Joypad					       *
;*									       *
;* Returns:								       *
;*	Input handled							       *
;*									       *
;* Register Usage:							       *
;*	All Registers Restored						       *
;*									       *
;* NOTE:  SHOULD CONVERT TO THE GPU					       *
;*=============================================================================*

input:
	movem.l	d0-d7/a0-a1,-(sp)

;****************************************
;* Load Turtle Package into GPU		*
;****************************************

	lea	TURTLE_S,a0
	lea	turtpak,a1
	move.l	#TURTLE_E,d0
	sub.l	#TURTLE_S,d0
	jsr	gpuload

;****************************************
;* Handle View Point Rotation and	*
;* Translation using Joypad		*
;****************************************

	move.l	pad_now,d0
	move.w	#0,d1			; PITCH
	move.w	#0,d2			; YAW
	move.w	#0,d3			; ROLL
	move.w	#0,d4			; VELOCITY

.chk_U:	btst.l	#JOY_UP,d0
	beq.s	.no_U
	addq.w	#4,d1			; PITCH Down
.no_U:

.chk_D:	btst.l	#JOY_DOWN,d0
	beq.s	.no_D
	subq.w	#4,d1			; PITCH Up
.no_D:

.chk_L:	btst.l	#JOY_LEFT,d0
	beq.s	.no_L
	addq.w	#4,d2			; YAW Left
.no_L:

.chk_R:	btst.l	#JOY_RIGHT,d0
	beq.s	.no_R
	subq.w	#4,d2			; YAW Right
.no_R:

.chk_1:	btst.l	#KEY_1,d0
	beq.s	.no_1
	addq.w	#4,d3			; ROLL CounterClockwise
.no_1:

.chk_3:	btst.l	#KEY_3,d0
	beq.s	.no_3
	subq.w	#4,d3			; ROLL Clockwise
.no_3:

.chk_A:	btst.l	#FIRE_A,d0
	beq.s	.no_A
	addq.w	#4,d4			; FORWARD
.no_A:

.chk_B:	btst.l	#FIRE_B,d0
	beq.s	.no_B
	subq.w	#4,d4			; REVERSE
.no_B:

.chk_C:	btst.l	#FIRE_C,d0
	beq.s	.no_C
	add.w	#20,d4			; FAST FORWARD
.no_C:

	moveq.l	#0,d0			; call TURTLE package for necessary
	jsr	do_turtle		; view point rotation and translations

;****************************************
;* Light Source Toggle and Intensity	*
;****************************************

	move.l	pad_shot,d0

.chk_4:	btst.l	#KEY_4,d0
	beq.s	.no_4
	eor.w	#-1,sun_flg		; Toggle Sun On/Off
.no_4:

.chk_6:	btst.l	#KEY_6,d0
	beq.s	.no_6
	eor.w	#-1,bulb_flg		; Toggle InScene On/Off
.no_6:

.chk_5:	btst.l	#KEY_5,d0
	beq.s	.no_5
	eor.w	#-1,amb_flg		; Toggle Ambient On/Off
.no_5:

;****************************************
;* INTENSITY				*
;****************************************

	move.l	pad_now,d0
	move.b	#0,d2

chk_7:	btst.l	#KEY_7,d0
	beq.s	.no_7
	addq.b	#1,d2			; Increase Intensity

; since intensity isn't used in this
; version, overload this key

	cmp.w	#-160,stretch
	ble.s	.skipstm
	subq.w	#2,stretch
.skipstm:
.no_7:

.chk_9:	btst.l	#KEY_9,d0
	beq.s	.no_9
	subq.b	#1,d2			; Decrease Intensity

; since intensity isn't used in this
; version, overload this key

	cmp.w	#0,stretch
	bge.s	.skipst
	addq.w	#2,stretch
.skipst:
.no_9:

;****************************************
;* and build lighting model		*
;****************************************

	lea	litemodel,a0

.amb:	move.w	amb_flg,d0		; if (Ambient On) then alter ambient intensity
	beq	.noamb
	add.b	d2,ambient+1
.noamb:
	move.w	ambient,(a0)+

.sun:	move.w	sun_flg,d0
	beq	.nosun
	add.b	d2,sun+1		; if (Sun On) then update intensity and add sun
	lea	sun,a1
	move.l	(a1)+,(a0)+
	move.l	(a1)+,(a0)+
.nosun:

.blb:	move.w	bulb_flg,d0
	beq.s	.noblb
	add.b	d2,bulb+1		; if (Bulb On) then update intensity and add bulb
	lea	bulb,a1
	move.l	(a1)+,(a0)+
	move.l	(a1)+,(a0)+
.noblb:
	move.w	#0,(a0)+		; end of lighting model list

;****************************************
;* Number of CUBES			*
;****************************************

	move.l	pad_shot,d0
	move.w	#0,d2
.chk_S:
	btst.l	#KEY_STAR,d0
	beq.s	.no_S
	addq.w	#1,d2			; more cubes
.no_S:

.chk_H:	btst.l	#KEY_HASH,d0
	beq.s	.no_H
	subq.w	#1,d2			; fewer cubes
.no_H:
	tst.w	d2			; any change in number of cubes
	beq	.same			; no change in number of cubes

	add.w	ncubes,d2		; update number of cubes
	and.w	#$F,d2			; a maximum of 16 cubes
	move.w	d2,ncubes		; save number of cubes

.bldcube:
	lea	turtle+turtlsiz,a0	; address of first turtle

	move.w	d2,d4			; number of turtles
	beq.s	.noexp

	ext.l	d2
	add.l	#1,d2
	move.l	d2,nturtles		; number of turtles
.noexp:
	move.w	#0,drawlist
	move.w	#0,scrublist

	move.w	#0,d1
	move.w	#0,d2
	move.w	#0,d3

	move.w	#1,d7
.loop:
	move.w	d1,xposn(a0)		; Initialize a Cube
	move.w	d2,yposn(a0)
	move.w	d3,zposn(a0)

	move.w	drawlist,turtlnk(a0)
	move.w	d7,drawlist		; Link to DRAWLIST

	addq.w	#1,d7
	adda.l	#turtlsiz,a0

	add.w	#$200,d2
	dbra	d4,.loop		; All X
.same:

;****************************************
;* CUBE Rotation and Propogation	*
;****************************************

	move.l	pad_shot,d0

.chk_8: btst.l	#KEY_8,d0
	beq.s	.no_8
	eor.w	#-1,rotate_flg
.no_8:
	move.w	rotate_flg,d1
	beq.s	.done

	moveq	#1,d0			; turtle index
	moveq	#6,d1			; pitch
	moveq	#6,d2			; yaw
	moveq	#6,d3			; roll
	moveq	#0,d4			; velocity
	jsr	do_turtle		; Cube Rotation
.done:

;****************************************
;* IF QUIT				*
;****************************************

	move.l	pad_shot,d0

chk_0:	btst.l	#KEY_0,d0
	beq.s	.no_0
	move.w	#-1,gameover		; quit
.no_0:

	movem.l	(sp)+,d0-d7/a0-a1
	rts

;*******************************************************************************
;*******************************************************************************
;*******************************************************************************
;*******************************************************************************

;*=============================================================================*
;* INITURTL	- Initialize the TURTLE database			       *
;*									       *
;* Given:								       *
;*	Control								       *
;*									       *
;* Returns:								       *
;*	All Turtles initialized to Origin				       *
;*									       *
;* Register Usage:							       *
;*	All Registers Restored						       *
;*									       *
;*=============================================================================*

initurtl:
	movem.l	d0-d2/a0,-(sp)

	move.l	#0,nturtles
	move.w	#0,stretch

	lea	turtle,a0
	clr	d0
	move	#$4000,d1

	move	#maxturtl-1,d2
.clrlp:	move	d1,xrite(a0)		; FOR (All Turtles) DO
	move	d0,yrite(a0)		; init to origin - ordirnally aligned
	move	d0,zrite(a0)
	move	d0,xdown(a0)
	move	d1,ydown(a0)
	move	d0,zdown(a0)
	move	d0,xhead(a0)
	move	d0,yhead(a0)
	move	d1,zhead(a0)
	move	d0,xposn(a0)
	move	d0,yposn(a0)
	move	d0,zposn(a0)
	move	d0,turtlnk(a0)
	add.l	#turtlsiz,a0
	dbra	d2,.clrlp

	lea	turtle,a0
	move	#$fe00,zposn(a0)	; position viewpt in front of object

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

;*=============================================================================*
;* CLRSCREEN   BLTTER Zero fill the draw buffer and Zbuffer		       *
;*									       *
;* Given:								       *
;*	DRAW_PTR = Ptr to Current draw buffer				       *
;*									       *
;* Returns:								       *
;*	Draw buffer and Zbuffer zeroed					       *
;*									       *
;* Register Usage:							       *
;*	All Registers Restored						       *
;*									       *
;*=============================================================================*

clrscreen:
	movem.l	d0/a0,-(sp)		; save registers

	moveq.l	#0,d0
	move.l	draw_ptr,a0
	jsr	clrbuffer

	movem.l	(sp)+,a0/d0		; restore registers
	rts

;*=============================================================================*
;* CLRBUFFER	- BLTTER Zero fill a 320x200x2 screen buffer		       *
;*									       *
;* Given:								       *
;*	D0 = Data Pattern to fill with					       *
;*	A0 = Ptr to Buffer to Clear					       *
;*									       *
;* Returns:								       *
;*	Draw buffer zeroed						       *
;*									       *
;* Register Usage:							       *
;*	All Registers Restored						       *
;*									       *
;*=============================================================================*

clrbuffer:
	movem.l	d0-d1/a0-a1,-(sp)	; save registers

	move.l	#B_CMD,a1		; wait for BLTTER Idle
.wtblt:	move.l	(a1),d1
	lsr.w	#1,d1
	bcc	.wtblt

 	move.l	#(PITCH2|PIXEL16|WID320|XADDPHR),A1_FLAGS
	move.l	a0,A1_BASE		; point to the buffer

	move.l	d0,B_PATD
	move.l	d0,B_PATD+4		; select fill pattern

	clr.l	d0
	move.l	d0,A1_PIXEL		; point to (0,0)

	move.w	#1,d0
	swap	d0
	move.w	#-320,d0
	move.l	d0,A1_STEP		; step -320 x, +1 y each line

	move.w	#200,d0
	swap	d0
	move.w	#320,d0
	move.l	d0,B_COUNT		; do 320x200

	move.l	#(PATDSEL|UPDA1),B_CMD	; start the BLTTER

	movem.l	(sp)+,d0-d1/a0-a1	; restore registers
	rts

;*=============================================================================*
;* DO_TURTLE	- Execute the turtle package				       *
;*									       *
;* Given:								       *
;*	d0 = Index of Turtle to Operate on				       *
;*	d1 = PITCH							       *
;*	d2 = YAW							       *
;*	d3 = ROLL							       *
;*	d4 = VELOCITY							       *
;*									       *
;* Returns:								       *
;*	Turtle updated							       *
;*									       *
;* Register Usage:							       *
;*	All Registers Restored						       *
;*									       *
;*=============================================================================*

do_turtle:
	movem.l	a0/d0-d4,-(sp)		; save registers

	jsr	gpuwait			; wait for GPU to stop

	mulu	#turtlsiz,d0
	add.l	#turtle,d0		; d0 = address of turtle record
	move.l	d0,INPUT1		; turtle pointer
	move.l	d1,INPUT2		; pitch
	move.l	d2,INPUT3		; yaw
	move.l	d3,INPUT4		; roll
	move.l	d4,INPUT5		; velocity

	lea	TURTLE_S,a0		; run the turtle oackage
	jsr	gpurun			; in the GPU

	movem.l	(sp)+,a0/d0-d4		; restore registers
	rts

;*=============================================================================*
;* DO_FASTDRAW	- Execute the Polyhedron Draw package			       *
;*									       *
;* Given:								       *
;*	D0 = Ptr to Turtle to Draw					       *
;*									       *
;* Returns:								       *
;*	Object Drawn							       *
;*									       *
;* Register Usage:							       *
;*	All Registers Restored						       *
;*									       *
;*=============================================================================*

do_fastdraw:
	movem.l	a0/d0,-(sp)		; save registers

	jsr	gpuwait			; wait for GPU to stop

	move.l	d0,INPUT3		; pass pointer to viewed object
	move.l	model_ptr,INPUT1	; pointer to instance
	move.l	#turtle,INPUT2		; turtle[0] is viewer
	move.l	#litemodel,INPUT4	; pointer to lighting model
	move.l	draw_ptr,INPUT5		; tell GPU where to find parameters
	move.l	#instance,INPUT6	; use for vertex copies

	lea	TXTCRY_S,a0		; run the polyhedron draw
	jsr	gpurun			; package in the GPU

	movem.l	(sp)+,a0/d0		; restore registers
	rts

;*=============================================================================*
;* DO_SORT	- Execute GPU Bubble Sort				       *
;*									       *
;* Given:								       *
;*	DRAWLIST  = Last Frame's Sorted See-ables (Inverted, Please)	       *
;*	SCRUBLIST = Last Frame's UNSee-ables				       *
;*	NTURTLES  = Number of Active Turtles				       *
;*	TURTLE    = Turtle Record Array					       *
;*									       *
;* Returns:								       *
;*	DRAWLIST  = Painter's Sorted See-ables list root index		       *
;*	SCRUBLIST =  UNSee-ables list root index			       *
;*									       *
;* Register Usage:							       *
;*	All Registers Restored						       *
;*									       *
;* Externals:								       *
;*	GPURUN, GPULOAD							       *
;*									       *
;*=============================================================================*

do_sort:
	movem.l	a0/d0-d1,-(sp)		; save registers

	jsr	gpuwait			; wait for GPU to stop

	lea	SORT_S,a0		; load the polyhedron sort 
	lea	bsort,a1		; routine in GPU RAM
	move.l	#SORT_E,d0
	sub.l	#SORT_S,d0
	jsr	gpuload

	move.l	#turtle,INPUT1		; address of viewpt record
	move.l	#drawlist,INPUT2	; address of drawlist root
	move.l	#scrublist,INPUT3	; address of scrublist root
	move.l	#turtle+turtlsiz,INPUT4	; address of turtle[1]
	move.l	nturtles,d0
	beq	skipsort
	move.l	d0,INPUT5		; number of active turtles
	move.l	#turtlsiz,d0
	move.l	d0,INPUT6		; length of a turtle record
   
	lea	SORT_S,a0		; run the polyhedron sort
	jsr	gpurun			; routine in GPU

skipsort:
	movem.l	(sp)+,d0-d1/a0		; restore registers
	rts

;*******************************************************************************
;* LOCAL RAM								       *
;*******************************************************************************

	.bss

;*=============================================================================*
;*=============================================================================*

		.phrase

disp_ptr:	.ds.l	1		; Display buffer ptr
draw_ptr:	.ds.l	1		; Draw buffer ptr
zbuf_ptr:	.ds.l	1		; Z buffer ptr

drawlist:	.ds.w	1		; Root (Index really) to List of See-able turtles
scrublist:	.ds.w	1		; Root (Index really) to List of UNSee-able turtles
newlist:	.ds.w	1

model_ptr:	.ds.l	1		; Ptr to Instance

		.phrase

instance:	.ds.l	4*2048		; Storage for INSTANCE (32K Bytes)

		.phrase

litemodel:	.ds.w	12		; Lighting Model (Enough for Ambient and 2 sources)

		.phrase

gameover:	.ds.w	1		; Game Over Flag (0 ==> Game Active)
rotate_flg:	.ds.w	1		; Cube rotation Flag (0 ==> Sit Still)
sun_flg:	.ds.w	1		; Sun Lighting Flag (0 ==> No Sun)
bulb_flg:	.ds.w	1		; InScene Lighting Flag (0 ==> No Bulb)
amb_flg:	.ds.w	1		; Ambient Lighting Flag (0 ==> No Intensity Change)

nturtles:	.ds.l	1		; Number of turtles in space

ncubes:		.ds.w	1		; Number of Cubes in space (Less One)
stretch:	.ds.w	1		; stretch factor to modify the cube

;*======================================*
;* TURTLE RECORDS			*
;*======================================*

xrite	=	0			; IMPORTANT NOTE:
yrite	=	xrite+2			; These first record offsets are hard-wired
zrite	=	yrite+2			; into associated GPU routines.
xdown	=	zrite+2			; DO NOT Insert, Delete or Swap any of these
ydown	=	xdown+2			;	^
zdown	=	ydown+2			;	|
xhead	=	zdown+2			;	|
yhead	=	xhead+2			;	|
zhead	=	yhead+2			;	|
xposn	=	zhead+2			;	|
yposn	=	xposn+2			;	|
zposn	=	yposn+2			;	v
turtlnk =	zposn+2			; Dont change this or anything above here
turtlsiz =	turtlnk+2
maxturtl =	1400

		.phrase

turtle:		.ds.b	maxturtl*turtlsiz ; All Motion Objects

		.phrase

time1:		.ds.l	1		; to calculate time for
time2:		.ds.l	1		; processing different parts
time3:		.ds.l	1		; of the program
time4:		.ds.l	1

;*******************************************************************************
;* CONSTANT DATA							       *
;*******************************************************************************

	.data

;*=============================================================================*
;*=============================================================================*

		.phrase

ambient:	.dc.w	$0080		; Ambient Intensity
	
bulb:		.dc.w	$00FF		; Intensity (InScene Light)
		.dc.w	$f000		; X
		.dc.w	$f000		; Y
		.dc.w	$f000		; Z

sun:		.dc.w	$00ff		; Intensity (Sun)
		.dc.w	$4000		; X
		.dc.w	$0000		; Y
		.dc.w	$0000		; Z

		.phrase

;*******************************************************************************
;* END OF FILE								       *
;*******************************************************************************

	.end

