///////////////////////////////////////////////////////////////////////////////
/// @file deScene.hpp
///
/// @brief scene-management routines
///
/// @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 Mar 2002
/// @author Assassin
/// @remarks Creation
///
/// @date Mar 2003
/// @author Masterg
/// @remarks Terrain added
///
///////////////////////////////////////////////////////////////////////////////

#ifndef DESCENE_HPP
#define DESCENE_HPP

// get rid of the annoying diamond-inheritance warning
#pragma warning (disable : 4250)

#include "deGlobalTypes.hpp"
#include "deMath.hpp"			// transforms
#include "deWorld.hpp"			// world object
#include "deRenderStates.hpp"	// renderlight

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

#ifdef USING_DESTINY3D
#ifdef _DEBUG
#	ifdef DESTINY3D_STATIC_LINK
#		pragma comment(lib, "deScene_sd")
#	else
#		pragma comment(lib, "deScened")
#	endif //DESTINY3D_STATIC_LINK
#else
#	ifdef DESTINY3D_STATIC_LINK
#		pragma comment(lib, "deScene_s")
#	else
#		pragma comment(lib, "deScene")
#	endif //DESTINY3D_STATIC_LINK
#endif //_DEBUG
#endif //USING_DESTINY3D

// external
class IdeActor;
class IdeAnimatedMesh;
class IdeBitmapProxy;
class IdeBoundingVolume;
class IdeCamera;
class IdeDriver;
class IdeLineBrush;
class IdeMesh;
class IdePlaneFrustum;
class IdePortal;
class IdeRender;
class IdeRenderLight;
class IdeRenderMaterial;
class IdeRenderTexture;
class IdeSurface;
class IdeVertexBuffer;
class IdeWorld;

//defined within
class IdeSceneGraph;
class IdeCollision;
class IdeSceneRoom;
class IdeSceneObject;
class IdeSceneABT;
class IdeSceneActor;
class IdeSceneSky;
class IdeSceneStaticMesh;
class IdeSceneTerrain;
class IdeSceneLight;

// deprecated
class IdeSceneAnimatedMesh;

// factory functions
DESCENE_API deBoolean		IdeScene_Initialize();
DESCENE_API void			IdeScene_ShutDown();
/// Get the IdeSceneGraph singleton pointer
DESCENE_API IdeSceneGraph*	IdeSceneGraph_GetSceneGraphPtr();
/// Create an instance of IdeCollision
DESCENE_API IdeCollision*	IdeCollision_CreateCollision();
/// Get the IdeSceneRoom WorldObject interface ID
DESCENE_API long			IdeSceneRoom_GetWOInterfaceID();
/// Get the IdeSceneObject WorldObject interface ID
DESCENE_API long			IdeSceneObject_GetWOInterfaceID();

//specific factory functions
/// create an instance of IdeSceneABT
DESCENE_API IdeSceneABT *		IdeSceneObject_CreateSceneABT();
/// create an instance of IdeSceneActor
DESCENE_API IdeSceneActor*		IdeSceneObject_CreateSceneActor();
DESCENE_API IdeSceneAnimatedMesh* IdeSceneObject_CreateSceneAnimatedMesh();
/// create an instance of IdeSceneRoom
DESCENE_API IdeSceneRoom*		IdeSceneRoom_CreateRoom();
/// create an instance of IdeSceneSky
DESCENE_API IdeSceneSky *		IdeSceneObject_CreateSceneSky();
/// create an instance of IdeSceneStaticMesh
DESCENE_API IdeSceneStaticMesh*	IdeSceneObject_CreateSceneStaticMesh();
/// create an instance of IdeSceneTerrain
DESCENE_API IdeSceneTerrain*	IdeSceneObject_CreateSceneTerrain();
/// create an instance of IdeSceneLight
DESCENE_API IdeSceneLight*		IdeSceneObject_CreateSceneLight();

/// @TODO remove IdeScene_TestABT
DESCENE_API deBoolean		IdeScene_TestABT();


