///////////////////////////////////////////////////////////////////////////////
/// @file deBrush.hpp
///
/// @brief Geometry Calculation & storage
///
/// @author Assassin
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Oct 2001
/// @author Assassin
/// @remarks Creation
///
/// @date Oct 2002
/// @author Assassin
/// @remarks Major restructuring and interface implementation, deWorld integration
///
///////////////////////////////////////////////////////////////////////////////

#ifndef DEBRUSH_HPP
#define DEBRUSH_HPP

#include "deGlobalTypes.hpp"
#include "deList.hpp"
#include "deArray.hpp"
//#include "deLine.hpp"
//#include "deDriver.hpp"
#include "deRenderStates.hpp"
#include "deWorld.hpp"

#if defined(DEBRUSH_DLL_EXPORTS) || defined(DESTINY3D_EXPORT_ALL)
#	define DEBRUSH_API extern "C" DEDLL_EXPORT
#elif defined(DESTINY3D_STATIC_LINK)
#	define DEBRUSH_API extern "C"
#else
#	define DEBRUSH_API extern "C" DEDLL_IMPORT
#endif

#ifdef USING_DESTINY3D
#ifdef _DEBUG
#	ifdef DESTINY3D_STATIC_LINK
#		pragma comment(lib, "deBrush_sd")
#	else
#		pragma comment(lib, "deBrushd")
#	endif //DESTINY3D_STATIC_LINK
#else
#	ifdef DESTINY3D_STATIC_LINK
#		pragma comment(lib, "deBrush_s")
#	else
#		pragma comment(lib, "deBrush")
#	endif //DESTINY3D_STATIC_LINK
#endif //_DEBUG
#endif //USING_DESTINY3D


class IdeBrush;
class IdeGroupBrush;
class IdeBlockBrush;
class IdeCylinderBrush;
class IdeLathedBrush;
class IdeExtrudedBrush;
class IdeStaticBrush;
class IdeLineBrush;
class IdePrismBrush;
class IdeBezierBrush;

class IdeLine;
class IdeVertexBuffer;
class IdePlaneFrustum;
class IdeSceneNode;
class IdeSolidBrush;
struct deTransformInfo;

// factory functions down below

struct BIndexList
{
	deVertex *positions;
	deVertex *normals;
	deTexCoord *uvcoords;
	unsigned long numpoints;
	unsigned long numtexstages;

	unsigned short *indices;
	unsigned long numindices;
};

struct deBrushVertexData
{
	deVertex *positions;
	deVertex *normals;
	deTexCoord *uvcoords;
	deARGB *colors;
	unsigned long numpoints;
	unsigned long numtexstages;
};
struct deBrushIndexData
{
	// set only one of these to a valid pointer, and the other to NULL
	unsigned short*indices16;
	unsigned long *indices32;
	unsigned long numindices;
};


