* RotShape.s - rotating 3D shape demo

::
	ClrDA1IsStat			( suspend clock		)
	RECLAIMDISP				( Clear the screen  )
	TURNMENUOFF				( and get menu gone )

CODE

shapeNum	EQU	15

	GOSBVL	=SAVPTR			* Save internal pointers
	GOSBVL	=DisableIntr	* turn off interrupts
	GOSUB	WaitKeyUp		* Wait for user to let up on key

* clear annunciator
	D1=(5)	=ANNCTRL		* bits 0-5 are the symbols
	A=0		B				* zero them out
	DAT1=A	B			

	GOSUB	LoadData		* jump data space, getting address on stack
* data area	
data BSS	5				* 5 nibbles stores local data

LoadData
	C=RSTK					* the pointer to the data area
	D0=C	A
	R4=C	A				* address to data area, save throughout program

	A=0		A				* 
	DAT0=A	A				* clear this out - will be frame counter

	GOSBVL	=D0->Row1		* D0,A[A]->Top left corner of display
	ASL		W				* move up 5 nibbles
	ASL		W				* move up 5 nibbles
	ASL		W				* move up 5 nibbles
	ASL		W				* move up 5 nibbles
	ASL		W				* move up 5 nibbles
	R0=A	W				* globally save surface address in R0[5-9]
	GOSUBL	LoadFrameBuffer	* get the surface we draw to
	R0=C.F	A				* and store in R0[0-4]

	IF		0				* debugging code - loop till debugger sets A
	A=0		B
-	?A=0	B				
	GOYES	-
	ENDIF

* throughout this loop R0(buffer,screen) and R4(local data) must be left unchanged, everything else can be changed
MainLoop

	GOSUB	IncFrameCount	* inc frame count, return in A

	ASR		A				* div by 128, new shape number
	ASRB	A				
	ASRB	A				
	ASRB	A				

	GOSUBL	LoadShape		* get C[A] address of shape
	D0=C	A				* save here
	GOSUB	LoadShapeBuffer	* get C[A] address buffer for data
	R3=C	A				* save dest pointer for later
	D1=C	A				* save here for memcpy

	A=0		A				* zero out
	A=DAT0	B				* number of lines to draw
	D0=D0+	2				* point to line indices
	ASL		A				* each line is 8 nibbles ( 4 bytes)
	ASRB.F	A
	CD0EX	A				* the address
	C=C+A	A				* point to coord data
	D0=C	A
	A=0		A
	A=DAT0	B				* number of coords to copy/rotate
	C=A		A
	D=C		A				* backup here for later
	D0=D0+	2				* point to coord data, each 3 bytes, or 6 nibbles
	A=A+A	A
	C=A		A				* 2 times the value
	A=A+A	A				* 4 times
	A=A+C	A				* 6 times the value, so copy away!
	GOSUB	memcpy

	C=R3	A				* modified points buffer
	D1=C	A				* the points to rotate

	GOSUB	GetFrameCount	* get frame count in A[A]
	GOSUB	CreateAngles	* angles are 3*count, 2*count, 4*count into R2, uses A,B,C,R2

* prepare the scaling....
	GOSUB	GetFrameCount	* get frame count in A[A]
	A=A+A	B				* faster angle....
	GOSUB	SinCos			* get sin, cos of angle in A[B]
	A=C		B				* use cosine, and negate it
	A=-A	B				
	ASRB.F	B				* divide by 2
	?ABIT=0	6				* was pos, leave alone
	GOYES	+
	ABIT=1	7				* extend negative
+
	LC(2)	64				* value 1/2 in 1.7 fixed point
	A=A+C	B				* add it....

	C=D		A				* number of points to rotate
	GOSUBL	ScalePoints3D	* scale the points - (A,B,D)[W], D0, R1,R3
	GOSUBL	RotateShape3D	* rotate the shape - alters (A,B,C,D)[W], D0, D1, R1, R2[X], R3

* prepare screen transformation to apply this round
	GOSUB	GetFrameCount	* get the counter...
	C=A		B
	A=A+A	B				* double angle
	A=A+C	B				* triple angle
	GOSUB	SinCos			* get sin into A[B]
	C=0		A				* and then mult by 32 and add 64 for x offset
	C=-C-1	B
	A=A&C	A				* clear out
	?ABIT=0	7				* is positive?
	GOYES	+
	C=-C-1	A				* C=fff00
	A=A!C	A				* extend neg sign