//=============================================================
/// used to store & retrieve collision information.
/// Related functions: IdeCollision_CreateCollision.
//class IdeCollision
DE3D_INTERFACE_(IdeCollision)
{
protected:
	virtual ~IdeCollision() {}
public:
	/// release the collision class (deletes it)
	virtual long Release() = 0;
	
	/// level of detail needed for collision
	enum deCollideDetail
	{
		deCollidePoint		=0x01,		///< use a point or ray
		deCollideSphere		=0x02,		///< use a point with radius
		deCollideAABB		=0x04,		///< use axis-aligned bounding boxes
		deCollideOBB		=0x08,		///< use oriented bounding boxes
		deCollide_32Bit = 0x7fffffff
	};
	/// information about the object that will be colliding with things
	struct deCollideParams
	{
		deVec3d Start;					///< start point in universal space
		deVec3d Delta;					///< movement from start point
		deBoundSphere Sphere;			///< bounding sphere for colliding object
		deAABB AABB;					///< AABB for colliding object
		IdeBoundingVolume* CustomBV;	///< Custom Bounding Volume for colliding object
		deCollideDetail ThisDetail;		///< collision detail for this object (fill in relevant members: AABB, OBB, etc)
		deCollideDetail WorldDetail;	///< collision detail for other world objects
	};
	/// information about a collision that occurred
	struct deCollideInfo
	{
		deVec3d		Position;			///< position at which collision occurs
		deVec3d		Normal;				///< normal of surface which was collided with
		deDouble	Percent;			///< percent along the (start,stop) segment where collision occurred
		DWORD				Contents;
		IdeSurface*			Surface;
		IdeSceneObject*		HitObject;
		IdeSceneRoom*		HitRoom;
	};

	/// clear out all the collisions that have accrued
	virtual void		Reset() = 0;
	
	/// returns the number of collisions accrued
	virtual long		GetNumCollisions() = 0;
	/// retrieves a specific collision occurrence
	virtual void		GetCollision(long ColNum, deCollideInfo & collision) = 0;

	// for use by engine only
	virtual deBoolean	AddCollision(const deCollideInfo & collision) = 0;
};

//=============================================================
/// The interface class for storing and querying a 3D scene.
/// Related functions: IdeSceneGraph_GetSceneGraphPtr.
//class IdeSceneGraph
DE3D_INTERFACE_(IdeSceneGraph)
{
protected:
	virtual ~IdeSceneGraph() {}

public:
	struct deSceneTraversal
	{
		// input parameters
		IdeCamera * cam;
		IdeRender * render;
		long MaxTPortalDepth;
		//temporaries
		long CurrentPortalDepth;
		long CurrentPassNum;
		IdeSceneGraph* CurrentSceneGraph;
		IdePlaneFrustum* CurrentFrustum;
		deTransformInfo CurrentTransform;
		//output values
		deDouble FarthestDistanceFound;
	};
	
	// used internally by the engine only
	virtual long Traverse(deSceneTraversal* Params) = 0;

	/// specify a set of cull flags. Use bitwise OR to combine elements of deCullModes
	virtual deBoolean	SetCullFlags(long CullFlags) = 0;
	/// retrieve the current cull flags set
	virtual long		GetCullFlags() = 0;

	/// specify a set of debug flags. Use bitwise OR to combine elements of deDebugFlags
	virtual deBoolean	SetDebugFlags(long DebugFlags) = 0;
	/// retrieve the current debug flags set
	virtual long		GetDebugFlags() = 0;

	virtual IdeSceneRoom * FindRoomWithID(deWorldID WorldID, deObjectID ObjectID) = 0;

	/// Add an IdeSceneRoom object to the scenegraph
	virtual deBoolean AddRoom(IdeSceneRoom * Room) = 0;
	/// Remove an IdeSceneRoom object from the scenegraph
	virtual deBoolean RemoveRoom(IdeSceneRoom* Room) = 0;

	virtual deBoolean AddSceneObject(IdeSceneObject* Object) = 0;
	virtual void RemoveSceneObject(IdeSceneObject* Object) = 0;
	virtual void RepositionSceneObject(IdeSceneObject* Object) = 0;

	// used internally by the engine only
	virtual deBoolean PortalOccluded(IdePortal * portal) = 0;

	virtual DWORD TestIntersection(const deVec3d &Position, const deVec3d *Mins, const deVec3d *Maxs) = 0;
	/// test whether a collision occurs when using given Params
	virtual deBoolean TestCollision(const IdeCollision::deCollideParams & Params, IdeCollision * Collision) = 0;
	/// considers only the objects intersected at the start point
	virtual void ObjectExtents(IdeBoundingVolume* volume, IdeCollision * Results) = 0;
	virtual long LightExtents(const deVec3d& pos, const deAABB& bbox, IdeSceneLight** outBuffer, long bufferSize) = 0;
	
	/// different methods of culling that can be done in the scenegraph traversal
	enum deCullModes
	{
		// backface is done in hardware
		deCullFrustum			=(0x0001),		///< cull using a view frustum
		deCullDetail			=(0x0002),		///< cull using screen-contribution metric
		deCullOccludeSphere		=(0x0004),		///< cull using sphere occlusion
		deCullOccludeConvHull	=(0x0008),		///< cull using convex hull occlusion (not implemented)
		deCullOccludeRaster		=(0x0010),		///< cull using image-space occlusion (not implemented)
		deCullFarPlaneOptimize	=(0x0020),		///< not culling technically, but it can improve visual quality
		deCull_Max,
		deCull_32bit=(0x7fffffff)
	};
	
	/// debug flags for helping examine things
	enum deDebugFlags
	{
		deDrawAABB				=(0x0001),		///< render AABB's for objects (in blue)
		deDrawOBB				=(0x0002),		///< render OBB's for objects (in red)
		deDrawSphere			=(0x0004),		///< render bounding spheres for objects
		deDrawSpatialPartition	=(0x0008),		///< render the scenegraph octree
		deDebugFlag_Max,
		deDebugFlag_32bit=(0x7fffffff)
	};

	/// possible contents
	enum deContents
	{
		deContentsNone			=(0x00000000),	///< nothing here (note: you can't do a bitwise-AND and get 1 with this)
		deContentsClear			=(0x00000001),	///< see-through
		deContentsOpaque		=(0x00000002),	///< not see-through
		deContentsSolid			=(0x00000004),	///< impassable
		deContentsUser10		=(0x00100000),
		deContentsUser09		=(0x00200000),
		deContentsUser08		=(0x00400000),
		deContentsUser07		=(0x00800000),
		deContentsUser06		=(0x01000000),
		deContentsUser05		=(0x02000000),
		deContentsUser04		=(0x04000000),
		deContentsUser03		=(0x08000000),
		deContentsUser02		=(0x10000000),
		deContentsUser01		=(0x20000000),
		deContents_Max,
		deContents_32bit=(0x7fffffff)
	};
};

