#include <MLR\MLRHeaders.hpp>

extern bool dontSeeMe;

HGOSFONT3D Font_Arial8;

// the clipper is the "desciption" of the view frustrum
MLRClipper *theClipper;

// contains all necessary information to draw a shape
const int nrOfShapes = 2;
DrawShapeInformation *drawShapeInfo[nrOfShapes];
LinearMatrix4D *shapeOrigins[nrOfShapes], *invertedShapeOrigin[nrOfShapes];
IcoInfo icoInfo[nrOfShapes];

LinearMatrix4D cameraOrigin;

YawPitchRange Camera_Direction(0.0f, 0.0f, -10.0f);
Vector2DOf<Scalar> Camera_Shift(0.0f, 0.0f);

DynamicArrayOf<MLRState> *states;	// need 2

Matrix4D cameraToClip;

RGBAColor fogColor(0.2f, 0.2f, 0.2f, 1.0f);
RGBAColor bgColor(0.1f, 0.1f, 0.1f, 1.0f);
RGBAColor white(1.0f, 1.0f, 1.0f, 1.0f);

int activeLightType = 0;
DynamicArrayOf<MLRLight*> *sceneLights;	// need 8

MLRLightMap	*firstLightMap = NULL;

LinearMatrix4D displacementMatrix;
LinearMatrix4D *moreClones[nrOfShapes], *invertedMoreClones[nrOfShapes];

extern void _stdcall End3DScene();

// This function creates out of a frustum a camera-to-clip matrix
void
	SetPerspective(
		Scalar near_clip,
		Scalar far_clip,
		Scalar left_clip,
		Scalar right_clip,
		Scalar top_clip,
		Scalar bottom_clip,
		Matrix4D& cameraToClip
	)
{
	Verify(far_clip - near_clip > SMALL);
	Verify(left_clip - right_clip > SMALL);
	Verify(top_clip - bottom_clip > SMALL);

	//
	//-------------------------------------------------------
	// Calculate the horizontal, vertical, and forward ranges
	//-------------------------------------------------------
	//
	Scalar horizontal_range = APPLY_LEFT_SIGN(1.0f) / (left_clip - right_clip);
	Scalar vertical_range = APPLY_UP_SIGN(1.0f) / (top_clip - bottom_clip);
	Scalar depth_range = APPLY_FORWARD_SIGN(1.0f) / (far_clip - near_clip);

	//
	//------------------------------------------------------------------------
	// Set up the camera to clip matrix.  This matrix takes camera space
	// coordinates and maps them into a homogeneous culling space where valid
	// X, Y, and Z axis values (when divided by W) will all be between 0 and 1
	//------------------------------------------------------------------------
	//
	cameraToClip(LEFT_AXIS, LEFT_AXIS) = near_clip * horizontal_range;
	cameraToClip(LEFT_AXIS, UP_AXIS) = 0.0f;
	cameraToClip(LEFT_AXIS, FORWARD_AXIS) = 0.0f;
	cameraToClip(LEFT_AXIS, 3) = 0.0f;

	cameraToClip(UP_AXIS, LEFT_AXIS) = 0.0f;
	cameraToClip(UP_AXIS, UP_AXIS) = near_clip * vertical_range;
	cameraToClip(UP_AXIS, FORWARD_AXIS) = 0.0f;
	cameraToClip(UP_AXIS, 3) = 0.0f;

	cameraToClip(FORWARD_AXIS, LEFT_AXIS) = -right_clip * horizontal_range;
	cameraToClip(FORWARD_AXIS, UP_AXIS) = -bottom_clip * vertical_range;
	cameraToClip(FORWARD_AXIS, FORWARD_AXIS) = far_clip * depth_range;
	cameraToClip(FORWARD_AXIS, 3) = 1.0f;

	cameraToClip(3, LEFT_AXIS) = 0.0f;
	cameraToClip(3, UP_AXIS) = 0.0f;
	cameraToClip(3, FORWARD_AXIS) = -far_clip * near_clip * depth_range;
	cameraToClip(3, 3) = 0.0f;
}

// This function creates out of a frustum a world-to-clip matrix
void
	SetPerspective(
		Scalar near_clip,
		Scalar far_clip,
		const Radian &horizontal_fov,
		Scalar height_to_width,
		Matrix4D& cameraToClip
	)
{
	Verify(far_clip - near_clip > SMALL);
	Verify(horizontal_fov > SMALL);
	Verify(height_to_width > SMALL);

	//
	//-------------------------------------------------------------
	// Calculate the near plane offsets to the side culling planes
	//-------------------------------------------------------------
	//
	Scalar width = (Scalar)(near_clip * tan(horizontal_fov*0.5f));
	Scalar height = width * height_to_width;
	SetPerspective(near_clip, far_clip, width, -width, height, -height, cameraToClip);
}

#undef TRACE_ON