/// This is the basic geometry building block of the engine.
/// It can generate its own geometry from inputs or use geometry supplied by the user.
//class IdeBrush : virtual public IdeWorldObject
DE3D_INTERFACE(IdeBrush, IdeWorldObject)
{
protected:
	virtual ~IdeBrush() {}
public:
	enum deBrushType
	{
		Brush_Group,
		Brush_Block,
		Brush_Cylinder,
		Brush_Lathed,
		Brush_Extruded,
		Brush_Static,
		Brush_Line,
		Brush_Prism,
		Brush_Bezier,
		Brush_LargeStatic,
	};

	virtual void* GetBrushInterface(deBrushType Type) const = 0;
	
	virtual void GetWorldTransform(deTransformInfo & Matrix) const = 0;
//	virtual void SetWorldTransform(deTransformInfo & Matrix) = 0;
	virtual void Rotate(deVec3d &Center, deVec3d &Axis, deDouble Degrees) = 0;
	virtual void Rotate(deVec3d &Center, deTransformInfo &M) = 0;
	virtual void Translate(deVec3d &Delta) = 0;
	virtual void Scale(deVec3d &Center, deDouble scale) = 0;

	virtual deBoolean Update() = 0;
	virtual long GetLOD() const = 0;
	virtual long GetLOD2() const = 0;
	virtual void SetLOD(long LOD) = 0;
	virtual void SetLOD2(long LOD2) = 0;

	virtual long GetTexFacesNum() = 0;
	virtual long GetTexCoordsNum(long faceindex) = 0;
	virtual deTexCoord GetTexCoord(long faceindex, long index) = 0;
	virtual void SetTexCoord(long faceindex, long index, deTexCoord &coord) = 0;
	virtual void SetTexCoord(long faceindex, long index, deFloat u, deFloat v) = 0;
	virtual void SetTexture(long faceindex, IdeRenderTexture * tex) = 0;
	virtual IdeRenderTexture* GetTexture(long faceindex) = 0;
	virtual void SetSmooth(deBoolean SmoothNotSharp) = 0;
	virtual deBoolean GetSmooth() = 0;
	
	virtual long GetNumCVs() = 0;
	virtual void GetCVList(deVec3d buffer[]) = 0;
	virtual deVec3d GetCV(long num) = 0;
	virtual deBoolean SetCV(long num, deVec3d & CV) = 0;
	virtual deBoolean SetCVList(long num, deVec3d CVList[]) = 0;
	virtual deBoolean AddCV(deVec3d & point) = 0;

	virtual IdeBrush * Copy() = 0;

	virtual void GetAABB(deVec3d &Mins, deVec3d &Maxs) = 0;
//	deTList <deBPoly> & GetPolyList();
//	void GetPolyList(deTList <deBPoly*> & list);
	virtual long GetNumVBs() = 0;
	virtual IdeVertexBuffer * GetVertexBuffer(long index) = 0;
	virtual void SetDiffuseColor(deARGB color) = 0;
	virtual deARGB GetDiffuseColor() = 0;

	virtual void Subtract(IdeBrush * cutter) = 0;
};

/// Can store other brushes inside this one, and treat them as one.
//class IdeGroupBrush : virtual public IdeBrush
DE3D_INTERFACE(IdeGroupBrush, IdeBrush)
{
protected:
	virtual	~IdeGroupBrush() {}
public:

	virtual bool AddBrush(IdeBrush* brush) = 0;
	virtual bool RemoveBrush(IdeBrush* brush) = 0;

//	virtual void GetBrushList(deTList <IdeBrush*> &list) = 0;
};

/// just contains lines, defined by the CV's.
//class IdeLineBrush : virtual public IdeBrush
DE3D_INTERFACE(IdeLineBrush, IdeBrush)
{
protected:
	virtual ~IdeLineBrush() {}
public:
};

/// A convex hull brush - generates a convex hull that encloses the set of CV's.
//class IdeBlockBrush : virtual public IdeBrush
DE3D_INTERFACE(IdeBlockBrush, IdeBrush)
{
	// control vertices are the corner points
	// solid is the convex hull from the control vertices
protected:
	virtual ~IdeBlockBrush() {}
public:
	virtual deBoolean GetProjectedEdgePlanes(const deVec3d & Position, const deTransformInfo & transform, IdePlaneFrustum* pFrustum) = 0;
};

/// Makes cylinders of any shape and size.
//class IdeCylinderBrush : virtual public IdeBrush
DE3D_INTERFACE(IdeCylinderBrush, IdeBrush)
{
	/*
	Control Verts:	All used	0,1,2		0,1,2,3
	  ___			   __		   __		
	 / ._\ <-- 0	  /  \		  /  \		
	 \_| |. <-- 2	 4    \		 /    \		
	.|   | <-- 4	|   0--2	|  01  2	0---2
	 | . | <-- 3	 \  |1		 \    /		|1 /
	 | ._| <-- 1	  \_3		  \__/		3_/
	 \_|
	 0 & 1 are endpoints of line segment defining the center and length of the cylinder
	 2 is a point not on segment (0,1) that defines the circumference of the cylinder
	 3 is an optional point, and will cause the cylinder to be an arc wedge rotating from 2 to 3
	 4 is an optional point, and will cause the rotation from 2 to 3 to also go through 4
	*/
protected:
	virtual ~IdeCylinderBrush() {}
public:
};

