#include "Mix/Private/Dynamics/Vehicle.h"

#include "Mix/Private/Dynamics/Utility.h"
#include "Mix/Private/Dynamics/Shape.h"
#include "Mix/Private/Dynamics/ObjectContext.h"
#include "Mix/Dynamics/IShape.h"

#include "Mix/Graphics/Utility/IPerspectiveRenderer.h"

namespace Mix{ namespace Dynamics{

const wchar_t* Vehicle::FAILED_CREATE = L"ビハイクルの作成に失敗";

////////////////////////////////////////////////////////////////////////////////////////////////////
// VehicleWheel
////////////////////////////////////////////////////////////////////////////////////////////////////

VehicleWheel* VehicleWheel::CreateInstance( const Mix::Dynamics::VEHICLE_WHEEL_DESC& desc, Int32 index )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_DYNAMICS, VehicleWheel, desc, index );
}

VehicleWheel::VehicleWheel( const Mix::Dynamics::VEHICLE_WHEEL_DESC& desc, Int32 index ) :
m_pBulletVehicle( NULL ),
m_Index( index )
{
	btRaycastVehicle::btVehicleTuning tune;

	m_bFront = desc.bFront;
	m_Direction = desc.direction;
	m_Axis = desc.axis;

	m_ConnectionPoint = desc.connectionPoint;
	m_RollInfluence = 0.1f;

	m_Tire.radius = desc.tireRadius;
	m_Tire.friction = tune.m_frictionSlip;

	m_Suspension.restLength = desc.suspensionRestLength;
	m_Suspension.maxTravelCm = tune.m_maxSuspensionTravelCm;
	m_Suspension.maxForce = tune.m_maxSuspensionForce;
	m_Suspension.springStiffness = tune.m_suspensionStiffness;
	m_Suspension.damperRelaxation = tune.m_suspensionDamping;
	m_Suspension.damperCompression = tune.m_suspensionCompression;

	m_SteeringValue = 0.0f;
	m_EngineForce = 0.0f;
	m_BreakingForce = 0.0f;
}

VehicleWheel::~VehicleWheel( void )
{
}

void VehicleWheel::Bullet_SetRaycastVehicle( btRaycastVehicle* pObject )
{
	m_pBulletVehicle = pObject;

	if( m_pBulletVehicle != NULL )
	{
		//コメントアウトはビハイクルを作成する際に設定されているものになります

		btWheelInfo* pInfo = &m_pBulletVehicle->getWheelInfo( m_Index );

		//m_bFront
		//m_Direction
		//m_Axis
		//m_ConnectionPoint
		//m_Tire.radius
		//m_Suspension.restLength;

		pInfo->m_rollInfluence = m_RollInfluence;

		pInfo->m_frictionSlip = m_Tire.friction;

		pInfo->m_suspensionStiffness = m_Suspension.springStiffness;
		pInfo->m_wheelsDampingRelaxation = m_Suspension.damperRelaxation;
		pInfo->m_wheelsDampingCompression = m_Suspension.damperCompression;
		pInfo->m_maxSuspensionTravelCm = m_Suspension.maxTravelCm;
		pInfo->m_maxSuspensionForce = m_Suspension.maxForce;

		m_pBulletVehicle->setSteeringValue( m_SteeringValue, m_Index );
		m_pBulletVehicle->applyEngineForce( m_EngineForce, m_Index );
		m_pBulletVehicle->setBrake( m_BreakingForce, m_Index );
	}
}

Boolean VehicleWheel::IsFront( void ) const
{
	return m_bFront;
}

const Mix::Vector3& VehicleWheel::GetDirection( void ) const
{
	return m_Direction;
}

const Mix::Vector3& VehicleWheel::GetAxis( void ) const
{
	return m_Axis;
}

const Mix::Vector3& VehicleWheel::GetConnectionPoint( void ) const
{
	return m_ConnectionPoint;
}

