#include "MLRHeaders.hpp"
#include <MLR\MLRCulturShape.hpp>

extern DWORD gShowBirdView, gEnableDetailTexture, gEnableMultiTexture, gEnableLightMaps, gEnableCulturals;

DrawShapeInformation::DrawShapeInformation()
{
	shape = NULL;
	state = NULL;
	shapeToWorld = NULL;
	worldToShape = NULL;

	activeLights = NULL;
	nrOfActiveLights = 0;

	clippingFlags.SetClippingState(0);
	
	paintMeColor = NULL;
};

DrawScalableShapeInformation::DrawScalableShapeInformation() : DrawShapeInformation()
{
	scaling = NULL;
}

DrawEffectInformation::DrawEffectInformation()
{
	effect = NULL;
	state = NULL;
	effectToWorld = NULL;

#if 0	
	activeLights = NULL;
	nrOfActiveLights = 0;
#endif

	clippingFlags.SetClippingState(0);
};

DrawScreenQuadsInformation::DrawScreenQuadsInformation()
{
	coords = NULL;
	colors = NULL;
	texCoords = NULL;
	onOrOff = NULL;

	nrOfQuads = 0;
};

int tCounter = 0;

//#############################################################################
//###########################    MLRClipper    ################################
//#############################################################################

MLRClipper::ClassData*
	MLRClipper::DefaultData = NULL;

bool
	Immediate_Draw = false;

static bool __stdcall CheckImmediateDraw()
{
	return Immediate_Draw;
}

