//=============================================================================
//
// Copyright 1998 by Captivation Digital Laboratories, Inc.
// All Rights Reserved.
//
//=============================================================================
//
// "KRAD" -- Kamui Rendering/Animation Demonstration
//
// This file contains the main entry point of the KRAD program: kradmain()
//
// Different OS/Configuration use different primary entry points. Since the
// KRAD program is likely to be ported to different configuration in the near
// future, this file is kept separate from the real program entry point.
//
//=============================================================================
//-----------------------------------------------------------------------------
// $Revision: 12 $
// $NoKeywords: $
//=============================================================================

#include "krad.h"
#include "kamuipp.h"
#include "kppverts.h"
#include "globals.h"
#include "kalgebra.h"

//#define TEST_CKM

//=============================================================================
//=============================================================================	MODULE DEFINITIONS
//=============================================================================

//=============================================================================
//=============================================================================	MODULE VARIABLES
//=============================================================================

//=============================================================================
//=============================================================================	IMPLEMENATION OF <<< >>>
//=============================================================================












	KVContext myContext;

	//============================================================================= TestTree()
	//-----------------------------------------------------------------------------
	class TestThing : public SceneNode
	{
	public:
		KMVERTEX_00	Verts[16];
		kvector		points[8];
		int			mAge;
		int			mDepth;

		TestThing (NODE_DELETE_STYLE ndel, SceneNode* parent, float scale, kvector pos, int depth = 0, float xrot=0.0f, float yrot = 0.0f);
		virtual ~TestThing ();
		void	EvaluateState					(void);
		void	TransformAndRegisterTristrips	(kmatrix* m, NODE_LIST_BITS lbits);

	};
	//-----------------------------------------------------------------------------

	TestThing::TestThing (NODE_DELETE_STYLE ndel, SceneNode* parent, float scale, kvector pos, int depth, float xrot, float yrot)
		: SceneNode (ndel, parent)
	{
		points[0] = kvector (-scale, +scale, +2*scale);
		points[1] = kvector (+scale, +scale, +2*scale);
		points[2] = kvector (-scale, -scale, +2*scale);
		points[3] = kvector (+scale, -scale, +2*scale);
		points[4] = kvector (-scale, -scale,     0.0f);
		points[5] = kvector (+scale, -scale,     0.0f);
		points[6] = kvector (-scale, +scale,     0.0f);
		points[7] = kvector (+scale, +scale,     0.0f);

		Verts[0].ParamControlWord = Verts[ 8].ParamControlWord = KM_VERTEXPARAM_NORMAL;
		Verts[1].ParamControlWord = Verts[ 9].ParamControlWord = KM_VERTEXPARAM_NORMAL;
		Verts[2].ParamControlWord = Verts[10].ParamControlWord = KM_VERTEXPARAM_NORMAL;
		Verts[3].ParamControlWord = Verts[11].ParamControlWord = KM_VERTEXPARAM_NORMAL;
		Verts[4].ParamControlWord = Verts[12].ParamControlWord = KM_VERTEXPARAM_NORMAL;
		Verts[5].ParamControlWord = Verts[13].ParamControlWord = KM_VERTEXPARAM_NORMAL;
		Verts[6].ParamControlWord = Verts[14].ParamControlWord = KM_VERTEXPARAM_NORMAL;
		Verts[7].ParamControlWord = Verts[15].ParamControlWord = KM_VERTEXPARAM_ENDOFSTRIP;

		uint32 colormult = 0xff - (0x22 * depth);

		Verts[0].uBaseRGB.dwPacked = Verts[12].uBaseRGB.dwPacked = 0x00000101 * colormult;
		Verts[1].uBaseRGB.dwPacked = Verts[10].uBaseRGB.dwPacked = 0x00010101 * colormult;
		Verts[2].uBaseRGB.dwPacked = Verts[14].uBaseRGB.dwPacked = 0x00000001 * colormult;
		Verts[3].uBaseRGB.dwPacked = Verts[ 8].uBaseRGB.dwPacked = 0x00010001 * colormult;
		Verts[4].uBaseRGB.dwPacked = Verts[15].uBaseRGB.dwPacked = 0x00000000 * colormult;
		Verts[5].uBaseRGB.dwPacked = Verts[ 9].uBaseRGB.dwPacked = 0x00010000 * colormult;
		Verts[6].uBaseRGB.dwPacked = Verts[13].uBaseRGB.dwPacked = 0x00000100 * colormult;
		Verts[7].uBaseRGB.dwPacked = Verts[11].uBaseRGB.dwPacked = 0x00010100 * colormult;

		mTransform = Identity;
		mTransform.SetPos(pos);

		float cc = (float)cos(DEG2RAD(xrot));
		float ss = (float)sin(DEG2RAD(xrot));
		kmatrix XRM = kmatrix(	kvector( 1.0f, 0.0f, 0.0f),
								kvector( 0.0f,   cc,  -ss),
								kvector( 0.0f,   ss,   cc),
								kvector( 0.0f, 0.0f, 0.0f) );

		mTransform = mTransform * XRM;


		cc = (float)cos(DEG2RAD(yrot));
		ss = (float)sin(DEG2RAD(yrot));
		kmatrix YRM = kmatrix(	kvector(   cc, 0.0f,  -ss),
								kvector( 0.0f, 1.0f, 0.0f),
								kvector(   ss, 0.0f,   cc),
								kvector( 0.0f, 0.0f, 0.0f) );

		mTransform = mTransform * YRM;

		mDepth = depth;
		mAge = 0;
	}

	TestThing::~TestThing ()
	{
	}

	float cc = (float)cos(3.0f*PI/180.0f);
	float ss = (float)sin(3.0f*PI/180.0f);
	kmatrix ZRot = kmatrix(	kvector(   cc,  -ss, 0.0f),
							kvector(   ss,   cc, 0.0f),
							kvector( 0.0f, 0.0f, 1.0f),
							kvector( 0.0f, 0.0f, 0.0f) );

	const float c60 = (float)cos(DEG2RAD(60.0f));
	const float s60 = (float)sin(DEG2RAD(60.0f));

	void TestThing::EvaluateState (void)
	{
		mTransform = mTransform * ZRot;

		mAge++;
		if (mAge == 120)
		{
			switch (mDepth)
			{
				case 0: 	new TestThing (NODE_DEL_AUTO, this, 50.0f, kvector (   0    , +300    ,    0), 1);
							new TestThing (NODE_DEL_AUTO, this, 50.0f, kvector (-300*s60, -300*c60,    0), 1);
							new TestThing (NODE_DEL_AUTO, this, 50.0f, kvector ( 300*s60, -300*c60,    0), 1);
							break;
				case 1: 	new TestThing (NODE_DEL_AUTO, this, 30.0f, kvector (   0    ,  150    , 150), 2, 45, 0 );
							new TestThing (NODE_DEL_AUTO, this, 30.0f, kvector (-150*s60, -150*c60, 150), 2, 45, 0 );
							new TestThing (NODE_DEL_AUTO, this, 30.0f, kvector ( 150*s60, -150*c60, 150), 2, 45, 0 );
							break;
				case 2: 	new TestThing (NODE_DEL_AUTO, this, 10.0f, kvector (  0    ,  90    , 90), 3, 0, 45 );
							new TestThing (NODE_DEL_AUTO, this, 10.0f, kvector (-90*s60, -90*c60, 90), 3, 0, 45 );
							new TestThing (NODE_DEL_AUTO, this, 10.0f, kvector ( 90*s60, -90*c60, 90), 3, 0, 45 );
							break;
				case 3: 	new TestThing (NODE_DEL_AUTO, this, 5.0f, kvector (-40, -40, 40), 4, 0, 0 );
							new TestThing (NODE_DEL_AUTO, this, 5.0f, kvector (-40, +40, 40), 4, 0, 0 );
							new TestThing (NODE_DEL_AUTO, this, 5.0f, kvector (+40, -40, 40), 4, 0, 0 );
							new TestThing (NODE_DEL_AUTO, this, 5.0f, kvector (+40, +40, 40), 4, 0, 0 );
							break;
				case 4: 	new TestThing (NODE_DEL_AUTO, this, 5.0f, kvector (-60, -60, 0), 5, 0, 0 );
							new TestThing (NODE_DEL_AUTO, this, 5.0f, kvector (-60, +60, 0), 5, 0, 0 );
							new TestThing (NODE_DEL_AUTO, this, 5.0f, kvector (+60, -60, 0), 5, 0, 0 );
//							new TestThing (NODE_DEL_AUTO, this, 5.0f, kvector (+60, +60, 0), 5, 0, 0 );
							break;
				default:
							break;
			}
		}
	};

	void TestThing::TransformAndRegisterTristrips	(kmatrix* m, NODE_LIST_BITS lbits)
	{
		lbits;

		for (int i=0; i<8 ;i++ )
		{
			kvector t;
			ApplyMatrix (t, *m, points[i]);

			float r = reciprocal (t[VZ]);
			Verts[i].fX = t[VX] * r + 320.0f;
			Verts[i].fY = t[VY] * r + 240.0f;
			Verts[i].fZ = r;
		}

		Verts[12].fX = Verts[0].fX;	Verts[12].fY = Verts[0].fY;	Verts[12].fZ = Verts[0].fZ;
		Verts[10].fX = Verts[1].fX;	Verts[10].fY = Verts[1].fY;	Verts[10].fZ = Verts[1].fZ;
		Verts[14].fX = Verts[2].fX;	Verts[14].fY = Verts[2].fY;	Verts[14].fZ = Verts[2].fZ;
		Verts[ 8].fX = Verts[3].fX;	Verts[ 8].fY = Verts[3].fY;	Verts[ 8].fZ = Verts[3].fZ;
		Verts[15].fX = Verts[4].fX;	Verts[15].fY = Verts[4].fY;	Verts[15].fZ = Verts[4].fZ;
		Verts[ 9].fX = Verts[5].fX;	Verts[ 9].fY = Verts[5].fY;	Verts[ 9].fZ = Verts[5].fZ;
		Verts[13].fX = Verts[6].fX;	Verts[13].fY = Verts[6].fY;	Verts[13].fZ = Verts[6].fZ;
		Verts[11].fX = Verts[7].fX;	Verts[11].fY = Verts[7].fY;	Verts[11].fZ = Verts[7].fZ;

		myContext.Set();
		KAMUI_TRY (KAMUI_SET_VERTEX(Verts, KM_VERTEXTYPE_00, sizeof (KMVERTEX_00)*16));

	}