void __stdcall InitializeGameEngine()
{
//	Memory_Registration_Enabled=FALSE;
//	Armor_Level=0;
	
	//
	//---------------------
	// Initialize libraries
	//---------------------
	//
	Stuff::InitializeClasses();
	
	MidLevelRenderer::InitializeClasses(NULL, 8192*16, 1024*8);
//	MidLevelRenderer::InitializeStatistics();

	Font_Arial8=gos_LoadFont("Assets\\Graphics\\arial8.tga",0);
	//
	//------------------------
	// Set up the texture pool
	//------------------------
	//
	gos_PushCurrentHeap(MidLevelRenderer::TexturePoolHeap);
	TGAFilePool *pool = new TGAFilePool("Assets\\Graphics\\");
	Register_Object(pool);
	MLRTexturePool::Instance = new MLRTexturePool(pool);
	Check_Object(MLRTexturePool::Instance);
	Register_Object(MLRTexturePool::Instance);

	MLRTexturePool::Instance->Add("dirt");

	MLRTexturePool::Instance->LoadImages();

	gos_PopCurrentHeap();

	gos_PushCurrentHeap(MidLevelRenderer::StatesHeap);
	states = new DynamicArrayOf<MLRState>;
	states->SetLength(2);
	Register_Object(states);
	gos_PopCurrentHeap();

	(*states)[0].SetBackFaceOn();
	(*states)[0].SetDitherOff();
	(*states)[0].SetTextureCorrectionOn();
	(*states)[0].SetZBufferCompareOn();
	(*states)[0].SetZBufferWriteOn();

	(*states)[0].SetFilterMode(MLRState::BiLinearFilterMode);

#ifdef OLDFOG
	(*states)[0].SetFogMode(MLRState::DisableFogMode);
	(*states)[0].SetFogData(
		0,
		0.0f,
		1.0f,
		100.0f
	);
#else
	(*states)[0].SetFogMode(0);
#endif

	(*states)[0].SetLightingMode(MLRState::VertexLightingMode | MLRState::LightMapLightingMode);

	(*states)[1] = (*states)[0];

	//
	//--------------------
	// Set up a test light
	//--------------------
	//
	static Stuff::LinearMatrix4D lightToWorld;
	lightToWorld.BuildTranslation(Point3D(-5.0f, 0.0f, -5.0f));
	lightToWorld.BuildRotation(EulerAngles(0.0f, Pi_Over_4, 0.0f));

	gos_PushCurrentHeap(MidLevelRenderer::TexturePoolHeap);
	MLRTexture *texture = MLRTexturePool::Instance->Add("lightspot");
	Check_Object(texture);
	gos_PopCurrentHeap();

	gos_PushCurrentHeap(MidLevelRenderer::LightsHeap);
	firstLightMap = new MLRLightMap(texture);
	Register_Object(firstLightMap);

	sceneLights = new DynamicArrayOf<MLRLight*>;
	sceneLights->SetLength(8);
	Register_Object(sceneLights);

	(*sceneLights)[0] = new MLRAmbientLight;
	(*sceneLights)[1] = new MLRInfiniteLight;
	(*sceneLights)[2] = new MLRInfiniteLightWithFalloff;
	(*sceneLights)[3] = new MLRPointLight;
	(*sceneLights)[4] = new MLRSpotLight;
	(*sceneLights)[5] = new MLRPointLight;
	(*sceneLights)[6] = new MLRSpotLight;
	(*sceneLights)[7] = new MLRLookUpLight;

	Degree degree(5);
	Cast_Pointer(MLRSpotLight*, (*sceneLights)[4])->SetSpreadAngle(degree);
	Cast_Pointer(MLRSpotLight*, (*sceneLights)[6])->SetSpreadAngle(degree);
	gos_PopCurrentHeap();

	for(int i=0;i<8;i++)
	{
		Register_Object((*sceneLights)[i]);
		(*sceneLights)[i]->SetLightToWorldMatrix(lightToWorld);
			(*sceneLights)[i]->SetIntensity(1.0f);
		(*sceneLights)[i]->SetColor(RGBColor(1.0f, 0.0f, 1.0f));
	}
	
	for(i=2;i<7;i++)
	{
		Cast_Pointer(MLRInfiniteLightWithFalloff*, (*sceneLights)[i])->SetFalloffDistance(2.0f, 15.0f);
	}

	Cast_Pointer(MLRPointLight*, (*sceneLights)[5])->SetLightMap(firstLightMap);
	Cast_Pointer(MLRSpotLight*, (*sceneLights)[6])->SetLightMap(firstLightMap);

	Cast_Pointer(MLRLookUpLight*, (*sceneLights)[7])->SetMapOrigin(-40.0f, 0.0f, -40.0f);
	Cast_Pointer(MLRLookUpLight*, (*sceneLights)[7])->SetMapZoneSizeX(80.0f);
	Cast_Pointer(MLRLookUpLight*, (*sceneLights)[7])->SetMapZoneSizeZ(80.0f);
	Cast_Pointer(MLRLookUpLight*, (*sceneLights)[7])->SetMapSizeAndName(1, 1, "Assets\\Graphics\\lighttest.raw");

	// create 2 (*states) for multi textured cube
	(*states)[1].SetZBufferWriteOff();
	(*states)[1].SetAlphaMode(MLRState::AlphaInvAlphaMode);

	(*states)[0].SetPriority(MLRState::DefaultPriority);
	(*states)[1].SetPriority(MLRState::DefaultPriority + 1);

	gos_PushCurrentHeap(MidLevelRenderer::TexturePoolHeap);
	texture = MLRTexturePool::Instance->Add("ken");
	(*states)[0].SetTextureHandle(texture->GetTextureHandle());

	texture = MLRTexturePool::Instance->Add("Rock_Alpha");
	(*states)[1].SetTextureHandle(texture->GetTextureHandle());
	gos_PopCurrentHeap();

	gos_PushCurrentHeap(MidLevelRenderer::MiscellaneousHeap);
// creating the camera-to-clip-space matrix
	SetPerspective(1.0f, 300.0f, Pi_Over_3, 0.75f, cameraToClip);

	shapeOrigins[0] = new LinearMatrix4D;
	*shapeOrigins[0] = LinearMatrix4D::Identity;
	Register_Object(shapeOrigins[0]);

	invertedShapeOrigin[0] = new LinearMatrix4D;
	*invertedShapeOrigin[0] = LinearMatrix4D::Identity;
	Register_Object(invertedShapeOrigin[0]);

	moreClones[0] = new LinearMatrix4D;
	*moreClones[0] = LinearMatrix4D::Identity;
	Register_Object(moreClones[0]);

	invertedMoreClones[0] = new LinearMatrix4D;
	*invertedMoreClones[0] = LinearMatrix4D::Identity;
	Register_Object(invertedMoreClones[0]);

//	create a shape
	drawShapeInfo[0] = new DrawShapeInformation;
	Register_Object(drawShapeInfo[0]);

	icoInfo[0].type = MLR_I_DeT_TMeshClassID;
	icoInfo[0].depth = 3;
	icoInfo[0].indexed = true;
	icoInfo[0].radius = 1.0f;
	icoInfo[0].all = 1.0f;
	icoInfo[0].onOff = true;
	drawShapeInfo[0]->shape = CreateIndexedIcosahedron(icoInfo[0], &(*states));
//	drawShapeInfo[0]->shape = CreateIndexedTriIcosahedron_NoColor_NoLit(icoInfo[0], &((*states)[0]));

//	drawShapeInfo[0]->clippingFlags.SetClippingState(0x3f);
	drawShapeInfo[0]->clippingFlags.SetClippingState(0);
	drawShapeInfo[0]->shapeToWorld = shapeOrigins[0];
	drawShapeInfo[0]->worldToShape = invertedShapeOrigin[0];

	drawShapeInfo[0]->activeLights = (*sceneLights).GetData()+activeLightType;
	drawShapeInfo[0]->nrOfActiveLights = 1;

	drawShapeInfo[0]->paintMeColor = &white;

	shapeOrigins[0]->BuildTranslation(Point3D(-1.01f, 0.0f, 0.0f));
	shapeOrigins[0]->BuildRotation(EulerAngles(0.0f, 0.0f, 0.0f));

	invertedShapeOrigin[0]->Invert(*drawShapeInfo[0]->shapeToWorld);

	drawShapeInfo[0]->state = (*states)[0];

//	create another shape
	shapeOrigins[1] = new LinearMatrix4D;
	*shapeOrigins[1] = LinearMatrix4D::Identity;
	Register_Object(shapeOrigins[1]);

	invertedShapeOrigin[1] = new LinearMatrix4D;
	*invertedShapeOrigin[1] = LinearMatrix4D::Identity;
	Register_Object(invertedShapeOrigin[1]);

	moreClones[1] = new LinearMatrix4D;
	*moreClones[1] = LinearMatrix4D::Identity;
	Register_Object(moreClones[1]);

	invertedMoreClones[1] = new LinearMatrix4D;
	*invertedMoreClones[1] = LinearMatrix4D::Identity;
	Register_Object(invertedMoreClones[1]);

	drawShapeInfo[1] = new DrawShapeInformation;
	Register_Object(drawShapeInfo[1]);

	icoInfo[1].type = MLR_I_TMeshClassID;
	icoInfo[1].depth = 3;
	icoInfo[1].indexed = true;
	icoInfo[1].radius = 1.0f;
	icoInfo[1].all = 1.0f;
	icoInfo[1].onOff = true;

	gos_PopCurrentHeap();

	drawShapeInfo[1]->shape = CreateIndexedIcosahedron(icoInfo[1], &(*states));

//	drawShapeInfo[1]->clippingFlags.SetClippingState(0x3f);
	drawShapeInfo[1]->clippingFlags.SetClippingState(0);
	drawShapeInfo[1]->shapeToWorld = shapeOrigins[1];
	drawShapeInfo[1]->worldToShape = invertedShapeOrigin[1];

	drawShapeInfo[1]->activeLights = (*sceneLights).GetData()+activeLightType;
	drawShapeInfo[1]->nrOfActiveLights = 1;

	drawShapeInfo[1]->paintMeColor = &white;

	shapeOrigins[1]->BuildTranslation(Point3D(1.01f, 0.0f, 0.0f));
//	shapeOrigins[1]->BuildRotation(EulerAngles(0.2f, 0.4f, 0.6f));

	invertedShapeOrigin[1]->Invert(*drawShapeInfo[1]->shapeToWorld);

	drawShapeInfo[1]->state = (*states)[0];

//	misc.
	displacementMatrix.BuildTranslation(Point3D(0.1f, 0.1f, 0.1f));
	displacementMatrix.BuildRotation(EulerAngles(0.2f, 0.2f, 0.2f));

	gos_PushCurrentHeap(MidLevelRenderer::TexturePoolHeap);
	MLRTexturePool::Instance->LoadImages();
	gos_PopCurrentHeap();

	gos_PushCurrentHeap(MidLevelRenderer::SorterHeap);
	MLRSortByOrder *cameraSorter = new MLRSortByOrder(MLRTexturePool::Instance);
	Register_Object(cameraSorter);
	gos_PopCurrentHeap();

	gos_PushCurrentHeap(MidLevelRenderer::ClipperHeap);
	theClipper = new MLRClipper(0, cameraSorter);
	Register_Object(theClipper);
	gos_PopCurrentHeap();


	gos_PushCurrentHeap(MidLevelRenderer::MiscellaneousHeap);
	cameraOrigin.BuildRotation(
		EulerAngles(Camera_Direction.pitch, Camera_Direction.yaw, 0.0f)
	);
	cameraOrigin.BuildTranslation(Point3D(Camera_Direction));

	GOSVertex::farClipReciprocal = (1.0f-cameraToClip(2, 2))/cameraToClip(3, 2);
	gos_PopCurrentHeap();
}

