Code/HumanoidRetargeter/Core/Formats/Mmd/Bullet/BulletDynamics/RigidBody.cs

RigidBody class from a Bullet physics port. Implements a rigid body collision object, stores mass/inertia/velocities/forces, integrates velocities, applies impulses/forces/torques, manages sleeping/deactivation, constraints, and inertia tensor updates used by the dynamics solver.

Native Interop
/*
 * C# / XNA  port of Bullet (c) 2011 Mark Neale <[email protected]>
 *
 * Bullet Continuous Collision Detection and Physics Library
 * Copyright (c) 2003-2008 Erwin Coumans  http://www.bulletphysics.com/
 *
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from
 * the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */
// Adapted from BulletXNA 73b2e1b9: namespace isolation, no XNA rendering, one type per file.
#nullable disable
#pragma warning disable CS1591, CS0168, CS0219, CS0414, CS0660, CS0661, CS0659, CS0693, CS8981, CS0108, CS0114
using System;
using System.Collections.Generic;
using System.Diagnostics;
using HumanoidRetargeter.Core.Formats.Mmd.Bullet.BulletCollision;
using HumanoidRetargeter.Core.Formats.Mmd.Bullet.LinearMath;

namespace HumanoidRetargeter.Core.Formats.Mmd.Bullet.BulletDynamics;

internal class RigidBody : CollisionObject
{
	private const float MAX_ANGVEL = MathUtil.SIMD_HALF_PI;
	public static int uniqueId = 0;
	private IndexedBasisMatrix m_invInertiaTensorWorld = IndexedBasisMatrix.Identity;
	private IndexedVector3 m_linearVelocity;
	private IndexedVector3 m_angularVelocity;
	private float m_inverseMass;
	private IndexedVector3 m_linearFactor;
	private IndexedVector3 m_gravity;
	private IndexedVector3 m_gravity_acceleration;
	private IndexedVector3 m_invInertiaLocal;
	private IndexedVector3 m_totalForce;
	private IndexedVector3 m_totalTorque;
	private float m_linearDamping;
	private float m_angularDamping;
	private bool m_additionalDamping;
	private float m_additionalDampingFactor;
	private float m_additionalLinearDampingThresholdSqr;
	private float m_additionalAngularDampingThresholdSqr;
	private float m_additionalAngularDampingFactor;
	private float m_linearSleepingThreshold;
	private float m_angularSleepingThreshold;
	//m_optionalMotionState allows to automatic synchronize the world transform for active objects
	private IMotionState m_optionalMotionState;
	//keep track of typed constraints referencing this rigid body
	private IList<TypedConstraint> m_constraintRefs;
	private RigidBodyFlags m_rigidbodyFlags;
	public int m_debugBodyId;
	public IndexedVector3 m_deltaLinearVelocity;
	public IndexedVector3 m_deltaAngularVelocity;
	protected IndexedVector3 m_angularFactor;
	public IndexedVector3 m_invMass;
	protected IndexedVector3 m_pushVelocity;
	protected IndexedVector3 m_turnVelocity;
	//static RigidBody()
	//{
	//    String filename = @"C:\users\man\xna-rb-output.txt";
	//    s_filestream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.None);
	//    s_streamWriter = new StreamWriter(s_filestream);
	//}
	public RigidBody()
	{
	}

	public RigidBody(RigidBodyConstructionInfo constructionInfo)
	{
		SetupRigidBody(constructionInfo);
	}

	public RigidBody(float mass, IMotionState motionState, CollisionShape collisionShape, IndexedVector3 localInertia)
	{
		RigidBodyConstructionInfo cinfo = new RigidBodyConstructionInfo(mass, motionState, collisionShape, localInertia);
		SetupRigidBody(cinfo);
	}

	public override void Cleanup()
	{
		base.Cleanup();
		{
		}
	}