/****************************************************************************/
/**	Background surface setting **********************************************/
/****************************************************************************/
void	InitBackGround(void)
{
	KMSTATUS			status;
	KMVERTEXCONTEXT		BackVertexContext;		// Vertex context
	KMVERTEX_00			BV[3];					// pointer to Vertex
	PVOID				pBV[3];					// pointer to Vertex

	/* Clear VertexContext */
	memset(&BackVertexContext,0,sizeof(KMVERTEXCONTEXT));

	/* Setup VertexContext */
	BackVertexContext.RenderState	= KM_DEPTHMODE  		| KM_CULLINGMODE				// ISP/TSP IW
									| KM_SCREENCOORDINATION	| KM_SHADINGMODE
									| KM_MODIFIER 			| KM_ZWRITEDISABLE				// TSP CW
									| KM_SRCBLENDINGMODE
									| KM_SRCSELECT			| KM_DSTSELECT
									| KM_FOGMODE			| KM_USESPECULAR
									| KM_USEALPHA			| KM_IGNORETEXTUREALPHA
									| KM_FLIPUV 			| KM_CLAMPUV
									| KM_FILTERMODE			| KM_SUPERSAMPLE
									| KM_MIPMAPDADJUST 		| KM_TEXTURESHADINGMODE
									| KM_PARAMTYPE 			| KM_LISTTYPE 					// Param CW
									| KM_COLORTYPE			| KM_USESPECULAR
									| KM_UVFORMAT;

	// for ParameterControlWord
	BackVertexContext.ParamType				= KM_POLYGON;
	BackVertexContext.ListType				= KM_OPAQUE_POLYGON;
	BackVertexContext.ColorType				= KM_PACKEDCOLOR;
	BackVertexContext.bUseSpecular			= FALSE;
	BackVertexContext.UVFormat				= KM_32BITUV;

	// for ISP/TSP InstructionWord
	BackVertexContext.DepthMode				= KM_GREATER;
	BackVertexContext.CullingMode			= KM_NOCULLING;
	BackVertexContext.ScreenCoordination	= KM_SCREEN;
	BackVertexContext.ShadingMode			= KM_NOTEXTUREGOURAUD;
	BackVertexContext.SelectModifier		= KM_NOMODIFIER;
	BackVertexContext.bZWriteDisable		= FALSE;			/* not effective on ARC1 */

	// for TSP ControlWord
	BackVertexContext.SRCBlendingMode		= KM_ONE;
//	BackVertexContext.DSTBlendingMode		= KM_ZERO;	// must not set this parameter on background plane
	BackVertexContext.bSRCSel				= FALSE;			/* not effective on ARC1 */
	BackVertexContext.bDSTSel				= FALSE;			/* not effective on ARC1 */
	BackVertexContext.FogMode				= KM_NOFOG;			/* 11 is reserved */
	BackVertexContext.bUseSpecular			= FALSE;
	BackVertexContext.bUseAlpha				= FALSE;
	BackVertexContext.ClampUV				= KM_NOCLAMP;
	BackVertexContext.FilterMode			= KM_POINT_SAMPLE;
	BackVertexContext.bSuperSample			= FALSE;
	BackVertexContext.MipMapAdjust			= 0x00000004;		/* D=1.00 */
	BackVertexContext.TextureShadingMode	= KM_MODULATE;

	// for Texture ControlBit

	// No effect on ARC1
	BackVertexContext.bColorClamp			= FALSE;
	BackVertexContext.PaletteBank			= 0;

	// for GlobalColorData
	BackVertexContext.fFaceColorAlpha		= 1.0f;		// Face Color Alpha
	BackVertexContext.fFaceColorRed			= 1.0f;		// Face Color Red
	BackVertexContext.fFaceColorGreen		= 1.0f;		// Face Color Green
	BackVertexContext.fFaceColorBlue		= 1.0f;		// Face Color Blue
	BackVertexContext.fOffsetColorAlpha		= 1.0f;		// Specular Color Alpha
	BackVertexContext.fOffsetColorRed		= 1.0f;		// Specular Color Red
	BackVertexContext.fOffsetColorGreen		= 1.0f;		// Specular Color Green
	BackVertexContext.fOffsetColorBlue		= 1.0f;		// Specular Color Blue

	status = kmProcessVertexRenderState(&BackVertexContext);
	status = kmSetBackGroundRenderState(&BackVertexContext);

	//-----------------------------------------------------------------------------------
	// set VERTEX DATA

	// Vertex #1
	BV[0].ParamControlWord	= KM_VERTEXPARAM_NORMAL;
	BV[0].fX					=   0.0f;
	BV[0].fY					= 479.0f;
	BV[0].fZ					=   0.0001f;
	BV[0].uBaseRGB.byte.bBlue	=     64;
	BV[0].uBaseRGB.byte.bGreen	=     64;
	BV[0].uBaseRGB.byte.bRed	=     16;
	BV[0].uBaseRGB.byte.bAlpha	=      0;

	// Vertex #2
	BV[1].ParamControlWord	= KM_VERTEXPARAM_NORMAL;
	BV[1].fX					= 320.0f;
	BV[1].fY					=   0.0f;
	BV[1].fZ					=   0.0001f;
	BV[1].uBaseRGB.byte.bBlue	=    128;
	BV[1].uBaseRGB.byte.bGreen	=      0;
	BV[1].uBaseRGB.byte.bRed	=      0;
	BV[1].uBaseRGB.byte.bAlpha	=      0;

	// Vertex #3
	BV[2].ParamControlWord	= KM_VERTEXPARAM_ENDOFSTRIP;
	BV[2].fX					= 639.0f;
	BV[2].fY					= 479.0f;
	BV[2].fZ					=   0.0001f;
	BV[2].uBaseRGB.byte.bBlue	=     64;
	BV[2].uBaseRGB.byte.bGreen	=     64;
	BV[2].uBaseRGB.byte.bRed	=     16;
	BV[2].uBaseRGB.byte.bAlpha	=      0;

	pBV[0] = &BV[0];
	pBV[1] = &BV[1];
	pBV[2] = &BV[2];

	//-----------------------------------------------------------------------------------
	// set VERTEX
	status = kmSetBackGroundPlane(	pBV,					// pVertex
									KM_VERTEXTYPE_00,		// VertexType
									sizeof(KMVERTEX_00)		// StructSize
									);
}

