void CPhysicsObject::OutputDebugInfo() const {
	Msg("-----------------\n");

	if (m_pName)
		Msg("Object: %s\n", m_pName);

	Msg("Mass: %f (inv %f)\n", GetMass(), GetInvMass());

	Vector pos;
	QAngle ang;
	GetPosition(&pos, &ang);
	Msg("Position: %f %f %f\nAngle: %f %f %f\n", pos.x, pos.y, pos.z, ang.x, ang.y, ang.z);

	Vector inertia = GetInertia();
	Vector invinertia = GetInvInertia();
	Msg("Inertia: %f %f %f (inv %f %f %f)\n", inertia.x, inertia.y, inertia.z, invinertia.x, invinertia.y, invinertia.z);

	Vector vel;
	AngularImpulse angvel;
	GetVelocity(&vel, &angvel);
	Msg("Velocity: %f, %f, %f\nAng Velocity: %f, %f, %f\n", vel.x, vel.y, vel.z, angvel.x, angvel.y, angvel.z);

	float dampspeed, damprot;
	GetDamping(&dampspeed, &damprot);
	Msg("Damping %f linear, %f angular\n", dampspeed, damprot);

	Vector dragBasis;
	Vector angDragBasis;
	ConvertPosToHL(m_dragBasis, dragBasis);
	ConvertDirectionToHL(m_angDragBasis, angDragBasis);
	Msg("Linear Drag: %f, %f, %f (factor %f)\n", dragBasis.x, dragBasis.y, dragBasis.z, m_dragCoefficient);
	Msg("Angular Drag: %f, %f, %f (factor %f)\n", angDragBasis.x, angDragBasis.y, angDragBasis.z, m_angDragCoefficient);

	// TODO: Attached to x controllers

	Msg("State: %s, Collision %s, Motion %s, Drag %s, Flags %04X (game %04x, index %d)\n", 
		IsAsleep() ? "Asleep" : "Awake",
		IsCollisionEnabled() ? "Enabled" : "Disabled",
		IsStatic() ? "Static" : IsMotionEnabled() ? "Enabled" : "Disabled",
		IsDragEnabled() ? "Enabled" : "Disabled",
		m_pObject->getFlags(),
		GetGameFlags(),
		GetGameIndex()
	);

	
	const char *pMaterialStr = g_SurfaceDatabase.GetPropName(m_materialIndex);
	surfacedata_t *surfaceData = g_SurfaceDatabase.GetSurfaceData(m_materialIndex);
	if (surfaceData) {
		Msg("Material: %s : density(%f), thickness(%f), friction(%f), elasticity(%f)\n", 
			pMaterialStr, surfaceData->physics.density, surfaceData->physics.thickness, surfaceData->physics.friction, surfaceData->physics.elasticity);
	}

	Msg("-- COLLISION SHAPE INFO --\n");
	g_PhysicsCollision.OutputDebugInfo((CPhysCollide *)m_pObject->getCollisionShape()->getUserPointer());
}
void CPhysicsObject::ApplyTorqueCenter(const AngularImpulse &torque) {
	if (!IsMoveable() || !IsMotionEnabled()) {
		return;
	}
	Wake();

	btVector3 bullTorque;
	ConvertAngularImpulseToBull(torque, bullTorque);
	m_pObject->applyTorqueImpulse(bullTorque);
}
void CPhysicsObject::EnableMotion(bool enable) {
	if (IsMotionEnabled() == enable || IsStatic()) return;

	if (enable) {
		m_pObject->setFlags(m_pObject->getFlags() & ~(BT_DISABLE_MOTION));
	} else {
		m_pObject->setLinearVelocity(btVector3(0, 0, 0));
		m_pObject->setAngularVelocity(btVector3(0, 0, 0));

		m_pObject->setFlags(m_pObject->getFlags() | BT_DISABLE_MOTION);
	}
}
void CPhysicsObject::ApplyForceCenter(const Vector &forceVector) {
	if (!IsMoveable() || !IsMotionEnabled()) {
		return;
	}
	Wake();

	// forceVector is in kg*in/s*time
	// bullet takes forces in newtons, aka kg*m/s*time

	btVector3 force;
	ConvertForceImpulseToBull(forceVector, force);
	m_pObject->applyCentralImpulse(force);
}
void CPhysicsObject::EnableMotion( bool enable )
{
	bool isMoveable = IsMotionEnabled();

	// no change
	if ( isMoveable == enable )
		return;

	BEGIN_IVP_ALLOCATION();
	m_pObject->set_pinned( enable ? IVP_FALSE : IVP_TRUE );
	END_IVP_ALLOCATION();

	RecheckCollisionFilter();
}
void CPhysicsObject::ApplyForceOffset(const Vector &forceVector, const Vector &worldPosition) {
	if (!IsMoveable() || !IsMotionEnabled()) {
		return;
	}
	Wake();

	Vector local;
	WorldToLocal(&local, worldPosition);

	btVector3 force, offset;
	ConvertForceImpulseToBull(forceVector, force);
	ConvertPosToBull(local, offset);
	m_pObject->applyImpulse(force, offset);
	Wake();
}
void CPhysicsObject::WriteToTemplate( vphysics_save_cphysicsobject_t &objectTemplate )
{
	if ( m_collideType == COLLIDE_BALL )
	{
		objectTemplate.pCollide = NULL;
		objectTemplate.sphereRadius = GetSphereRadius();
	}
	else
	{
		objectTemplate.pCollide = GetCollide();
		objectTemplate.sphereRadius = 0;
	}
	objectTemplate.isStatic = IsStatic();
	objectTemplate.collisionEnabled = IsCollisionEnabled();
	objectTemplate.gravityEnabled = IsGravityEnabled();
	objectTemplate.dragEnabled = IsDragEnabled();
	objectTemplate.motionEnabled = IsMotionEnabled();
	objectTemplate.isAsleep = IsAsleep();
	objectTemplate.isTrigger = IsTrigger();
	objectTemplate.materialIndex = m_materialIndex;
	objectTemplate.mass = GetMass();

	objectTemplate.rotInertia = GetInertia();
	GetDamping( &objectTemplate.speedDamping, &objectTemplate.rotSpeedDamping );
	objectTemplate.massCenterOverride = m_massCenterOverride;
    
	objectTemplate.callbacks = m_callbacks;
	objectTemplate.gameFlags = m_gameFlags;
	objectTemplate.volume = GetVolume();
	objectTemplate.dragCoefficient = m_dragCoefficient;
	objectTemplate.angDragCoefficient = m_angDragCoefficient;
	objectTemplate.pShadow = m_pShadow;
	objectTemplate.hasShadowController = (m_pShadow != NULL) ? true : false;
	//bool			m_shadowTempGravityDisable;
	objectTemplate.collideType = m_collideType;
	objectTemplate.contentsMask = m_contentsMask;
	GetPosition( &objectTemplate.origin, &objectTemplate.angles );
	GetVelocity( &objectTemplate.velocity, &objectTemplate.angVelocity );
}
void CPhysicsObject::AddVelocity(const Vector *velocity, const AngularImpulse *angularVelocity) {
	if (!velocity && !angularVelocity) return;

	if (!IsMoveable() || !IsMotionEnabled()) {
		return;
	}
	Wake();

	btVector3 bullvelocity, bullangular;
	if (velocity) {
		ConvertPosToBull(*velocity, bullvelocity);
		m_pObject->setLinearVelocity(m_pObject->getLinearVelocity() + bullvelocity);
	}

	// Angular velocity is supplied in local space.
	if (angularVelocity) {
		ConvertAngularImpulseToBull(*angularVelocity, bullangular);
		bullangular = m_pObject->getWorldTransform().getBasis() * bullangular;

		m_pObject->setAngularVelocity(m_pObject->getAngularVelocity() + bullangular);
	}
}
bool CPhysicsObject::IsMoveable()
{
	if ( IsStatic() || !IsMotionEnabled() )
		return false;
	return true;
}