int LastKey=-1;
bool cloneMe = false;
bool visText = true;
bool animateTextures = false;
bool displacement = true;
int moreShapes = 20;
bool otherCamera=false;

void __stdcall DoGameLogic()
{
	gosEnum_KeyStatus status;
	
	//
	// Read keyboard
	//

	DWORD KeyPress, KeyPressAll=gos_GetKey();
	if( KeyPressAll )
		SPEW(( "Keyboard", "Key=0x%x, '%c'",KeyPressAll, KeyPressAll ));

	KeyPress = KeyPressAll&255;

	if( KeyPress=='m' || KeyPress=='M' )
	{
		gos_WalkMemoryHeap(StaticHeap, true);
	}


	if( KeyPress=='l' || KeyPress=='L' )
	{
		if(0==drawShapeInfo[0]->nrOfActiveLights)
		{
			drawShapeInfo[0]->nrOfActiveLights = 1;
			drawShapeInfo[1]->nrOfActiveLights = 1;
		}
		else
		{
			drawShapeInfo[0]->nrOfActiveLights = 0;
			drawShapeInfo[1]->nrOfActiveLights = 0;
		}
	}

	if( KeyPress=='d')
	{
		dontSeeMe = !dontSeeMe;
	}

	if( KeyPress=='c')
	{
		if(0==drawShapeInfo[0]->clippingFlags.GetClippingState())
		{
			drawShapeInfo[0]->clippingFlags.SetClippingState(0x3f);;
		}
		else
		{
			drawShapeInfo[0]->clippingFlags.SetClippingState(0);;
		}
	}
	if( KeyPress=='C' )
	{
		if(0==drawShapeInfo[1]->clippingFlags.GetClippingState())
		{
			drawShapeInfo[1]->clippingFlags.SetClippingState(0x3f);;
		}
		else
		{
			drawShapeInfo[1]->clippingFlags.SetClippingState(0);;
		}
	}

	if( KeyPress=='s')
	{
		icoInfo[0].onOff = !icoInfo[0].onOff;
	}
	if( KeyPress=='S' )
	{
		icoInfo[1].onOff = !icoInfo[1].onOff;
	}

	if( KeyPress=='o' || KeyPress=='O')
	{
		cloneMe = !cloneMe;
	}

	if( KeyPress=='a' || KeyPress=='A')
	{
		animateTextures = !animateTextures;
	}

	if( KeyPress=='p' || KeyPress=='p')
	{
		displacement = !displacement;
	}

	if( KeyPress=='7')
	{
		if(moreShapes>0)
			moreShapes--;
	}
	if( KeyPress=='8')
	{
		moreShapes++;
	}

	if( KeyPress=='h' || KeyPress=='H' || KeyPressAll==0x3b00)
	{
		visText = !visText;
	}

	if( KeyPress=='w' || KeyPress=='W')
	{
		otherCamera = !otherCamera;
	}

	int changed = 0;
	if( KeyPress=='}' )
	{
		switch(icoInfo[1].type)
		{
			case MLR_I_PMeshClassID:
				icoInfo[1].type = MLR_I_C_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_PMeshClassID:
				icoInfo[1].type = MLR_I_L_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_PMeshClassID:
				icoInfo[1].type = MLR_I_DT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_DT_PMeshClassID:
				icoInfo[1].type = MLR_I_C_DT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DT_PMeshClassID:
				icoInfo[1].type = MLR_I_L_DT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DT_PMeshClassID:
				icoInfo[1].type = MLR_I_DeT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_DeT_PMeshClassID:
				icoInfo[1].type = MLR_I_C_DeT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DeT_PMeshClassID:
				icoInfo[1].type = MLR_I_L_DeT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DeT_PMeshClassID:
				icoInfo[1].type = MLR_I_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_TMeshClassID:
				icoInfo[1].type = MLR_I_C_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_TMeshClassID:
				icoInfo[1].type = MLR_I_L_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_TMeshClassID:
				icoInfo[1].type = MLR_I_DeT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_DeT_TMeshClassID:
				icoInfo[1].type = MLR_I_C_DeT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DeT_TMeshClassID:
				icoInfo[1].type = MLR_I_L_DeT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DeT_TMeshClassID:
				icoInfo[1].type = MLR_I_DT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_DT_TMeshClassID:
				icoInfo[1].type = MLR_I_C_DT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DT_TMeshClassID:
				icoInfo[1].type = MLR_I_L_DT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DT_TMeshClassID:
				icoInfo[1].type = MLR_Terrain2ClassID;
				changed = 1;
			break;
			case MLR_Terrain2ClassID:
				icoInfo[1].type = MLR_I_PMeshClassID;
				changed = 1;
			break;
		}
		if(changed)
		{
			if(drawShapeInfo[1]->shape)
			{
				drawShapeInfo[1]->shape->DetachReference();
			}
			drawShapeInfo[1]->shape = 
				CreateIndexedIcosahedron(icoInfo[1], &(*states));
		}
	}

	if( KeyPress==']' )
	{
		switch(icoInfo[0].type)
		{
			case MLR_I_PMeshClassID:
				icoInfo[0].type = MLR_I_C_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_PMeshClassID:
				icoInfo[0].type = MLR_I_L_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_PMeshClassID:
				icoInfo[0].type = MLR_I_DT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_DT_PMeshClassID:
				icoInfo[0].type = MLR_I_C_DT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DT_PMeshClassID:
				icoInfo[0].type = MLR_I_L_DT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DT_PMeshClassID:
				icoInfo[0].type = MLR_I_DeT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_DeT_PMeshClassID:
				icoInfo[0].type = MLR_I_C_DeT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DeT_PMeshClassID:
				icoInfo[0].type = MLR_I_L_DeT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DeT_PMeshClassID:
				icoInfo[0].type = MLR_I_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_TMeshClassID:
				icoInfo[0].type = MLR_I_C_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_TMeshClassID:
				icoInfo[0].type = MLR_I_L_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_TMeshClassID:
				icoInfo[0].type = MLR_I_DeT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_DeT_TMeshClassID:
				icoInfo[0].type = MLR_I_C_DeT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DeT_TMeshClassID:
				icoInfo[0].type = MLR_I_L_DeT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DeT_TMeshClassID:
				icoInfo[0].type = MLR_I_DT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_DT_TMeshClassID:
				icoInfo[0].type = MLR_I_C_DT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DT_TMeshClassID:
				icoInfo[0].type = MLR_I_L_DT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DT_TMeshClassID:
				icoInfo[0].type = MLR_Terrain2ClassID;
				changed = 1;
			break;
			case MLR_Terrain2ClassID:
				icoInfo[0].type = MLR_I_PMeshClassID;
				changed = 1;
			break;
		}
		if(changed)
		{
			if(drawShapeInfo[0]->shape != NULL)
			{
				drawShapeInfo[0]->shape->DetachReference();
			}
			drawShapeInfo[0]->shape = 
				CreateIndexedIcosahedron(icoInfo[0], &(*states));
		}
	}

	if( KeyPress=='{' )
	{
		switch(icoInfo[1].type)
		{
			case MLR_I_PMeshClassID:
				icoInfo[1].type = MLR_Terrain2ClassID;
				changed = 1;
			break;
			case MLR_I_C_PMeshClassID:
				icoInfo[1].type = MLR_I_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_PMeshClassID:
				icoInfo[1].type = MLR_I_C_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_DT_PMeshClassID:
				icoInfo[1].type = MLR_I_L_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DT_PMeshClassID:
				icoInfo[1].type = MLR_I_DT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DT_PMeshClassID:
				icoInfo[1].type = MLR_I_C_DT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_DeT_PMeshClassID:
				icoInfo[1].type = MLR_I_L_DT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DeT_PMeshClassID:
				icoInfo[1].type = MLR_I_DeT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DeT_PMeshClassID:
				icoInfo[1].type = MLR_I_C_DeT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_TMeshClassID:
				icoInfo[1].type = MLR_I_L_DeT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_TMeshClassID:
				icoInfo[1].type = MLR_I_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_TMeshClassID:
				icoInfo[1].type = MLR_I_C_TMeshClassID;
				changed = 1;
			break;


			case MLR_I_DeT_TMeshClassID:
				icoInfo[1].type = MLR_I_L_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DeT_TMeshClassID:
				icoInfo[1].type = MLR_I_DeT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DeT_TMeshClassID:
				icoInfo[1].type = MLR_I_C_DeT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_DT_TMeshClassID:
				icoInfo[1].type = MLR_I_L_DT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DT_TMeshClassID:
				icoInfo[1].type = MLR_I_DeT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DT_TMeshClassID:
				icoInfo[1].type = MLR_I_C_DT_TMeshClassID;
				changed = 1;
			break;


			case MLR_Terrain2ClassID:
				icoInfo[1].type = MLR_I_L_DT_TMeshClassID;
				changed = 1;
			break;
		}
		if(changed)
		{
			if(drawShapeInfo[1]->shape != NULL)
			{
				drawShapeInfo[1]->shape->DetachReference();
			}
			drawShapeInfo[1]->shape = 
				CreateIndexedIcosahedron(icoInfo[1], &(*states));
		}
	}

	if( KeyPress=='[' )
	{
		switch(icoInfo[0].type)
		{
			case MLR_I_PMeshClassID:
				icoInfo[0].type = MLR_Terrain2ClassID;
				changed = 1;
			break;
			case MLR_I_C_PMeshClassID:
				icoInfo[0].type = MLR_I_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_PMeshClassID:
				icoInfo[0].type = MLR_I_C_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_DT_PMeshClassID:
				icoInfo[0].type = MLR_I_L_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DT_PMeshClassID:
				icoInfo[0].type = MLR_I_DT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DT_PMeshClassID:
				icoInfo[0].type = MLR_I_C_DT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_DeT_PMeshClassID:
				icoInfo[0].type = MLR_I_L_DT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DeT_PMeshClassID:
				icoInfo[0].type = MLR_I_DeT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DeT_PMeshClassID:
				icoInfo[0].type = MLR_I_C_DeT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_TMeshClassID:
				icoInfo[0].type = MLR_I_L_DeT_PMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_TMeshClassID:
				icoInfo[0].type = MLR_I_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_TMeshClassID:
				icoInfo[0].type = MLR_I_C_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_DeT_TMeshClassID:
				icoInfo[0].type = MLR_I_L_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DeT_TMeshClassID:
				icoInfo[0].type = MLR_I_DeT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DeT_TMeshClassID:
				icoInfo[0].type = MLR_I_C_DeT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_DT_TMeshClassID:
				icoInfo[0].type = MLR_I_L_DT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_C_DT_TMeshClassID:
				icoInfo[0].type = MLR_I_DeT_TMeshClassID;
				changed = 1;
			break;
			case MLR_I_L_DT_TMeshClassID:
				icoInfo[0].type = MLR_I_C_DT_TMeshClassID;
				changed = 1;
			break;
			case MLR_Terrain2ClassID:
				icoInfo[0].type = MLR_I_DT_TMeshClassID;
				changed = 1;
			break;
		}
		if(changed)
		{
			if(drawShapeInfo[0]->shape)
			{
				drawShapeInfo[0]->shape->DetachReference();
			}
			drawShapeInfo[0]->shape = 
				CreateIndexedIcosahedron(icoInfo[0], &(*states));
		}
	}

	if( KeyPress==',' )
	{
		if(activeLightType==0)
		{
			activeLightType=7;
		}
		else
		{
			activeLightType--;
		}


		drawShapeInfo[0]->activeLights = (*sceneLights).GetData()+activeLightType;
	}

	if( KeyPress=='<' )
	{
		if(activeLightType==0)
		{
			activeLightType=7;
		}
		else
		{
			activeLightType--;
		}

		drawShapeInfo[1]->activeLights = (*sceneLights).GetData()+activeLightType;
	}

	if( KeyPress=='.' )
	{
		if(activeLightType==7)
		{
			activeLightType=0;
		}
		else
		{
			activeLightType++;
		}

		drawShapeInfo[0]->activeLights = (*sceneLights).GetData()+activeLightType;
	}

	if( KeyPress=='>' )
	{
		if(activeLightType==7)
		{
			activeLightType=0;
		}
		else
		{
			activeLightType++;
		}

		drawShapeInfo[1]->activeLights = (*sceneLights).GetData()+activeLightType;
	}

	status = gos_GetKeyStatus(KEY_LSHIFT);
	if (status != KEY_FREE && status != KEY_RELEASED)
	{
		if (KeyPress == '!' ||
			KeyPress == '@' ||
			KeyPress == '#' ||
			KeyPress == '$' ||
			KeyPress == '%' ||
			KeyPress == '^'
			)
		{
			drawShapeInfo[1]->shape->DetachReference();

			switch(KeyPress)
			{
				case '!':
					icoInfo[1].depth = 0;
				break;
				case '@':
					icoInfo[1].depth = 1;
				break;
				case '#':
					icoInfo[1].depth = 2;
				break;
				case '$':
					icoInfo[1].depth = 3;
				break;
				case '%':
					icoInfo[1].depth = 4;
				break;
			}
			drawShapeInfo[1]->shape = 
				CreateIndexedIcosahedron(icoInfo[1], &(*states));
		}
		if(KeyPress == 'I')
		{
			icoInfo[1].indexed = !icoInfo[1].indexed;
			drawShapeInfo[1]->shape->DetachReference();
			drawShapeInfo[1]->shape = 
				CreateIndexedIcosahedron(icoInfo[1], &(*states));
		}
		if(KeyPress == '+')
		{
			icoInfo[1].radius += 0.2f;
			drawShapeInfo[1]->shape->DetachReference();
			drawShapeInfo[1]->shape = 
				CreateIndexedIcosahedron(icoInfo[1], &(*states));
		}
		if(KeyPress == '_')
		{
			if(icoInfo[1].radius > 0.39f)
			{
				icoInfo[1].radius -= 0.2f;
				drawShapeInfo[1]->shape->DetachReference();
				drawShapeInfo[1]->shape = 
					CreateIndexedIcosahedron(icoInfo[1], &(*states));
			}
		}
	}
	else
	{
		if (KeyPress >= '1' && KeyPress < '6')
		{
			drawShapeInfo[0]->shape->DetachReference();

			icoInfo[0].depth = KeyPress-'1';
			drawShapeInfo[0]->shape = 
				CreateIndexedIcosahedron(icoInfo[0], &(*states));
		}
		if(KeyPress == 'i')
		{
			icoInfo[0].indexed = !icoInfo[0].indexed;
			drawShapeInfo[0]->shape->DetachReference();
			drawShapeInfo[0]->shape = 
				CreateIndexedIcosahedron(icoInfo[0], &(*states));
		}
		if(KeyPress == '=')
		{
			icoInfo[0].radius += 0.2f;
			drawShapeInfo[0]->shape->DetachReference();
			drawShapeInfo[0]->shape = 
				CreateIndexedIcosahedron(icoInfo[0], &(*states));
		}
		if(KeyPress == '-')
		{
			if(icoInfo[0].radius > 0.39f)
			{
				icoInfo[0].radius -= 0.2f;
				drawShapeInfo[0]->shape->DetachReference();
				drawShapeInfo[0]->shape = 
					CreateIndexedIcosahedron(icoInfo[0], &(*states));
			}
		}

	}

	//
	//---------------
	// Read the mouse
	//---------------
	//
	int
		x_delta,
		y_delta;
	DWORD
		buttons;
	gos_GetMouseInfo(NULL, NULL, &x_delta, &y_delta, NULL, &buttons);
	Scalar
		x_speed = x_delta * 0.01f,
		y_speed = y_delta * 0.01f;

	//
	//------------------------------------------------------
	// If the left Ctrl button is held down, move the camera
	//------------------------------------------------------
	//
	status = gos_GetKeyStatus(KEY_LCONTROL);
	if (status != KEY_FREE && status != KEY_RELEASED)
	{
		Camera_Direction.pitch += y_speed;
		Camera_Direction.yaw -= x_speed;
	}

	//
	//------------------------------------------------------
	// If the left Shift button is held down, pan the camera
	//------------------------------------------------------
	//
	status = gos_GetKeyStatus(KEY_LSHIFT);
	if (status != KEY_FREE && status != KEY_RELEASED)
	{
		Camera_Shift.x += x_speed;
		Camera_Shift.y += y_speed;
	}

	//
	//----------------------------------------------------------------
	// If the left Alt button is held down, zoom the camera in and out
	//----------------------------------------------------------------
	//
	status = gos_GetKeyStatus(KEY_LMENU);
	if (status != KEY_FREE && status != KEY_RELEASED)
	{
		Camera_Direction.range *= 1.0f + 3.0f*y_speed;
	}

	//
	//----------------------
	// Set the camera matrix
	//----------------------
	//
	cameraOrigin.BuildRotation(
		EulerAngles(Camera_Direction.pitch, Camera_Direction.yaw, 0.0f)
	);
	UnitVector3D
		world_left,
		world_up;
	cameraOrigin.GetLocalLeftInWorld(&world_left);
	cameraOrigin.GetLocalUpInWorld(&world_up);
	Point3D translation(Camera_Direction);
	translation.AddScaled(translation, world_left, Camera_Shift.x);
	translation.AddScaled(translation, world_up, Camera_Shift.y);
	cameraOrigin.BuildTranslation(translation);

	static int i, j, count = 0;

	static YawPitchRoll angles(*shapeOrigins[0]);
//	static Point3D posCube(-1.01f, 0.0f, 0.0f);

	angles.yaw += 0.002f;
//	angles.pitch += 0.004f;
//	angles.roll += 0.0015f;

	shapeOrigins[0]->BuildRotation(angles);
//	shapeOrigins[0]->BuildTranslation(posCube);

	invertedShapeOrigin[0]->Invert(*drawShapeInfo[0]->shapeToWorld);

//	posCube.x = 1.01f;
	angles.yaw = -angles.yaw;

	shapeOrigins[1]->BuildRotation(angles);
//	shapeOrigins[1]->BuildTranslation(posCube);

	invertedShapeOrigin[1]->Invert(*drawShapeInfo[1]->shapeToWorld);

	angles.yaw = -angles.yaw;

	count++;
}

