#include "MLRHeaders.hpp"

//#############################################################################
//###### MLR_I_C_PMesh with color but no lighting one texture layer  #####
//#############################################################################

MLR_I_C_PMesh::ClassData*
	MLR_I_C_PMesh::DefaultData = NULL;

HGOSHEAP
	MLR_I_C_PMesh::PrimitiveHeap = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLR_I_C_PMesh::InitializeClass()
{
	Verify(!PrimitiveHeap);
	PrimitiveHeap = gos_CreateMemoryHeap("MLR_I_C_PMesh", 0, MidLevelRenderer::PrimitiveHeap);
	Check_Pointer(PrimitiveHeap);

	Verify(!DefaultData);
	Verify(gos_GetCurrentHeap() == StaticHeap);
	DefaultData =
		new ClassData(
			MLR_I_C_PMeshClassID,
			"MidLevelRenderer::MLR_I_C_PMesh",
			MLR_I_PMesh::DefaultData,
			(MLRPrimitiveBase::Factory)&Make
		);
	Register_Object(DefaultData);
}

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

	Check_Pointer(PrimitiveHeap);
	gos_DestroyMemoryHeap(PrimitiveHeap);
	PrimitiveHeap = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLR_I_C_PMesh::MLR_I_C_PMesh(
	ClassData *class_data,
	MemoryStream *stream,
	int version
):
	MLR_I_PMesh(class_data, stream, version)
{
	Check_Pointer(this);
	Check_Pointer(stream);

	if (version<3)
		STOP(("This class got created only after version 2 !"));
	else if (version<11)
	{
		int color_count;
		*stream >> color_count;
		stream->AdvancePointer(color_count*sizeof(DWORD));
	}
	else
		MemoryStreamIO_Read(stream, &colors);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLR_I_C_PMesh::MLR_I_C_PMesh(ClassData *class_data):
	MLR_I_PMesh(class_data)
{
	Check_Pointer(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	MLR_I_C_PMesh::Copy(MLR_I_C_TMesh *tMesh)
{
	Check_Object(this);
	Check_Object(tMesh);

	int len;
	const ColorType *_colors;

	MLR_I_PMesh::Copy(tMesh);

	if(tMesh->dataStore!=NULL && tMesh->dataStore->colors.GetLength()>0)
	{
		tMesh->GetColorData(&_colors, &len);
		dataStore->colors.SetLength(len);
		Mem_Copy(dataStore->colors.GetData(), _colors, len*sizeof(ColorType), dataStore->colors.GetSize());
		SetColorData(dataStore->colors.GetData(), len);
	}
	else
	{
		tMesh->GetColorData(&_colors, &len);
		SetColorData(_colors, len);
	}

	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLR_I_C_PMesh::~MLR_I_C_PMesh()
{
	Check_Object(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLR_I_C_PMesh*
	MLR_I_C_PMesh::Make(
		MemoryStream *stream,
		int version
	)
{
	Check_Object(stream);

	gos_PushCurrentHeap(PrimitiveHeap);
	MLR_I_C_PMesh *mesh = new MLR_I_C_PMesh(DefaultData, stream, version);
	gos_PopCurrentHeap();

	return mesh;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLR_I_C_PMesh::Save(MemoryStream *stream)
{
	Check_Object(this);
	Check_Object(stream);

	MLR_I_PMesh::Save(stream);

	*stream << static_cast<int>(0);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLR_I_C_PMesh::TestInstance() const
{
	Verify(IsDerivedFrom(DefaultData));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLR_I_C_PMesh::SetColorData(
		const ColorType *data,
		int dataSize
	)
{
	Check_Object(this); 
	Check_Pointer(data);

	Verify(coords.GetLength() == 0 || dataSize == coords.GetLength());
	Verify(texCoords.GetLength() == 0 || dataSize == texCoords.GetLength());

	colors.AssignData(data, dataSize);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLR_I_C_PMesh::GetColorData(
		const ColorType **data,
		int *dataSize
	)
{
	Check_Object(this); 
	*data = colors.GetData();
	*dataSize = colors.GetLength();
}

#undef I_SAY_YES_TO_DUAL_TEXTURES
#define I_SAY_YES_TO_COLOR
#undef I_SAY_YES_TO_LIGHTING

#define CLASSNAME MLR_I_C_PMesh
#define CLASSNAMENOCOLOR MLR_I_PMesh

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	This include contains follwing functions:
//	void MLR_I_C_PMesh::TransformNoClip(Matrix4D*, GOSVertexPool*);
//	int MLR_I_C_PMesh::Clip(MLRClippingState, GOSVertexPool*);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#include <MLR\MLRPrimitiveClipping.hpp>

#undef I_SAY_YES_TO_COLOR
#undef CLASSNAME
#undef CLASSNAMENOCOLOR

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLR_I_C_PMesh*
	MidLevelRenderer::CreateIndexedCube_Color_NoLit(
		Scalar half, 
		const ColorType *colors,
		MLRState *state
	)
{
	gos_PushCurrentHeap(MLR_I_C_PMesh::PrimitiveHeap);
	MLR_I_C_PMesh *ret = new MLR_I_C_PMesh;
	Register_Object(ret);

	DynamicArrayOf<Point3D> *coords = &ret->dataStore->coords;
	Check_Object(coords);
	coords->SetLength(8);

	(*coords)[0] = Point3D( half, -half,  half);
	(*coords)[1] = Point3D(-half, -half,  half);
	(*coords)[2] = Point3D( half, -half, -half);
	(*coords)[3] = Point3D(-half, -half, -half);
	(*coords)[4] = Point3D(-half,  half,  half);
	(*coords)[5] = Point3D( half,  half,  half);
	(*coords)[6] = Point3D( half,  half, -half);
	(*coords)[7] = Point3D(-half,  half, -half);

	DynamicArrayOf<BYTE> *lengths = &ret->dataStore->lengths;
	Check_Object(lengths);
	lengths->SetLength(6);

	int i;

	for(i=0;i<6;i++)
	{
		(*lengths)[i] = 4;
	}

	ret->SetSubprimitiveLengths(lengths->GetData(), 6);

	ret->SetCoordData(coords->GetData(), 8);

	DynamicArrayOf<BYTE> *index = &ret->dataStore->index;
	Check_Object(index);
	index->SetLength(6*4);

	(*index)[0] = 0;
	(*index)[1] = 2;
	(*index)[2] = 6;
	(*index)[3] = 5;

	(*index)[4] = 0;
	(*index)[5] = 5;
	(*index)[6] = 4;
	(*index)[7] = 1;

	(*index)[8] = 5;
	(*index)[9] = 6;
	(*index)[10] = 7;
	(*index)[11] = 4;

	(*index)[12] = 2;
	(*index)[13] = 3;
	(*index)[14] = 7;
	(*index)[15] = 6;

	(*index)[16] = 1;
	(*index)[17] = 4;
	(*index)[18] = 7;
	(*index)[19] = 3;

	(*index)[20] = 0;
	(*index)[21] = 1;
	(*index)[22] = 3;
	(*index)[23] = 2;

	ret->SetIndexData(index->GetData(), 6*4);

	ret->FindFacePlanes();

	if(colors!=NULL)
	{
#if COLOR_AS_DWORD==0
		Check_Object(colors);
#endif
		ret->dataStore->colors.AssignData(colors, 8);
		ret->SetColorData(
			ret->dataStore->colors.GetData(),
			ret->dataStore->colors.GetLength()
		);
	}

	DynamicArrayOf<Vector2DScalar> *texCoords = &ret->dataStore->texCoords;
	Check_Object(texCoords);
	texCoords->SetLength(8);

	(*texCoords)[0] = Vector2DScalar(0.0f, 0.0f);
	(*texCoords)[1] = Vector2DScalar(0.0f, 0.0f);
	(*texCoords)[2] = Vector2DScalar(0.0f, 0.0f);
	(*texCoords)[3] = Vector2DScalar(0.0f, 0.0f);

	(*texCoords)[4] = Vector2DScalar(0.0f, 0.0f);
	(*texCoords)[5] = Vector2DScalar(0.0f, 0.0f);
	(*texCoords)[6] = Vector2DScalar(0.0f, 0.0f);
	(*texCoords)[7] = Vector2DScalar(0.0f, 0.0f);

	if(state != NULL)
	{
		ret->SetReferenceState(*state);
		if(state->GetTextureHandle() > 0)
		{
			(*texCoords)[0] = Vector2DScalar(0.0f, 0.0f);
			(*texCoords)[1] = Vector2DScalar(1.0f, 0.0f);
			(*texCoords)[2] = Vector2DScalar(0.25f, 0.25f);
			(*texCoords)[3] = Vector2DScalar(0.75f, 0.25f);

			(*texCoords)[4] = Vector2DScalar(1.0f, 1.0f);
			(*texCoords)[5] = Vector2DScalar(0.0f, 1.0f);
			(*texCoords)[6] = Vector2DScalar(0.25f, 0.75f);
			(*texCoords)[7] = Vector2DScalar(0.75f, 0.75f);
		}
	}
	ret->SetTexCoordData(texCoords->GetData(), 8);

	gos_PopCurrentHeap();
	return ret;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLR_I_PMesh*
	MidLevelRenderer::CreateIndexedViewFrustrum_Color_NoLit(
		MLRState *state,
		Stuff::Scalar near_clip,
		Stuff::Scalar far_clip,
		Stuff::Scalar left_clip,
		Stuff::Scalar right_clip,
		Stuff::Scalar top_clip,
		Stuff::Scalar bottom_clip,
		const ColorType &color
	)
{
	gos_PushCurrentHeap(MLR_I_C_PMesh::PrimitiveHeap);
	MLR_I_C_PMesh *ret = new MLR_I_C_PMesh();
	Register_Object(ret);

	DynamicArrayOf<Point3D> *coords = &ret->dataStore->coords;
	Check_Object(coords);
	coords->SetLength(8);

	Scalar right_far, left_far, top_far, bottom_far;
	Scalar fac = (near_clip + far_clip) / near_clip;

	right_far = right_clip*fac;
	left_far = left_clip*fac;
	top_far = top_clip*fac;
	bottom_far = bottom_clip*fac;

	(*coords)[0] = Point3D(left_far, bottom_far, far_clip);
	(*coords)[1] = Point3D(right_far, bottom_far, far_clip);
	(*coords)[2] = Point3D(left_clip, bottom_clip, near_clip);
	(*coords)[3] = Point3D(right_clip, bottom_clip, near_clip);
	(*coords)[4] = Point3D(right_far, top_far, far_clip);
	(*coords)[5] = Point3D(left_far, top_far, far_clip);
	(*coords)[6] = Point3D(left_clip, top_clip, near_clip);
	(*coords)[7] = Point3D(right_clip, top_clip, near_clip);

	DynamicArrayOf<BYTE> *lengths = &ret->dataStore->lengths;
	Check_Object(lengths);
	lengths->SetLength(6);

	int i;

	for(i=0;i<6;i++)
	{
		(*lengths)[i] = 4;
	}

//	ret->SetSubprimitiveLengths(lengths, 6);
	ret->SetSubprimitiveLengths(lengths->GetData(), 5);

	ret->SetCoordData(coords->GetData(), 8);

	DynamicArrayOf<BYTE> *index = &ret->dataStore->index;
	Check_Object(index);
	index->SetLength(6*4);

	(*index)[0] = 0;
	(*index)[1] = 5;
	(*index)[2] = 4;
	(*index)[3] = 1;

	(*index)[4] = 0;
	(*index)[5] = 1;
	(*index)[6] = 3;
	(*index)[7] = 2;

	(*index)[8] = 0;
	(*index)[9] = 2;
	(*index)[10] = 6;
	(*index)[11] = 5;

	(*index)[12] = 1;
	(*index)[13] = 4;
	(*index)[14] = 7;
	(*index)[15] = 3;

	(*index)[16] = 2;
	(*index)[17] = 3;
	(*index)[18] = 7;
	(*index)[19] = 6;

//	(*index)[20] = 5;
//	(*index)[21] = 6;
//	(*index)[22] = 7;
//	(*index)[23] = 4;

//	ret->SetIndexData(index, 6*4);
	ret->SetIndexData(index->GetData(), 5*4);

	ret->FindFacePlanes();

	DynamicArrayOf<ColorType> *colors = &ret->dataStore->colors;
	Check_Object(colors);
	colors->SetLength(8);
#if COLOR_AS_DWORD
	(*colors)[0] = color;
	for(i=1;i<8;i++)
	{
		(*colors)[i] = (*colors)[0];
	}

#else
	for(i=0;i<8;i++)
	{
		(*colors)[i] = color;
	}

	for(i=0;i<4;i++)
	{
		(*colors)[i].red *= 0.8f;;
		(*colors)[i].green *= 0.8f;;
		(*colors)[i].blue *= 0.8f;;

		(*colors)[i+4].red *= 1.2f;;
		(*colors)[i+4].green *= 1.2f;;
		(*colors)[i+4].blue *= 1.2f;;
	}
#endif

	ret->SetColorData(colors->GetData(), 8);

	DynamicArrayOf<Vector2DScalar> *texCoords = &ret->dataStore->texCoords;
	Check_Object(texCoords);
	texCoords->SetLength(8);

	(*texCoords)[0] = Vector2DScalar(0.0f, 0.0f);
	(*texCoords)[1] = Vector2DScalar(0.0f, 0.0f);
	(*texCoords)[2] = Vector2DScalar(0.0f, 0.0f);
	(*texCoords)[3] = Vector2DScalar(0.0f, 0.0f);

	(*texCoords)[4] = Vector2DScalar(0.0f, 0.0f);
	(*texCoords)[5] = Vector2DScalar(0.0f, 0.0f);
	(*texCoords)[6] = Vector2DScalar(0.0f, 0.0f);
	(*texCoords)[7] = Vector2DScalar(0.0f, 0.0f);

	ret->SetTexCoordData(texCoords->GetData(), 8);

	if(state != NULL)
	{
		ret->SetReferenceState(*state);
	}

	gos_PopCurrentHeap();
	return ret;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRShape*
	MidLevelRenderer::CreateIndexedIcosahedron_Color_NoLit(
		IcoInfo& icoInfo,
		MLRState *state
	)
{
	gos_PushCurrentHeap(ShapeHeap);
	MLRShape *ret = new MLRShape(20);
	Register_Object(ret);
	gos_PopCurrentHeap();

	gos_PushCurrentHeap(MLR_I_C_PMesh::PrimitiveHeap);
	int i, j, k;
	long    nrTri = (long) ceil (icoInfo.all * pow (4, icoInfo.depth));
	Point3D v[3];

	if(3*nrTri >= Limits::Max_Number_Vertices_Per_Mesh)
	{
		nrTri = Limits::Max_Number_Vertices_Per_Mesh/3;
	}

	int uniquePoints = 0;
	for (k=0;k<20;k++)
	{
		MidLevelRenderer::triDrawn = 0;
		MLR_I_C_PMesh *mesh = new MLR_I_C_PMesh();
		Register_Object(mesh);

		DynamicArrayOf<BYTE> *lengths = &mesh->dataStore->lengths;
		Check_Object(lengths);
		lengths->SetLength(nrTri);

		for(i=0;i<nrTri;i++)
		{
			(*lengths)[i] = 3;
		}

		DynamicArrayOf<Point3D> *coords = &mesh->dataStore->coords;
		Check_Object(coords);
		coords->SetLength(nrTri*3);

		DynamicArrayOf<BYTE> *index = &mesh->dataStore->index;
		Check_Object(index);
		index->SetLength(nrTri*3);

		DynamicArrayOf<Vector2DScalar> *texCoords = &mesh->dataStore->texCoords;
		Check_Object(texCoords);
		texCoords->SetLength(nrTri*3);

		DynamicArrayOf<ColorType> *colors = &mesh->dataStore->colors;
		Check_Object(colors);
		colors->SetLength(nrTri*3);

// setup vertex position information
	    for (j=0;j<3;j++)
		{
			v[j].x = vdata[tindices[k][j]][0];
			v[j].y = vdata[tindices[k][j]][1];
			v[j].z = vdata[tindices[k][j]][2];
		}
		subdivide (coords->GetData(), v[0], v[1], v[2], icoInfo.depth, nrTri, icoInfo.radius);

		mesh->SetSubprimitiveLengths(lengths->GetData(), nrTri);


		if(icoInfo.indexed==true)
		{
			uniquePoints = 1;
			Point3D *collapsedCoords = new Point3D [nrTri*3];
			Check_Pointer(collapsedCoords);
			collapsedCoords[0] = (*coords)[0];
			(*index)[0] = 0;

			for(i=1;i<nrTri*3;i++)
			{
				for(j=0;j<uniquePoints;j++)
				{
					if((*coords)[i] == collapsedCoords[j])
					{
						break;
					}
				}
				if(j==uniquePoints)
				{
					collapsedCoords[uniquePoints++] = (*coords)[i];
				}
				(*index)[i] = static_cast<BYTE>(j);
			}
			coords->AssignData(collapsedCoords, uniquePoints);
			mesh->SetCoordData(coords->GetData(), uniquePoints);
			Check_Pointer(collapsedCoords);
			delete [] collapsedCoords;
		}
		else
		{
			uniquePoints = nrTri*3;
			for(i=0;i<nrTri*3;i++)
			{
				(*index)[i] = static_cast<BYTE>(i);
			}
			mesh->SetCoordData(coords->GetData(), nrTri*3);
		}

		mesh->SetIndexData(index->GetData(), nrTri*3);

		mesh->FindFacePlanes();

		if(state == NULL)
		{
			for(i=0;i<uniquePoints;i++)
			{
				(*texCoords)[i] = Vector2DScalar(0.0f, 0.0f);
			}
		}
		else
		{
			mesh->SetReferenceState(*state);
			if(state->GetTextureHandle() > 0)
			{
				for(i=0;i<uniquePoints;i++)
				{
					(*texCoords)[i] = 
						Vector2DScalar(
							(1.0f + (*coords)[i].x)/2.0f,
							(1.0f + (*coords)[i].y)/2.0f
						);
					(*texCoords)[i+uniquePoints] = 
						Vector2DScalar(
							(1.0f + (*coords)[i].x)/2.0f,
							(1.0f + (*coords)[i].z)/2.0f
						);
				}
			}
			else
			{
				for(i=0;i<uniquePoints;i++)
				{
					(*texCoords)[i] = Vector2DScalar(0.0f, 0.0f);
				}
			}
		}
		mesh->SetTexCoordData(texCoords->GetData(), uniquePoints);

		for(i=0;i<uniquePoints;i++)
		{
#if COLOR_AS_DWORD>0
				RGBAColor c(
					(1.0f + (*coords)[i].x)/2.0f,
					(1.0f + (*coords)[i].y)/2.0f,
					(1.0f + (*coords)[i].z)/2.0f,
					1.0f
				);
			(*colors)[i] = GOSCopyColor(&c); 
#else
			(*colors)[i] = 
				RGBAColor(
					(1.0f + (*coords)[i].x)/2.0f,
					(1.0f + (*coords)[i].y)/2.0f,
					(1.0f + (*coords)[i].z)/2.0f,
					1.0f
				);
#endif
		}
		mesh->SetColorData(colors->GetData(), uniquePoints);

		ret->Add(mesh);
		mesh->DetachReference();
	}

	gos_PopCurrentHeap();
	return ret;
}
