////////////////////////////////////////////////////////////////////////////////
// Mesh.h
// Class Declaration
// Copyright Bjoern Ganster
// Continually rewritten since 2001
////////////////////////////////////////////////////////////////////////////////

#ifndef Meshes__H
#define Meshes__H

#include "MeshPolygon.h"
#include "RenderableObject.h"
#include "Texture.h"

#include <vector>

struct MeshEdge {
	size_t vertexIndex1, vertexIndex2;
	std::vector<MeshPolygon*> polies;
	std::vector<bool> edgeReversedInPoly; // indicates if this edge is reversed in polies[i], needed for shadow volumes!
};

class Mesh: public RenderableObject
{
public:
	Color mWireframeColor;
	Mesh* mShadowProxy;

	// Standard RenderableObject members: constructor, destructor, rendering
	Mesh(const char* className = "Mesh", BGClassID classID = MeshID, RenderableObject* parent = NULL);
	~Mesh() OVERRIDE;

	// Copy data from other mesh (not including childs)
	void copyMesh(const Mesh* other);

	void renderSelf() OVERRIDE;

	// Create a point and add it to the points' container
	size_t addPoint(double x, double y, double z);

	size_t addPoint(const Point3D& p);

	// Get/set points
	bool getVertex(size_t index, Point3D& p) const;
	void setVertex(size_t index, const Point3D& p);

	// Set vertex coordinates
	void setVertexCoords(size_t baseIndex, size_t indexInPoly, double x, double y, double z);

	// Get number of texture coordinates
	size_t getTexCoordCount() const;

	// Get point statistics
	size_t getRecursivePointCount() const OVERRIDE;
	size_t getVertexCount() const;

	// Polygon access
	size_t getPolygonCount() const;
	MeshPolygon* getPolygon(size_t num);
	const MeshPolygon* getPolygon(size_t num) const;

	// Load from file
	bool loadFromObj(const PathChar* FileName);

	// Save to file
	bool saveToObj(const PathChar* FileName, bool saveUVs = false);

	// Get min/max mesh coords to decide about grid sizes, taking into account transformations
	bool getMinCoordsHere(Point3D& value) OVERRIDE;
	bool getMaxCoordsHere(Point3D& value) OVERRIDE;

	// Reduce polygons to triangles
	void reducePolygonsToTriangles();

	// Calculate normals for polygons and vertices
	void calculateNormals(double scaleFactor = 1.0);

	// Mark front-facing polygons
	void markFrontFacingPolygons(const Point3D& ls) OVERRIDE;

	// Render shadow volumes
	void renderShadowVolumes(const Point3D& ls) const OVERRIDE;

	// Return number of contained polygons
	virtual size_t getRecursivePolygonCount() const
	{
		return polygons.size();
	}

	// Set per vertex lighting
	void setPerVertexLighting(bool newVal);

	void scaleNormals(double factor);

	// Texture access
	void setTexture(Texture* newText);
	const Texture* getTexture() const;
	Texture* getTexture();

	// Transform all vertices using m
	void applyMatrix(const Matrix& m) OVERRIDE;

	// Get texture coordinates
	bool getTexCoords(size_t i, double& u, double& v) const;

	// Set texture coordinates
	bool setTexCoords(size_t i, double u, double v);

	// Prepare to render polygon
	void setRenderingBuffers(size_t mIndexInMesh, size_t vertexCount, bool textured);

	// Add a new polygon and return it
	MeshPolygon* addPolygon(size_t polygonCount);
	MeshPolygon* addTriangle ()
	{ return addPolygon(3); }
	MeshPolygon* addTriangle (size_t vi1, size_t vi2, size_t vi3);
	MeshPolygon* addQuad ()
	{ return addPolygon(4); }

	// Add new texture coordinates to this mesh and return their index
	size_t addTexCoords (double u, double v);

	// Transform all vertices in the scene and cache them
	void cacheTransformedVertices(const Matrix& m) OVERRIDE;

	Point3D getTransformedVertex(size_t index) const;

	// Hand over mesh vertices to OpenGL
	void glVertex(size_t i) const;
	void glTransformedVertex(size_t index) const;

	virtual void renderWireframe() OVERRIDE;

	// Make sure all childs use the same texture
	void applyTexture(Texture* texture) OVERRIDE;

	// Set wireframe color for this object and its childs
	void setRecursiveWireframeColor(const Color& c) OVERRIDE;

	// Delete all children (for meshes, also clears the mesh)
	void clear() OVERRIDE;

	// Find mesh edges - sets the watertight flag depending on the outcome
	void findMeshEdges();

	// Create triangles from  pairs of edges that share a vertex in order to fill mesh holes
	bool fillHoles();

	// Close a mesh by creating a new triangle for each open edge that connects to a point in the middle of the mesh
	// Not fully tested yet. May change the convex hull of an object, so use with caution.
	bool fillHoles2();

	// Close a mesh by creating a new triangle for each open edge that connects to point given as an argument
	bool fillHoles3(const Point3D& newP);

	// Copy shadow proxy from other Mesh
	void copyShadowProxy(Mesh* other);


	void mirror(double sx, double sy, double sz, double tolerance);
protected:
	Texture* mTexture;
	Color mDefaultPolygonColor;
	std::vector <double> points;
	std::vector <double> textureCoords;
	std::vector<MeshPolygon*> polygons;

	// List of edges a constructed by findMeshEdges()
	std::vector<MeshEdge> mMeshEdges;

	// Caches transformed vertices to speed up repeated collision queries
	std::vector <Point3D> mTransformedVertices;

	// Recursive Part of mesh size calculation
	void getSizeRecursive (Point3D& minCoords, Point3D& maxCoords, 
		size_t& vertices, size_t& polygons, const Matrix& m) const OVERRIDE;

	// Find polygon edges
	void findPolygonEdges(MeshPolygon* poly);
};

#endif