//=============================================================
/// a base class for dealing with Scene Rooms, which can contain objects and link to other Scene Rooms.
/// Related functions: IdeSceneRoom_CreateRoom, IdeSceneRoom_GetWOInterfaceID.
//class IdeSceneRoom : virtual public IdeWorldObject
DE3D_INTERFACE(IdeSceneRoom, IdeWorldObject)
{
protected:
	virtual ~IdeSceneRoom() {}
public:

	// used internally by the engine only
	virtual void SetRoomListPtr(void * ptr) = 0;
	virtual void*GetRoomListPtr() = 0;
	
	// used internally by the engine only
	virtual long Traverse(IdeSceneGraph::deSceneTraversal* Params) = 0;
	virtual deBoolean TestCollision(const IdeCollision::deCollideParams & Params, IdeCollision * Collision) = 0;
	virtual long GetPassNum() = 0;
	virtual void GetAABB(deVec3d &Min, deVec3d &Max) = 0;

	virtual void  SetContents(DWORD contents) = 0;
	virtual DWORD GetContents() = 0;

	/// add an IdeSceneObject to the scene room
	virtual deBoolean AddSceneObject(IdeSceneObject * obj) = 0;
	/// remove an IdeSceneObject from the scene room
	virtual deBoolean RemoveSceneObject(IdeSceneObject * obj) = 0;
	/// add a portal to the scene room
	virtual deBoolean AddPortal(IdePortal * portal) = 0;
};