void __stdcall UpdateDisplay()
{
	Scalar z = 1.0f;
	theClipper->StartDraw(cameraOrigin, cameraToClip, fogColor, &bgColor, (*states)[0], &z);
	int renderedTriangles = 0;

	if(animateTextures == true)
	{
		if((*states)[0].GetTextureHandle())
		{
			MLRTexture *texture = (*MLRTexturePool::Instance)[(*states)[0].GetTextureHandle()];
			texture->SetAnimateTexture(true);
			Stuff::AffineMatrix4D &textureMatrix = texture->GetTextureMatrix();
			textureMatrix(3, 0) += 0.005f;
			textureMatrix(3, 1) += 0.005f;
		}
		if((*states)[1].GetTextureHandle())
		{
			MLRTexture *texture = (*MLRTexturePool::Instance)[(*states)[1].GetTextureHandle()];
			texture->SetAnimateTexture(true);
			Stuff::AffineMatrix4D &textureMatrix = texture->GetTextureMatrix();
			textureMatrix(3, 0) -= 0.005f;
			textureMatrix(3, 1) -= 0.005f;
		}
	}
	else
	{
		if((*states)[0].GetTextureHandle())
		{
			MLRTexture *texture = (*MLRTexturePool::Instance)[(*states)[0].GetTextureHandle()];
			texture->SetAnimateTexture(false);
		}
		if((*states)[1].GetTextureHandle())
		{
			MLRTexture *texture = (*MLRTexturePool::Instance)[(*states)[1].GetTextureHandle()];
			texture->SetAnimateTexture(false);
		}
	}

	if(icoInfo[0].onOff == true && drawShapeInfo[0]->shape != NULL)
	{
		theClipper->DrawShape(drawShapeInfo[0]);
		renderedTriangles += drawShapeInfo[0]->shape->GetNumDrawnTriangles();
	}

	if(icoInfo[1].onOff == true && drawShapeInfo[1]->shape != NULL && cloneMe == false)
	{
		theClipper->DrawShape(drawShapeInfo[1]);
		renderedTriangles += drawShapeInfo[1]->shape->GetNumDrawnTriangles();
	}

	if(cloneMe == true && drawShapeInfo[0]->shape != NULL)
	{
		drawShapeInfo[0]->shapeToWorld = shapeOrigins[1];
		drawShapeInfo[0]->worldToShape = invertedShapeOrigin[1];

		theClipper->DrawShape(drawShapeInfo[0]);
		renderedTriangles += drawShapeInfo[0]->shape->GetNumDrawnTriangles();

		drawShapeInfo[0]->shapeToWorld = shapeOrigins[0];
		drawShapeInfo[0]->worldToShape = invertedShapeOrigin[0];
	}

	for(int i=0;i<moreShapes;i++)
	{
		if(i&1)
		{
			if(drawShapeInfo[1]->shape != NULL)
			{
				if(displacement)
				{
					*invertedMoreClones[1] = *shapeOrigins[1];

					for(int j=0;j<1+(i>>1);j++)
					{
						moreClones[1]->Multiply(*invertedMoreClones[1], displacementMatrix); 
						*invertedMoreClones[1] = *moreClones[1];
					}

					invertedMoreClones[1]->Invert(*moreClones[1]);

					drawShapeInfo[1]->shapeToWorld = moreClones[1];
					drawShapeInfo[1]->worldToShape = invertedMoreClones[1];
				}
				theClipper->DrawShape(drawShapeInfo[1]);
				renderedTriangles += drawShapeInfo[1]->shape->GetNumDrawnTriangles();

				if(displacement)
				{
					drawShapeInfo[1]->shapeToWorld = shapeOrigins[1];
					drawShapeInfo[1]->worldToShape = invertedShapeOrigin[1];
				}
			}
		}
		else
		{
			if(drawShapeInfo[0]->shape != NULL)
			{
				if(displacement)
				{
					*invertedMoreClones[0] = *shapeOrigins[0];

					for(int j=0;j<1+(i>>1);j++)
					{
						moreClones[0]->Multiply(*invertedMoreClones[0], displacementMatrix); 
						*invertedMoreClones[0] = *moreClones[0];
					}

					invertedMoreClones[0]->Invert(*moreClones[0]);

					drawShapeInfo[0]->shapeToWorld = moreClones[0];
					drawShapeInfo[0]->worldToShape = invertedMoreClones[0];
				}

				theClipper->DrawShape(drawShapeInfo[0]);
				renderedTriangles += drawShapeInfo[0]->shape->GetNumDrawnTriangles();

				if(displacement)
				{
					drawShapeInfo[0]->shapeToWorld = shapeOrigins[0];
					drawShapeInfo[0]->worldToShape = invertedShapeOrigin[0];
				}
			}
		}
	}

	theClipper->RenderNow();

	if(otherCamera==true)
	{
		SetViewportScalars(0.25f, 0.25f, 0.0f, 0.0f);
		ClearZBuffer();
		SetDefaultRenderStates();
		theClipper->ResetSorter((*states)[0]);

		if(animateTextures == true)
		{
			if((*states)[0].GetTextureHandle())
			{
				MLRTexture *texture = (*MLRTexturePool::Instance)[(*states)[0].GetTextureHandle()];
				texture->SetAnimateTexture(true);
				Stuff::AffineMatrix4D &textureMatrix = texture->GetTextureMatrix();
				textureMatrix(3, 0) += 0.005f;
				textureMatrix(3, 1) += 0.005f;
			}
			if((*states)[1].GetTextureHandle())
			{
				MLRTexture *texture = (*MLRTexturePool::Instance)[(*states)[1].GetTextureHandle()];
				texture->SetAnimateTexture(true);
				Stuff::AffineMatrix4D &textureMatrix = texture->GetTextureMatrix();
				textureMatrix(3, 0) -= 0.005f;
				textureMatrix(3, 1) -= 0.005f;
			}
		}
		else
		{
			if((*states)[0].GetTextureHandle())
			{
				MLRTexture *texture = (*MLRTexturePool::Instance)[(*states)[0].GetTextureHandle()];
				texture->SetAnimateTexture(false);
			}
			if((*states)[1].GetTextureHandle())
			{
				MLRTexture *texture = (*MLRTexturePool::Instance)[(*states)[1].GetTextureHandle()];
				texture->SetAnimateTexture(false);
			}
		}

		if(icoInfo[0].onOff == true && drawShapeInfo[0]->shape != NULL)
		{
			theClipper->DrawShape(drawShapeInfo[0]);
			renderedTriangles += drawShapeInfo[0]->shape->GetNumDrawnTriangles();
		}

		if(icoInfo[1].onOff == true && drawShapeInfo[1]->shape != NULL && cloneMe == false)
		{
			theClipper->DrawShape(drawShapeInfo[1]);
			renderedTriangles += drawShapeInfo[1]->shape->GetNumDrawnTriangles();
		}

		if(cloneMe == true && drawShapeInfo[0]->shape != NULL)
		{
			drawShapeInfo[0]->shapeToWorld = shapeOrigins[1];
			drawShapeInfo[0]->worldToShape = invertedShapeOrigin[1];

			theClipper->DrawShape(drawShapeInfo[0]);
			renderedTriangles += drawShapeInfo[0]->shape->GetNumDrawnTriangles();

			drawShapeInfo[0]->shapeToWorld = shapeOrigins[0];
			drawShapeInfo[0]->worldToShape = invertedShapeOrigin[0];
		}

		for(int i=0;i<moreShapes;i++)
		{
			if(i&1)
			{
				if(drawShapeInfo[1]->shape != NULL)
				{
					if(displacement)
					{
						*invertedMoreClones[1] = *shapeOrigins[1];

						for(int j=0;j<1+(i>>1);j++)
						{
							moreClones[1]->Multiply(*invertedMoreClones[1], displacementMatrix); 
							*invertedMoreClones[1] = *moreClones[1];
						}

						invertedMoreClones[1]->Invert(*moreClones[1]);

						drawShapeInfo[1]->shapeToWorld = moreClones[1];
						drawShapeInfo[1]->worldToShape = invertedMoreClones[1];
					}
					theClipper->DrawShape(drawShapeInfo[1]);
					renderedTriangles += drawShapeInfo[1]->shape->GetNumDrawnTriangles();

					if(displacement)
					{
						drawShapeInfo[1]->shapeToWorld = shapeOrigins[1];
						drawShapeInfo[1]->worldToShape = invertedShapeOrigin[1];
					}
				}
			}
			else
			{
				if(drawShapeInfo[0]->shape != NULL)
				{
					if(displacement)
					{
						*invertedMoreClones[0] = *shapeOrigins[0];

						for(int j=0;j<1+(i>>1);j++)
						{
							moreClones[0]->Multiply(*invertedMoreClones[0], displacementMatrix); 
							*invertedMoreClones[0] = *moreClones[0];
						}

						invertedMoreClones[0]->Invert(*moreClones[0]);

						drawShapeInfo[0]->shapeToWorld = moreClones[0];
						drawShapeInfo[0]->worldToShape = invertedMoreClones[0];
					}

					theClipper->DrawShape(drawShapeInfo[0]);
					renderedTriangles += drawShapeInfo[0]->shape->GetNumDrawnTriangles();

					if(displacement)
					{
						drawShapeInfo[0]->shapeToWorld = shapeOrigins[0];
						drawShapeInfo[0]->worldToShape = invertedShapeOrigin[0];
					}
				}
			}
		}

		theClipper->RenderNow();
	}

	char shapeDesc[256];
	if(visText==true)
	{
		int yOffset = 200;

		gos_TextSetRegion( 0, 0, 640, 480 );
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 1.0, 0, 1, 0, 0 );
		gos_TextSetPosition( 500, 0+yOffset );
		gos_TextDraw( "Shift -> change 2nd shape" );
		gos_TextSetPosition( 520, 10+yOffset );
		gos_TextDraw( "1 - 20 tri" );
		gos_TextSetPosition( 520, 20+yOffset );
		gos_TextDraw( "2 - 80 tri" );
		gos_TextSetPosition( 520, 30+yOffset );
		gos_TextDraw( "3 - 320 tri" );
		gos_TextSetPosition( 520, 40+yOffset );
		gos_TextDraw( "4 - 1280 tri" );
		gos_TextSetPosition( 520, 50+yOffset );
		gos_TextDraw( "5 - 5120 tri" );
		gos_TextSetPosition( 520, 60+yOffset );
		gos_TextDraw( "s - shape on/off" );
		gos_TextSetPosition( 520, 70+yOffset );
		gos_TextDraw( "i - non-/indexed" );
		gos_TextSetPosition( 520, 80+yOffset );
		gos_TextDraw( "c - non-/clipped" );
		gos_TextSetPosition( 520, 90+yOffset );
		gos_TextDraw( "= - radius += 0.2" );
		gos_TextSetPosition( 520, 100+yOffset );
		gos_TextDraw( "- - radius -= 0.2" );
		gos_TextSetPosition( 520, 110+yOffset );
		gos_TextDraw( "[/] - cycles types" );

		gos_TextSetPosition( 520, 160+yOffset );
		gos_TextDraw( "p - (no) displacement" );
		gos_TextSetPosition( 520, 170+yOffset );
		gos_TextDraw( "d - (do not) draw" );
		gos_TextSetPosition( 520, 180+yOffset );
		gos_TextDraw( ",/. - cyc.light type" );
		gos_TextSetPosition( 520, 190+yOffset );
		gos_TextDraw( "a - toggle anim.tex." );
		gos_TextSetPosition( 520, 200+yOffset );
		gos_TextDraw( "l - lights on/off" );
		gos_TextSetPosition( 520, 210+yOffset );
		gos_TextDraw( "o - clone on/off" );
		gos_TextSetPosition( 520, 220+yOffset );
		gos_TextDraw( "7/8 - less/more shapes" );
		gos_TextSetPosition( 520, 230+yOffset );
		gos_TextDraw( "F1/h - help on/off" );

		char shapeDesc[256];

		if(icoInfo[0].onOff && drawShapeInfo[0]->shape != NULL)
		{
			sprintf(shapeDesc, "Shape 1: 20 %s, %d tris, %sindexed, %s clipped, radius %.1fm, %s lit",
				icoInfo[0].GetTypeName(),
				drawShapeInfo[0]->shape->GetNumPrimitives(),
				icoInfo[0].indexed?"":"non",
				drawShapeInfo[0]->clippingFlags.GetClippingState()?"":"not",
				icoInfo[0].radius,
				drawShapeInfo[0]->nrOfActiveLights?"":"not"
			);
			gos_TextSetPosition( 10, 450 );
			gos_TextDraw( shapeDesc );
		}

		if(icoInfo[1].onOff && drawShapeInfo[1]->shape != NULL)
		{
			if(cloneMe)
			{
				gos_TextSetPosition( 10, 460 );
				gos_TextDraw( "Shape 2: cloned" );
			}
			else
			{
				sprintf(shapeDesc, "Shape 2: 20 %s, %d tris, %sindexed, %sclipped, radius %.1fm, %s lit",
					icoInfo[1].GetTypeName(),
					drawShapeInfo[1]->shape->GetNumPrimitives(),
					icoInfo[1].indexed?"":"non",
					drawShapeInfo[1]->clippingFlags.GetClippingState()?"":"not ",
					icoInfo[1].radius,
					drawShapeInfo[1]->nrOfActiveLights?"":"not"
				);
				gos_TextSetPosition( 10, 460 );
				gos_TextDraw( shapeDesc );
			}
		}

		int nrOfShapes = (icoInfo[0].onOff?1:0) + (icoInfo[1].onOff?1:0) + moreShapes;
		sprintf(shapeDesc, "%d Shape%s visible", nrOfShapes, (nrOfShapes==1)?"":"s");
		gos_TextSetPosition( 520, 450 );
		gos_TextDraw( shapeDesc );

		if(drawShapeInfo[1]->nrOfActiveLights)
		{
			gos_TextSetPosition( 520, 460 );
			switch(activeLightType)
			{
				case 0:
					gos_TextDraw( "ambient light" );
				break;
				case 1:
					gos_TextDraw( "infinite light" );
				break;
				case 2:
					gos_TextDraw( "infinit light w/falloff" );
				break;
				case 3:
					gos_TextDraw( "point light" );
				break;
				case 4:
					gos_TextDraw( "spot light" );
				break;
				case 5:
					gos_TextDraw( "point light w/LM" );
				break;
				case 6:
					gos_TextDraw( "spot light w/LM" );
				break;
				case 7:
					gos_TextDraw( "lookup light" );
				break;
			}
		}
	}
	
	static __int64 timeCounter, tempCounter;
	extern __int64 frequency;

	tempCounter = GetCycles();

	sprintf(shapeDesc, "%ld", (frequency/(tempCounter - timeCounter)));
	gos_TextSetPosition( 5, 5 );
	gos_TextDraw( shapeDesc );
	sprintf(shapeDesc, "%d", renderedTriangles/3);
	gos_TextSetPosition( 5, 15 );
	gos_TextDraw( shapeDesc );

	timeCounter = tempCounter;

}