void VehicleWheel::SetConnectionPoint( const Mix::Vector3& cp )
{
	m_ConnectionPoint = cp;

	if( m_pBulletVehicle != NULL )
	{
		m_pBulletVehicle->getWheelInfo( m_Index ).m_chassisConnectionPointCS = ToBulletVector3( m_ConnectionPoint );
	}
}

Float32 VehicleWheel::GetRollInfluence( void ) const
{
	return m_RollInfluence;
}

void VehicleWheel::SetRollInfluence( Float32 rollInfluence )
{
	m_RollInfluence = max( 0.0f, rollInfluence );

	if( m_pBulletVehicle != NULL )
	{
		m_pBulletVehicle->getWheelInfo( m_Index ).m_rollInfluence = m_RollInfluence;
	}
}

const Mix::Dynamics::IVehicleWheel::TIRE& VehicleWheel::GetTire( void ) const
{
	return m_Tire;
}

void VehicleWheel::SetTire( const Mix::Dynamics::IVehicleWheel::TIRE& tire )
{
	m_Tire.radius = max( 0.0f, tire.radius );
	m_Tire.friction = max( 0.0f, tire.friction );

	if( m_pBulletVehicle != NULL )
	{
		btWheelInfo* pInfo = &m_pBulletVehicle->getWheelInfo( m_Index );

		pInfo->m_wheelsRadius = m_Tire.radius;
		pInfo->m_frictionSlip = m_Tire.friction;
	}
}

const Mix::Dynamics::IVehicleWheel::SUSPENSION& VehicleWheel::GetSuspension( void ) const
{
	return m_Suspension;
}

void VehicleWheel::SetSuspension( const Mix::Dynamics::IVehicleWheel::SUSPENSION& suspension )
{
	m_Suspension.restLength = max( 0.0f, suspension.restLength );
	m_Suspension.springStiffness = max( 0.0f, suspension.springStiffness );
	m_Suspension.damperRelaxation = max( 0.0f, suspension.damperRelaxation );
	m_Suspension.damperCompression = max( 0.0f, suspension.damperCompression );

	if( m_pBulletVehicle != NULL )
	{
		btWheelInfo* pInfo = &m_pBulletVehicle->getWheelInfo( m_Index );

		pInfo->m_suspensionRestLength1 = m_Suspension.restLength;
		pInfo->m_suspensionStiffness = m_Suspension.springStiffness;
		pInfo->m_wheelsDampingRelaxation = m_Suspension.damperRelaxation;
		pInfo->m_wheelsDampingCompression = m_Suspension.damperCompression;
	}
}

Float32 VehicleWheel::GetSteeringValue( void ) const
{
	return m_SteeringValue;
}

void VehicleWheel::SetSteeringValue( Float32 value )
{
	m_SteeringValue = value;

	if( m_pBulletVehicle != NULL )
	{
		m_pBulletVehicle->setSteeringValue( m_SteeringValue, m_Index );
	}
}

Float32 VehicleWheel::GetEngineForce( void ) const
{
	return m_EngineForce;
}

void VehicleWheel::SetEngineForce( Float32 force )
{
	m_EngineForce = force;

	if( m_pBulletVehicle != NULL )
	{
		m_pBulletVehicle->applyEngineForce( m_EngineForce, m_Index );
	}
}

Float32 VehicleWheel::GetBreakingForce( void ) const
{
	return m_BreakingForce;
}

void VehicleWheel::SetBreakingForce( Float32 force )
{
	m_BreakingForce = max( 0.0f, force );

	if( m_pBulletVehicle != NULL )
	{
		m_pBulletVehicle->setBrake( m_BreakingForce, m_Index );
	}
}

Boolean VehicleWheel::OnGround( void ) const
{
	if( m_pBulletVehicle == NULL )
	{
		return False;
	}

	return ( m_pBulletVehicle->getWheelInfo( m_Index ).m_raycastInfo.m_groundObject != NULL );
}

