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


		#include "physic_bullet/bullet_item.h"
		#include "physic_bullet/bullet_world.h"
		#include "BulletCollision/CollisionDispatch/btGhostObject.h"
		#include "physic_bullet/bullet_character_controller.h"
		#include "physic/physic_item_desc.h"
		#include "core/item.h"
		#include "core/terrain.h"
		#include "scene3d/mitem.h"
		#include "math/matrix4.h"
		#include "log/log.h"

		using namespace GS;
		using namespace GS::S3D;


//------------------------------------------------------------------------------
static Vector4		btTonVector(const btVector3 &v)
{	return Vector4(v.x(), v.y(), v.z());	}
static btVector3	nTobtVector(const Vector4 &v)
{	return btVector3(v.x, v.y, v.z);	}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				BulletMotionState::setWorldTransform(const btTransform &comt)
{
	btTransform	wt = comt;
	const Vector4 &com = item->GetCenter();
	wt.setOrigin(wt.getOrigin() - wt.getBasis() * btVector3(com.x, com.y, com.z));
	item->TransformToMatrix4(wt, bullet_matrix);
	bullet_matrix = bullet_matrix * Matrix4::ScaleMatrix(item->GetScale());
}
void				BulletMotionState::getWorldTransform(btTransform &wt) const
{
	item->TransformFromMatrix4(engine_matrix, wt);
	const Vector4 &com = item->GetCenter();
	wt.setOrigin(wt.getOrigin() + wt.getBasis() * btVector3(com.x, com.y, com.z));
}
BulletMotionState::BulletMotionState(BulletPhysicItem *_item) : item(_item)
{
	MItem *mitem = (MItem *)_item->GetUserPointer();
	bullet_matrix = mitem->GetBaseItem()->GetMatrix();
	engine_matrix = bullet_matrix;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
uint				BulletPhysicItem::GetSelfMask() const
{
	btBroadphaseProxy *handle = NULL;
	if	(rigid_body)
		handle = rigid_body->getBroadphaseHandle();
	if	(ghost_object)
		handle = ghost_object->getBroadphaseHandle();

	return handle ? handle->m_collisionFilterGroup : 0;
}
void				BulletPhysicItem::SetSelfMask(uint m)
{
	self_mask = m;

	btBroadphaseProxy *handle = NULL;
	if	(rigid_body)
		handle = rigid_body->getBroadphaseHandle();
	if	(ghost_object)
		handle = ghost_object->getBroadphaseHandle();

	if	(handle)
	{
		handle->m_collisionFilterGroup = (short)m;

		// Refresh pair cache.
		btworld->getBroadphase()->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(handle, btworld->getDispatcher());
	}
}
uint				BulletPhysicItem::GetCollisionMask() const
{
	btBroadphaseProxy *handle = NULL;
	if	(rigid_body)
		handle = rigid_body->getBroadphaseHandle();
	if	(ghost_object)
		handle = ghost_object->getBroadphaseHandle();

	return handle ? handle->m_collisionFilterMask : 0;
}
void				BulletPhysicItem::SetCollisionMask(uint m)
{
	collision_mask = m;

	btBroadphaseProxy *handle = NULL;
	if	(rigid_body)
		handle = rigid_body->getBroadphaseHandle();
	if	(ghost_object)
		handle = ghost_object->getBroadphaseHandle();

	if	(handle)
	{
		handle->m_collisionFilterMask = (short)m;

		// Refresh pair cache.
		btworld->getBroadphase()->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(handle, btworld->getDispatcher());
	}
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				BulletPhysicItem::SetLinearDamping(float k)
{
	if	(rigid_body)
		rigid_body->setDamping(1.f - k, rigid_body->getAngularDamping());
}
float				BulletPhysicItem::GetLinearDamping() const
{
	return rigid_body ? 1.f - rigid_body->getLinearDamping() : 0;
}
void				BulletPhysicItem::SetAngularDamping(float k)
{
	if	(rigid_body)
		rigid_body->setDamping(rigid_body->getLinearDamping(), 1.f - k);
}
float				BulletPhysicItem::GetAngularDamping() const
{
	return rigid_body ? 1.f - rigid_body->getAngularDamping() : 0;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				BulletPhysicItem::SetLinearFactor(const Vector4 &k)
{
	if	(rigid_body)
		rigid_body->setLinearFactor(btVector3(k.x, k.y, k.z));
}
void				BulletPhysicItem::SetAngularFactor(const Vector4 &k)
{
	if	(rigid_body)
		rigid_body->setAngularFactor(btVector3(k.x, k.y, k.z));
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				BulletPhysicItem::TransformFromMatrix4(const Matrix4 &m, btTransform &transform)
{
	btScalar scalar[15];
	scalar[0] = m.m[0][0]; scalar[1] = m.m[1][0]; scalar[2] = m.m[2][0]; scalar[3] = 1;
	scalar[4] = m.m[0][1]; scalar[5] = m.m[1][1]; scalar[6] = m.m[2][1]; scalar[7] = 1;
	scalar[8] = m.m[0][2]; scalar[9] = m.m[1][2]; scalar[10] = m.m[2][2]; scalar[11] = 1;
	scalar[12] = m.m[0][3]; scalar[13] = m.m[1][3]; scalar[14] = m.m[2][3];
	transform.setFromOpenGLMatrix(scalar);
}
void				BulletPhysicItem::TransformToMatrix4(const btTransform &transform, Matrix4 &m)
{
	btScalar scalar[16];
	transform.getOpenGLMatrix(scalar);
	m.m[0][0] = scalar[0]; m.m[1][0] = scalar[1]; m.m[2][0] = scalar[2]; m.m[3][0] = 0;
	m.m[0][1] = scalar[4]; m.m[1][1] = scalar[5]; m.m[2][1] = scalar[6]; m.m[3][1] = 0;
	m.m[0][2] = scalar[8]; m.m[1][2] = scalar[9]; m.m[2][2] = scalar[10]; m.m[3][2] = 0;
	m.m[0][3] = scalar[12]; m.m[1][3] = scalar[13]; m.m[2][3] = scalar[14]; m.m[3][3] = scalar[15];
}
void				BulletPhysicItem::GetGraphicMatrix(Matrix4 &m)
{
	if	(ghost_object)
	{
		btTransform	wt = ghost_object->getWorldTransform();
		wt.setOrigin(wt.getOrigin() - wt.getBasis() * btVector3(center.x, center.y, center.z));
		TransformToMatrix4(wt, m);
	}
	else
		if	(motion_state)
			m = motion_state->GetGraphicMatrix();
}
void				BulletPhysicItem::SetEngineMatrix(const Matrix4 &m)
{
	if	(motion_state)
		motion_state->SetEngineMatrix(m);
}
void				BulletPhysicItem::GetMatrix(Matrix4 &m)
{
	if	(ghost_object)
		TransformToMatrix4(ghost_object->getWorldTransform(), m);
	else
		if	(rigid_body)
			TransformToMatrix4(rigid_body->getWorldTransform(), m);
}
void				BulletPhysicItem::SetMatrix(const Matrix4 &m)
{
	Vector4 p;
	Matrix3 m3;
	m.Decompose(&p, 0, &m3);
	Matrix4 m4(Matrix4::FromMatrix3(m3));
	m4.SetRow(3, p);

	btTransform	wt;
	TransformFromMatrix4(m4, wt);
	wt.setOrigin(wt.getOrigin() + wt.getBasis() * btVector3(center.x, center.y, center.z));

	if	(ghost_object)
		ghost_object->setWorldTransform(wt);
	else
		if	(rigid_body)
			rigid_body->setWorldTransform(wt);
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				BulletPhysicItem::SetSleeping(bool sleep)
{
	if	(!rigid_body)
		return;

	if	(sleep)
			rigid_body->setActivationState(WANTS_DEACTIVATION);
	else	rigid_body->activate();
}
bool				BulletPhysicItem::IsSleeping() const
{	return rigid_body ? rigid_body->wantsSleeping() : false;	}
void				BulletPhysicItem::SetActive(bool active)
{
	if	(!rigid_body)
		return;

	if	(active)
	{
		/*
			Note the activation state MUST be changed from
			DISABLE_SIMULATION or activate() will silently fail.
		*/
		rigid_body->getBroadphaseHandle()->m_collisionFilterGroup = self_mask;
		rigid_body->getBroadphaseHandle()->m_collisionFilterMask = collision_mask;
		rigid_body->forceActivationState(ACTIVE_TAG);
		rigid_body->activate();
	}
	else
	{
		rigid_body->setActivationState(DISABLE_SIMULATION);
		rigid_body->getBroadphaseHandle()->m_collisionFilterGroup = 0;
		rigid_body->getBroadphaseHandle()->m_collisionFilterMask = 0;
	}
}
bool				BulletPhysicItem::GetActive() const
{	return rigid_body ? rigid_body->isActive() : false;		}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				BulletPhysicItem::VehicleSetForce(float F, uint i)
{
	if	(vehicle && (i < (uint)vehicle->getNumWheels()))
		vehicle->applyEngineForce(F, i);
}
void				BulletPhysicItem::VehicleSetBrake(float F, uint i)
{
	if	(vehicle && (i < (uint)vehicle->getNumWheels()))
		vehicle->setBrake(F, i);
}
void				BulletPhysicItem::VehicleSetSteering(float v, uint i)
{
	if	(vehicle && (i < (uint)vehicle->getNumWheels()))
		vehicle->setSteeringValue(v, i);
}
void				BulletPhysicItem::VehicleSetFriction(float f, uint i)
{
	if	(vehicle && (i < (uint)vehicle->getNumWheels()))
		vehicle->getWheelInfo(i).m_frictionSlip = f;
}
Matrix4			BulletPhysicItem::VehicleGetWheelMatrix(uint i)
{
	Matrix4 m(Matrix4::IdentityMatrix());
	if	(vehicle && (i < (uint)vehicle->getNumWheels()))
	{
		vehicle->updateWheelTransform(i, true);
		TransformToMatrix4(vehicle->getWheelInfo(i).m_worldTransform, m);
	}
	return m;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				BulletPhysicItem::CharacterSetRotationMatrix(const Matrix3 &m)
{
	if	(ghost_object)
	{
		btMatrix3x3	basis
		(
			m.m[0][0], m.m[0][1], m.m[0][2],
			m.m[1][0], m.m[1][1], m.m[1][2],
			m.m[2][0], m.m[2][1], m.m[2][2]
		);
		ghost_object->getWorldTransform().setBasis(basis);
	}
}
void				BulletPhysicItem::CharacterSetVelocity(const Vector4 &v)
{
	if	(character_controller)
		character_controller->setWalkDirection(nTobtVector(v));
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				BulletPhysicItem::SetScale(const Vector4 &_scale)
{
	scale = _scale;
	if	(compound)
		compound->setLocalScaling(nTobtVector(scale));
}
Vector4				BulletPhysicItem::GetScale() const
{	return scale;	}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				BulletPhysicItem::ResetBody()
{
	if	(rigid_body)
	{
		rigid_body->setLinearVelocity(btVector3(0, 0, 0));
		rigid_body->setAngularVelocity(btVector3(0, 0, 0));
		rigid_body->clearForces();
	}
}
void				BulletPhysicItem::ForceUpdateMassShapePhysic(const PhysicItemDesc &desc, PhysicWorld *world)
{
	float total_mass = 0;
	if (!desc.shape_list.GetCount())
		return;
	
	Array <btScalar> mass_array;
	mass_array.Allocate(desc.shape_list.GetCount());
	center.Set(0, 0, 0);
	btScalar *pmass_array = mass_array.c_ptr();

	ListForeachPtr(PhysicShape *, shape, desc.shape_list)
	{
		Vector4 shape_center = shape->position;
		center += shape_center * shape->mass;
		total_mass += shape->mass;
		*pmass_array++ = shape->mass;
	}
	center /= total_mass;
	btTransform	principal;
	btVector3 body_inertia(0, 0, 0);
	compound->calculatePrincipalAxisTransform(mass_array, principal, body_inertia);

	rigid_body->setMassProps(total_mass, body_inertia);
	rigid_body->updateInertiaTensor();
			
}
//------------------------------------------------------------------------------
float				BulletPhysicItem::SetupCollisionShapes(const PhysicItemDesc &desc, Array <btScalar> &mass_array, PhysicWorld *world)
{
	float total_mass = 0;
	if	(!desc.shape_list.GetCount())
		return total_mass;

	mass_array.Allocate(desc.shape_list.GetCount());
	btScalar *pmass_array = mass_array.c_ptr();

	// WTF man... can't Bullet handle COM offset by itself?
	shapes.Allocate(desc.shape_list.GetCount());

	center.Set(0, 0, 0);

	uint n = 0;
	ListForeachPtr(PhysicShape *, shape, desc.shape_list)
	{
		btCollisionShape *btshape = NULL;
		Vector4 shape_center = shape->position;

		switch (shape->GetType())
		{
			case PhysicShape::TypeNone:
				break;

			case PhysicShape::TypeHeightmap:
				if	(float *ph = shape->GetHeightmap())
				{
					float min, max;
					min = max = ph[0];
					for	(int v = 0; v < shape->GetHeight(); ++v)
						for	(int u = 0; u < shape->GetWidth(); ++u)
						{
							if	(ph[0] > max)
								max = ph[0];
							if	(ph[0] < min)
								min = ph[0];
							ph++;
						}

					btshape = new btHeightfieldTerrainShape(shape->GetWidth(), shape->GetHeight(), (void *)shape->GetHeightmap(), 1.f, min, max, 1, PHY_FLOAT, false);
				}
				break;

			case PhysicShape::TypeSphere:
				btshape = new btSphereShape(shape->dimensions.x);
				break;

			case PhysicShape::TypeBox:
			{
				const Vector4 &d = shape->dimensions;
				btshape = new btBoxShape(btVector3(d.x * 0.5f, d.y * 0.5f, d.z * 0.5f));
			}
			break;

			case PhysicShape::TypeCapsule:
			{
				const Vector4 &d = shape->dimensions;
				btshape = new btCapsuleShapeZ(d.x * 0.5f, d.z);
			}
			break;

			case PhysicShape::TypeCylinder:
			{
				const Vector4 &d = shape->dimensions;
				btshape = new btCylinderShapeZ(btVector3(d.x * 0.5f, d.y * 0.5f, d.z * 0.5f));
			}
			break;

			case PhysicShape::TypeCone:
			{
				const Vector4 &d = shape->dimensions;
				btshape = new btConeShapeZ(d.x * 0.5f, d.z * 0.5f);
			}
			break;

			case PhysicShape::TypeConvex:
				if	(BulletConvex *convex = ((BulletWorld *)world)->LoadConvex(shape->path))
				{
					shapes[n].convex = convex;

					shape_center = convex->center * shape->GetMatrix();
					btshape = convex->convex;
				}
				break;

			case PhysicShape::TypeMesh:
				if	(desc.physic_mode == PhysicItemDesc::Mode_Static)
				{
					/*
						[EJ] 06/03/13 - Bullet SILENTLY rescales the cached mesh
						vertices to comply with the item scale. In order to support
						multiple scales on the same mesh the path is suffixed with
						the item scale.
					*/
					String suffix = String::Format("%.02f_%.02f_%.02f", scale.x, scale.y, scale.z);

					if	(BulletMesh *mesh = ((BulletWorld *)world)->LoadMesh(shape->path, suffix))
					{
						shapes[n].mesh = mesh;

						shape_center = mesh->center * shape->GetMatrix();
						btshape = mesh->mesh;
					}
				}
				break;
		}

		shapes[n].shape = btshape;

		center += shape_center * shape->mass;
		total_mass += shape->mass;
		*pmass_array++ = shape->mass;

		++n;
	}

	center /= total_mass;
	if	(desc.physic_mode == PhysicItemDesc::Mode_Vehicle)
		center.Set(0, 0, 0);

	n = 0;
	ListForeachPtr(PhysicShape *, shape, desc.shape_list)
	{
		if	(btCollisionShape *btshape = shapes[n].shape)
		{
			Vector4 shape_offset(0, 0, 0);

			if (shape->GetType() == PhysicShape::TypeHeightmap)
			{
				float *ph = shape->GetHeightmap();

				float min, max;
				min = max = ph[0];

				for	(int v = 0; v < shape->GetHeight(); ++v)
					for	(int u = 0; u < shape->GetWidth(); ++u)
					{
						if	(ph[0] > max) max = ph[0];
						if	(ph[0] < min) min = ph[0];
						ph++;
					}

				btshape->setLocalScaling(btVector3(1, 1, 1));

				// Damn... what a mess.
				float hy = (max - min) * -0.5f;
				shape_offset.Set(0, min - hy, 0);
			}

			Matrix4 m = Matrix4::TransformationMatrix(shape->position + shape_offset - center, shape->rotation, shape->scale);
			btTransform	transform;
			TransformFromMatrix4(m, transform);

			compound->addChildShape(transform, btshape);
		}
		++n;
	}
	return total_mass;
}
bool				BulletPhysicItem::SetupCharacterController(const PhysicItemDesc &desc)
{
	ghost_object = new btPairCachingGhostObject();
	ghost_object->setUserPointer((PhysicItem *)this);

#if	0
	convex_shape = new btCylinderShape(btVector3(desc.character.radius, desc.character.height * 0.5f, desc.character.radius));
	center.Set(0, desc.character.height * 0.5f, 0);
#else
	float height = Types::Max(desc.character.height - desc.character.radius * 2.f, 0.f);
	convex_shape = new btCapsuleShape(desc.character.radius, height);	// Height is the distance between the center of the two spheres whose convex hull is a capsule.
	center.Set(0, (height + desc.character.radius * 2.f) * 0.5f, 0);
#endif

	ghost_object->setCollisionShape(convex_shape);
	ghost_object->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);

#if	1
	character_controller = new btKinematicCharacterController(ghost_object, convex_shape, desc.character.max_step);
#else
	btCustomCharacterController *cc = new btCustomCharacterController(ghost_object, convex_shape, desc.character.max_step, btworld->getCollisionWorld());
	character_controller = cc;
#endif
	return true;
}
bool				BulletPhysicItem::SetupKinematicDynamicBody(const PhysicItemDesc &desc, PhysicWorld *world)
{
	// Setup collision shapes.
	Array <btScalar> mass_array;

	compound = new btCompoundShape;
	float total_mass = SetupCollisionShapes(desc, mass_array, world);

	if	(!compound->getNumChildShapes())
		return true;

	// Initialize physic mode.
	compound->setLocalScaling(nTobtVector(scale));
	btVector3 body_inertia(0, 0, 0);

	switch (desc.physic_mode)
	{
		case PhysicItemDesc::Mode_None:
			break;

		case PhysicItemDesc::Mode_Dynamic:
		case PhysicItemDesc::Mode_Vehicle:
			if	(compound->getNumChildShapes())
			{
				btTransform	principal;
				compound->calculatePrincipalAxisTransform(mass_array, principal, body_inertia);
			}
			else
			{
				total_mass = 1;
				body_inertia.setValue(1, 1, 1);
			}
			break;

		case PhysicItemDesc::Mode_Static:
		case PhysicItemDesc::Mode_Kinematic:
			total_mass = 0;
			break;
	}

	// Allocate motion state.
	motion_state = new BulletMotionState(this);

	// Create rigid body.
	rigid_body = new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(total_mass, motion_state, compound, body_inertia));
	rigid_body->setUserPointer((PhysicItem *)this);

	// Vehicle specialization.
	if	(desc.physic_mode == PhysicItemDesc::Mode_Vehicle)
	{
		rigid_body->setActivationState(DISABLE_DEACTIVATION);

		vehicle_raycaster = new btDefaultVehicleRaycaster(btworld);
		vehicle = new btRaycastVehicle(btRaycastVehicle::btVehicleTuning(), rigid_body, vehicle_raycaster);
		vehicle->setCoordinateSystem(0, 1, 2);

		// Add wheels.
		ListForeachPtr(PhysicWheel *, wheel, desc.vehicle.wheel_list)
		{
			btRaycastVehicle::btVehicleTuning tuning;

			tuning.m_suspensionStiffness = wheel->stiffness;
			tuning.m_suspensionDamping = wheel->damping;
			tuning.m_suspensionCompression = wheel->damping;
			tuning.m_frictionSlip = wheel->friction;
			tuning.m_maxSuspensionTravelCm = wheel->max_compression * 10.f;		// m to cm.

			Vector4	o = wheel->ref_matrix.GetRow(3),
					u = wheel->ref_matrix.GetRow(1).Reversed(),
					l = wheel->ref_matrix.GetRow(0).Reversed();

			vehicle->addWheel(btVector3(o.x, o.y, o.z), btVector3(u.x, u.y, u.z), btVector3(l.x, l.y, l.z), wheel->rest_length, wheel->radius > 0.01f ? wheel->radius : 0.01f, tuning, false);
		}
	}

	// Set defaults.
	SetLinearFactor(desc.linear_factor);
	SetAngularFactor(desc.angular_factor);
	SetLinearDamping(desc.linear_damping);
	SetAngularDamping(desc.angular_damping);

	if	(desc.shape_list.GetCount())
	{
		PhysicShape *shape = desc.shape_list.GetRoot()->Object();
		rigid_body->setFriction(shape->static_friction);
		rigid_body->setRestitution(shape->restitution);
	}

	if	(desc.physic_mode == PhysicItemDesc::Mode_Kinematic)
	{
		rigid_body->setCollisionFlags(rigid_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
		rigid_body->setActivationState(DISABLE_DEACTIVATION);
	}
	return true;
}
bool				BulletPhysicItem::SetupBody(const PhysicItemDesc &desc, PhysicWorld *world)
{
	// EJ 11/10
	//
	// - Bullet constraint holds strong/unmanaged reference to Bullet rigid bodies.
	// - A Bullet rigid body is not meant to be radically modified once created.

// BulletWorld *world = (PhysicWorld *)world;

	if	(rigid_body || ghost_object)
		return true;

	DeleteBody();

	switch (desc.physic_mode)
	{
		case PhysicItemDesc::Mode_None:
			return true;

		case PhysicItemDesc::Mode_Character:
			if	(!SetupCharacterController(desc))
				return false;

			btworld->addCollisionObject(ghost_object, btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter);
			btworld->addAction(character_controller);
			break;

		default:
			if	(!SetupKinematicDynamicBody(desc, world))
				return false;

			if	(rigid_body)
			{
				btworld->addRigidBody(rigid_body);
				const Vector4 &g(world->GetGravity());
				rigid_body->setGravity(btVector3(g.x, g.y, g.z));
			}
			if	(vehicle)
				btworld->addVehicle(vehicle);
			break;
	}

	SetCollisionMask(desc.collision_mask);
	SetSelfMask(desc.self_mask);
	return true;
}
void				BulletPhysicItem::DeleteBody()
{
	// Destroy all shapes.
	if	(compound)
		while (compound->getNumChildShapes())
			compound->removeChildShapeByIndex(0);

	// The collision shape for mesh/convex are cached and should not be deleted here!
	for (uint n = 0; n < shapes.GetCount(); ++n)
		if	(shapes[n].convex.IsValid() || shapes[n].mesh.IsValid())
			shapes[n].shape.Detach();

	shapes.Free();

	// Destroy rigid body.
	if	(rigid_body)
		btworld->removeRigidBody(rigid_body);
	rigid_body = NULL;

	if	(vehicle)
		btworld->removeVehicle(vehicle);
	vehicle = NULL;
	vehicle_raycaster = NULL;

	if	(ghost_object)
		btworld->removeCollisionObject(ghost_object);
	ghost_object = NULL;

	if	(character_controller)
		btworld->removeAction(character_controller);
	character_controller = NULL;

	compound = NULL;
	motion_state = NULL;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				BulletPhysicItem::SetGravity(const Vector4 &g)
{
	if	(rigid_body)
		rigid_body->setGravity(btVector3(g.x, g.y, g.z));
}
Vector4				BulletPhysicItem::GetGravity() const
{
	if	(!rigid_body)
		return Vector4(0, 0, 0);
	btVector3 g = rigid_body->getGravity();
	return Vector4(g.x(), g.y(), g.z());
}
void				BulletPhysicItem::ApplyImpulse(const Vector4 &I, const Vector4 *p)
{
	if	(!rigid_body)
		return;

	SetSleeping(false);

	if	(p && (I.Len() > 0.0001))
	{
		btVector3 l(p->x, p->y, p->z);
		btVector3 J(I.x, I.y, I.z);
		btScalar k = rigid_body->computeImpulseDenominator(l, J.normalized());
		rigid_body->applyImpulse(J / k, l - rigid_body->getCenterOfMassPosition());
	}
	else
	{
		btVector3 J(I.x, I.y, I.z);
		rigid_body->applyCentralImpulse(J / rigid_body->getInvMass());
	}
}
void				BulletPhysicItem::ApplyForce(const Vector4 &F, const Vector4 *p)
{
	if	(!rigid_body)
		return;

	SetSleeping(false);
	if	(p)
			rigid_body->applyForce(btVector3(F.x, F.y, F.z), btVector3(p->x, p->y, p->z) - rigid_body->getCenterOfMassPosition());
	else	rigid_body->applyCentralForce(btVector3(F.x, F.y, F.z));
}
void				BulletPhysicItem::ApplyTorque(const Vector4 &T)
{
	if	(rigid_body)
		rigid_body->applyTorque(rigid_body->getCenterOfMassTransform().getBasis() * btVector3(T.x, T.y, T.z));
}
void				BulletPhysicItem::SetAngularVelocity(const Vector4 &w)
{
	if	(rigid_body)
		rigid_body->setAngularVelocity(btVector3(w.x, w.y, w.z));
}
Vector4				BulletPhysicItem::GetAngularVelocity() const
{
	if	(!rigid_body)
		return Vector4(0, 0, 0);
	const btVector3	&v = rigid_body->getAngularVelocity();
	return Vector4(v.x(), v.y(), v.z());
}
void				BulletPhysicItem::SetLinearVelocity(const Vector4 &v)
{
	if	(rigid_body)
		rigid_body->setLinearVelocity(btVector3(v.x, v.y, v.z));
}
Vector4				BulletPhysicItem::GetLinearVelocity() const
{
	if	(!rigid_body)
		return Vector4(0, 0, 0);
	const btVector3	&v = rigid_body->getLinearVelocity();
	return Vector4(v.x(), v.y(), v.z());
}
Vector4				BulletPhysicItem::GetLocalPointVelocity(const Vector4 &p) const
{
	if	(!rigid_body)
		return Vector4(0, 0, 0);
	btVector3 v = rigid_body->getVelocityInLocalPoint(rigid_body->getCenterOfMassTransform().getBasis() * btVector3(p.x, p.y, p.z));
	return Vector4(v.x(), v.y(), v.z());
}
Vector4				BulletPhysicItem::GetWorldPointVelocity(const Vector4 &wp) const
{
	if	(!rigid_body)
		return Vector4(0, 0, 0);
	btVector3 v = rigid_body->getVelocityInLocalPoint(btVector3(wp.x, wp.y, wp.z) - rigid_body->getCenterOfMassPosition());
	return Vector4(v.x(), v.y(), v.z());
}
Vector4				BulletPhysicItem::GetCenterOfMass() const
{
	if	(!rigid_body)
		return Vector4(0, 0, 0);
	btVector3 p = rigid_body->getCenterOfMassPosition();
	return Vector4(p.x(), p.y(), p.z());
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
BulletPhysicItem::BulletPhysicItem(btDiscreteDynamicsWorld *w)
{
	btworld = w;

	center.Set(0, 0, 0);
	scale.Set(1, 1, 1);
}
BulletPhysicItem::~BulletPhysicItem()
{
	DeleteBody();
}
//----------------------------------------------------------------------------------