//=============================================================
/// A base class for dealing with Scene Objects. A scene object occupies the space
/// that is defined by scene rooms.
/// Related functions: IdeSceneObject_GetWOInterfaceID.
//class IdeSceneObject : virtual public IdeWorldObject
DE3D_INTERFACE(IdeSceneObject, IdeWorldObject)
{
protected:
	virtual ~IdeSceneObject() {}
public:

	enum activate_t
	{
		activate_visible = 0,
		activate_collide = 1,
		activate_count,
		activate_32bit =0x7fffffff
	};
	
	// list of sub-class types for GetSOInterface
	enum interface_t
	{
		iface_IdeSceneObject=0,
		iface_IdeSceneStaticMesh=1,
		iface_IdeSceneSky=2,
		iface_IdeSceneTerrain=3,
		iface_IdeSceneABT=4,
		iface_IdeSceneAnimatedMesh=5,
		iface_IdeSceneActor=6,
		iface_IdeSceneLight=7,
		// 6 is max
		iface_32Bit=0x7fffffff
	};
	virtual IdeSceneObject::interface_t GetSOIType() = 0;
	virtual void* GetSOInterface(IdeSceneObject::interface_t i) = 0;

	virtual void		PreCache(IdeDriver* pDriver) = 0;
	
	// used internally by the engine only
	virtual long		Traverse(IdeSceneGraph::deSceneTraversal* Params) = 0;

	/// Set the activation state of the object
	virtual void		SetActivation(activate_t a_type, deBoolean Active) = 0;
	/// Retrieve the activation state of the object
	virtual deBoolean	GetActivation(activate_t a_type) const = 0;
	
	/// retrieve the world transformation of this object.
	/// All bounding volumes are relative to the translation of this
	virtual void		GetWorldTransform(deTransformInfo & mat) = 0;
	/// set the world transformation of this object
	virtual void		SetWorldTransform(const deTransformInfo & mat) = 0;
	
	/// retrieve the local AABB (computed as the extents of the object on its local axes)
	virtual void		GetLocalAABB(deAABB &bbox) = 0;
	/// retrieve the oriented bounding box in world coordinates (local AABB transformed into world space)
	virtual void		GetWorldOBB(deOBB &bbox) = 0;
	/// retrieve the world AABB of the object. This AABB is guaranteed to contain the world OBB
	/// for the current orientation, and may contain the OBB no matter what its orientation.
	virtual void		GetWorldAABB(deAABB &bbox) = 0;
	
	virtual deVec3d		GetBoundCenter() = 0;
	virtual deVec3d		GetOccludeCenter() = 0;
	virtual void		GetWorldPos(deVec3d & PosVector) = 0;
	
	virtual deVec3d		GetWorldBoundCenter() = 0;
	virtual deVec3d		GetWorldOccludeCenter() = 0;
	virtual deDouble	GetBoundRadius() = 0;
	virtual deDouble	GetOccludeRadius() = 0;
	
	virtual deBoolean	IsTransparent() = 0;
	
	virtual deBoolean	OccludesObject(deVec3d &position, IdeSceneObject *so, deVec3d &NormalizedDisplacement) = 0;
	
	// used internally by the engine only
	virtual long		GetCurrentPassNum() const = 0;
	virtual deBoolean	AddRoomReference(IdeSceneRoom * ref, void * ptr) = 0;
	virtual void*		GetRoomReference(IdeSceneRoom * ref) = 0;
	virtual deBoolean	RemoveRoomReference(IdeSceneRoom * ref) = 0;
};

//=============================================================
/// scene object used for storing & rendering large, static polygonal datasets.
/// Related functions: IdeSceneObject_CreateSceneABT
//class IdeSceneABT : virtual public IdeSceneObject
DE3D_INTERFACE(IdeSceneABT, IdeSceneObject)
{
protected:
	virtual ~IdeSceneABT() {}
public:
	virtual deBoolean AddGeometry(IdeMesh* pMesh, const deTransformInfo & worldpos) = 0;
};