+	ASRB.F	A				* to mult by 32, already FP 1.7, so shift 2 places
	ASRB.F	A
	LC(2)	64
	A=A+C	B				* the x offset
	ASL		X
	ASL		A				* x in position
	LC(2)	32				* the y offset always 32
	A=C		B				* set it
	LC(2)	128				* 128 scale = no scaling
	B=C		B	
	GOSUBL	SetScreenTrans	* and set it : alters A,C

	C=R0	A				* get screen area
	D0=C	A				* into D0
	GOSUB	ClearImage		* erase all- alters A,C,D0

	GOSUB	LoadShapeBuffer	* get C[A] address buffer for coords
	R1=C					* save here, for drawing lines

	GOSUB	GetFrameCount	* get the counter...
	ASR		A				* div by 128, new shape number
	ASRB	A				
	ASRB	A				
	ASRB	A				

	GOSUBL	LoadShape		* get C[A] address of shape
	D0=C	A				* pointer to line info
	
	GOSUBL	DrawShape3D		* and draw it - leaves R0,R4 untouched
	GOSUBL	FlipFrameBuffer	* flip the double buffer to screen	

checkkey
* read the keyboard
	LC(3)	#1FF			* load keyboard rows
	OUT=C					* set the out register (todo - bug? need even aligned? call routine?)
	GOSBVL	=CINRTN			* read in register
	LA(5)	#803F			* all key mask
	A=A&C	A
	?A#0	A
	GOYES	exit			* and keep going till keypress
	GOTO	MainLoop
exit
	GOSUB	WaitKeyUp       *
	GOSUBL	RestoreScreen	* restore the address of the display
	GOSBVL	=AllowIntr      * restore interrupts
	GOVLNG	=GETPTRLOOP     * and exit program

* wait here till no keys down
* modifies A[5], C[3], more?
WaitKeyUp
	LC(3)	#1FF
	OUT=C
	GOSBVL	=CINRTN
	LA(5)	#803F
	A=A&C	A
	?A#0	A
	GOYES	WaitKeyUp
	RTN

* given angle in A[B], fill R2 with three angles, 2A,3A,4A - uses A,B,C,R2
CreateAngles	
	C=A		B				* the low byte of frame count
	A=A+C	B
	B=A		B				* 2 times
	A=A+C	B				* 3 times
	C=C+A	B				* 4 times
	CSL		X
	CSL		A
	C=A		B				* store more values....
	CSL		W
	CSL		W
	C=B		B				* now LSB= 3*frame, 2*frame, 4*frame
	R2=C	W				* low 3 bytes are angles to rotate shape
	RTN


* returns frame count into A[A] - modifies D0, A[A]
* todo - base it on an internal timer? =TIMER1
GetFrameCount
	A=R4	A				* local data pointer
	D0=A	A				* point to 5 nib frame count
	A=DAT0	A				* read it
	RTN

* increment frame count - modifies D0, A[A], returns count in A[A]
IncFrameCount
	A=R4	A				* local data pointer
	D0=A	A				* point to 5 nib frame count
	A=DAT0	A				* read it
	A=A+1	A				* increment
	DAT0=A	A				* save it back

	RTN

* include files here
	INCLUDE SinCos.s
	INCLUDE DrawLine.s
	INCLUDE Rot2D.s
	INCLUDE Misc.s
	INCLUDE Shape.s
	INCLUDE Shape3D.s
	INCLUDE FrameBuffer.s
	
* the shapes we support	
	INCLUDE CubeLoad.s
	INCLUDE TetraLoad.s
	INCLUDE OctaLoad.s
	INCLUDE IcosaLoad.s
	INCLUDE DodecaLoad.s
	INCLUDE MiscShape.s

ENDCODE
	RECLAIMDISP				( clear display )
	TURNMENUOFF				( and get menu gone )

	"    By Chris Lomont"	( final text output )
	DISPROW3
	"         2001"
	DISPROW4
	"    www.lomont.org"
	DISPROW5
	ZERO UNCOERCE		    ( make a zero on stack for WAIT - keypress...)
	xWAIT					( wait till key pressed )
	ClrDAsOK				( restore screen and exit)
	DROP					( drop last keypress )
;


* end RotShape.s