int* bad_boy = (int*)0x16c7be8;

void __stdcall TerminateGameEngine()
{
	for(int i=0;i<nrOfShapes;i++)
	{
		if(drawShapeInfo[i]->shape != NULL)
		{
			drawShapeInfo[i]->shape->DetachReference();
		}
		
		Unregister_Object(drawShapeInfo[i]);
		delete drawShapeInfo[i];

		Unregister_Object(shapeOrigins[i]);
		delete shapeOrigins[i];

		Unregister_Object(invertedShapeOrigin[i]);
		delete invertedShapeOrigin[i];

		Unregister_Object(moreClones[i]);
		delete moreClones[i];

		Unregister_Object(invertedMoreClones[i]);
		delete invertedMoreClones[i];
	}

	Unregister_Object(theClipper);
	delete theClipper;

	for(i=0;i<8;i++)
	{
		Unregister_Object((*sceneLights)[i]);
		delete (*sceneLights)[i];
	}

	sceneLights->SetLength(0);
	Unregister_Object(sceneLights);
	delete sceneLights;

	states->SetLength(0);
	Unregister_Object(states);
	delete states;

	//
	//-------------------
	// Turn off libraries
	//-------------------
	//
//	MemoryBlockBase::UsageReport();
	Unregister_Object(MLRTexturePool::Instance);
	delete MLRTexturePool::Instance;
	MLRTexturePool::Instance = NULL;

	MidLevelRenderer::TerminateClasses();
	Stuff::TerminateClasses();
}


