/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


#ifndef	__NBIH__
#define	__NBIH__


		#include "geometry/bounding_box.h"
		#include "container/narray.h"
		#include "memory/nauto_ptr.h"


namespace GS {
	namespace BIH {

// Bounding interval hierarchy node.
struct	Node
{
		char			axis;				///< @TODO: Packed bitfield!
		void			*p;					///< Pointer to child nodes or index array.

		union
		{
			uint		count;				///< Index count in leaf.
			float		split[2];			///< Split planes.
		};

		Node() : axis(3), p(0) {}
		~Node();
};

struct	StackEntry
{
		Node			*node;
		float			tmin, tmax;
};

//
struct	Trace
{
		StackEntry		stack[65];
		uint			stack_pos;

		bool			want_closest;

		bool			has_i;				///< Do we have an intersection.
		float			i_t;				///< Distance to intersection from ray's origin.
		Vector4			s;					///< Ray origin.
		Vector4			d;					///< Ray direction.

		uint			node_visited;		///< Number of nodes visited.

		Trace(bool closest = true) : want_closest(closest), has_i(false) {}
};

/*!
	@short	Bounding interval hierarchy.

	This is a fully generic bounding interval hierarchy implementation.
	In order to use this structure on a custom set of data you need to derive
	from this class and provide the implementation for the TraceLeaf method.

	In order to build the structure you simply provide a list of volumes to the
	build() methods.

	@author	Emmanuel Julien (ejulien@gsworks.fr)
*/
class	Tree
{
protected:

		/// Minimum leaf volume count.
		uint			min_leaf_vcount;

		MinMax			minmax;				///< Hierarchy bounding box.
		AutoPtr <Node>	root;				///< Hierarchy root node.

		Array <uint> sarray;				///< Index array.

		uint			node_count;
		uint			leaf_count;
		uint			depth;
/*!
	@name	Trace functions.
	@{
*/
		/// Trace a leaf.
virtual	void			TraceLeaf(Node *leaf, float tmin, float tmax, Trace &trace, void *parm = 0) = 0;
		/// Trace a node.
		void			TraceNode(Node *node, float tmin, float tmax, Trace &trace);
/// @}

/*!
	@name	Intersection functions.
	@{
*/
		/// Intersect a node.
		uint			IntersectNode(Node *node, MinMax &sub_mm, uint *index_array, uint max_index);
/// @}

/*!
	@name	Build functions.
	@{
*/
		/// Create a leaf.
		void			MakeNodeLeaf(Node *node, uint count, uint *sarray, MinMax *varray);
		/// Perform a node split.
		void			DoNodeSplit(MinMax &minmax, uint count, uint *sarray, MinMax *varray, uint &pivot, Node *node, uint &split_axis);
		/// Split an index list of volumes.
		bool			Split(MinMax &minmax, uint count, uint *sarray, MinMax *varray, Node *node, uint depth);

		/// Build hierarchy from a set of input volumes.
virtual	bool			Build(uint volume_count, MinMax *varray);
/// @}

public:

		/// Intersect tree with an axis aligned bounding box.
		uint			Intersect(MinMax &minmax, uint *index_array, uint max_index);
		/*
			@short	Raytrace hierarchy.
			@note	Ray direction must be normalized.
		*/
virtual	void			Raytrace(Trace &trace, const Vector4 &s, const Vector4 &d, float l = -1.f, void *parm = 0);

		/// Delete hierarchy.
virtual	void			Free();

		Tree();
virtual	~Tree();
};

	} // BIH
} // GS


#endif	// __NBIH__
