/******************************************************************************

 @File         PVRTFixedPoint.cpp

 @Title        PVRTFixedPoint

 @Version      

 @Copyright    Copyright (c) Imagination Technologies Limited.

 @Platform     Independant

 @Description  Converts MAX exported meshes to fixed point objects for use with
               opengles lite.

******************************************************************************/
#include <math.h>
#include <string.h>
#include "PVRTContext.h"
#include "PVRTFixedPoint.h"

/********************************************************
** Most of the code only applies to CommonLite profile **
********************************************************/
#ifdef PVRT_FIXED_POINT_ENABLE

/*!***************************************************************************
 @Function		CreateFixedObjectMesh
 @Input			mesh	The mesh to create the fixed point version from
 @Returns		A fixed point version of mesh
 @Description	Converts model floating point data to fixed point
*****************************************************************************/
HeaderStruct_Fixed_Mesh *CreateFixedObjectMesh(HeaderStruct_Mesh *mesh)
{
	HeaderStruct_Fixed_Mesh *new_mesh = new HeaderStruct_Fixed_Mesh;

	new_mesh->fCenter[0] = PVRTF2X(mesh->fCenter[0]);
	new_mesh->fCenter[1] = PVRTF2X(mesh->fCenter[1]);
	new_mesh->fCenter[2] = PVRTF2X(mesh->fCenter[2]);


	new_mesh->nNumVertex = mesh->nNumVertex;
	new_mesh->nNumFaces = mesh->nNumFaces;
	new_mesh->nNumStrips = mesh->nNumStrips;
	new_mesh->nMaterial = mesh->nMaterial;

	if(mesh->nNumVertex)
	{
		new_mesh->pVertex = new VERTTYPE[mesh->nNumVertex*3];
		for(unsigned int i = 0; i < mesh->nNumVertex*3; i++)		// each vertex is 3 floats
			new_mesh->pVertex[i] = PVRTF2X(mesh->pVertex[i]);
	}
	else
	{
		new_mesh->pVertex = 0;
		new_mesh->nNumVertex = 0;
	}

	if(mesh->pUV)
	{
		new_mesh->pUV = new VERTTYPE[mesh->nNumVertex*2];
		for(unsigned int i = 0; i < mesh->nNumVertex*2; i++)		// UVs come in pairs of floats
			new_mesh->pUV[i] = PVRTF2X(mesh->pUV[i]);
	}
	else
		new_mesh->pUV = 0;

	if(mesh->pNormals)
	{
		new_mesh->pNormals = new VERTTYPE[mesh->nNumVertex*3];
		for(unsigned int i = 0; i < mesh->nNumVertex*3; i++)		// each normal is 3 floats
			new_mesh->pNormals[i] = PVRTF2X(mesh->pNormals[i]);
	}
	else
	{
		new_mesh->pNormals = 0;
	}

	/*
	 * Format of packedVerts is
	 *		Position
	 *		Normal / Colour
	 *		UVs
	 */

#define MF_NORMALS 1
#define MF_VERTEXCOLOR 2
#define MF_UV 3

	if(mesh->pPackedVertex)
	{
		unsigned int nPackedVertSize = mesh->nNumVertex * 3 +
					(mesh->nFlags & MF_NORMALS		? mesh->nNumVertex * 3 : 0) +
					(mesh->nFlags & MF_VERTEXCOLOR	? mesh->nNumVertex * 3 : 0) +
					(mesh->nFlags & MF_UV			? mesh->nNumVertex * 2 : 0);

		new_mesh->pPackedVertex = new VERTTYPE[nPackedVertSize];
		for(unsigned int i = 0; i < nPackedVertSize; i++)
			new_mesh->pPackedVertex[i] = PVRTF2X(mesh->pPackedVertex[i]);
	}
	else
		new_mesh->pPackedVertex = 0;

	// simply copy reference to all properties which do not need conversion (indicies)

	new_mesh->pVertexColor				= mesh->pVertexColor;
	new_mesh->pVertexMaterial			= mesh->pVertexMaterial;
	new_mesh->pFaces					= mesh->pFaces;
	new_mesh->pStrips					= mesh->pStrips;
	new_mesh->pStripLength				= mesh->pStripLength;

	// we're leaving the patch stuff alone

	new_mesh->Patch.nType				= mesh->Patch.nType;
	new_mesh->Patch.nNumPatches			= mesh->Patch.nNumPatches;
	new_mesh->Patch.nNumVertices		= mesh->Patch.nNumVertices;
	new_mesh->Patch.nNumSubdivisions	= mesh->Patch.nNumSubdivisions;
	new_mesh->Patch.pControlPoints		= mesh->Patch.pControlPoints;
	new_mesh->Patch.pUVs				= mesh->Patch.pUVs;

	return new_mesh;
}

/*!***************************************************************************
 @Function		FreeFixedObjectMesh
 @Input			mesh	The mesh to delete
 @Description	Release memory allocated in CreateFixedObjectMesh()
*****************************************************************************/
void FreeFixedObjectMesh(HeaderStruct_Fixed_Mesh* mesh)
{

	delete[] mesh->pVertex;
	delete[] mesh->pUV;
	delete[] mesh->pNormals;
	delete[] mesh->pPackedVertex;

	delete mesh;
}

#endif

/*!***************************************************************************
 @Function		PVRTLoadHeaderObject
 @Input			headerObj			Pointer to object structure in the header file
 @Return		directly usable geometry in fixed or float format as appropriate
 @Description	Converts the data exported by MAX to fixed point when used in OpenGL
				ES common-lite profile.
*****************************************************************************/
HeaderStruct_Mesh_Type *PVRTLoadHeaderObject(const void *headerObj)
{
#ifdef PVRT_FIXED_POINT_ENABLE
	return (HeaderStruct_Mesh_Type*) CreateFixedObjectMesh((HeaderStruct_Mesh *) headerObj);
#else
	HeaderStruct_Mesh_Type *new_mesh = new HeaderStruct_Mesh_Type;
	memcpy (new_mesh,headerObj,sizeof(HeaderStruct_Mesh_Type));
	return (HeaderStruct_Mesh_Type*) new_mesh;
#endif
}

/*!***************************************************************************
 @Function		PVRTUnloadHeaderObject
 @Input			headerObj			Pointer returned by LoadHeaderObject
 @Description	Releases memory allocated by LoadHeaderObject when geometry no longer
				needed.
*****************************************************************************/
void PVRTUnloadHeaderObject(HeaderStruct_Mesh_Type* headerObj)
{
#ifdef PVRT_FIXED_POINT_ENABLE
	FreeFixedObjectMesh(headerObj);
#else
	delete headerObj;
#endif
}

/*****************************************************************************
 End of file (PVRTFixedPoint.cpp)
*****************************************************************************/