	protected void SetupRigidBody(RigidBodyConstructionInfo constructionInfo)
	{
		m_internalType = CollisionObjectTypes.CO_RIGID_BODY;
		m_linearVelocity = IndexedVector3.Zero;
		m_angularVelocity = IndexedVector3.Zero;
		m_angularFactor = IndexedVector3.One;
		m_linearFactor = IndexedVector3.One;
		m_gravity = IndexedVector3.Zero;
		m_gravity_acceleration = IndexedVector3.Zero;
		m_totalForce = IndexedVector3.Zero;
		m_totalTorque = IndexedVector3.Zero;
		SetDamping(constructionInfo.m_linearDamping, constructionInfo.m_angularDamping);
		m_linearSleepingThreshold = constructionInfo.m_linearSleepingThreshold;
		m_angularSleepingThreshold = constructionInfo.m_angularSleepingThreshold;
		m_optionalMotionState = constructionInfo.m_motionState;
		m_contactSolverType = 0;
		m_frictionSolverType = 0;
		m_additionalDamping = constructionInfo.m_additionalDamping;
		m_additionalDampingFactor = constructionInfo.m_additionalDampingFactor;
		m_additionalLinearDampingThresholdSqr = constructionInfo.m_additionalLinearDampingThresholdSqr;
		m_additionalAngularDampingThresholdSqr = constructionInfo.m_additionalAngularDampingThresholdSqr;
		m_additionalAngularDampingFactor = constructionInfo.m_additionalAngularDampingFactor;
		if (m_optionalMotionState != null)
		{
			m_optionalMotionState.GetWorldTransform(out m_worldTransform);
		}
		else
		{
			SetWorldTransform(ref constructionInfo.m_startWorldTransform);
		}

		m_interpolationWorldTransform = m_worldTransform;
		m_interpolationLinearVelocity = IndexedVector3.Zero;
		m_interpolationAngularVelocity = IndexedVector3.Zero;
		//moved to btCollisionObject
		m_friction = constructionInfo.m_friction;
		m_restitution = constructionInfo.m_restitution;
		SetCollisionShape(constructionInfo.m_collisionShape);
		m_debugBodyId = uniqueId++;
		SetMassProps(constructionInfo.m_mass, constructionInfo.m_localInertia);
		UpdateInertiaTensor();
		m_rigidbodyFlags = RigidBodyFlags.BT_NONE;
		m_constraintRefs = new List<TypedConstraint>();
		m_deltaLinearVelocity = IndexedVector3.Zero;
		m_deltaAngularVelocity = IndexedVector3.Zero;
		m_invMass = m_inverseMass * m_linearFactor;
		m_pushVelocity = IndexedVector3.Zero;
		m_turnVelocity = IndexedVector3.Zero;
	}

	public void ProceedToTransform(ref IndexedMatrix newTrans)
	{
		SetCenterOfMassTransform(ref newTrans);
	}

	public static RigidBody Upcast(CollisionObject colObj)
	{
		if ((colObj.GetInternalType() & CollisionObjectTypes.CO_RIGID_BODY) != 0)
		{
			return colObj as RigidBody;
		}

		return null;
	}

	public void PredictIntegratedTransform(float timeStep, out IndexedMatrix predictedTransform)
	{
		TransformUtil.IntegrateTransform(ref m_worldTransform, ref m_linearVelocity, ref m_angularVelocity, timeStep, out predictedTransform);
		MathUtil.SanityCheckVector(m_worldTransform._basis[1]);
	}

	public void SaveKinematicState(float timeStep)
	{
		//todo: clamp to some (user definable) safe minimum timestep, to limit maximum angular/linear velocities
		if (timeStep != 0f)
		{
			//if we use motionstate to synchronize world transforms, get the new kinematic/animated world transform
			if (GetMotionState() != null)
			{
				GetMotionState().GetWorldTransform(out m_worldTransform);
			}

			IndexedVector3 linVel = IndexedVector3.Zero, angVel = IndexedVector3.Zero;
			// debug steps to track NaN's
			IndexedMatrix worldTransform = m_worldTransform;
			TransformUtil.CalculateVelocity(ref m_interpolationWorldTransform, ref worldTransform, timeStep, out m_linearVelocity, out m_angularVelocity);
			SetWorldTransform(ref worldTransform);
			m_interpolationLinearVelocity = m_linearVelocity;
			m_interpolationAngularVelocity = m_angularVelocity;
			SetInterpolationWorldTransform(ref m_worldTransform);
		//printf("angular = %f %f %f\n",m_angularVelocity.getX(),m_angularVelocity.getY(),m_angularVelocity.getZ());
		}
	}

	public void ApplyGravity()
	{
		if (IsStaticOrKinematicObject())
		{
			return;
		}

		ApplyCentralForce(ref m_gravity);
	}

	public void SetGravity(IndexedVector3 acceleration)
	{
		SetGravity(ref acceleration);
	}

