////////////////////////////////////////////////////////////////////////////////
// Class RenderableObject
// Base class for renderable objects
// Copyright Bjoern Ganster
// Developed since 2000
////////////////////////////////////////////////////////////////////////////////

#ifndef RenderableObject__h
#define RenderableObject__h

////////////////////////////////////////////////////////////////////////////////
// Includes & Forwards

#include "BGCPString.h"
#include "BoundingBox.h"
#include "Color.h"
#include "Matrix.h"
#include "Point3D.h"
#include "Texture.h"

#include <GL/gl.h>

#include <math.h>

class MatrixStack;

#define FILE_NUMBER FILE_NO_RENDERABLEOBJECT_H

////////////////////////////////////////////////////////////////////////////////
// Defines

#ifndef M_PI
#define M_PI 3.141592654
#endif

#ifdef WIN32
const char DirSepChar = '\\';
#endif
#ifndef WIN32
const char DirSepChar = '/';
#endif

////////////////////////////////////////////////////////////////////////////////
// Class RenderableObject

class RenderableObject: public VirtualClass {
public:
	Color color;

	// Constructor
	RenderableObject(const char* className = "RenderableObject", 
		BGClassID classID = RenderableObjectID, RenderableObject* parent = NULL);

	// Destructor
	~RenderableObject() OVERRIDE;

	// Render entire scene
	virtual void render();
	virtual void renderSelf()
	{ }
	virtual void renderChilds();

	// Mark front-facing polygons (requires neighbourhood information)
	virtual void markFrontFacingPolygons(const Point3D& ls);

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

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

	// Return number of contained points
	virtual size_t getRecursivePointCount() const;

	// Add contained object
	bool addChild(RenderableObject* obj);

	// Get number of contained objects
	virtual size_t getObjectCount() const;

	// Get contained object
	virtual RenderableObject* getObject(size_t index);
	virtual const RenderableObject* getObject(size_t index) const;

	// Detach a child from this object
	virtual bool removeObject(RenderableObject* obj, bool);
	bool removeObject (size_t i, bool deleteObject);

	// Remove parent objects
	void removeParent(RenderableObject* obj);

	// Get/set object's name
	const BGCPString& getName() const;
	void setName(const BGCPString& newName);

	// Mesh size calculation
	void getSize(Point3D& minCoords, Point3D& maxCoords, size_t& vertices, size_t& polygons) const;

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

	// Set/get matrix
	const Matrix& getMatrix() const;
	Matrix& getMatrix();
	virtual void setMatrix(const Matrix& _M);

	// Get min/max mesh coords, taking into account transformations
	virtual bool getMinCoords(Point3D& value);
	virtual bool getMaxCoords(Point3D& value);

	// Get min/max coords for this node, taking into account transformations
	virtual bool getMinCoordsHere(Point3D& value);
	virtual bool getMaxCoordsHere(Point3D& value);

	// Get min/max coords as a bounding box
	BoundingBox getBoundingBox() const;
	
	// Transform all vertices using m
	virtual void applyMatrix(const Matrix& m);

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

	// Load from file
	// Differs from Mesh::loadFromObj in that the groups inside a .obj file are put into several meshes
	virtual bool loadFromObj (const PathChar* fileName);

	RenderableObject* getParent();

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

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

	virtual void renderWireframe();

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

	template <typename T>
	T* getChild(size_t i)
	{
		SET_SCOPE;
		if (i < mChilds.size()) {
			RETURN dynamic_cast<T*>(mChilds[i]); 
		} else {
			RETURN nullptr;
		}
	}

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

	// Get bounding box, using transformed vertices
	BoundingBox getTransformedBB();

	// Find child by name
	const RenderableObject* findChildByName(const BGCPString& name) const;
	RenderableObject* findChildByName(const BGCPString& name);

	// Flags
	static const DWORD Flag_invisible = 1;
	static const DWORD Flag_waterTight = 2;
	void setFlag(DWORD flag);
	void setFlagRecursive(DWORD flag);
	void clearFlag(DWORD flag);
	void clearFlagRecursive(DWORD flag);
	DWORD getFlags() const;

	// Set color recursively
	void setColorRec(const Color& aColor);

protected:
	Matrix mM;
	RenderableObject* mParent;
	std::vector <RenderableObject*> mChilds;
	BGCPString mName;
	Point3D mMinCoords, mMaxCoords;
	DWORD mFlags;

	// Save to file (recursive part)
	void saveToObjRec(BGCPString& lines, bool saveUVs, RenderableObject* child, size_t& vnum, size_t& tnum);
};

void setMatrixIfNN (RenderableObject* ro, const Matrix& M);

#undef FILE_NUMBER

#endif