static void __stdcall EnableImmediateDraw()
{
	Immediate_Draw=!Immediate_Draw;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRClipper::InitializeClass()
{
	Verify(!DefaultData);
	Verify(gos_GetCurrentHeap() == StaticHeap);
	DefaultData =
		new ClassData(
			MLRClipperClassID,
			"MidLevelRenderer::MLRClipper",
			RegisteredClass::DefaultData
		);
	Register_Object(DefaultData);

	AddDebuggerMenuItem("Libraries\\MLR\\Immediate Draw", CheckImmediateDraw, EnableImmediateDraw, NULL );
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRClipper::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRClipper::MLRClipper(AndyDisplay *ad, MLRSorter *s):
	RegisteredClass(DefaultData), display(ad)
{
	Verify(gos_GetCurrentHeap() == ClipperHeap);
	frameRate = 0;
	usedTime = 0.0f;
	nowTime = 0.0f;

	sorter = s;
//	camMatrix;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRClipper::~MLRClipper()
{
	if(sorter)
	{
		Unregister_Object(sorter);
		delete sorter;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MLRClipper::UpdateClipperCameraData(
		const LinearMatrix4D &camera_to_world,
		const Matrix4D &cameraToClip
	)

{
	Check_Object(this);

	Check_Object(&cameraToClip);

	cameraToClipMatrix = cameraToClip;

	cameraToWorldMatrix = camera_to_world;

	worldToCameraMatrix.Invert(cameraToWorldMatrix);

	worldToClipMatrix.Multiply(worldToCameraMatrix, cameraToClip);

	cameraPosition = cameraToWorldMatrix;
	UnitVector3D v;
	cameraToWorldMatrix.GetLocalForwardInWorld(&v);
	cameraDirection.Normalize(v);


}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRClipper::StartDraw (
		const LinearMatrix4D &camera_to_world,
		const Matrix4D &cameraToClip,
		const RGBAColor &,
		const RGBAColor *background_color,
		const MLRState &default_state,
		const Scalar *z_value,
		float top, float left, float bottom, float right
	)
{
	Check_Object(this);

	Check_Object(&cameraToClip);

	cameraToClipMatrix = cameraToClip;
//
//	No detail under software rasterizer
//
	if(Environment.Renderer == 3)
	{
		gEnableDetailTexture = 0;
	}

	MLRState::SetAGPAvailable(0<gos_GetMachineInformation(gos_Info_HasAGPAvailable));
	MLRState::SetMaxUV(static_cast<float>(gos_GetMachineInformation(gos_Info_GetMaximumUVSize, 256)));

	MLRState::SetCurrentTextureSize(256);
	if(MLRState::GetHasMaxUVs() && MLRState::GetMaxUV() < 32.0f)
	{
		gEnableLightMaps = 0;
	}

	MLRState::SetCanBumpEnvMap(0<gos_GetMachineInformation(gos_Info_CanBumpEnvMap));
	MLRState::SetCanBumpDotMap(0<gos_GetMachineInformation(gos_Info_CanBumpDotMap));

	if(gEnableMultiTexture!=0)
	{
		MLRState::SetMultitextureLightMap(0<gos_GetMachineInformation(gos_Info_CanMultitextureLightMap));
		MLRState::SetMultitextureSpecularMap(0<gos_GetMachineInformation(gos_Info_CanMultitextureSpecularMap));
		MLRState::SetMultitextureDetailMap(0<gos_GetMachineInformation(gos_Info_CanMultitextureDetail));
	}
	else
	{
		MLRState::SetMultitextureLightMap(false);
		MLRState::SetMultitextureSpecularMap(false);
		MLRState::SetMultitextureDetailMap(false);
	}

	if(tCounter++>5000)
	{
		tCounter = 0;
	}
//
// Make viewport the whole screen
//
	gos_PushCurrentHeap(ClipperHeap);
	Scalar z = 1.0f;
	DWORD back_color = 0;
	bool
		fill = false,
		clear = false;
	if (z_value)
	{
		Check_Pointer(z_value);
		z = *z_value;
		fill = true;
	}
	if (background_color)
	{
		Check_Pointer(background_color);
		back_color = GOSCopyColor(background_color);
		clear = true;

		MLRState::fogColor = back_color;
	}


	SetViewportScalars(top, left, bottom, right);
	gos_SetupViewport(
		fill,
		z,
		clear,
		back_color,
		top,
		left,
		bottom,
		right
	);

	SetDefaultRenderStates();

	if(cameraToClip(3, 2)>SMALL || cameraToClip(3, 2)<-SMALL)
	{
		sorter->SetFarClipReciprocal((1.0f-cameraToClip(2, 2))/cameraToClip(3, 2));
	}

	sorter->StartDraw(default_state);

	cameraToWorldMatrix = camera_to_world;

	worldToCameraMatrix.Invert(cameraToWorldMatrix);

// reset the CulturalShape containers
	MLRCulturShape::lastUsedMesh = 0;
	MLRCulturShape::lastUsedVertex = 0;

#ifdef LAB_ONLY

	if(gShowBirdView && Matrix4D::Identity != cameraToClip)
	{
		static YawPitchRange Camera_Direction(-Pi_Over_6, 0.0f, 15.0f);
		static Vector2DOf<Scalar> Camera_Shift(0.0f, 0.0f);
		static LinearMatrix4D birdsEye = LinearMatrix4D::Identity;

		//
		//---------------
		// 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
		//------------------------------------------------------
		//
		gosEnum_KeyStatus 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;

			Camera_Direction.range = Camera_Direction.range > 0.0f ? Camera_Direction.range : 0.0f;
		}

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

		LinearMatrix4D worldToBird = LinearMatrix4D::Identity;

		worldToBird.Multiply(worldToCameraMatrix, birdsEye);
		worldToCameraMatrix = worldToBird;

//	push the far clip out

		Scalar near_clip, far_clip, left_clip, right_clip,	top_clip, bottom_clip;
		Matrix4D birdToClip;

		cameraToClip.GetPerspective(&near_clip, &far_clip, &left_clip, &right_clip,	&top_clip, &bottom_clip);
		
		birdToClip.SetPerspective(
			near_clip,
			far_clip+2*Camera_Direction.range,
			left_clip,
			right_clip,
			top_clip,
			bottom_clip
		);

		worldToClipMatrix.Multiply(worldToCameraMatrix, birdToClip);
	}
	else
#endif

	worldToClipMatrix.Multiply(worldToCameraMatrix, cameraToClip);

	cameraPosition = cameraToWorldMatrix;
	UnitVector3D v;
	cameraToWorldMatrix.GetLocalForwardInWorld(&v);
	cameraDirection.Normalize(v);

//	Tell_Value(cameraPosition);

	MLRPrimitiveBase::InitializeDraw();
	sorter->Reset();

	allVerticesToDraw.Reset();

#ifdef CalDraw
	ToBeDrawnPrimitive::allVerticesToDraw = &allVerticesToDraw;
#endif

#ifdef LAB_ONLY
	if(gShowBirdView && Matrix4D::Identity != cameraToClip)
	{

		DrawShapeInformation drawShapeInfo;

		Scalar near_clip, far_clip, left_clip, right_clip,	top_clip, bottom_clip;
		RGBAColor fruCol(0.0f, 0.5f, 0.0f, 0.5f);
		MLRState fruState;

		cameraToClip.GetPerspective(&near_clip, &far_clip, &left_clip, &right_clip,	&top_clip, &bottom_clip);

		gos_PushCurrentHeap(ShapeHeap);
		drawShapeInfo.shape = new MLRShape(1);
		gos_PopCurrentHeap();

		Register_Object(drawShapeInfo.shape);

		fruState.SetTextureHandle(0);
		fruState.SetRenderDeltaMask(MLRState::TextureMask);

#ifdef OLDFOG
		fruState.SetFogMode(MLRState::DisableFogMode);
#else
		fruState.SetFogMode(0);
#endif

		fruState.SetZBufferCompareOn();
		fruState.SetZBufferWriteOn();
		fruState.SetBackFaceOff();
		fruState.SetWireFrameMode(MLRState::WireFrameAddMode);

		fruState.SetFilterMode(MLRState::BiLinearFilterMode);
		fruState.SetAlphaMode(MLRState::AlphaInvAlphaMode);
		fruState.SetPriority(MLRState::PriorityCount-1);

		MLRPrimitiveBase *primitive = 
			CreateIndexedViewFrustrum_Color_NoLit(
				&fruState, near_clip, far_clip, left_clip,	right_clip,	top_clip, bottom_clip,
#if COLOR_AS_DWORD>0
				GOSCopyColor(&fruCol)
#else				
				fruCol
#endif
			);

		drawShapeInfo.shape->Add(primitive);

		drawShapeInfo.clippingFlags.SetClippingState(0x3f);

		drawShapeInfo.shapeToWorld = &cameraToWorldMatrix;
		drawShapeInfo.worldToShape = &worldToCameraMatrix;

		DrawShape(&drawShapeInfo);

		drawShapeInfo.shape->DetachReference();

		gos_SetRenderState(	gos_State_Fog, 0);
	}
#endif

	gos_PopCurrentHeap();

//
// End timing function
//
}

static	AffineMatrix4D scaledShapeToWorld;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRClipper::DrawShape (DrawShapeInformation *dInfo)
{
	Check_Object(this);
//
// Statistic timing function
//
	MLR_RENDER("DrawShape");
	Start_Timer(Shape_Setup_Time);

	gos_PushCurrentHeap(ClipperHeap);
	MLRShape *shape = dInfo->shape;
	Check_Object(shape);

	MLRPrimitiveBase *primitive = NULL;
	Matrix4D shapeToClipMatrix;

	shapeToClipMatrix = Matrix4D::Identity;

	if(shape->IsDerivedFrom(MLRCulturShape::DefaultData))
	{
		if(MLRCulturShape::culturalRevolution!=NULL && gEnableCulturals!=0)
		{
			if(MLRCulturShape::lastUsedMesh >= MLRCulturShape::nrOfNaturalMeshes)
			{
				gos_PopCurrentHeap();
				return;
			}

			MLRCulturShape *culturShape = Cast_Object(MLRCulturShape*, shape);

			shapeToClipMatrix.Multiply(*dInfo->shapeToWorld, worldToClipMatrix);

			dInfo->state.SetFogMode(0);
			dInfo->state.SetPriority(1);
			dInfo->state.SetAlphaMode(MLRState::AlphaInvAlphaMode);
			dInfo->state.SetRenderPermissionMask(dInfo->state.GetRenderPermissionMask() & ~MLRState::AlphaMask);

			culturShape->culturalRevolution->InitializePrimitives(true, dInfo->state);

			int i;
			Point3D sp;
			Normal3D np;

			Vector3D v;

			sp.x = culturShape->centerInWorldX;
			sp.y = cameraPosition.y;
			sp.z = culturShape->centerInWorldZ;

			v.Subtract(sp, cameraPosition);
			v.y = 0.0;
			sp.Multiply(cameraPosition, *dInfo->worldToShape);

			if( (culturShape->fadeOutEnd+culturShape->radius) * (culturShape->fadeOutEnd+culturShape->radius) > v.GetLengthSquared() )
//			if( (culturShape->fadeOutEnd-culturShape->radius) * (culturShape->fadeOutEnd-culturShape->radius) < v.GetLengthSquared() )
			{
				v.Multiply(cameraDirection, *dInfo->worldToShape);
				np.Normalize(v);

			//	gos_GetViewport( &ViewportScalars::MulX, &ViewportScalars::MulY, &ViewportScalars::AddX, &ViewportScalars::AddY );

			#ifdef LAB_ONLY
				if(gShowBirdView)
				{
					dInfo->clippingFlags = 0x3f;
			#ifdef OLDFOG
					dInfo->state.SetFogMode(MLRState::DisableFogMode);
			#else
					dInfo->state.SetFogMode(0);
			#endif
					dInfo->state.SetRenderPermissionMask (
						dInfo->state.GetRenderPermissionMask() & ~MLRState::FogMask
					);
				}
			#endif

				paintMeColorDW = GOSCopyColor(MLRCulturShape::isDayTime ? &MLRCulturShape::dayColor : &MLRCulturShape::nightColor);
			#if !COLOR_AS_DWORD
				paintMeColorF = MLRCulturShape::isDayTime ? MLRCulturShape::dayColor : MLRCulturShape::nightColor;
			#endif

				Stop_Timer(Shape_Setup_Time);

				i = 0;
				while(i<culturShape->culturals.GetLength())
				{
					if(MLRCulturShape::lastUsedMesh >= MLRCulturShape::nrOfNaturalMeshes)
					{
						gos_PopCurrentHeap();
						return;
					}

					int usedVertices = 0;
					for(;i<culturShape->culturals.GetLength();i++)
					{
						v.Subtract(culturShape->culturals[i].loc, sp);
						v.y = 0.0f;

						Scalar dist = v.GetLengthSquared();
						if(dist > culturShape->fadeOutEnd*culturShape->fadeOutEnd)
						{
							continue;
						}

						Scalar scale = 1.0f;
						if(dist > culturShape->fadeOutStart*culturShape->fadeOutStart)
						{
							dist = Sqrt(dist) - culturShape->fadeOutStart;
							scale = 1.0f - dist/(culturShape->fadeOutEnd-culturShape->fadeOutStart);
						}

						RGBAColor fade = MLRCulturShape::isDayTime ? MLRCulturShape::dayColor : MLRCulturShape::nightColor;
						fade.alpha = scale;

						primitive = culturShape->culturalRevolution->allPrimitives[culturShape->culturals[i].type];
						Check_Object(primitive);

						const Point3D *points = NULL;
						const Vector2DScalar *texCoords = NULL;
						int nrOfPoints, nrOfTexCoords;

						primitive->GetCoordData(&points, &nrOfPoints);
						primitive->GetTexCoordData(&texCoords, &nrOfTexCoords);

						Verify(nrOfPoints==nrOfTexCoords);

						if( MLRCulturShape::lastUsedVertex + usedVertices + nrOfPoints >=
							MLRCulturShape::nrOfNaturalMeshes*Limits::Max_Number_Vertices_Per_Mesh)
						{
							i = culturShape->culturals.GetLength();
							break;
						}

						if(usedVertices + nrOfPoints > Limits::Max_Number_Vertices_Per_Mesh)
						{
							break;
						}

						LinearMatrix4D myOwnLittleWorld;

						myOwnLittleWorld = culturShape->culturals[i].loc;
						if(culturShape->culturals[i].yaw == 0xff)
						{
							v.y = 0.0f;
							v.Negate(v);

							myOwnLittleWorld.AlignLocalAxisToWorldVector(v, Z_Axis, Y_Axis, -1);
						}
						else
						{
							myOwnLittleWorld.BuildRotation(YawPitchRoll(2.0f*culturShape->culturals[i].yaw*Radians_Per_Degree, 0.0f, 0.0f));
						}

		//					myOwnLittleWorld(0,0) = scale;
		//					myOwnLittleWorld(1,1) = scale;
		//					myOwnLittleWorld(2,2) = scale; 

						LinearMatrix4D myOwnLittleShape;

						Point3D *coords = MLRCulturShape::theNaturalCoords->GetData() + MLRCulturShape::lastUsedVertex + usedVertices;
						Vector2DScalar *nTexCoords = MLRCulturShape::theNaturalTexCoords->GetData() + MLRCulturShape::lastUsedVertex + usedVertices;
						BYTE *indices = MLRCulturShape::theNaturalIndicies->GetData() + MLRCulturShape::lastUsedVertex + usedVertices;
						ColorType *colors = MLRCulturShape::theNaturalColors->GetData() + MLRCulturShape::lastUsedVertex + usedVertices;
		#if COLOR_AS_DWORD >0
						DWORD color = GOSCopyColor(&fade);
		#endif
						for(int j=0;j<nrOfPoints;j++)
						{
							coords[j].Multiply(points[j], myOwnLittleWorld);
							nTexCoords[j] = texCoords[j];

							indices[j] = static_cast<BYTE>(usedVertices+j);
		#if COLOR_AS_DWORD >0
							colors[j] = color;
		#else
							colors[j] = fade;
		#endif
						}

						usedVertices += nrOfPoints;

		//					myOwnLittleShape.Invert(myOwnLittleWorld);
					}

					MLR_I_C_TMesh *activeMesh = NULL;
					if(usedVertices==0)
					{
						gos_PopCurrentHeap();
						return;
					}
					else
					{
						activeMesh = (*MLRCulturShape::theNaturals)[MLRCulturShape::lastUsedMesh++];
					}

					activeMesh->SetCoordData(MLRCulturShape::theNaturalCoords->GetData() + MLRCulturShape::lastUsedVertex, usedVertices);
					activeMesh->SetTexCoordData(MLRCulturShape::theNaturalTexCoords->GetData() + MLRCulturShape::lastUsedVertex, usedVertices);
					activeMesh->SetIndexData(MLRCulturShape::theNaturalIndicies->GetData() + MLRCulturShape::lastUsedVertex, usedVertices);
					activeMesh->SetColorData(MLRCulturShape::theNaturalColors->GetData() + MLRCulturShape::lastUsedVertex, usedVertices);

					activeMesh->SetSubprimitiveLengths(NULL, (int)(usedVertices*0.33333333333333333333333333333334f), false);

					activeMesh->SetReferenceState(culturShape->culturalRevolution->allPrimitives[0]->GetReferenceState());
					activeMesh->CombineStates(dInfo->state);

					MLRCulturShape::lastUsedVertex += usedVertices;

					if(activeMesh->GetReferenceState().GetDrawNowMode()==MLRState::DrawNowOffMode && !Immediate_Draw)
					{
						Start_Timer(Shape_Setup_Time);
						ToBeDrawnPrimitive *tbdp = sorter->GetCurrentTBDP();
						if(tbdp==NULL)
						{
							gos_PopCurrentHeap();
							return;
						}
						Check_Pointer(tbdp);

						tbdp->type = 1;

						tbdp->primitive = activeMesh;
						Verify(activeMesh->GetNumPasses() < 2);

						tbdp->state = activeMesh->GetCurrentState();
		//					tbdp->cameraPosition.Multiply(sp, myOwnLittleShape);
		//					tbdp->cameraDirection.Multiply(np, myOwnLittleShape);
						tbdp->cameraPosition = cameraPosition;
						tbdp->cameraDirection = cameraDirection;
						tbdp->clippingFlags = dInfo->clippingFlags;

						Check_Object(&tbdp->shapeToClipMatrix);

		//					tbdp->shapeToClipMatrix.Multiply(myOwnLittleWorld, shapeToClipMatrix);
						tbdp->shapeToClipMatrix = shapeToClipMatrix;
						tbdp->worldToShape = *dInfo->worldToShape;

		#if COLOR_AS_DWORD >0
		//					tbdp->paintMeColor = GOSCopyColor(&fade);
						tbdp->paintMeColor = GOSCopyColor(dInfo->paintMeColor);
		#else
		//					tbdp->paintMeColor = fade;
						tbdp->paintMeColor = dInfo->paintMeColor;
		#endif
						tbdp->nrOfActiveLights = 0;

						sorter->IncreaseTBDPCounter();
						Stop_Timer(Shape_Setup_Time);
					}
					else
					{
			#ifdef LAB_ONLY
						const BYTE *length_array;
						const Point3D *coord_array;
						int vcount, icount;
						activeMesh->GetSubprimitiveLengths(&length_array, &icount);
						activeMesh->GetCoordData(&coord_array, &vcount);

						if(icount==0)
						{
							icount = 3 * activeMesh->GetNumPrimitives() * activeMesh->GetNumPasses();
						}
						else
						{
							if(length_array != NULL)
							{
								int j=0;
								for(int i=0;i<icount;i++)
								{
									j+=length_array[i];
								}
								icount = j;
							}
							else
							{
								icount *= 3;
							}

							icount *= activeMesh->GetNumPasses();
						}

						if(Limits::Max_Number_Vertices_Per_Frame < allVerticesToDraw.GetLast() + vcount)
						{
							SPEWALWAYS((0, "Not drawing ScreenQuads. Too many vertices! Raid a bug to Art!"));
							gos_PopCurrentHeap();
							return;
						}


						if(Limits::Max_Number_Vertices_Per_Frame < allVerticesToDraw.GetLastIndex() + icount)
						{
							SPEWALWAYS((0, "Not drawing MLR-mesh. Too many indices! Raid a bug to Art!"));
							gos_PopCurrentHeap();
							return;
						}
			#endif

		//					Matrix4D myOwnLittleClipMatrix;

		//					myOwnLittleClipMatrix.Multiply(myOwnLittleWorld, shapeToClipMatrix);
						
						if(activeMesh->TransformAndClip(
							&shapeToClipMatrix,
							dInfo->clippingFlags,
							&allVerticesToDraw,
							NULL,
							paintMeColorDW
						))
						{
							if(activeMesh->GetVisible())
							{
								Verify(activeMesh->GetNumPasses() < 2);
								sorter->DrawPrimitive(activeMesh);
							}
						}
#ifdef LAB_ONLY
						Set_Statistic(Number_Of_Primitives, Number_Of_Primitives+1);

						if(activeMesh->IsDerivedFrom(MLRIndexedPrimitiveBase::DefaultData))
						{
							const Point3D *coords;
							const BYTE *indices;
							int nr;

							(Cast_Pointer(MLRIndexedPrimitiveBase*, activeMesh))->GetIndexData(&indices, &nr);
							NumAllIndices += nr;

							activeMesh->GetCoordData(&coords, &nr);
							NumAllVertices += nr;

							Set_Statistic(Index_Over_Vertex_Ratio, (Scalar)NumAllIndices/(Scalar)NumAllVertices);
						}
#endif
					}
				}
			}
		}
	}
	else
	{
		if(dInfo->nrOfActiveLights > Limits::Max_Number_Of_Lights_Per_Primitive)
		{
			dInfo->nrOfActiveLights = Limits::Max_Number_Of_Lights_Per_Primitive;
		}

		shapeToClipMatrix.Multiply(*dInfo->shapeToWorld, worldToClipMatrix);

		shape->InitializePrimitives(true, dInfo->state);

		int i, j;
		Point3D sp;
		Normal3D np;

		Vector3D v;

		int	nrOfLightMaps = 0;
		sp.Multiply(cameraPosition, *dInfo->worldToShape);
		v.Multiply(cameraDirection, *dInfo->worldToShape);

		np.Normalize(v);

		for(i=0;i<dInfo->nrOfActiveLights;i++)
		{
			dInfo->activeLights[i]->SetLightToShapeMatrix(*dInfo->worldToShape);
			nrOfLightMaps += (dInfo->activeLights[i]->GetLightMap()) ? 1 : 0;
		}

		if(!gEnableLightMaps)
		{
			nrOfLightMaps = 0;
		}

	//	gos_GetViewport( &ViewportScalars::MulX, &ViewportScalars::MulY, &ViewportScalars::AddX, &ViewportScalars::AddY );

	#ifdef LAB_ONLY
		if(gShowBirdView)
		{
			dInfo->clippingFlags = 0x3f;
	#ifdef OLDFOG
			dInfo->state.SetFogMode(MLRState::DisableFogMode);
	#else
			dInfo->state.SetFogMode(0);
	#endif
			dInfo->state.SetRenderPermissionMask (
				dInfo->state.GetRenderPermissionMask() & ~MLRState::FogMask
			);
		}
	#endif

		if(dInfo->paintMeColor!=NULL)
		{
	#if COLOR_AS_DWORD
			paintMeColorDW = GOSCopyColor(dInfo->paintMeColor);
	#else
			paintMeColorF = *dInfo->paintMeColor;
			paintMeColorDW = GOSCopyColor(dInfo->paintMeColor);
	#endif
		}

		Stop_Timer(Shape_Setup_Time);

		for(i=0;i<shape->numPrimitives;i++)
		{
			primitive = shape->allPrimitives[i];
			Check_Object(primitive);

			if(primitive->GetCurrentState().GetDrawNowMode()==MLRState::DrawNowOffMode && !Immediate_Draw)
			{
				Start_Timer(Shape_Setup_Time);

				ToBeDrawnPrimitive *tbdp = sorter->GetCurrentTBDP();
				if(tbdp==NULL)
				{
					gos_PopCurrentHeap();
					return;
				}
				Check_Pointer(tbdp);
				tbdp->type = 0;

				tbdp->primitive = primitive;

				tbdp->state = primitive->GetCurrentState();
				tbdp->cameraPosition = sp;
				tbdp->cameraDirection = np;
				tbdp->clippingFlags = dInfo->clippingFlags;

				Check_Object(&tbdp->shapeToClipMatrix);
				tbdp->shapeToClipMatrix = shapeToClipMatrix;
				tbdp->worldToShape = *dInfo->worldToShape;

#if COLOR_AS_DWORD==0
				Check_Object(dInfo->paintMeColor);
#endif
				if(dInfo->paintMeColor)
				{
					tbdp->paintMeColor = GOSCopyColor(dInfo->paintMeColor);
				}
				else
				{
#if COLOR_AS_DWORD>0
					tbdp->paintMeColor = 0xffffffff;
#else
					tbdp->paintMeColor = RGBAColor::White;
#endif
				}

				Verify(dInfo->nrOfActiveLights <= Limits::Max_Number_Of_Lights_Per_Primitive);

				tbdp->nrOfActiveLights = dInfo->nrOfActiveLights;

				for(j=0;j<tbdp->nrOfActiveLights;j++)
				{
					Check_Object(dInfo->activeLights[j]);
					tbdp->activeLights[j] = dInfo->activeLights[j];
				}

				sorter->IncreaseTBDPCounter();
				Stop_Timer(Shape_Setup_Time);
			}
			else
			{
	#ifdef LAB_ONLY
				const BYTE *length_array;
				const Point3D *coord_array;
				int vcount, icount;
				primitive->GetSubprimitiveLengths(&length_array, &icount);
				primitive->GetCoordData(&coord_array, &vcount);

				if(icount==0)
				{
					icount = 3 * primitive->GetNumPrimitives() * primitive->GetNumPasses();
				}
				else
				{
					if(length_array != NULL)
					{
						int j=0;
						for(int i=0;i<icount;i++)
						{
							j+=length_array[i];
						}
						icount = j;
					}
					else
					{
						icount *= 3;
					}

					icount *= primitive->GetNumPasses();
				}

				if(Limits::Max_Number_Vertices_Per_Frame < allVerticesToDraw.GetLast() + vcount)
				{
					SPEWALWAYS((0, "Not drawing ScreenQuads. Too many vertices! Raid a bug to Art!"));
					gos_PopCurrentHeap();
					return;
				}


				if(Limits::Max_Number_Vertices_Per_Frame < allVerticesToDraw.GetLastIndex() + icount)
				{
					SPEWALWAYS((0, "Not drawing MLR-mesh. Too many indices! Raid a bug to Art!"));
					gos_PopCurrentHeap();
					return;
				}
	#endif

				if(nrOfLightMaps)
				{
					MLRLightMap::SetDrawData
						(
							&allVerticesToDraw,
							&shapeToClipMatrix,
							dInfo->clippingFlags,
							dInfo->state
						);
				}

				if(primitive->FindBackFace(sp, np))
				{
					primitive->Lighting(dInfo->activeLights, dInfo->nrOfActiveLights);

					FogData fogData;
					bool fog = primitive->FogMesh(dInfo->worldToShape, &sp, &fogData);

					if(dInfo->clippingFlags.GetClippingState() != 0)
					{
						if(primitive->TransformAndClip(
							&shapeToClipMatrix,
							dInfo->clippingFlags,
							&allVerticesToDraw,
							fog ? &fogData : NULL,
							paintMeColorDW
							)
						)
						{
							if(primitive->GetVisible())
							{
								for(j=0;j<primitive->GetNumPasses();j++)
								{
									sorter->DrawPrimitive(primitive, j);
								}
								
							}
						}
					}
					else
					{
						primitive->TransformNoClip(
							&shapeToClipMatrix,
							&allVerticesToDraw,
							fog ? &fogData : NULL,
							paintMeColorDW
						);

						for(j=0;j<primitive->GetNumPasses();j++)
						{
							sorter->DrawPrimitive(primitive, j);
						}
					}

	#ifdef LAB_ONLY
					Set_Statistic(Number_Of_Primitives, Number_Of_Primitives+1);

					if(primitive->IsDerivedFrom(MLRIndexedPrimitiveBase::DefaultData))
					{
						const Point3D *coords;
						const BYTE *indices;
						int nr;

						(Cast_Pointer(MLRIndexedPrimitiveBase*, primitive))->GetIndexData(&indices, &nr);
						NumAllIndices += nr;

						primitive->GetCoordData(&coords, &nr);
						NumAllVertices += nr;

						Set_Statistic(Index_Over_Vertex_Ratio, (Scalar)NumAllIndices/(Scalar)NumAllVertices);
					}
	#endif
					if(nrOfLightMaps)
					{
						MLRLightMap::DrawLightMaps(sorter, false);
					}
				}
			}
		}
	}
//
// End timing function
//
	gos_PopCurrentHeap();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRClipper::DrawScalableShape (DrawScalableShapeInformation *dInfo)
{
	Check_Object(this);
//
// Statistic timing function
//
	MLR_RENDER("DrawScalableShape");
	Start_Timer(Shape_Setup_Time);

	MLRShape *shape = dInfo->shape;
	MLRPrimitiveBase *primitive = NULL;

	Matrix4D shapeToClipMatrix;

	shapeToClipMatrix.Multiply(*dInfo->shapeToWorld, worldToClipMatrix);

	shape->InitializePrimitives(true, dInfo->state, 1);

	if(dInfo->scaling != NULL)
	{
		LinearMatrix4D scale = LinearMatrix4D::Identity;

		scale(0,0) = dInfo->scaling->x;
		scale(1,1) = dInfo->scaling->y;
		scale(2,2) = dInfo->scaling->z; 

		scaledShapeToWorld.Multiply(scale, *dInfo->shapeToWorld);

		shapeToClipMatrix.Multiply(scaledShapeToWorld, worldToClipMatrix);
	}
	else
	{
		shapeToClipMatrix.Multiply(*dInfo->shapeToWorld, worldToClipMatrix);
	}

	int i, j;

#ifdef LAB_ONLY
	if(gShowBirdView)
	{
		dInfo->clippingFlags = 0x3f;
	}
#endif

	Stop_Timer(Shape_Setup_Time);

	for(i=0;i<shape->numPrimitives;i++)
	{
		primitive = shape->allPrimitives[i];
		Check_Object(primitive);

#ifdef LAB_ONLY
		Set_Statistic(Number_Of_Primitives, Number_Of_Primitives+1);
#endif

		if(primitive->GetCurrentState().GetDrawNowMode()==MLRState::DrawNowOffMode && !Immediate_Draw)
		{
			Start_Timer(Shape_Setup_Time);
			for(int k=0;k<primitive->GetNumPasses();k++)
			{
				ToBeDrawnPrimitive *tbdp = sorter->GetCurrentTBDP();
				if(tbdp==NULL)
				{
					return;
				}
				Check_Pointer(tbdp);
				tbdp->type = 1;

				tbdp->primitive = primitive;

				tbdp->state = primitive->GetCurrentState();
				tbdp->cameraPosition = Point3D::Identity;
				tbdp->cameraDirection = UnitVector3D(1.0f, 0.0f, 0.0f);
				tbdp->clippingFlags = dInfo->clippingFlags;

				Check_Object(&tbdp->shapeToClipMatrix);
				tbdp->shapeToClipMatrix = shapeToClipMatrix;
				tbdp->worldToShape = LinearMatrix4D::Identity;

#if COLOR_AS_DWORD==0
				Check_Object(dInfo->paintMeColor);
#endif
				if(dInfo->paintMeColor)
				{
					tbdp->paintMeColor = GOSCopyColor(dInfo->paintMeColor);
				}
				else
				{
#if COLOR_AS_DWORD>0
					tbdp->paintMeColor = 0xffffffff;
#else
					tbdp->paintMeColor = RGBAColor::White;
#endif
				}

				Verify(dInfo->nrOfActiveLights <= Limits::Max_Number_Of_Lights_Per_Primitive);
				tbdp->nrOfActiveLights = dInfo->nrOfActiveLights;

				for(j=0;j<tbdp->nrOfActiveLights;j++)
				{
					Check_Object(dInfo->activeLights[j]);
					tbdp->activeLights[j] = dInfo->activeLights[j];
				}
				
				sorter->IncreaseTBDPCounter();
			}
			Stop_Timer(Shape_Setup_Time);
		}
		else
		{

#ifdef LAB_ONLY
			const BYTE *length_array;
			const Point3D *coord_array;
			int vcount, icount;
			primitive->GetSubprimitiveLengths(&length_array, &icount);
			primitive->GetCoordData(&coord_array, &vcount);

			if(icount==0)
			{
				icount = 3 * primitive->GetNumPrimitives() * primitive->GetNumPasses();
			}
			else
			{
				if(length_array != NULL)
				{
					int j=0;
					for(int i=0;i<icount;i++)
					{
						j+=length_array[i];
					}
					icount = j;
				}
				else
				{
					icount *= 3;
				}

				icount *= primitive->GetNumPasses();
			}

			if(Limits::Max_Number_Vertices_Per_Frame < allVerticesToDraw.GetLast() + vcount)
			{
				SPEWALWAYS((0, "Not drawing ScreenQuads. Too many vertices! Raid a bug to Art!"));
				gos_PopCurrentHeap();
				return;
			}


			if(Limits::Max_Number_Vertices_Per_Frame < allVerticesToDraw.GetLastIndex() + icount)
			{
				SPEWALWAYS((0, "Not drawing MLR-mesh. Too many indices! Raid a bug to Art!"));
				gos_PopCurrentHeap();
				return;
			}
#endif

#if COLOR_AS_DWORD==0
			Check_Object(dInfo->paintMeColor);
#endif
			if(dInfo->clippingFlags.GetClippingState() != 0)
			{
				if(primitive->TransformAndClip(&shapeToClipMatrix, dInfo->clippingFlags, &allVerticesToDraw, NULL, paintMeColorDW))
				{
					if(primitive->GetVisible())
					{
						for(j=0;j<primitive->GetNumPasses();j++)
						{
							sorter->DrawPrimitive(primitive, j);
							
						}
					}
				}
			}
			else
			{
				primitive->TransformNoClip(&shapeToClipMatrix, &allVerticesToDraw, NULL, paintMeColorDW);

				for(j=0;j<primitive->GetNumPasses();j++)
				{
					sorter->DrawPrimitive(primitive, j);
				}
			}
		}
	}
//
// End timing function
//
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRClipper::DrawEffect (DrawEffectInformation *dInfo)
{
//
// Statistic timing function
//

	Check_Object(this);
	Check_Object(dInfo);
	Check_Object(dInfo->effect);

#ifdef LAB_ONLY
	if(gShowBirdView)
	{
		dInfo->clippingFlags = 0x3f;
	}
#endif

	if(dInfo->state.GetDrawNowMode()==MLRState::DrawNowOffMode && !Immediate_Draw)
	{
		ToBeDrawnPrimitive *tbdp = sorter->GetCurrentTBDP();
		if(tbdp==NULL)
		{
			return;
		}

		Check_Pointer(tbdp);
		tbdp->type = 2;

		Check_Object(dInfo->effect);
		tbdp->primitive = dInfo->effect;

		tbdp->state = dInfo->state;
		tbdp->cameraPosition;
		tbdp->cameraDirection;
		tbdp->clippingFlags = dInfo->clippingFlags;

		tbdp->shapeToClipMatrix.Multiply(*dInfo->effectToWorld, worldToClipMatrix);

		tbdp->worldToShape = LinearMatrix4D::Identity;

		tbdp->allVerticesToDraw = &allVerticesToDraw;

		tbdp->nrOfActiveLights = 0;

#if COLOR_AS_DWORD>0
		tbdp->paintMeColor = 0xffffffff;
#else
		tbdp->paintMeColor = RGBAColor::White;
#endif


		sorter->IncreaseTBDPCounter();
	}
	else
	{
		dInfo->effect->SetEffectToClipMatrix(dInfo->effectToWorld, &worldToClipMatrix);
		dInfo->effect->Draw(dInfo, &allVerticesToDraw, sorter);
	}
//
// End timing function
//
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRClipper::DrawScreenQuads (DrawScreenQuadsInformation *dInfo)
{
//
// Statistic timing function
//

	Check_Object(this);
	Check_Object(dInfo);

#ifdef LAB_ONLY
	if(Limits::Max_Number_Vertices_Per_Frame + 4*Limits::Max_Number_ScreenQuads_Per_Frame <
		allVerticesToDraw.GetLast() + dInfo->nrOfQuads * 4)
	{
		SPEWALWAYS((0, "Not drawing ScreenQuads. Too many vertices! Raid a bug to Art!"));
		return;
	}
#endif

//	gos_GetViewport( &ViewportScalars::MulX, &ViewportScalars::MulY, &ViewportScalars::AddX, &ViewportScalars::AddY );

	GOSVertex *vertices	= allVerticesToDraw.GetActualVertexPool();

	int i, j;

	dInfo->currentNrOfQuads = 0;

	for(i=0,j=0;i<dInfo->nrOfQuads;i++)
	{
		if(dInfo->onOrOff[i] == true)
		{
			dInfo->currentNrOfQuads += 4;
			for(;j<dInfo->currentNrOfQuads;j++)
			{
				int offset = (i<<2) + (j&3);

				Verify(dInfo->coords[offset].x >= 0.0f && dInfo->coords[offset].x <= dInfo->coords[offset].w );
				Verify(dInfo->coords[offset].y >= 0.0f && dInfo->coords[offset].y <= dInfo->coords[offset].w );
				Verify(dInfo->coords[offset].z >= 0.0f && dInfo->coords[offset].z <= dInfo->coords[offset].w );

				vertices[j].x = (1.0f-dInfo->coords[offset].x)*ViewportScalars::MulX + ViewportScalars::AddX;
				vertices[j].y = (1.0f-dInfo->coords[offset].y)*ViewportScalars::MulY + ViewportScalars::AddY;
				vertices[j].z = dInfo->coords[offset].z;
				vertices[j].rhw = dInfo->coords[offset].w;

				vertices[j].argb = GOSCopyColor(dInfo->colors + offset);

				vertices[j].u = dInfo->texCoords[offset][0];
				vertices[j].v = dInfo->texCoords[offset][1];

			}
		}
	}

	if(j>0)
	{
		allVerticesToDraw.Increase(j);

		sorter->AddScreenQuads(vertices, dInfo);
	}
//
// End timing function
//
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRClipper::Clear (unsigned int flags)
{
	Check_Object(this);
}