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


#ifndef	__NITEM__
#define	__NITEM__


		#include "math/matrix3.h"
		#include "math/matrix4.h"
		#include "math/quaternion.h"
		#include "data/registry.h"
		#include "memory/bit_field.h"


namespace GS {
	class MinMax;
	class Frustum;

	namespace Core {
		struct ResourceFactories;
		class Item;

	typedef	List <Item *> ItemList;

/*!
	@short	Common properties to light/object and camera.

	This class describe a location and orientation in space.
	The position is described as a vector.
	@see	nVector.

	Items can be parented to form a hierarchy where each child inherits its
	parent transformation.
	@see	SetParent().

	@author Emmanuel Julien (ejulien@gsworks.fr)
*/
class	Item
{
public:

#define	ItemFlagNone					0

#define	ItemFlagHasTarget				(1 << 0)
#define ItemFlagInvisible				(1 << 1)
#define	ItemFlagInheritPositionOnly		(1 << 2)

#define ItemFlagLocalMatrixDirty		(1 << 3)
#define ItemFlagWorldMatrixDirty		(1 << 4)
#define ItemFlagInverseWorldMatrixDirty	(1 << 5)
#define	ItemFlagRotationMatrixDirty		(1 << 6)

#define ItemFlagBoneHint				(1 << 16)

private:

		Math::rOrder		rorder;						///< Euler rotation order.
		Vector4				position,					///< Position.
							rotation,					///< Orientation as 3 Euler angles.
							scale;						///< Scale.

		Matrix3				rotation_matrix;

protected:

		Item				*parent;					///< Parent item. The item will inherit all of its parent motion.
		ItemList			children;

		Matrix4				local_matrix,				///< Local matrix.
							prv_matrix,					///< Previous world matrix.
							matrix,						///< World matrix.
							imatrix;					///< Inverse world matrix.
		Matrix4				pivot_matrix;				///< Offset matrix.

		/// Compute world local matrix.
		void				ComputeLocalMatrix();
		/// Compute world hierarchy matrix.
virtual	void				ComputeMatrix();
		/// Compute world inverse matrix.
		void				ComputeInverseMatrix();

public:

		NPLACEMENT_NEW(Item3d)

		Registry		registry;

virtual	void				SetParent(Item * = 0);
		const ItemList		&GetChildren() const { return children; }
		Item				*GetParent() const { return parent; }

		void				MarkTransformationDirty(bool children_only = false);
		void				MarkWorldTransformationDirty();

		const Vector4		&GetPosition() const;
		void				SetPosition(const Vector4 &);

		void				SetRotation(const Vector4 &);
		void				SetRotation(const Quaternion &);
		void				SetRotation(const Matrix3 &);
		const Vector4		&GetRotation() const;

		void				SetScale(const Vector4 &);
		const Vector4		&GetScale() const;

		void				SetPivot(const Matrix4 &);
		const Matrix4		&GetPivot() const;

		Matrix4				GetMatrixNoPivot();
		void				SetMatrix(const Matrix4 &);

		const Matrix4		&GetPreviousMatrix() const;
		void				SetPreviousMatrix(const Matrix4 &);
		const Matrix4		&GetLocalMatrix();

		const Matrix4		&GetMatrix();
		const Matrix4		&GetMatrix() const { return matrix; }

		const Matrix4		&GetInverseMatrix();
		const Matrix4		&GetInverseMatrix() const { return imatrix; }

		const Matrix3		&GetRotationMatrix();
		const Matrix3		&GetRotationMatrix() const { return rotation_matrix; }

		BitField			item_flags;
		Vector4				target;			///< Target position.

		/// Is this item linked to a given item?
		bool				IsLinkedTo(Item *);

		/// Set item position in world space (taking account of parent transformations).
		void				OffsetWorldPosition(const Vector4 &);

		/// Transfer a 4x4 matrix to item position/scale and rotation components.
		void				SnapshotTransformation(const Matrix4 &, bool parent_space = false, bool only_matrix = false);

		/*!
			@short	Set item target location.

			@note	When a target location exists the item align its local Z
					axis (0,0,1} so that it always point towards the target
					location.
		*/
		void				SetTarget(const Vector4 * = 0);
		void				SetTarget(const Vector4 &v) { SetTarget(&v); }
		Vector4				GetTarget() { return target; }

		float				opacity;			///< Item opacity.

		void				SetRotationOrder(Math::rOrder);
		Math::rOrder		GetRotationOrder() const { return rorder; }

		/// Compute the item axis-aligned bounding box.
virtual	void				ComputeLocalMinMax(MinMax &) const;

		void				*mitem;				///< Managed item.

		/// Setup item render data.
virtual	void				RenderSetup(ResourceFactories * = 0) = 0;

		bool				FromMetaTag(NML::Tag &);
		NML::Tag			*AsMetaTag() const;

		Item();
virtual	~Item();
};

typedef Item * pItem;

	} // Core
} // GS


#endif	// __NITEM__
