#pragma once

// class CMayaCryMeshUtil
// Used to convert from Maya geometric shape to CryEngine geometry representation,
// primarily for exporting a CGF file.
// This class performs all necessary topology transformations between the two,
// including triangulation of non-triangular faces, splitting vertices where necessary
// and reconstruction of smoothing group info (not impl.yet)
// 
// Usage: construct an instance passing the mesh DagPath and desirable space to it.
// Fetch the CryEngine format representation of equivalent mesh.
class CMayaCryMeshUtil
{
public:
	CMayaCryMeshUtil(const MDagPath& pathMesh, MSpace::Space nSpace = MSpace::kObject);
	~CMayaCryMeshUtil(void);

	// the number of Cry Engine format vertices in the array of CryVertices
	unsigned numCryVerts() const {return m_arrCryVerts.size();}

	// the number of original vertices supplied by the Maya mesh
	unsigned numMayaVerts() const {return m_numMayaVerts;}

	// mapping between the maya and cry vertex indices
	unsigned getMayaVertByCryVert (unsigned nMayaVert) const;

	// number of faces in the maya model, a face may be non-triangular
	int numMayaFaces() const {return m_numMayaFaces;}

	// number of texture vertices used by the mesh
	int numTVerts() const {return m_numTVerts;}

	// number of texture vertices
	unsigned numCryUVs () const {return m_arrCryUVs.size();}
	// texture vertex array
	CryUV* getCryUVs() {return &m_arrCryUVs[0];}

	// number of texture faces; this is either 0 or equal to the numCryFaces
	int numCryTexFaces () const {return m_arrCryTexFaces.size();}
	// texture faces (each face refers to 3 texture vertices from getCryUVs() array)
	CryTexFace* getCryTexFaces() {return &m_arrCryTexFaces[0];}

	// the number of faces (CryFaces, which have the smoothing group and material info and are only triangular)
	unsigned numCryFaces() const {return m_arrCryFaces.size();}
	
	// the array of CryFaces, which have the smoothing group and material info and are only triangular
	CryFace* getCryFaces(){return &m_arrCryFaces[0];}

	// array of CryVertices - one cryvertex is a pair of normal and position
	CryVertex* getCryVerts() {return &m_arrCryVerts[0];}

	// the name of the mesh object
	MString name() const {return m_fnMesh.name();}

	// number of materials used by the object
	int numMaterials ()const {return m_arrShaders.length ();}
	// the shader that is used as the i-th material
	MObject getMaterialShader (int i) {return m_arrShaders[i];}

	unsigned numCryVertColors ()const {return m_arrCryVertColors.size();}
	const CryIRGB* getCryVertColors () const {return &m_arrCryVertColors[0];}

	// flips all CryFaces
	void flipCryFaces ();

	// deletes unused UVs
	void compactCryUVs();

	// deletes ununsed vertices
	void compactCryVerts();
protected:
	// computes the CryVertex array out of decoupled vertex/normal representation of Maya
	void initCryVerts();

	// if necessary, adds the CryVertex to the m_arrCryVerts and returns its index
	int getCryVertexIndex (int nMayaVertex, int nMayaNormal);

	// adds multivertex polygon (after triangulation) to the array of CryFaces.
	// this may take 0 (if the polygon is degraded), 1 (if it's a triangle) or more (if it has
	// more than 3 vertices) CryFace records in the cry face array
	// returns the number of CryFace records added
	int addCryFaces (int* pCryVerts, int* pCryUVs, int numVerts, int nMayaFaceIndex);

	// adds a single 3-vertex cry face
	void addSingleCryFace (int pCryVerts[3], int pCryUVs[3], int nSmoothingGroup = 0, int nMatID = -1);

	// calculates the bounding box of the given polygon in Maya vertices
	void getCryFaceBBox (int* pCryVerts, int numVerts, Vec3& ptBBoxMin, Vec3& ptBBoxMax);

	// calculates the bounding box projection along the given axis area
	float getBBoxAreaAlongAxis (Vec3& ptBBoxMin, Vec3& ptBBoxMax, int nAxis);

	// init m_arrMayaFaceMtlId and corresponding array of material objects
	void initMaterialMap();


	// convert the UV coordinate to Cry UV array
	void initCryUVs();

	// initializes the vertex color array
	void initCryVertColors();
protected:							 
	// the path and the function set of the mesh being processed
	MDagPath m_pathMesh;
	MFnMesh m_fnMesh;

	// space in which to retrieve the normals and points
	MSpace::Space m_nSpace;

	// misc. parameters of the processed mesh
	int m_numMayaVerts, m_numMayaFaces, m_numTVerts, m_numCVerts, m_numNormals;

	// array of cry vertices
	typedef std::vector<CryVertex> CryVertexArray;
	CryVertexArray m_arrCryVerts;
	
	// map from cry to maya vertex indices
	std::vector<unsigned> m_arrMayaToCryVertMap;

	typedef std::vector<CryFace> CryFaceArray;
	CryFaceArray m_arrCryFaces;

	// the original point array
	MPointArray m_arrMayaVerts;

	// the original Normal array
	MFloatVectorArray m_arrMayaNormals;

	// utility structure used for denoting a polygon vertex
	struct MayaCryVertex
	{
		MayaCryVertex () {}
		MayaCryVertex (int vertex, int normal): nVertex(vertex), nNormal(normal) {}
		bool operator < (const MayaCryVertex& that) const {return nVertex < that.nVertex || (nVertex == that.nVertex && nNormal < that.nNormal);}

		int nVertex, nNormal;
	};

	// mapping from the pair "Maya Vertex", "Maya Normal"
	typedef std::map<MayaCryVertex, int> MayaCryVertMap;
	MayaCryVertMap m_mapMayaCryVerts;


	// this is the mapping Maya Face -> material index
	MIntArray m_arrMayaFaceMtlId;

	// array of surface shaders used by the Maya faces
	MObjectArray m_arrShaders;

	// array of UVs
	typedef std::vector<CryUV> CryUVArray;
	CryUVArray m_arrCryUVs;

	// array of texture faces
	typedef std::vector<CryTexFace> CryTexFaceArray;
	CryTexFaceArray m_arrCryTexFaces;

	// array of vertex colors
	typedef std::vector<CryIRGB> CryIRGBArray;
	CryIRGBArray m_arrCryVertColors;
};