//=============================================================
/// scene object used for storing & rendering large terrains based on heightmaps.
/// Related functions: IdeSceneObject_CreateSceneTerrain
//class IdeSceneTerrain : virtual public IdeSceneObject
DE3D_INTERFACE(IdeSceneTerrain, IdeSceneObject)
{
protected:
	virtual ~IdeSceneTerrain() {}
public:
	virtual deBoolean SetTerrainHeightMap(IdeBitmapProxy * bmp) = 0;
	virtual deBoolean SetTerrainColorMap(IdeBitmapProxy * bmp) = 0;
	virtual deBoolean SetTerrainDetailMap(IdeBitmapProxy * bmp) = 0;
	
	virtual deVec3d GetTerrainScale() = 0;
	virtual void SetTerrainScale(deVec3d vScale) = 0;
	virtual void SetTerrainScale(deFloat x, deFloat y, deFloat z) = 0;

	virtual deTexCoord GetDetailRepeat() = 0;
	virtual void SetDetailRepeat(deTexCoord Repeat) = 0;
	virtual void SetDetailRepeat(deFloat u, deFloat v) = 0;
	
	virtual void SetHeightAt(unsigned char ucHeight, long x, long y) = 0;
	virtual unsigned char GetTrueHeightAt(long x, long y) = 0;
	virtual deFloat GetScaledHeightAt(long x, long y) = 0;

	virtual deDouble GetLODBias() = 0;
	virtual void SetLODBias(deDouble Bias) = 0;

	virtual long GetGMMChunkSize() = 0;
	virtual void SetGMMChunkSize(long ChunkSize) = 0;

	virtual deBoolean BuildRenderable() = 0;
	virtual deBoolean BuildGeoMipMap(IdeDriver* pDriver) = 0;
};

//=============================================================
/// scene object used for rendering 360-degree skies, for atmospheric effect without a lot of geometry.
/// Related functions: IdeSceneObject_CreateSceneSky
//class IdeSceneSky : virtual public IdeSceneObject
DE3D_INTERFACE(IdeSceneSky, IdeSceneObject)
{
protected:
	virtual ~IdeSceneSky() {}
public:

	enum SkyType
	{
		SKY_NONE = 0,
		SKY_BOX,
		SKY_DOME,
		SKY_SECTOR,
		SKY_FORCE_32BIT = 0x7fffffff
	};

	struct SkyInfo
	{
		union Box_t
		{
			struct FaceNames_t
			{
				IdeBitmapProxy * NegX;
				IdeBitmapProxy * NegY;
				IdeBitmapProxy * NegZ;
				IdeBitmapProxy * PosX;
				IdeBitmapProxy * PosY;
				IdeBitmapProxy * PosZ;
			} FaceNames;
			IdeBitmapProxy* Faces[6];
		};

		struct Dome_t
		{
			/// @todo implement sky dome
		};

		struct Sector_t
		{
			/// @todo implement sky sector
		};

		SkyType type;
		union
		{
			Box_t Box;
			Dome_t Dome;
			Sector_t Sector;
		};
	};

	virtual deBoolean	IsLockedToCam() const = 0;
	virtual void		LockToCam(deBoolean Lock) = 0;

	virtual deBoolean	GetInfo(SkyInfo * info) const = 0;
	virtual deBoolean	SetInfo(const SkyInfo * info) = 0;
};



//=============================================================
//class IdeSceneAnimatedMesh : virtual public IdeSceneObject
DE3D_INTERFACE(IdeSceneAnimatedMesh, IdeSceneObject)
{
protected:
	virtual ~IdeSceneAnimatedMesh() {}
public:
	virtual void SetMesh(IdeAnimatedMesh * mesh) = 0;
};

//=============================================================
/// used to create instances of a static mesh in a scene.
/// Related functions: IdeSceneObject_CreateSceneStaticMesh
//class IdeSceneStaticMesh : virtual public IdeSceneObject
DE3D_INTERFACE(IdeSceneStaticMesh, IdeSceneObject)
{
protected:
	virtual ~IdeSceneStaticMesh() {}
public:
	virtual void SetMesh(IdeMesh* mesh) = 0;
	virtual void SetTransparent(deBoolean Trans) = 0;
};

//=============================================================
/// used to create instances of actors in a scene.
/// Related functions: IdeSceneObject_CreateSceneActor
//class IdeSceneActor : virtual public IdeSceneObject
DE3D_INTERFACE(IdeSceneActor, IdeSceneObject)
{
protected:
	virtual ~IdeSceneActor() {}
public:
	virtual void SetActor(IdeActor* actor) = 0;
};

//=============================================================
/// used to place lights in a scene.
/// Related functions: IdeSceneObject_CreateSceneLight
//class IdeSceneLight : virtual public IdeSceneObject
DE3D_INTERFACE(IdeSceneLight, IdeSceneObject)
{
protected:
	virtual ~IdeSceneLight() {}
public:
	virtual void SetLightData(const IdeRenderLight::LightData& lightdata) = 0;
	virtual const IdeRenderLight::LightData* GetLightData() = 0;
	virtual const IdeRenderLight* GetRenderLight() = 0;
};

#endif






