Mix::Dynamics::IVehicleWheel::CONTACT VehicleWheel::GetContact( void ) const
{
	IVehicleWheel::CONTACT ret;

	if( ( m_pBulletVehicle != NULL ) &&
		( m_pBulletVehicle->getWheelInfo( m_Index ).m_raycastInfo.m_groundObject != NULL ) )
	{
		const btWheelInfo::RaycastInfo& info = m_pBulletVehicle->getWheelInfo( m_Index ).m_raycastInfo;

		ret.worldPosition = ToMixVector3( info.m_contactPointWS );
		ret.worldNormal = ToMixVector3( info.m_contactNormalWS );
	}
	else
	{
		ret.worldPosition = Mix::Vector3::Zero();
		ret.worldNormal = Mix::Vector3::Zero();
	}

	return ret;
}

const Mix::Matrix4x4& VehicleWheel::GetWorldMatrix( void )
{
	if( m_pBulletVehicle != NULL )
	{
		m_pBulletVehicle->updateWheelTransform( m_Index, true );
		m_WorldMat = ToMixMatrix4x4( m_pBulletVehicle->getWheelInfo( m_Index ).m_worldTransform );
	}

	return m_WorldMat;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Vehicle
////////////////////////////////////////////////////////////////////////////////////////////////////

Vehicle* Vehicle::CreateInstance( Float32 mass, Mix::Dynamics::IShape* pShape )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_DYNAMICS, Vehicle, mass, pShape );
}

Vehicle::Vehicle( Float32 mass, Mix::Dynamics::IShape* pShape ) :
Mix::Dynamics::Object( Mix::Dynamics::OF_ALL, Mix::Dynamics::OF_ALL, Mix::Dynamics::DD_WIREFRAME | Mix::Dynamics::DD_AXIS ),
m_pShape( NULL ),
m_pContext( NULL ),
m_Mass( mass ),
m_pBulletMotionState( NULL ),
m_pBulletRigidBody( NULL ),
m_pBulletVehicleRaycaster( NULL ),
m_pBulletVehicle( NULL ),
m_UserIndex( 0 ),
m_pUserPtr( NULL )
{
	MIX_ASSERT( pShape != NULL );

	MIX_ADD_REF( pShape );
	m_pShape = pShape;
}

Vehicle::~Vehicle( void )
{
	Vehicle::WheelList::iterator it_wheel_begin = m_WheelList.begin();
	Vehicle::WheelList::iterator it_wheel_end = m_WheelList.end();
	Vehicle::WheelList::iterator it_wheel;

	for( it_wheel = it_wheel_begin; it_wheel != it_wheel_end; ++it_wheel )
	{
		( *it_wheel )->Bullet_SetRaycastVehicle( NULL );
	}

	MIX_LIB_DELETE_T( ObjectContext, m_pContext );

	MIX_LIB_DELETE( m_pBulletVehicle );
	MIX_LIB_DELETE( m_pBulletVehicleRaycaster );

	MIX_LIB_DELETE( m_pBulletRigidBody );
	MIX_LIB_DELETE( m_pBulletMotionState );

	MIX_RELEASE( m_pShape );

	for( it_wheel = it_wheel_begin; it_wheel != it_wheel_end; ++it_wheel )
	{
		MIX_RELEASE( ( *it_wheel ) );
	}
}