	public void SetGravity(ref IndexedVector3 acceleration)
	{
		if (m_inverseMass != 0f)
		{
			m_gravity = acceleration * (1f / m_inverseMass);
		}

		m_gravity_acceleration = acceleration;
	}

	public IndexedVector3 GetGravity()
	{
		return m_gravity_acceleration;
	}

	public void SetDamping(float lin_damping, float ang_damping)
	{
		m_linearDamping = MathUtil.Clamp(lin_damping, 0f, 1f);
		m_angularDamping = MathUtil.Clamp(ang_damping, 0f, 1f);
	}

	public float GetLinearDamping()
	{
		return m_linearDamping;
	}

	public float GetAngularDamping()
	{
		return m_angularDamping;
	}

	public float GetLinearSleepingThreshold()
	{
		return m_linearSleepingThreshold;
	}

	public float GetAngularSleepingThreshold()
	{
		return m_angularSleepingThreshold;
	}

	public void ApplyDamping(float timeStep)
	{
		//On new damping: see discussion/issue report here: http://code.google.com/p/bullet/issues/detail?id=74
		//todo: do some performance comparisons (but other parts of the engine are probably bottleneck anyway
		//#define USE_OLD_DAMPING_METHOD 1
		m_linearVelocity *= (float)Math.Pow((1f - m_linearDamping), timeStep);
		m_angularVelocity *= (float)Math.Pow((1f - m_angularDamping), timeStep);
		MathUtil.SanityCheckVector(ref m_linearVelocity);
		MathUtil.SanityCheckVector(ref m_angularVelocity);
		if (m_additionalDamping)
		{
			//Additional damping can help avoiding lowpass jitter motion, help stability for ragdolls etc.
			//Such damping is undesirable, so once the overall simulation quality of the rigid body dynamics system has improved, this should become obsolete
			if ((m_angularVelocity.LengthSquared() < m_additionalAngularDampingThresholdSqr) && (m_linearVelocity.LengthSquared() < m_additionalLinearDampingThresholdSqr))
			{
				m_angularVelocity *= m_additionalDampingFactor;
				m_linearVelocity *= m_additionalDampingFactor;
			}

			MathUtil.SanityCheckVector(ref m_linearVelocity);
			MathUtil.SanityCheckVector(ref m_angularVelocity);
			float speed = m_linearVelocity.Length();
			if (speed < m_linearDamping)
			{
				float dampVel = 0.005f;
				if (speed > dampVel)
				{
					IndexedVector3 dir = m_linearVelocity;
					dir.Normalize();
					m_linearVelocity -= dir * dampVel;
				}
				else
				{
					m_linearVelocity = IndexedVector3.Zero;
				}
			}

			float angSpeed = m_angularVelocity.Length();
			if (angSpeed < m_angularDamping)
			{
				float angDampVel = 0.005f;
				if (angSpeed > angDampVel)
				{
					IndexedVector3 dir = m_angularVelocity;
					dir.Normalize();
					m_angularVelocity -= dir * angDampVel;
				}
				else
				{
					m_angularVelocity = IndexedVector3.Zero;
				}
			}
		}

		MathUtil.SanityCheckVector(ref m_linearVelocity);
		MathUtil.SanityCheckVector(ref m_angularVelocity);
	}

	public void SetMassProps(float mass, IndexedVector3 inertia)
	{
		SetMassProps(mass, ref inertia);
	}

	public void SetMassProps(float mass, ref IndexedVector3 inertia)
	{
		if (MathUtil.FuzzyZero(mass))
		{
			m_collisionFlags |= CollisionFlags.CF_STATIC_OBJECT;
			m_inverseMass = 0f;
		}
		else
		{
			m_collisionFlags &= (~CollisionFlags.CF_STATIC_OBJECT);
			m_inverseMass = 1.0f / mass;
		}

		m_gravity = mass * m_gravity_acceleration;
		m_invInertiaLocal = new IndexedVector3((inertia.X != 0f) ? 1f / inertia.X : 0f, (inertia.Y != 0f) ? 1f / inertia.Y : 0f, (inertia.Z != 0f) ? 1f / inertia.Z : 0f);
		m_invMass = m_linearFactor * m_inverseMass;
	}

	public IndexedVector3 GetLinearFactor()
	{
		return m_linearFactor;
	}

