#include <sps2lib.h>
#include <sps2tags.h>
#include <sps2util.h>
#include <sps2regstructs.h>
#include "PS2Defines.h"
#include "ps2matrix4x4.h"
#include "sps2wrap.h"
#include "dma.h"
#include "entities.h"

// Initialise static member
int Cube::iStaticAddr = 0;

Cube::Cube()
{
	// Initialise some default vaules
	World = Matrix4x4::IDENTITY;
	WVP = Matrix4x4::IDENTITY;
	WorldLoaded = false;
	LoadCubeData();
}

Cube::~Cube()
{
	// Nothing to destruct
}

// Load the world matrix
void Cube::SetWorldMatrix(const Matrix4x4 & matWorld)
{
	World = matWorld;
	WVP = World * Pipeline.GetViewProjection();
	WorldLoaded = true;
}

// Load the cube data into static DMA memory
void Cube::LoadCubeData(void)
{
	// Check if data already loaded - return if it is.
	// We only need the cube data loaded once.
	if(Cube::iStaticAddr)return;
	
	const int iDraw = 0;
	const int iDontDraw = 1;
		
	const float fDraw = *((float *)&iDraw);
	const float fDontDraw = *((float *)&iDontDraw);
		
	printf("Loading Cube Data\n");
	
	// Get the address of static data that we can call to later.
	Cube::iStaticAddr = VIFStaticDMA.GetPointer();
	
	VIFStaticDMA.Add32(FLUSH);			// Make sure VU1 isn't busy
	VIFStaticDMA.Add32(STCYCL(1,1));	// Unpack linearly, i.e. don't skip any spaces
	VIFStaticDMA.Add32(BASE(32));		// The double buffers start at VU1 address 32 (giving us 32 QW to store data that won't change)
	VIFStaticDMA.Add32(OFFSET(496));	// The size of each buffer.

	VIFStaticDMA.AddUnpack(V4_32, 0, 1);	// Unpack 1QW - the scale vector
	VIFStaticDMA.AddVector(Pipeline.GetScaleVector());
	

	// The first face draws two triangle
	// Next faces draw four triangles
	// Five triangles needed for last face
	// Some triangles are "zero" area and will be culled by GS
	int iTriangles = 2 + (4 * 4) + 5;
	int iVerts = iTriangles + 2;
	
	// We want to unpack 3 quad words of misc data, and then 3QW per vertex starting at
	// VU mem location 32 (we will upload the matrices to the first 16QW per frame).
	VIFStaticDMA.AddUnpack(V4_32, 0, 2 + iVerts * 3, 1);
	
	// VU32 iVerts is in position "x" LSWord of the qword
	VIFStaticDMA.Add128(iVerts*3);
	
	// Add the GIFTag VU33
	VIFStaticDMA.Add128(GS_GIFTAG_BATCH(	iVerts,						// NLOOP
	 										1,							// EOP
	 										1,							// PRE
	 										GS_PRIM(PRIM_TRI_STRIP, 	// PRIM
													PRIM_IIP_GOURAUD, 
													PRIM_TME_ON,
													PRIM_FGE_OFF, 
													PRIM_ABE_ON, 
													PRIM_AA1_OFF, 
													PRIM_FST_STQ, 
													PRIM_CTXT_CONTEXT1, 
													PRIM_FIX_NOFIXDDA),					
	 										GIF_FLG_PACKED,				// FLG
	 										GS_BATCH_3(	GIF_REG_ST,
	 													GIF_REG_RGBAQ, 	// BATCH
	 													GIF_REG_XYZ2)));

	
	// Front face
	VIFStaticDMA.AddVector(Vector4( 0, 0, 1, fDraw));   		// STQ - 1
	VIFStaticDMA.AddVector(Vector4( 0, 0, 1, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1, 1, 1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 0, 1, 1, fDraw));   		// STQ - 2
	VIFStaticDMA.AddVector(Vector4( 0, 0, 1, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1,-1, 1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 1, 0, 1, fDraw));   		// STQ - 3
	VIFStaticDMA.AddVector(Vector4( 0, 0, 1, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4( 1, 1, 1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 1, 1, 1, fDraw));  			// STQ - 4
	VIFStaticDMA.AddVector(Vector4( 0, 0, 1, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4( 1,-1, 1, 1));				// Vert

	// Right face
	VIFStaticDMA.AddVector(Vector4( 1, 0, 1, fDontDraw));   	// STQ - 5
	VIFStaticDMA.AddVector(Vector4( 1, 0, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4( 1, 1, 1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 1, 1, 1, fDontDraw));   	// STQ - 6
	VIFStaticDMA.AddVector(Vector4( 1, 0, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4( 1,-1, 1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 2, 0, 1, fDraw));   		// STQ - 7
	VIFStaticDMA.AddVector(Vector4( 1, 0, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4( 1, 1,-1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 2, 1, 1, fDraw));   		// STQ - 8
	VIFStaticDMA.AddVector(Vector4( 1, 0, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4( 1,-1,-1, 1));				// Vert

	// Back face
	VIFStaticDMA.AddVector(Vector4( 2, 0, 1, fDontDraw));   	// STQ - 9
	VIFStaticDMA.AddVector(Vector4( 0, 0,-1, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4( 1, 1,-1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 2, 1, 1, fDontDraw));   	// STQ - 10
	VIFStaticDMA.AddVector(Vector4( 0, 0,-1, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4( 1,-1,-1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 3, 0, 1, fDraw));   		// STQ - 11
	VIFStaticDMA.AddVector(Vector4( 0, 0,-1, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1, 1,-1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 3, 1, 1, fDraw));   		// STQ - 12
	VIFStaticDMA.AddVector(Vector4( 0, 0,-1, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1,-1,-1, 1));				// Vert

	// Left face
	VIFStaticDMA.AddVector(Vector4( 3, 0, 1, fDontDraw));   	// STQ - 13
	VIFStaticDMA.AddVector(Vector4(-1, 0, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1, 1,-1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 3, 1, 1, fDontDraw));   	// STQ - 14
	VIFStaticDMA.AddVector(Vector4(-1, 0, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1,-1,-1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 4, 0, 1, fDraw));   		// STQ - 15
	VIFStaticDMA.AddVector(Vector4(-1, 0, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1, 1, 1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 4, 1, 1, fDraw));   		// STQ - 16
	VIFStaticDMA.AddVector(Vector4(-1, 0, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1,-1, 1, 1));				// Vert
	
	
	// Bottom face
	VIFStaticDMA.AddVector(Vector4( 1, 0, 1, fDontDraw));   	// STQ - 17
	VIFStaticDMA.AddVector(Vector4( 0,-1, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4( 1,-1, 1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 0, 0, 1, fDontDraw));   	// STQ - 18
	VIFStaticDMA.AddVector(Vector4( 0,-1, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1,-1, 1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 1, 1, 1, fDraw));   		// STQ - 19
	VIFStaticDMA.AddVector(Vector4( 0,-1, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4( 1,-1,-1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 0, 1, 1, fDraw));   		// STQ - 20
	VIFStaticDMA.AddVector(Vector4( 0,-1, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1,-1,-1, 1));				// Vert
	
	// Top face
	VIFStaticDMA.AddVector(Vector4( 0, 0, 1, fDontDraw));   	// STQ - 21
	VIFStaticDMA.AddVector(Vector4( 0, 1, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1, 1,-1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 1, 0, 1, fDontDraw));   	// STQ - 22
	VIFStaticDMA.AddVector(Vector4( 0, 1, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4( 1, 1,-1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 0, 0, 1, fDontDraw));     	// STQ - 23
	VIFStaticDMA.AddVector(Vector4( 0, 1, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1, 1,-1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 1, 1, 1, fDraw));   		// STQ - 24
	VIFStaticDMA.AddVector(Vector4( 0, 1, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4( 1, 1, 1, 1));				// Vert
	VIFStaticDMA.AddVector(Vector4( 0, 1, 1, fDraw));   		// STQ - 25
	VIFStaticDMA.AddVector(Vector4( 0, 1, 0, 0));				// Normal
	VIFStaticDMA.AddVector(Vector4(-1, 1, 1, 1));				// Vert
	
	
	// Flush to make sure VU1 isn't doing anything.
	VIFStaticDMA.Add32(FLUSH);
	// Then run the microcode.
	VIFStaticDMA.Add32(MSCALL(0));

	// Return back to the dynamic chain (note that we aren't aligned on a QWORD boundary, but
	// it doesn't matter because the packet class will sort that out for us).
	VIFStaticDMA.DMARet();
}
	

// Render the cube.
void Cube::Render(void) const
{
	// check world matrix has been loaded (at least once!)
	// and that the DMA data has been initialised
	// Bomb out if they havn't since something is wrong
	assert(WorldLoaded && (Cube::iStaticAddr));
	
	// Wait for all to be idle in VU1 land
	// Before uploading the data
	VIFDynamicDMA.Add32(FLUSH);
	
	// Upload the matrices in the dynamic buffer
	// because they can change every frame.
	VIFDynamicDMA.AddUnpack(V4_32, 1, 16);
	VIFDynamicDMA.AddMatrix(Pipeline.GetLightDirs());
	VIFDynamicDMA.AddMatrix(Pipeline.GetLightCols());
	VIFDynamicDMA.AddMatrix(WVP);
	VIFDynamicDMA.AddMatrix(World);
	VIFDynamicDMA.DMACall(Cube::iStaticAddr);
}