//============================================================================= kradmain()
//-----------------------------------------------------------------------------
void kradmain (void)
{
	infoout << endl;
	infoout << "KRAD - Kamui Rendering/Animation Demonstration" << endl;
	infoout << "Developed by Captivation Digital Laboratories, Inc." << endl;
    infoout << "for Sega of America, Inc." << endl;
	infoout << endl;

	InitializeAggressiveMath();

	theKamui = new KKamui(	128,				//nKForOpaquePoly =
							128,				//nKForOpaqueMod	=
							128,				//nKForTransPoly	=
							128,				//nKForTransMod	=
							KM_VGA,				//nVideoMode		=
							KM_DSPMODE_VGA,		//nDisplayMode	=
							KM_DSPBPP_RGB888,	//nBpp			=
							FALSE,				//nDither			=
							FALSE				//nAntiAlias		=
						);
//	theKamui->EnableCallbacks();
	theScene = new SceneRoot (NODE_DEL_AUTO);

	InitBackGround();

	SceneCamera* myCam = new SceneCamera(NODE_DEL_AUTO, theScene);
	myCam->ActivateAsPrimary();

#ifdef TEST_CKM
	Kbunnyobject1Model	bunny(NODE_DEL_MANUAL, theScene);
//	KTorus01Model bunny(NODE_DEL_MANUAL, theScene);
#else
	TestThing	tri	 (NODE_DEL_MANUAL, theScene, 75.0f, kvector(  0,  60, -200));
#endif

	for (int i=1; i<1000 ;i++ )
		theScene->EvaluateAndRender();

}

//=============================================================================	END-OF-FILE