	public void SetLinearFactor(IndexedVector3 linearFactor)
	{
		m_linearFactor = linearFactor;
		m_invMass = m_linearFactor * m_inverseMass;
	}

	public float GetInvMass()
	{
		return m_inverseMass;
	}

	public IndexedBasisMatrix GetInvInertiaTensorWorld()
	{
		return m_invInertiaTensorWorld;
	}

	public void IntegrateVelocities(float step)
	{
		if (IsStaticOrKinematicObject())
			return;
		m_linearVelocity += m_totalForce * (m_inverseMass * step);
		MathUtil.SanityCheckVector(ref m_linearVelocity);
		m_angularVelocity += m_invInertiaTensorWorld * m_totalTorque * step;
		MathUtil.SanityCheckVector(ref m_angularVelocity);
		float angvel = m_angularVelocity.Length();
		if (angvel * step > MAX_ANGVEL)
		{
			m_angularVelocity *= (MAX_ANGVEL / step) / angvel;
		}

		MathUtil.SanityCheckVector(ref m_angularVelocity);
	}

	public void SetCenterOfMassTransform(ref IndexedMatrix xform)
	{
		if (IsKinematicObject())
		{
			SetInterpolationWorldTransform(ref m_worldTransform);
		}
		else
		{
			SetInterpolationWorldTransform(ref xform);
		}

		m_interpolationLinearVelocity = GetLinearVelocity();
		m_interpolationAngularVelocity = GetAngularVelocity();
		SetWorldTransform(ref xform);
		UpdateInertiaTensor();
	}

	public void ApplyCentralForce(ref IndexedVector3 force)
	{
		m_totalForce += force * m_linearFactor;
	}

	public IndexedVector3 GetTotalForce()
	{
		return m_totalForce;
	}

	public IndexedVector3 GetTotalTorque()
	{
		return m_totalTorque;
	}

	public IndexedVector3 GetInvInertiaDiagLocal()
	{
		return m_invInertiaLocal;
	}

	public void SetInvInertiaDiagLocal(ref IndexedVector3 diagInvInertia)
	{
		m_invInertiaLocal = diagInvInertia;
	}

	public void SetSleepingThresholds(float linear, float angular)
	{
		m_linearSleepingThreshold = linear;
		m_angularSleepingThreshold = angular;
	}

	public void ApplyTorque(IndexedVector3 torque)
	{
		ApplyTorque(ref torque);
	}

	public void ApplyTorque(ref IndexedVector3 torque)
	{
		m_totalTorque += torque * m_angularFactor;
	}

	public void ApplyForce(ref IndexedVector3 force, ref IndexedVector3 rel_pos)
	{
		ApplyCentralForce(ref force);
		IndexedVector3 tempTorque = IndexedVector3.Cross(rel_pos, force);
		tempTorque *= m_angularFactor;
		ApplyTorque(IndexedVector3.Cross(rel_pos, (force * m_linearFactor)));
	}

	public void ApplyCentralImpulse(ref IndexedVector3 impulse)
	{
		m_linearVelocity += impulse * m_linearFactor * m_inverseMass;
		MathUtil.SanityCheckVector(ref m_linearVelocity);
	}

	public void ApplyTorqueImpulse(IndexedVector3 torque)
	{
		ApplyTorqueImpulse(ref torque);
	}

	public void ApplyTorqueImpulse(ref IndexedVector3 torque)
	{
		m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
	}

	public void ApplyImpulse(IndexedVector3 impulse, IndexedVector3 rel_pos)
	{
		ApplyImpulse(ref impulse, ref rel_pos);
	}

	public void ApplyImpulse(ref IndexedVector3 impulse, ref IndexedVector3 rel_pos)
	{
		if (m_inverseMass != 0f)
		{
			ApplyCentralImpulse(ref impulse);
			if (m_angularFactor.LengthSquared() > 0f)
			{
				ApplyTorqueImpulse(IndexedVector3.Cross(rel_pos, (impulse * m_linearFactor)));
			}
		}
	}

	//Optimization for the iterative solver: avoid calculating constant terms involving inertia, normal, relative position
	public void InternalApplyImpulse(IndexedVector3 linearComponent, IndexedVector3 angularComponent, float impulseMagnitude, String caller)
	{
		if (impulseMagnitude > 20f)
		{
			int ibreak = 0;
		}

		InternalApplyImpulse(ref linearComponent, ref angularComponent, impulseMagnitude, caller);
	}

