#include "Mix/Tool/Win32/Core/Dynamics/Impl/World.h"

#include "Mix/Tool/Win32/Core/Dynamics/Impl/StaticPlane.h"
#include "Mix/Tool/Win32/Core/Dynamics/Impl/StaticMesh.h"
#include "Mix/Tool/Win32/Core/Dynamics/Impl/PointJoint.h"
#include "Mix/Tool/Win32/Core/Dynamics/Impl/HingeJoint.h"
#include "Mix/Tool/Win32/Core/Dynamics/Impl/BallJoint.h"
#include "Mix/Tool/Win32/Core/Dynamics/Impl/RigidBody.h"
#include "Mix/Tool/Win32/Core/Dynamics/Impl/KinematicCharacter.h"
#include "Mix/Tool/Win32/Core/Graphics/LineHelper.h"

#include "btBulletDynamicsCommon.h"
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
#include "BulletDynamics/Character/btKinematicCharacterController.h"

extern ContactAddedCallback gContactAddedCallback;

namespace Mix{ namespace Tool{ namespace Win32{ namespace Dynamics{ namespace Impl{

	////////////////////////////////////////////////////////////////////////////////////////////////////
// World::CustomMaterialCombinerCallback
////////////////////////////////////////////////////////////////////////////////////////////////////

bool World::CustomMaterialCombinerCallback( btManifoldPoint& cp,
											const btCollisionObjectWrapper* cow0, int partId0, int index0,
											const btCollisionObjectWrapper* cow1, int partId1, int index1 )
{
	const btCollisionObject* colObj0 = cow0->getCollisionObject();
	const btCollisionObject* colObj1 = cow1->getCollisionObject();

	float friction0 = colObj0->getFriction();
	float restitution0 = colObj0->getRestitution();
	float friction1 = colObj1->getFriction();
	float restitution1 = colObj1->getRestitution();

	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( MIX_TEST_BIT( colObj0->getCollisionFlags(), btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK ) ==  btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK )
	{
		const btCollisionShape* pCollShape = colObj0->getCollisionShape();
		if( pCollShape != NULL )
		{
			int shapeType = pCollShape->getShapeType();

			if( shapeType == TRIANGLE_MESH_SHAPE_PROXYTYPE )
			{
				const Mix::Tool::Win32::Dynamics::Impl::StaticMesh* pStaticMesh = static_cast<const Mix::Tool::Win32::Dynamics::Impl::StaticMesh*>( colObj0->getUserPointer() );
				const Mix::Tool::Win32::Dynamics::MATERIAL* pMaterial = pStaticMesh->GetMaterialPtrByPolygonIndex( index0 );

				friction0 = pMaterial->friction;
				restitution0 = pMaterial->restitution;
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( MIX_TEST_BIT( colObj1->getCollisionFlags(), btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK ) ==  btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK )
	{
		const btCollisionShape* pCollShape = colObj1->getCollisionShape();
		if( pCollShape != NULL )
		{
			int shapeType = pCollShape->getShapeType();

			if( shapeType == TRIANGLE_MESH_SHAPE_PROXYTYPE )
			{
				const Mix::Tool::Win32::Dynamics::Impl::StaticMesh* pStaticMesh = static_cast<const Mix::Tool::Win32::Dynamics::Impl::StaticMesh*>( colObj1->getUserPointer() );
				const Mix::Tool::Win32::Dynamics::MATERIAL* pMaterial = pStaticMesh->GetMaterialPtrByPolygonIndex( index1 );

				friction1 = pMaterial->friction;
				restitution1 = pMaterial->restitution;
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	cp.m_combinedFriction = ( friction0 + friction1 ) * 0.5f;
	cp.m_combinedRestitution = ( restitution0 + restitution1 ) * 0.5f;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// World
////////////////////////////////////////////////////////////////////////////////////////////////////

World::World( void ) :
m_pDispatcher( NULL ),
m_pBroadphas( NULL ),
m_pSolver( NULL ),
m_pConfiguration( NULL ),
m_pWorld( NULL ),
m_pGhostPairCallback( NULL ),
m_PickPreDist( 0.0f ),
m_pPick( NULL ),
m_pPickRigidBody( NULL )
{
	gContactAddedCallback = World::CustomMaterialCombinerCallback;
}

World::~World( void )
{
	Picker_Release();

	for( World::CollisionObjectList::iterator it = m_CollisionObjectList.begin(); it != m_CollisionObjectList.end(); ++it )
	{
		DetachCollisionObject( ( *it ) );
	}

	MIX_DELETE( m_pWorld );
	MIX_DELETE( m_pGhostPairCallback );
	MIX_DELETE( m_pDispatcher );
	MIX_DELETE( m_pBroadphas );
	MIX_DELETE( m_pSolver );
	MIX_DELETE( m_pConfiguration );
}

bool World::Initialize( void )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pConfiguration = new btDefaultCollisionConfiguration();
	if( m_pConfiguration == NULL )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pDispatcher = new	btCollisionDispatcher( m_pConfiguration );
	m_pBroadphas = new btDbvtBroadphase();
	m_pSolver = new btSequentialImpulseConstraintSolver();
	if( ( m_pDispatcher == NULL ) ||
		( m_pBroadphas == NULL ) ||
		( m_pSolver == NULL ) )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pGhostPairCallback = new btGhostPairCallback();
	if( m_pGhostPairCallback != NULL )
	{
		//キャラクターコントローラー衝突応答用
		m_pBroadphas->getOverlappingPairCache()->setInternalGhostPairCallback( m_pGhostPairCallback );
	}
	else
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pWorld = new btDiscreteDynamicsWorld( m_pDispatcher, m_pBroadphas, m_pSolver, m_pConfiguration );
	if( m_pWorld != NULL )
	{
		m_pWorld->getDispatchInfo().m_allowedCcdPenetration = 0.0001f;
	}
	else
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	return true;
}

void World::SetGravity( const D3DXVECTOR3& gravity )
{
	m_pWorld->setGravity( btVector3( gravity.x, gravity.y, gravity.z ) );
}

D3DXVECTOR3 World::GetGravity( void )
{
	btVector3 gravity = m_pWorld->getGravity();

	return D3DXVECTOR3( gravity.x(), gravity.y(), gravity.z() );
}

bool World::AddCollisionObject( Mix::Tool::Win32::Dynamics::CollisionObject* pCollisionObject )
{
	if( pCollisionObject == NULL )
	{
		return false;
	}

	World::CollisionObjectList::iterator it = m_CollisionObjectList.find( pCollisionObject );
	if( it == m_CollisionObjectList.end() )
	{
		AttachCollisionObject( pCollisionObject );
		m_CollisionObjectList.insert( pCollisionObject );
	}
	else
	{
		return false;
	}

	return true;
}

bool World::RemoveCollisionObject( Mix::Tool::Win32::Dynamics::CollisionObject* pCollisionObject )
{
	if( pCollisionObject == NULL )
	{
		return false;
	}

	World::CollisionObjectList::iterator it = m_CollisionObjectList.find( pCollisionObject );
	if( it != m_CollisionObjectList.end() )
	{
		DetachCollisionObject( pCollisionObject );
		m_CollisionObjectList.erase( it );
	}
	else
	{
		return false;
	}

	return true;
}

bool World::AddJoint( Mix::Tool::Win32::Dynamics::Joint* pJoint )
{
	if( pJoint == NULL )
	{
		return false;
	}

	World::JointList::iterator it = m_JointList.find( pJoint );
	if( it == m_JointList.end() )
	{
		AttachJoint( pJoint );
		m_JointList.insert( pJoint );
	}
	else
	{
		return false;
	}

	return true;
}

bool World::RemoveJoint( Mix::Tool::Win32::Dynamics::Joint* pJoint )
{
	if( pJoint == NULL )
	{
		return false;
	}

	World::JointList::iterator it = m_JointList.find( pJoint );
	if( it != m_JointList.end() )
	{
		DetachJoint( pJoint );
		m_JointList.erase( it );
	}
	else
	{
		return false;
	}

	return true;
}

void World::Update( float dt )
{
	m_pWorld->stepSimulation( dt );
}

void World::Draw(	Mix::Tool::Win32::Graphics::LineHelper* pLineHelper,
					const D3DXVECTOR4& collObjColor,
					const D3DXVECTOR4& jointAxisColor,
					const D3DXVECTOR4& jointPivotColor,
					const D3DXVECTOR4& jointLimitColor )
{
	if( m_CollisionObjectList.size() > 0 )
	{
		World::CollisionObjectList::iterator it_begin = m_CollisionObjectList.begin();
		World::CollisionObjectList::iterator it_end = m_CollisionObjectList.end();
		World::CollisionObjectList::iterator it;

		for( it = it_begin; it != it_end; ++it )
		{
			( *it )->Draw( pLineHelper, collObjColor );
		}
	}

	if( m_JointList.size() > 0 )
	{
		World::JointList::iterator it_begin = m_JointList.begin();
		World::JointList::iterator it_end = m_JointList.end();
		World::JointList::iterator it;

		for( it = it_begin; it != it_end; ++it )
		{
			( *it )->Draw( pLineHelper, jointAxisColor, jointPivotColor, jointLimitColor );
		}
	}
}

void World::Picker_Catch( const D3DXVECTOR3& eyePos, const D3DXVECTOR3& fromWorldPos, const D3DXVECTOR3& toWorldPos )
{
	if( m_pPick != NULL )
	{
		m_pWorld->removeConstraint( m_pPick );
		MIX_DELETE( m_pPick );
	}

	btVector3 rayFrom( fromWorldPos.x, fromWorldPos.y, fromWorldPos.z );
	btVector3 rayTo( toWorldPos.x, toWorldPos.y, toWorldPos.z );

	btCollisionWorld::ClosestRayResultCallback result( rayFrom, rayTo );

	result.m_collisionFilterGroup = btBroadphaseProxy::DefaultFilter;
	result.m_collisionFilterMask = btBroadphaseProxy::DefaultFilter;

	m_pWorld->rayTest( rayFrom, rayTo, result );
	if( result.hasHit() == true )
	{
		Mix::Tool::Win32::Dynamics::CollisionObject* pCollisionObject = static_cast<Mix::Tool::Win32::Dynamics::CollisionObject*>( result.m_collisionObject->getUserPointer() );
		Mix::Tool::Win32::Object::TYPE objType = pCollisionObject->GetType();

		if( objType == Mix::Tool::Win32::Object::DYNAMICS__RIGID_BODY )
		{
			Mix::Tool::Win32::Dynamics::Impl::RigidBody* pRigidBody = static_cast<Mix::Tool::Win32::Dynamics::Impl::RigidBody*>( pCollisionObject );
			Mix::Tool::Win32::Dynamics::RigidBody::STATUS rbStatus = pRigidBody->GetStatus();

			if( rbStatus == Mix::Tool::Win32::Dynamics::RigidBody::DEFAULT )
			{
				const D3DXVECTOR3& pos = pRigidBody->GetWorldPosition();
				const D3DXQUATERNION& rot = pRigidBody->GetWorldRotation();

				D3DXVECTOR3 hitPoint( result.m_hitPointWorld.x(), result.m_hitPointWorld.y(), result.m_hitPointWorld.z() );

				D3DXMATRIX worldMat;
				D3DXMATRIX toLocalMat;
				D3DXVECTOR3 pivotA;

				D3DXMatrixRotationQuaternion( &worldMat, &( pRigidBody->GetWorldRotation() ) );
				worldMat._41 = pos.x;
				worldMat._42 = pos.y;
				worldMat._43 = pos.z;
				worldMat._44 = 1.0f;

				D3DXVec3TransformCoord( &pivotA, &hitPoint, D3DXMatrixInverse( &toLocalMat, NULL, &worldMat ) );

				m_pPick = new btPoint2PointConstraint( *( pRigidBody->Bullet_GetRigidBodyPtr() ), btVector3( pivotA.x, pivotA.y, pivotA.z ) );
				if( m_pPick != NULL )
				{
					m_pPick->setParam( BT_CONSTRAINT_STOP_CFM, 0.9f );
					m_pPick->setParam( BT_CONSTRAINT_STOP_ERP, 0.9f );
					m_pPick->setDbgDrawSize( 1.0f );
					m_pWorld->addConstraint( m_pPick );

					m_pPickRigidBody = pRigidBody;
					m_pPickRigidBody->SetPick( true );

					m_PickPreDist = D3DXVec3Length( &( hitPoint - eyePos ) );

					Picker_Update( fromWorldPos, toWorldPos );
				}
			}
		}
	}
}

void World::Picker_Update( const D3DXVECTOR3& eyePos, const D3DXVECTOR3& toWorldPos )
{
	if( m_pPick != NULL )
	{
		D3DXVECTOR3 dir;
		D3DXVECTOR3 pivotB;

		D3DXVec3Normalize( &dir, &( toWorldPos - eyePos ) );
		pivotB = eyePos + ( dir * m_PickPreDist );

		m_pPick->setPivotB( btVector3( pivotB.x, pivotB.y, pivotB.z ) );
	}
}

void World::Picker_Release( void )
{
	if( m_pPickRigidBody != NULL )
	{
		m_pPickRigidBody->SetPick( false );
		m_pPickRigidBody = NULL;
	}

	if( m_pPick != NULL )
	{
		m_pWorld->removeConstraint( m_pPick );
		MIX_DELETE( m_pPick );
	}
}

void World::AttachCollisionObject( Mix::Tool::Win32::Dynamics::CollisionObject* pCollisionObject, bool bSetWorldPtr )
{
	if( pCollisionObject != NULL )
	{
		Mix::Tool::Win32::Object::TYPE type = pCollisionObject->GetType();

		if( type == Mix::Tool::Win32::Object::DYNAMICS__STATIC_PLANE )
		{
			Mix::Tool::Win32::Dynamics::Impl::StaticPlane* pObj = static_cast<Mix::Tool::Win32::Dynamics::Impl::StaticPlane*>( pCollisionObject );
			btRigidBody* pRigidBody = pObj->Bullet_GetRigidBodyPtr();

			if( pRigidBody != NULL )
			{
				m_pWorld->addRigidBody( pRigidBody, pObj->GetGroup(), pObj->GetGroupMask() );
			}

			if( bSetWorldPtr == true )
			{
				pObj->SetWorldPtr( this );
			}
		}
		else if( type == Mix::Tool::Win32::Object::DYNAMICS__STATIC_MESH )
		{
			Mix::Tool::Win32::Dynamics::Impl::StaticMesh* pObj = static_cast<Mix::Tool::Win32::Dynamics::Impl::StaticMesh*>( pCollisionObject );
			btRigidBody* pRigidBody = pObj->Bullet_GetRigidBodyPtr();

			if( pRigidBody != NULL )
			{
				m_pWorld->addRigidBody( pRigidBody, pObj->GetGroup(), pObj->GetGroupMask() );
			}

			if( bSetWorldPtr == true )
			{
				pObj->SetWorldPtr( this );
			}
		}
		else if( type == Mix::Tool::Win32::Object::DYNAMICS__RIGID_BODY )
		{
			Mix::Tool::Win32::Dynamics::Impl::RigidBody* pObj = static_cast<Mix::Tool::Win32::Dynamics::Impl::RigidBody*>( pCollisionObject );
			btRigidBody* pRigidBody = pObj->Bullet_GetRigidBodyPtr();

			if( pRigidBody != NULL )
			{
				m_pWorld->addRigidBody( pRigidBody, pObj->GetGroup(), pObj->GetGroupMask() );
			}

			if( bSetWorldPtr == true )
			{
				pObj->SetWorldPtr( this );
			}
		}
		else if( type == Mix::Tool::Win32::Object::DYNAMICS__KINEMATIC_CHARACTER )
		{
			Mix::Tool::Win32::Dynamics::Impl::KinematicCharacter* pObj = static_cast<Mix::Tool::Win32::Dynamics::Impl::KinematicCharacter*>( pCollisionObject );
			btPairCachingGhostObject* pGhostObject = pObj->Bullet_GetGhostObjectPtr();
			btKinematicCharacterController* pCharacterController = pObj->Bullet_GetCharacterControllerPtr();

			if( ( pGhostObject != NULL ) &&
				( pCharacterController != NULL ) )
			{
				m_pWorld->addCollisionObject( pObj->Bullet_GetGhostObjectPtr(), pObj->GetGroup(), pObj->GetGroupMask() );
				m_pWorld->addCharacter( pObj->Bullet_GetCharacterControllerPtr() );
			}

			if( bSetWorldPtr == true )
			{
				pObj->SetWorldPtr( this );
			}
		}
	}
}

void World::DetachCollisionObject( Mix::Tool::Win32::Dynamics::CollisionObject* pCollisionObject, bool bSetWorldPtr )
{
	if( pCollisionObject != NULL )
	{
		Mix::Tool::Win32::Object::TYPE type = pCollisionObject->GetType();

		if( m_pPickRigidBody == pCollisionObject )
		{
			Picker_Release();
		}

		if( type == Mix::Tool::Win32::Object::DYNAMICS__STATIC_PLANE )
		{
			Mix::Tool::Win32::Dynamics::Impl::StaticPlane* pObj = static_cast<Mix::Tool::Win32::Dynamics::Impl::StaticPlane*>( pCollisionObject );
			btRigidBody* pRigidBody = pObj->Bullet_GetRigidBodyPtr();

			if( pRigidBody != NULL )
			{
				m_pWorld->removeRigidBody( pRigidBody );
			}

			if( bSetWorldPtr == true )
			{
				pObj->SetWorldPtr( NULL );
			}
		}
		else if( type == Mix::Tool::Win32::Object::DYNAMICS__STATIC_MESH )
		{
			Mix::Tool::Win32::Dynamics::Impl::StaticMesh* pObj = static_cast<Mix::Tool::Win32::Dynamics::Impl::StaticMesh*>( pCollisionObject );
			btRigidBody* pRigidBody = pObj->Bullet_GetRigidBodyPtr();

			if( pRigidBody != NULL )
			{
				m_pWorld->removeRigidBody( pRigidBody );
			}

			if( bSetWorldPtr == true )
			{
				pObj->SetWorldPtr( NULL );
			}
		}
		else if( type == Mix::Tool::Win32::Object::DYNAMICS__RIGID_BODY )
		{
			Mix::Tool::Win32::Dynamics::Impl::RigidBody* pObj = static_cast<Mix::Tool::Win32::Dynamics::Impl::RigidBody*>( pCollisionObject );
			btRigidBody* pRigidBody = pObj->Bullet_GetRigidBodyPtr();

			if( pRigidBody != NULL )
			{
				m_pWorld->removeRigidBody( pRigidBody );
			}

			if( bSetWorldPtr == true )
			{
				pObj->SetWorldPtr( NULL );
			}
		}
		else if( type == Mix::Tool::Win32::Object::DYNAMICS__KINEMATIC_CHARACTER )
		{
			Mix::Tool::Win32::Dynamics::Impl::KinematicCharacter* pObj = static_cast<Mix::Tool::Win32::Dynamics::Impl::KinematicCharacter*>( pCollisionObject );
			btPairCachingGhostObject* pGhostObject = pObj->Bullet_GetGhostObjectPtr();
			btKinematicCharacterController* pCharacterController = pObj->Bullet_GetCharacterControllerPtr();

			if( pGhostObject != NULL )
			{
				m_pWorld->removeCollisionObject( pGhostObject );
			}

			if( pCharacterController != NULL )
			{
				m_pWorld->removeCharacter( pCharacterController );
			}

			if( bSetWorldPtr == true )
			{
				pObj->SetWorldPtr( NULL );
			}
		}
	}
}

void World::AttachJoint( Mix::Tool::Win32::Dynamics::Joint* pJoint, bool bSetWorldPtr )
{
	if( pJoint != NULL )
	{
		Mix::Tool::Win32::Object::TYPE objType = pJoint->GetType();
		bool bDisableCollision = ( ( pJoint->GetRigidBodyA() != NULL ) && ( pJoint->GetRigidBodyB() != NULL ) && ( pJoint->GetCollisionDisabled() == true ) );

		if( objType == Mix::Tool::Win32::Object::DYNAMICS__POINT_JOINT )
		{
			Mix::Tool::Win32::Dynamics::Impl::PointJoint* pImplJoint = static_cast<Mix::Tool::Win32::Dynamics::Impl::PointJoint*>( pJoint );
			btPoint2PointConstraint* pBulletConstraint = static_cast<btPoint2PointConstraint*>( pImplJoint->Bullet_GetTypedConstraintPtr() );

			if( pBulletConstraint != NULL )
			{
				m_pWorld->addConstraint( pBulletConstraint, bDisableCollision );
			}

			if( bSetWorldPtr == true )
			{
				pImplJoint->SetWorldPtr( this );
			}
		}
		else if( objType == Mix::Tool::Win32::Object::DYNAMICS__HINGE_JOINT )
		{
			Mix::Tool::Win32::Dynamics::Impl::HingeJoint* pImplJoint = static_cast<Mix::Tool::Win32::Dynamics::Impl::HingeJoint*>( pJoint );
			btHingeConstraint* pBulletConstraint = static_cast<btHingeConstraint*>( pImplJoint->Bullet_GetTypedConstraintPtr() );

			if( pBulletConstraint != NULL )
			{
				m_pWorld->addConstraint( pBulletConstraint, bDisableCollision );
			}

			if( bSetWorldPtr == true )
			{
				pImplJoint->SetWorldPtr( this );
			}
		}
		else if( objType == Mix::Tool::Win32::Object::DYNAMICS__BALL_JOINT )
		{
			Mix::Tool::Win32::Dynamics::Impl::BallJoint* pImplJoint = static_cast<Mix::Tool::Win32::Dynamics::Impl::BallJoint*>( pJoint );
			btConeTwistConstraint* pBulletConstraint = static_cast<btConeTwistConstraint*>( pImplJoint->Bullet_GetTypedConstraintPtr() );

			if( pBulletConstraint != NULL )
			{
				m_pWorld->addConstraint( pBulletConstraint, bDisableCollision );
			}

			if( bSetWorldPtr == true )
			{
				pImplJoint->SetWorldPtr( this );
			}
		}
	}
}

void World::DetachJoint( Mix::Tool::Win32::Dynamics::Joint* pJoint, bool bSetWorldPtr )
{
	if( pJoint != NULL )
	{
		Mix::Tool::Win32::Object::TYPE objType = pJoint->GetType();

		if( objType == Mix::Tool::Win32::Object::DYNAMICS__POINT_JOINT )
		{
			Mix::Tool::Win32::Dynamics::Impl::PointJoint* pImplJoint = static_cast<Mix::Tool::Win32::Dynamics::Impl::PointJoint*>( pJoint );
			btPoint2PointConstraint* pBulletConstraint = static_cast<btPoint2PointConstraint*>( pImplJoint->Bullet_GetTypedConstraintPtr() );

			if( pBulletConstraint != NULL )
			{
				m_pWorld->removeConstraint( pBulletConstraint );
			}

			if( bSetWorldPtr == true )
			{
				pImplJoint->SetWorldPtr( NULL );
			}
		}
		else if( objType == Mix::Tool::Win32::Object::DYNAMICS__HINGE_JOINT )
		{
			Mix::Tool::Win32::Dynamics::Impl::HingeJoint* pImplJoint = static_cast<Mix::Tool::Win32::Dynamics::Impl::HingeJoint*>( pJoint );
			btHingeConstraint* pBulletConstraint = static_cast<btHingeConstraint*>( pImplJoint->Bullet_GetTypedConstraintPtr() );

			if( pBulletConstraint != NULL )
			{
				m_pWorld->removeConstraint( pBulletConstraint );
			}

			if( bSetWorldPtr == true )
			{
				pImplJoint->SetWorldPtr( NULL );
			}
		}
		else if( objType == Mix::Tool::Win32::Object::DYNAMICS__BALL_JOINT )
		{
			Mix::Tool::Win32::Dynamics::Impl::BallJoint* pImplJoint = static_cast<Mix::Tool::Win32::Dynamics::Impl::BallJoint*>( pJoint );
			btConeTwistConstraint* pBulletConstraint = static_cast<btConeTwistConstraint*>( pImplJoint->Bullet_GetTypedConstraintPtr() );

			if( pBulletConstraint != NULL )
			{
				m_pWorld->removeConstraint( pBulletConstraint );
			}

			if( bSetWorldPtr == true )
			{
				pImplJoint->SetWorldPtr( NULL );
			}
		}
	}
}

}}}}}
