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


#ifndef	__NBULLET_ITEM__
#define	__NBULLET_ITEM__


		#include "physic_bullet/bullet_world.h"
		#include "physic/physic_item.h"
		#include "math/matrix4.h"
		#include "container/narray.h"
		#include "memory/nauto_ptr.h"

		#include "BulletDynamics/Character/btKinematicCharacterController.h"


namespace GS {
	namespace S3D {
		class BulletPhysicItem;

//
class	BulletMotionState : public btDefaultMotionState
{
		BulletPhysicItem *item;
		Matrix4			bullet_matrix, engine_matrix;

public:

		/// Return the last matrix Bullet sent.
		const Matrix4	&GetGraphicMatrix() const { return bullet_matrix; }
		void			SetEngineMatrix(const Matrix4 &m) { engine_matrix = m; }

		/// Transform to Bullet.
virtual	void			getWorldTransform(btTransform &centerOfMassWorldTrans) const;
		/// Transform from Bullet.
virtual	void			setWorldTransform(const btTransform &centerOfMassWorldTrans);

		BulletMotionState(BulletPhysicItem *);
};

/*
	@short	Bullet physic item.
	@author	Emmanuel Julien (ejulien@gsworks.fr)
*/
class	BulletPhysicItem : public PhysicItem
{
		friend class BulletWorld;

		btDiscreteDynamicsWorld *btworld;

struct	ShapeData
{
		AutoPtr <btCollisionShape> shape;

		SharedPtr <BulletConvex> convex;
		SharedPtr <BulletMesh> mesh;
};

		Array <ShapeData> shapes;

		uint			collision_mask, self_mask;	// cached copies to properly handle activation/deactivation.

public:

		AutoPtr <BulletMotionState> motion_state;

		AutoPtr <btCompoundShape> compound;
		AutoPtr <btRigidBody> rigid_body;

		AutoPtr <btDefaultVehicleRaycaster> vehicle_raycaster;
		AutoPtr <btRaycastVehicle> vehicle;

		AutoPtr <btPairCachingGhostObject> ghost_object;
		AutoPtr <btConvexShape> convex_shape;
		AutoPtr <btCharacterControllerInterface> character_controller;

		Vector4			center;
		Vector4			scale;

		bool			SetupCharacterController(const PhysicItemDesc &);
		bool			SetupKinematicDynamicBody(const PhysicItemDesc &, PhysicWorld *);
		float			SetupCollisionShapes(const PhysicItemDesc &, Array <btScalar> &, PhysicWorld *);
		void			ForceUpdateMassShapePhysic(const PhysicItemDesc &, PhysicWorld *);

		/// Create a Bullet transformation from a 4x4 matrix.
static	void			TransformFromMatrix4(const Matrix4 &, btTransform &);
		/// Create a 4x4 matrix to a Bullet transformation.
static	void			TransformToMatrix4(const btTransform &, Matrix4 &);

		/*
			@short	Return the center of mass offset.
			Bullet does not handle offset center of mass directly.
		*/
		const Vector4	&GetCenter() const { return center; }

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

		//----------------------------------------------------------------------
		void			SetSelfMask(uint m);
		uint			GetSelfMask() const;
		void			SetCollisionMask(uint m);
		uint			GetCollisionMask() const;
		//----------------------------------------------------------------------

		//----------------------------------------------------------------------
		void			SetLinearFactor(const Vector4 &);
		void			SetAngularFactor(const Vector4 &);

		void			SetLinearDamping(float = 0.999f);
		float			GetLinearDamping() const;
		void			SetAngularDamping(float = 0.99f);
		float			GetAngularDamping() const;

		void			SetGravity(const Vector4 &);
		Vector4			GetGravity() const;
		void			ApplyImpulse(const Vector4 &I, const Vector4 *p = 0);
		void			ApplyForce(const Vector4 &F, const Vector4 *p = 0);
		void			ApplyTorque(const Vector4 &T);

		void			SetAngularVelocity(const Vector4 &);
		Vector4			GetAngularVelocity() const;
		void			SetLinearVelocity(const Vector4 &);
		Vector4			GetLinearVelocity() const;

		Vector4			GetLocalPointVelocity(const Vector4 &) const;
		Vector4			GetWorldPointVelocity(const Vector4 &) const;

		Vector4			GetCenterOfMass() const;
		//----------------------------------------------------------------------

		//----------------------------------------------------------------------
		void			GetGraphicMatrix(Matrix4 &);
		void			SetEngineMatrix(const Matrix4 &);
		void			GetMatrix(Matrix4 &);
		void			SetMatrix(const Matrix4 &);
		//----------------------------------------------------------------------

		//----------------------------------------------------------------------
virtual	void			VehicleSetForce(float F, uint wheel_index);
virtual	void			VehicleSetBrake(float F, uint wheel_index);
virtual	void			VehicleSetSteering(float v, uint wheel_index);
virtual	void			VehicleSetFriction(float f, uint wheel_index);

virtual	Matrix4			VehicleGetWheelMatrix(uint wheel_index);
		//----------------------------------------------------------------------

		//----------------------------------------------------------------------
virtual	void			CharacterSetRotationMatrix(const Matrix3 &);
virtual	void			CharacterSetVelocity(const Vector4 &);
		//----------------------------------------------------------------------

virtual	void			SetSleeping(bool sleep = false);
virtual	bool			IsSleeping() const;

virtual	void			SetActive(bool active);
virtual	bool			GetActive() const;

virtual	void			ResetBody();

virtual	bool			SetupBody(const PhysicItemDesc &, PhysicWorld *);
virtual	void			DeleteBody();

		BulletPhysicItem(btDiscreteDynamicsWorld * = 0);
virtual	~BulletPhysicItem();
};

	} // S3D
} // GS


#endif	// __NBULLET_ITEM__