/// Makes a surface by revolving a line around an axis.
//class IdeLathedBrush : virtual public IdeBrush
DE3D_INTERFACE(IdeLathedBrush, IdeBrush)
{
protected:
	virtual ~IdeLathedBrush() {}
public:
	enum LatheStyle
	{
		LatheCap = 0,	// puts caps on the ends of the lathe
		LatheCylinder,	// embeds the lathe in the smallest cylinder possible
		LatheSurface,	// no solid styling, just lathes the line into a surface
		Lathe_32bit = 0x7fffffff,
	};

	virtual void SetLine(IdeLine * line) = 0;
	virtual IdeLine * GetLine() = 0;

	virtual LatheStyle GetStyle() = 0;
	virtual deDouble GetDegree() = 0;
	virtual void SetStyle(LatheStyle style) = 0;
	virtual void SetDegree(deDouble RotDegree) = 0;
};

/// makes a surface by extruding a line along another line.
//class IdeExtrudedBrush : virtual public IdeBrush
DE3D_INTERFACE(IdeExtrudedBrush, IdeBrush)
{
protected:
	virtual ~IdeExtrudedBrush() {}
public:
	virtual void SetSourceLine(IdeLine * source) = 0;
	virtual void SetExtrudeLine(IdeLine * extrude) = 0;
	virtual void MakeSolid(deBoolean IsSolid) = 0;
};

// obfuscated, no longer documented
//class IdeStaticBrush : virtual public IdeBrush
DE3D_INTERFACE(IdeStaticBrush, IdeBrush)
{
protected:
	virtual ~IdeStaticBrush() {}
public:
	virtual void SetTextureState(IdeRenderTexture* texture) = 0;
//	virtual void AddPoly(deBPoly & poly);
	virtual void AddIndexedBuffer(BIndexList indexbuffer) = 0;
	virtual void BuildIndexedBuffers() = 0;

	virtual deBoolean AddVertices(const deBrushVertexData & vertexdata, long & indexoffset) = 0;
	virtual deBoolean AddIndices(const deBrushIndexData & vertexdata, long indexoffset) = 0;
};

/// A convex hull brush - creates a convex hull defined by the input planes (stored in CV's).
//class IdePrismBrush : virtual public IdeBrush
DE3D_INTERFACE(IdePrismBrush, IdeBrush)
{
	/*
	p0 = normal, p1 = sample on plane
	p2 = normal, p3 = sample on plane
	p4 = normal, p5 = sample on plane
	p6 = normal, p7 = sample on plane
	...
	*/
protected:
	virtual ~IdePrismBrush() {}
public:
};

/// Holds a bezier surface, defined by the input CV's.
//class IdeBezierBrush : virtual public IdeBrush
DE3D_INTERFACE(IdeBezierBrush, IdeBrush)
{
protected:
	virtual ~IdeBezierBrush() {}
public:
};

// A variant on the StaticBrush, exposes things more directly
// obfuscated, no longer documented
//class IdeLargeStaticBrush : virtual public IdeBrush
DE3D_INTERFACE(IdeLargeStaticBrush, IdeBrush)
{
protected:
	virtual ~IdeLargeStaticBrush() {}
public:
	virtual deBoolean SetNumTextures(long NumTextures) = 0;
	virtual void SetWorldTransform(deTransformInfo & Matrix) = 0;
	virtual deBoolean SetVertexBuffer(long TextureNum, IdeVertexBuffer* VBuffer) = 0;
};


// factory functions
	DEBRUSH_API deBoolean		IdeBrush_Initialize();
	DEBRUSH_API long			IdeBrush_GetWOInterfaceID();
	DEBRUSH_API IdeBrush*		IdeBrush_CreateBrush(IdeBrush::deBrushType Type);
	DEBRUSH_API deBoolean		IdeBrush_LoadFromXFile(const char * filename, deTList<IdeStaticBrush*> & brushplist);
	DEBRUSH_API deBoolean		IdeBrush_LoadLargeStaticeFromXFile(const char * filename, IdeLargeStaticBrush* pBrush, const deTransformInfo * Transform = NULL);
	/// ONLY FOR TESTING PURPOSES!
	/// DO NOT use Quake 3 maps created in whole or in part with tools that restrict usage of the content.
	/// Q3Radiant may not be used to create content for Destiny3D without a full license to the Quake 3 engine.
	DEBRUSH_API deBoolean		IdeBrush_LoadFromQ3BSP(const char * filename, IdeLargeStaticBrush* pBrush, deDouble Scale = 1.0);

#endif