//
// Setup the GameOS structure
//
void __stdcall GetGameOSEnvironment( char* CommandLine )
{
	Environment.applicationName		= "MLR Stress Test";
	Environment.screenWidth				= 640;
	Environment.screenHeight			= 480;
	Environment.fullScreen				= FALSE;
	Environment.bitDepth					= 16;
	Environment.debugLog					= "MStress.txt";
	Environment.spew						= "GameOS_Memory*";			//"GameOS*";

	Environment.UpdateRenderers			= UpdateDisplay;
	Environment.DoGameLogic				= DoGameLogic;
	Environment.InitializeGameEngine	= InitializeGameEngine;
	Environment.TerminateGameEngine	= TerminateGameEngine;

	Environment.FullScreenDevice		= 0;

	Environment.Renderer				= 0;

	Environment.AntiAlias				= 0;			// true/false - Enable full screen antialiasing

//
// Texture infomation
//
	Environment.Texture_S_256			= 8;
	Environment.Texture_S_128			= 0;
	Environment.Texture_S_64			= 8;
	Environment.Texture_S_32			= 0;
	Environment.Texture_S_16			= 0;

	Environment.Texture_K_256			= 2;
	Environment.Texture_K_128			= 0;
	Environment.Texture_K_64			= 0;
	Environment.Texture_K_32			= 0;
	Environment.Texture_K_16			= 0;

	Environment.Texture_A_256			= 0;
	Environment.Texture_A_128			= 0;
	Environment.Texture_A_64			= 0;
	Environment.Texture_A_32			= 0;
	Environment.Texture_A_16			= 0;
}