	public void ClearForces()
	{
		m_totalForce = IndexedVector3.Zero;
		m_totalTorque = IndexedVector3.Zero;
	}

	public void UpdateInertiaTensor()
	{
		m_invInertiaTensorWorld = m_worldTransform._basis.Scaled(ref m_invInertiaLocal) * m_worldTransform._basis.Transpose();
	}

	public IndexedVector3 GetCenterOfMassPosition()
	{
		return m_worldTransform._origin;
	}

	public IndexedQuaternion GetOrientation()
	{
		return m_worldTransform._basis.GetRotation();
	}

	public IndexedMatrix GetCenterOfMassTransform()
	{
		return m_worldTransform;
	}

	public IndexedVector3 GetLinearVelocity()
	{
		return m_linearVelocity;
	}

	public IndexedVector3 GetAngularVelocity()
	{
		return m_angularVelocity;
	}

	public void SetLinearVelocity(IndexedVector3 lin_vel)
	{
		SetLinearVelocity(ref lin_vel);
	}

	public void SetLinearVelocity(ref IndexedVector3 lin_vel)
	{
		m_linearVelocity = lin_vel;
		MathUtil.SanityCheckVector(ref m_linearVelocity);
	}

	public void SetAngularVelocity(IndexedVector3 ang_vel)
	{
		SetAngularVelocity(ref ang_vel);
	}

	public void SetAngularVelocity(ref IndexedVector3 ang_vel)
	{
		m_angularVelocity = ang_vel;
	}

	public IndexedVector3 GetVelocityInLocalPoint(ref IndexedVector3 rel_pos)
	{
		//we also calculate lin/ang velocity for kinematic objects
		IndexedVector3 temp = new IndexedVector3(m_angularVelocity.Y * rel_pos.Z - m_angularVelocity.Z * rel_pos.Y, m_angularVelocity.Z * rel_pos.X - m_angularVelocity.X * rel_pos.Z, m_angularVelocity.X * rel_pos.Y - m_angularVelocity.Y * rel_pos.X);
		return new IndexedVector3(m_linearVelocity.X + temp.X, m_linearVelocity.Y + temp.Y, m_linearVelocity.Z + temp.Z);
	//return m_linearVelocity + IndexedVector3.Cross(m_angularVelocity,rel_pos);
	//for kinematic objects, we could also use use:
	//		return 	(m_worldTransform(rel_pos) - m_interpolationWorldTransform(rel_pos)) / m_kinematicTimeStep;
	}

	public void Translate(ref IndexedVector3 v)
	{
		m_worldTransform._origin += v;
	}

	public void GetAabb(out IndexedVector3 aabbMin, out IndexedVector3 aabbMax)
	{
		GetCollisionShape().GetAabb(m_worldTransform, out aabbMin, out aabbMax);
	}

	public float ComputeImpulseDenominator(ref IndexedVector3 pos, ref IndexedVector3 normal)
	{
		IndexedVector3 r0 = pos - GetCenterOfMassPosition();
		IndexedVector3 c0 = r0.Cross(ref normal);
		IndexedVector3 vec = (c0 * GetInvInertiaTensorWorld()).Cross(ref r0);
		return m_inverseMass + IndexedVector3.Dot(normal, vec);
	}

	public float ComputeAngularImpulseDenominator(ref IndexedVector3 axis)
	{
		IndexedVector3 vec = axis * GetInvInertiaTensorWorld();
		return axis.Dot(ref vec);
	}

	public void UpdateDeactivation(float timeStep)
	{
		if ((GetActivationState() == ActivationState.ISLAND_SLEEPING) || (GetActivationState() == ActivationState.DISABLE_DEACTIVATION))
		{
			return;
		}

		if ((GetLinearVelocity().LengthSquared() < m_linearSleepingThreshold * m_linearSleepingThreshold) && (GetAngularVelocity().LengthSquared() < m_angularSleepingThreshold * m_angularSleepingThreshold))
		{
			m_deactivationTime += timeStep;
		}
		else
		{
			m_deactivationTime = 0f;
			SetActivationState(ActivationState.UNDEFINED);
		}
	}