Boolean Vehicle::Initialize( const Mix::Dynamics::VEHICLE_WHEEL_DESC* wheels, UInt32 wheelNum, const wchar_t* pDebugName )
{
	MIX_ASSERT( pDebugName != NULL );
	MIX_ASSERT( wheels != NULL );
	MIX_ASSERT( wheelNum > 0 );

	MIX_ASSERT( m_pShape != NULL );

	MIX_ASSERT( m_pContext == NULL );
	MIX_ASSERT( m_pBulletMotionState == NULL );
	MIX_ASSERT( m_pBulletRigidBody == NULL );
	MIX_ASSERT( m_pBulletVehicleRaycaster == NULL );
	MIX_ASSERT( m_pBulletVehicle == NULL );

	btCollisionShape* pBulletCollisionShape = dynamic_cast<Mix::Dynamics::Shape*>( m_pShape )->Bullet_GetCollisionShapePtr();
	btVector3 localInertia( 0.0f, 0.0f, 0.0f );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// コンテキストの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pContext = MIX_LIB_NEW_T( Mix::Memory::SECTION_DYNAMICS, Mix::Dynamics::ObjectContext, this, pDebugName );
	if( m_pContext == NULL )
	{
		MIX_LOG_ERROR( L"%s : %s : DebugName[%s]", Vehicle::FAILED_CREATE, Mix::STR_OUTOFMEMORY, pDebugName );
		return False;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Bullet : モーションステートの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pBulletMotionState = MIX_LIB_NEW btDefaultMotionState();
	if( m_pBulletMotionState == NULL )
	{
		MIX_LOG_ERROR( L"%s : %s : DebugName[%s]", Vehicle::FAILED_CREATE, Mix::STR_OUTOFMEMORY, pDebugName );
		return False;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Bullet : リジッドボディを作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pBulletCollisionShape->calculateLocalInertia( m_Mass, localInertia );

	m_pBulletRigidBody = MIX_LIB_NEW btRigidBody( btRigidBody::btRigidBodyConstructionInfo( m_Mass, m_pBulletMotionState, pBulletCollisionShape, localInertia ) );
	if( m_pBulletRigidBody != NULL )
	{
		m_pBulletRigidBody->setActivationState( DISABLE_DEACTIVATION );
		m_pBulletRigidBody->setUserPointer( m_pContext );
	}
	else
	{
		MIX_LOG_ERROR( L"%s : %s : DebugName[%s]", Vehicle::FAILED_CREATE, Mix::STR_OUTOFMEMORY, pDebugName );
		return False;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ホイールリストを作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_WheelList.reserve( wheelNum );

	for( UInt32 i = 0; i < wheelNum; i++ )
	{
		Mix::Dynamics::VehicleWheel* pWheel = VehicleWheel::CreateInstance( wheels[i], i );

		if( pWheel != NULL )
		{
			m_WheelList.push_back( pWheel );
		}
		else
		{
			MIX_LOG_ERROR( L"%s : %s : DebugName[%s]", Vehicle::FAILED_CREATE, Mix::STR_OUTOFMEMORY, pDebugName );
			return False;
		}
	}

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

	// Bullet : ビハイクルはワールドに追加された際に作成されます

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

	return True;
}

void Vehicle::Reset( const btTransform& worldTr )
{
	MIX_ASSERT( m_pBulletRigidBody != NULL );
	MIX_ASSERT( m_pBulletVehicle != NULL );

	Mix::Dynamics::World* pWorld = GetWorldPtr();

	m_pBulletRigidBody->setCenterOfMassTransform( worldTr );
	m_pBulletRigidBody->setLinearVelocity( btVector3( 0.0f, 0.0f, 0.0f ) );
	m_pBulletRigidBody->setAngularVelocity( btVector3( 0.0f, 0.0f, 0.0f ) );

	if( pWorld != NULL )
	{
		btBroadphaseProxy* pBulletBroadphaseHandle = m_pBulletRigidBody->getBroadphaseHandle();
		if( pBulletBroadphaseHandle != NULL )
		{
			btDynamicsWorld* pBulletDynamicsWorld = pWorld->Bullet_GetDynamicsWorldPtr();

			MIX_ASSERT( pBulletDynamicsWorld->getBroadphase() != NULL );
			pBulletDynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs( pBulletBroadphaseHandle, pBulletDynamicsWorld->getDispatcher() );
		}
	}

	m_pBulletVehicle->resetSuspension();
}

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

void Vehicle::OnAttachToWorld( Mix::Dynamics::World* pWorld )
{
	MIX_ASSERT( m_pBulletVehicleRaycaster == NULL );
	MIX_ASSERT( m_pBulletVehicle == NULL );
	MIX_ASSERT( pWorld->Bullet_GetDynamicsWorldPtr() != NULL );

	m_pBulletVehicleRaycaster = MIX_LIB_NEW btDefaultVehicleRaycaster( pWorld->Bullet_GetDynamicsWorldPtr() );
	if( m_pBulletVehicleRaycaster != NULL )
	{
		m_pBulletVehicle = MIX_LIB_NEW btRaycastVehicle( m_BulletVehicleTuning, m_pBulletRigidBody, m_pBulletVehicleRaycaster );
		if( m_pBulletVehicle != NULL )
		{
			UIntT wheelNum = m_WheelList.size();

			m_pBulletVehicle->setCoordinateSystem( 0, 1, 2 );

			for( UIntT i = 0; i < wheelNum; i++ )
			{
				Mix::Dynamics::VehicleWheel* pWheel = m_WheelList[i];

				m_pBulletVehicle->addWheel(
					ToBulletVector3( pWheel->GetConnectionPoint() ),
					ToBulletVector3( pWheel->GetDirection() ),
					ToBulletVector3( pWheel->GetAxis() ),
					pWheel->GetSuspension().restLength,
					pWheel->GetTire().radius,
					m_BulletVehicleTuning,
					( pWheel->IsFront() == True ) );

				pWheel->Bullet_SetRaycastVehicle( m_pBulletVehicle );
			}
		}
		else
		{
			MIX_LIB_DELETE( m_pBulletVehicleRaycaster );
		}
	}
}

void Vehicle::OnDetachFromWorld( Mix::Dynamics::World* pWorld )
{
	MIX_LIB_DELETE( m_pBulletVehicle );
	MIX_LIB_DELETE( m_pBulletVehicleRaycaster );

	UIntT wheelNum = m_WheelList.size();

	for( UIntT i = 0; i < wheelNum; i++ )
	{
		m_WheelList[i]->Bullet_SetRaycastVehicle( NULL );
	}
}

Mix::Dynamics::ObjectContext* Vehicle::GetContextPtr( void ) const
{
	return m_pContext;
}

btCollisionObject* Vehicle::Bullet_GetCollisionObjectPtr( void ) const
{
	return m_pBulletRigidBody;
}

btRigidBody* Vehicle::Bullet_GetRigidBodyPtr( void ) const
{
	return m_pBulletRigidBody;
}

btActionInterface* Vehicle::Bullet_GetActionInterfacePtr( void ) const
{
	return m_pBulletVehicle;
}

btRaycastVehicle* Vehicle::Bullet_GetRaycastVehiclePtr( void ) const
{
	return m_pBulletVehicle;
}

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

void Vehicle::Reset( void )
{
	Reset( m_pBulletRigidBody->getWorldTransform() );
}

void Vehicle::Reset( const Mix::Quaternion& worldRot, const Mix::Vector3& worldPos )
{
	Reset( btTransform( ToBulletQuaternion( worldRot ), ToBulletVector3( worldPos ) ) );
}

UInt32 Vehicle::GetWheelNum( void ) const
{
	return static_cast<UInt32>( m_pBulletVehicle->getNumWheels() );
}

Boolean Vehicle::GetWheel( UInt32 wheelIndex, Mix::Dynamics::IVehicleWheel** ppWheel )
{
	if( ( m_WheelList.size() <= wheelIndex ) ||
		( ppWheel == NULL ) )
	{
		return False;
	}

	Mix::Dynamics::VehicleWheel* pWheel = m_WheelList[wheelIndex];

	MIX_ADD_REF( pWheel );
	( *ppWheel ) = pWheel;

	return True;
}

Mix::Dynamics::IVehicleWheel* Vehicle::GetWheelPtr( UInt32 wheelIndex ) const
{
	if( m_WheelList.size() <= wheelIndex )
	{
		return NULL;
	}

	return m_WheelList[wheelIndex];
}

Float32 Vehicle::GetCurrentSpeedKmHour( void ) const
{
	MIX_ASSERT( m_pBulletVehicle != NULL );

	return m_pBulletVehicle->getCurrentSpeedKmHour();
}

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

Mix::Dynamics::IObject::TYPE Vehicle::GetType( void ) const
{
	return Mix::Dynamics::IObject::VEHICLE;
}

Boolean Vehicle::GetShape( Mix::Dynamics::IShape** ppShape )
{
	MIX_ASSERT( m_pShape != NULL );

	if( ppShape == NULL )
	{
		return False;
	}

	MIX_ADD_REF( m_pShape );
	( *ppShape ) = m_pShape;

	return True;
}

Float32 Vehicle::GetShapeMargin( void ) const
{
	MIX_ASSERT( m_pShape != NULL );

	return m_pShape->GetMargin();
}

void Vehicle::SetShapeMargin( Float32 margin )
{
	MIX_ASSERT( m_pShape != NULL );

	m_pShape->SetMargin( margin );
}

UInt16 Vehicle::GetFilterGroup( void ) const
{
	return Object::Bullet_GetFilterGroup();
}

void Vehicle::SetFilterGroup( UInt16 filterGroup )
{
	Object::Bullet_SetFilterGroup( filterGroup );
}

UInt16 Vehicle::GetFilterMask( void ) const
{
	return Object::Bullet_GetFilterMask();
}

void Vehicle::SetFilterMask( UInt16 filterMask )
{
	Object::Bullet_SetFilterMask( filterMask );
}

const Mix::Dynamics::MATERIAL& Vehicle::GetMaterial( void ) const
{
	MIX_ASSERT( m_pContext != NULL );

	return m_pContext->GetMaterial();
}

void Vehicle::SetMaterial( const Mix::Dynamics::MATERIAL& material )
{
	MIX_ASSERT( m_pContext != NULL );

	m_pContext->SetMaterial( material );
}

Mix::Quaternion Vehicle::GetWorldRotation( void ) const
{
	MIX_ASSERT( m_pBulletRigidBody != NULL );

	return ToMixQuaternion( m_pBulletRigidBody->getWorldTransform().getRotation() );
}

Mix::Vector3 Vehicle::GetWorldPosition( void ) const
{
	MIX_ASSERT( m_pBulletRigidBody != NULL );

	return ToMixVector3( m_pBulletRigidBody->getWorldTransform().getOrigin() );
}

Mix::Matrix4x4 Vehicle::GetWorldMatrix( void ) const
{
	MIX_ASSERT( m_pBulletRigidBody != NULL );

	return ToMixMatrix4x4( m_pBulletRigidBody->getWorldTransform() );
}

void Vehicle::SetWorldRotation( const Mix::Quaternion& rot )
{
	MIX_ASSERT( m_pBulletRigidBody != NULL );

	m_pBulletRigidBody->getWorldTransform().setRotation( ToBulletQuaternion( rot ) );
}

void Vehicle::SetWorldPosition( const Mix::Vector3& pos )
{
	MIX_ASSERT( m_pBulletRigidBody != NULL );

	m_pBulletRigidBody->getWorldTransform().setOrigin( ToBulletVector3( pos ) );
}

void Vehicle::SetWorldTransform( const Mix::Quaternion& rot, const Mix::Vector3& pos )
{
	MIX_ASSERT( m_pBulletRigidBody != NULL );

	btTransform tr;

	tr.setRotation( ToBulletQuaternion( rot ) );
	tr.setOrigin( ToBulletVector3( pos ) );

	m_pBulletRigidBody->setWorldTransform( tr );
}

Boolean Vehicle::IsInWorld( void ) const
{
	MIX_ASSERT( m_pBulletRigidBody != NULL );

	return ( m_pBulletRigidBody->isInWorld() == true );
}

Mix::Geometry::AABB Vehicle::GetBounds( void ) const
{
	MIX_ASSERT( m_pBulletRigidBody != NULL );

	btVector3 aabbMin;
	btVector3 aabbMax;

	m_pBulletRigidBody->getAabb( aabbMin, aabbMax );

	return Mix::Geometry::AABB( ToMixVector3( aabbMin ), ToMixVector3( aabbMax ) );
}

Boolean Vehicle::AddListener( Mix::Dynamics::IObjectListener* pListener )
{
	MIX_ASSERT( m_pContext != NULL );

	return m_pContext->AddListener( pListener );
}

void Vehicle::RemoveListener( Mix::Dynamics::IObjectListener* pListener )
{
	MIX_ASSERT( m_pContext != NULL );

	m_pContext->RemoveListener( pListener );
}

Int32 Vehicle::GetUserIndex( void ) const
{
	return m_UserIndex;
}

void Vehicle::SetUserIndex( Int32 index )
{
	m_UserIndex = index;
}

void* Vehicle::GetUserPtr( void ) const
{
	return m_pUserPtr;
}

void Vehicle::SetUserPtr( void* pData )
{
	m_pUserPtr = pData;
}

UInt32 Vehicle::Debug_GetDrawFlags( void ) const
{
	return m_DebugDrawFlags;
}

void Vehicle::Debug_SetDrawFlags( UInt32 flags )
{
	m_DebugDrawFlags = flags;
}

Float32 Vehicle::Debug_GetDrawAxisScaling( void ) const
{
	return m_DebugDrawAxisScaling;
}

void Vehicle::Debug_SetDrawAxisScaling( Float32 scaling )
{
	m_DebugDrawAxisScaling = max( 0.0f, scaling );
}

void Vehicle::Debug_Draw( Mix::Graphics::Utility::IPerspectiveRenderer* pPerspectiveRenderer, Float32 opacity )
{
	Mix::Matrix4x4 oldMat = pPerspectiveRenderer->GetMatrix();
	Mix::Vector4 oldColor = pPerspectiveRenderer->GetColor();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 軸
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( MIX_TESTBIT( m_DebugDrawFlags, Mix::Dynamics::DD_AXIS ) == Mix::Dynamics::DD_AXIS )
	{
		Vehicle::WheelList::iterator it_wheel_begin = m_WheelList.begin();
		Vehicle::WheelList::iterator it_wheel_end = m_WheelList.end();
		Vehicle::WheelList::iterator it_wheel;

		pPerspectiveRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, opacity ) );

		//リジッドボディ
		pPerspectiveRenderer->SetMatrix( GetWorldMatrix() );
		pPerspectiveRenderer->AddAxis( m_DebugDrawAxisScaling );

		//ホイール
		for( it_wheel = it_wheel_begin; it_wheel != it_wheel_end; ++it_wheel )
		{
			Mix::Dynamics::VehicleWheel* pWheel = ( *it_wheel );

			pPerspectiveRenderer->SetMatrix( pWheel->GetWorldMatrix() );
			pPerspectiveRenderer->AddAxis( m_DebugDrawAxisScaling );
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ワイヤーフレーム
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( MIX_TESTBIT( m_DebugDrawFlags, Mix::Dynamics::DD_WIREFRAME ) == Mix::Dynamics::DD_WIREFRAME )
	{
		Vehicle::WheelList::iterator it_wheel_begin = m_WheelList.begin();
		Vehicle::WheelList::iterator it_wheel_end = m_WheelList.end();
		Vehicle::WheelList::iterator it_wheel;

		pPerspectiveRenderer->SetColor( Mix::Dynamics::Debug::GetRigidBodyColor( m_pBulletRigidBody, opacity ) );

		//リジッドボディ
		pPerspectiveRenderer->SetMatrix( GetWorldMatrix() );
		m_pShape->DebugDraw( pPerspectiveRenderer );

		//ホイール
		for( it_wheel = it_wheel_begin; it_wheel != it_wheel_end; ++it_wheel )
		{
			Mix::Dynamics::VehicleWheel* pWheel = ( *it_wheel );

			//ディスク
			pPerspectiveRenderer->SetMatrix( pWheel->GetWorldMatrix() );
			pPerspectiveRenderer->AddDisc( pWheel->GetAxis(), pWheel->GetTire().radius );
		}
	}

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

	pPerspectiveRenderer->SetColor( oldColor );
	pPerspectiveRenderer->SetMatrix( oldMat );
}

}}
