////////////////////////////////////////////////////////////////////////////////
// MeshPolygon.h
// Declaration of a class that stores mesh polygons
// Copyright Bjoern Ganster
// Written since 2001
////////////////////////////////////////////////////////////////////////////////

#ifndef MeshPolygon__h
#define MeshPolygon__h

#include "BoundingBox.h"
#include "intersections.h"
#include "Matrix.h"
#include "Point3D.h"
#include "RenderableObject.h"
#include "Texture.h"

#include <vector>

class ManagedTexture;
class Mesh;
class MeshPolygon;

////////////////////////////////////////////////////////////////////////////////
// Mesh Polygon

class MeshPolygon: public VirtualClass
{
public:
	bool isVisible;          // Render polygon?
	size_t num;              // The number of the polygon
	double mark;             // User-defined data markings on the polygon
	Point3D transformedNormal;
	bool PerVertexLighting;  // true: set color and normals for each vertex
							// false: set color and normal from above values
	ManagedTexture* m_manText;

	// Constructor
	MeshPolygon (size_t pointCount, Mesh* parent, size_t newIndex);

	// Destructor
	~MeshPolygon () OVERRIDE;

	// Create new polygon
	static MeshPolygon* copy(const MeshPolygon* other, Mesh* parent);

	// Set index into mesh vertices
	void setVertexIndex(unsigned int indexInPoly, unsigned int indexInMesh);

	// Get index into mesh vertices
	unsigned int getVertexIndex(size_t indexInPoly) const;

	// Get number of vertices in this polygon
	// todo: rename to getVertexCount
	size_t getVertexCount() const
	{ return mVertexIndices.size(); }

	// Find opposed edges for all edges in the polygon
	void findOpposedEdges();

	// Render a polygon
	void render(bool hasTexture, bool useTransformedVertices) const;

	// Query owning Mesh
	inline Mesh* getParent()
	{ return m_parent; }
	inline const Mesh* getParent() const
	{ return m_parent; }

	// Get/set texture coordinates
	unsigned int getTexCoordIndex(unsigned int indexInPoly) const;

	// Set texture coordinates for a vertex
	void setTexCoordIndex(unsigned int indexInPoly, unsigned int indexInMeshTexCoords);

	bool textured() const
	{
		return mTextured;
	}

	// Get vertex coordinates
	Point3D getVertexCoords(size_t indexInPoly) const;

	// Get transformed coordinates
	Point3D getTransformedVertexCoords(size_t indexInPoly, const Matrix& M) const;

	// Check for collision with another polygon
	bool collides(const MeshPolygon* other) const;

	// Assuming that other moves with vector movement, check for collision with other polygon
	bool collides(const MeshPolygon* other, const Point3D& movement) const;

	// Get the plane containing the polygon
	bool getPlane(Plane& p) const;

	// Get the line segment ls where this polygon intersects a straight line sl
	bool intersects(const StraightLine& sl, LineSegment& ls) const;

	// Get min and max from the transformed coordinates
	void getTransformedMinMax(Point3D& polyMin, Point3D& polyMax) const;

	// Get transformed bounding box
	BoundingBox getTransformedBB() const;

	Point3D getTransformedNormal() const;

	// Calculate the distance of a point from a polygon
	double distanceTo(const Point3D& p) const;

	// Calculate the center of the polygon
	Point3D getCenter() const;

protected:
	std::vector<unsigned int> mVertexIndices;
	std::vector<unsigned int> mTexCoordIndices;
	Mesh* m_parent;
	bool mTextured;
};

////////////////////////////////////////////////////////////////////////////////

// If the ray given by origin, dir intersects the Triangle, this function
// returns the distance of the intersection, otherwise, it returns -1
void testProximity (const Triangle& T, const Point3D& origin, 
    const Point3D& dir, MeshPolygon* poly, double& minDistSoFar, Point3D& intersection);

// Test if the ray given by origin, dir intersects ro or one of its childs,
// at a nearer distance than minDistSoFar. If it does, set minDistSoFar,
// and returns the nearest intersected object
RenderableObject* traverseScene (const Point3D& origin, const Point3D& dir, 
    RenderableObject* ro, double& minDistSoFar, Point3D& intersection);

// Test if the given LineSegment intersects a polygon
IntersectionResult intersectsTransformedPoly(const MeshPolygon* poly, const LineSegment& ls);

#endif