	public bool WantsSleeping()
	{
		if (GetActivationState() == ActivationState.DISABLE_DEACTIVATION)
		{
			return false;
		}

		//disable deactivation
		if (BulletGlobals.gDisableDeactivation || BulletGlobals.gDeactivationTime == 0f)
		{
			return false;
		}

		if ((GetActivationState() == ActivationState.ISLAND_SLEEPING) || (GetActivationState() == ActivationState.WANTS_DEACTIVATION))
		{
			return true;
		}

		if (m_deactivationTime > BulletGlobals.gDeactivationTime)
		{
			return true;
		}

		return false;
	}

	public BroadphaseProxy GetBroadphaseProxy()
	{
		return m_broadphaseHandle;
	}

	public void SetNewBroadphaseProxy(BroadphaseProxy broadphaseProxy)
	{
		m_broadphaseHandle = broadphaseProxy;
	}

	//btMotionState allows to automatic synchronize the world transform for active objects
	public IMotionState GetMotionState()
	{
		return m_optionalMotionState;
	}

	public void SetMotionState(IMotionState motionState)
	{
		m_optionalMotionState = motionState;
		if (m_optionalMotionState != null)
		{
			motionState.GetWorldTransform(out m_worldTransform);
		}
	}

	//for experimental overriding of friction/contact solver func
	int m_contactSolverType;
	int m_frictionSolverType;
	public void SetAngularFactor(float angFac)
	{
		m_angularFactor = new IndexedVector3(angFac);
	}

	public void SetAngularFactor(IndexedVector3 angFac)
	{
		SetAngularFactor(ref angFac);
	}

	public void SetAngularFactor(ref IndexedVector3 angFac)
	{
		m_angularFactor = angFac;
	}

	public IndexedVector3 GetAngularFactor()
	{
		return m_angularFactor;
	}

	public void SetFlags(RigidBodyFlags flags)
	{
		m_rigidbodyFlags = flags;
	}

	public RigidBodyFlags GetFlags()
	{
		return m_rigidbodyFlags;
	}

	public IndexedVector3 GetDeltaLinearVelocity()
	{
		return m_deltaLinearVelocity;
	}

	public IndexedVector3 GetDeltaAngularVelocity()
	{
		return m_deltaAngularVelocity;
	}

	public IndexedVector3 GetPushVelocity()
	{
		return m_pushVelocity;
	}

	public IndexedVector3 GetTurnVelocity()
	{
		return m_turnVelocity;
	}

	//is this rigidbody added to a btCollisionWorld/btDynamicsWorld/btBroadphase?
	public bool IsInWorld()
	{
		return (GetBroadphaseProxy() != null);
	}

	public override bool CheckCollideWithOverride(CollisionObject co)
	{
		RigidBody otherRb = RigidBody.Upcast(co);
		if (otherRb == null)
			return true;
		for (int i = 0; i < m_constraintRefs.Count; ++i)
		{
			TypedConstraint c = m_constraintRefs[i];
			if (c.IsEnabled())
			{
				if (c.GetRigidBodyA() == otherRb || c.GetRigidBodyB() == otherRb)
				{
					return false;
				}
			}
		}

		return true;
	}

	public void AddConstraintRef(TypedConstraint c)
	{
		if (!m_constraintRefs.Contains(c))
		{
			m_constraintRefs.Add(c);
		}

		m_checkCollideWith = true;
	}

	public void RemoveConstraintRef(TypedConstraint c)
	{
		m_constraintRefs.Remove(c);
		m_checkCollideWith = m_constraintRefs.Count > 0;
	}

	public TypedConstraint GetConstraintRef(int index)
	{
		return m_constraintRefs[index];
	}

	public int GetNumConstraintRefs()
	{
		return m_constraintRefs.Count;
	}

	////////////////////////////////////////////////
	public IndexedVector3 InternalGetDeltaLinearVelocity()
	{
		return m_deltaLinearVelocity;
	}

	public void InternalSetDeltaLinearVelocity(ref IndexedVector3 v)
	{
		m_deltaLinearVelocity = v;
		MathUtil.SanityCheckVector(ref m_deltaLinearVelocity);
	}

	public IndexedVector3 InternalGetDeltaAngularVelocity()
	{
		return m_deltaAngularVelocity;
	}

	public void InternalSetDeltaAngularVelocity(ref IndexedVector3 v)
	{
		m_deltaAngularVelocity = v;
		MathUtil.SanityCheckVector(ref m_deltaAngularVelocity);
	}

	public IndexedVector3 InternalGetAngularFactor()
	{
		return m_angularFactor;
	}

	public IndexedVector3 InternalGetInvMass()
	{
		return m_invMass;
	}

	public IndexedVector3 InternalGetPushVelocity()
	{
		return m_pushVelocity;
	}

	public IndexedVector3 InternalGetTurnVelocity()
	{
		return m_turnVelocity;
	}

	public void InternalSetTurnVelocity(ref IndexedVector3 velocity)
	{
		m_turnVelocity = velocity;
	}

	public void InternalSetPushVelocity(ref IndexedVector3 velocity)
	{
		m_pushVelocity = velocity;
	}

	public void InternalGetVelocityInLocalPointObsolete(ref IndexedVector3 rel_pos, ref IndexedVector3 velocity)
	{
		velocity = GetLinearVelocity() + m_deltaLinearVelocity + IndexedVector3.Cross((GetAngularVelocity() + m_deltaAngularVelocity), rel_pos);
	}

	public void InternalGetAngularVelocity(ref IndexedVector3 angVel)
	{
		angVel = GetAngularVelocity() + m_deltaAngularVelocity;
	}

	//Optimization for the iterative solver: avoid calculating constant terms involving inertia, normal, relative position
	public void InternalApplyImpulse(ref IndexedVector3 linearComponent, ref IndexedVector3 angularComponent, float impulseMagnitude, String caller)
	{
		if (m_inverseMass != 0f)
		{
			m_deltaLinearVelocity.X += impulseMagnitude * linearComponent.X;
			m_deltaLinearVelocity.Y += impulseMagnitude * linearComponent.Y;
			m_deltaLinearVelocity.Z += impulseMagnitude * linearComponent.Z;
			//m_deltaLinearVelocity += linearComponent*impulseMagnitude;
			m_deltaAngularVelocity.X += angularComponent.X * (impulseMagnitude * m_angularFactor.X);
			m_deltaAngularVelocity.Y += angularComponent.Y * (impulseMagnitude * m_angularFactor.Y);
			m_deltaAngularVelocity.Z += angularComponent.Z * (impulseMagnitude * m_angularFactor.Z);
			//m_deltaAngularVelocity += angularComponent*(impulseMagnitude*m_angularFactor);
			MathUtil.SanityCheckVector(ref m_deltaLinearVelocity);
			MathUtil.SanityCheckVector(ref m_deltaAngularVelocity);
		}
	}

	public void InternalApplyPushImpulse(IndexedVector3 linearComponent, IndexedVector3 angularComponent, float impulseMagnitude)
	{
		InternalApplyPushImpulse(ref linearComponent, ref angularComponent, impulseMagnitude);
	}

	public void InternalApplyPushImpulse(ref IndexedVector3 linearComponent, ref IndexedVector3 angularComponent, float impulseMagnitude)
	{
		if (m_inverseMass != 0f)
		{
			m_pushVelocity += linearComponent * impulseMagnitude;
			m_turnVelocity += angularComponent * (impulseMagnitude * m_angularFactor);
		}
	}

	public void InternalWritebackVelocity()
	{
		if (m_inverseMass != 0f)
		{
			SetLinearVelocity(GetLinearVelocity() + m_deltaLinearVelocity);
			SetAngularVelocity(GetAngularVelocity() + m_deltaAngularVelocity);
		//m_deltaLinearVelocity = IndexedVector3.Zero;
		//m_deltaAngularVelocity = IndexedVector3.Zero;
		//m_originalBody->setCompanionId(-1);
		}
	}

	public void InternalWritebackVelocity(float timeStep)
	{
		if (m_inverseMass != 0f)
		{
			SetLinearVelocity(GetLinearVelocity() + m_deltaLinearVelocity);
			SetAngularVelocity(GetAngularVelocity() + m_deltaAngularVelocity);
			//correct the position/orientation based on push/turn recovery
			IndexedMatrix newTransform;
			TransformUtil.IntegrateTransform(GetWorldTransform(), m_pushVelocity, m_turnVelocity, timeStep, out newTransform);
			SetWorldTransform(ref newTransform);
		//m_originalBody->setCompanionId(-1);
		}
	//m_deltaLinearVelocity = IndexedVector3.Zero;
	//m_deltaAngularVelocity = IndexedVector3.Zero;
	//m_pushVelocity = IndexedVector3.Zero;
	//m_turnVelocity = IndexedVector3.Zero;
	}
}