private void AddAxisLockConstraint()
        {
            if (LockAxisConstraint == null)
            {
                // Lock that axis by creating a 6DOF constraint that has one end in the world and
                //    the other in the object.
                // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
                // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380

                // Remove any existing axis constraint (just to be sure)
                RemoveAxisLockConstraint();

                BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
                                                                        OMV.Vector3.Zero, OMV.Quaternion.Identity,
                                                                        false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
                LockAxisConstraint = axisConstrainer;
                m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);

                // The constraint is tied to the world and oriented to the prim.

                // Free to move linearly in the region
                OMV.Vector3 linearLow  = OMV.Vector3.Zero;
                OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.WorldMax;
                axisConstrainer.SetLinearLimits(linearLow, linearHigh);

                // Angular with some axis locked
                float       fPI         = (float)Math.PI;
                OMV.Vector3 angularLow  = new OMV.Vector3(-fPI, -fPI, -fPI);
                OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI);
                if (m_controllingPrim.LockedAxis.X != 1f)
                {
                    angularLow.X  = 0f;
                    angularHigh.X = 0f;
                }
                if (m_controllingPrim.LockedAxis.Y != 1f)
                {
                    angularLow.Y  = 0f;
                    angularHigh.Y = 0f;
                }
                if (m_controllingPrim.LockedAxis.Z != 1f)
                {
                    angularLow.Z  = 0f;
                    angularHigh.Z = 0f;
                }
                if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh))
                {
                    m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits",
                                             m_controllingPrim.LocalID);
                }

                m_physicsScene.DetailLog(
                    "{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}",
                    m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh);

                // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
                axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);

                axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass);
            }
        }
        private void AddAxisLockConstraint()
        {
            if (LockAxisConstraint == null)
            {
                // Lock that axis by creating a 6DOF constraint that has one end in the world and
                //    the other in the object.
                // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
                // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380

                // Remove any existing axis constraint (just to be sure)
                RemoveAxisLockConstraint();

                BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
                    OMV.Vector3.Zero, OMV.Quaternion.Identity,
                    false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
                LockAxisConstraint = axisConstrainer;
                m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);

                // The constraint is tied to the world and oriented to the prim.

                // Free to move linearly in the region
                OMV.Vector3 linearLow = OMV.Vector3.Zero;
                OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.WorldMax;
                axisConstrainer.SetLinearLimits(linearLow, linearHigh);

                // Angular with some axis locked
                float fPI = (float)Math.PI;
                OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI);
                OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI);
                if (m_controllingPrim.LockedAxis.X != 1f)
                {
                    angularLow.X = 0f;
                    angularHigh.X = 0f;
                }
                if (m_controllingPrim.LockedAxis.Y != 1f)
                {
                    angularLow.Y = 0f;
                    angularHigh.Y = 0f;
                }
                if (m_controllingPrim.LockedAxis.Z != 1f)
                {
                    angularLow.Z = 0f;
                    angularHigh.Z = 0f;
                }
                if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh))
                {
                    m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits",
                        m_controllingPrim.LocalID);
                }

                m_physicsScene.DetailLog(
                    "{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}",
                    m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh);

                // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
                axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);

                axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass);
            }
        }
        private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
        {
            // Zero motion for children so they don't interpolate
            childPrim.ZeroMotion(true);

            // Relative position normalized to the root prim
            // Essentually a vector pointing from center of rootPrim to center of childPrim
            OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;

            // real world coordinate of midpoint between the two objects
            OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);

            DetailLog(
                "{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
                rootPrim.LocalID,
                rootPrim.LocalID, rootPrim.PhysBody.AddrString,
                childPrim.LocalID, childPrim.PhysBody.AddrString,
                rootPrim.Position, childPrim.Position, midPoint);

            // create a constraint that allows no freedom of movement between the two objects
            // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818

            BSConstraint6Dof constrain = new BSConstraint6Dof(
                PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true);
            // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );

            /* NOTE: below is an attempt to build constraint with full frame computation, etc.
             *     Using the midpoint is easier since it lets the Bullet code manipulate the transforms
             *     of the objects.
             * Code left for future programmers.
            // ==================================================================================
            // relative position normalized to the root prim
            OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
            OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;

            // relative rotation of the child to the parent
            OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
            OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);

            DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
            BS6DofConstraint constrain = new BS6DofConstraint(
                        PhysicsScene.World, rootPrim.Body, childPrim.Body,
                        OMV.Vector3.Zero,
                        OMV.Quaternion.Inverse(rootPrim.Orientation),
                        OMV.Vector3.Zero,
                        OMV.Quaternion.Inverse(childPrim.Orientation),
                        true,
                        true
                        );
            // ==================================================================================
            */

            PhysicsScene.Constraints.AddConstraint(constrain);

            // zero linear and angular limits makes the objects unable to move in relation to each other
            constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
            constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);

            // tweek the constraint to increase stability
            constrain.UseFrameOffset(BSParam.LinkConstraintUseFrameOffset);
            constrain.TranslationalLimitMotor(BSParam.LinkConstraintEnableTransMotor,
                BSParam.LinkConstraintTransMotorMaxVel,
                BSParam.LinkConstraintTransMotorMaxForce);
            constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
            if (BSParam.LinkConstraintSolverIterations != 0f)
            {
                constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
            }
            return constrain;
        }
        private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
        {
            // Zero motion for children so they don't interpolate
            childPrim.ZeroMotion(true);

            // Relative position normalized to the root prim
            // Essentually a vector pointing from center of rootPrim to center of childPrim
            OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;

            // real world coordinate of midpoint between the two objects
            OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);

            DetailLog(
                "{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
                rootPrim.LocalID,
                rootPrim.LocalID, rootPrim.PhysBody.AddrString,
                childPrim.LocalID, childPrim.PhysBody.AddrString,
                rootPrim.Position, childPrim.Position, midPoint);

            // create a constraint that allows no freedom of movement between the two objects
            // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818

            BSConstraint6Dof constrain = new BSConstraint6Dof(
                PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true);

            // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );

            /* NOTE: below is an attempt to build constraint with full frame computation, etc.
             *     Using the midpoint is easier since it lets the Bullet code manipulate the transforms
             *     of the objects.
             * Code left for future programmers.
             * // ==================================================================================
             * // relative position normalized to the root prim
             * OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
             * OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
             *
             * // relative rotation of the child to the parent
             * OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
             * OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
             *
             * DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
             * BS6DofConstraint constrain = new BS6DofConstraint(
             *          PhysicsScene.World, rootPrim.Body, childPrim.Body,
             *          OMV.Vector3.Zero,
             *          OMV.Quaternion.Inverse(rootPrim.Orientation),
             *          OMV.Vector3.Zero,
             *          OMV.Quaternion.Inverse(childPrim.Orientation),
             *          true,
             *          true
             *          );
             * // ==================================================================================
             */

            PhysicsScene.Constraints.AddConstraint(constrain);

            // zero linear and angular limits makes the objects unable to move in relation to each other
            constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
            constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);

            // tweek the constraint to increase stability
            constrain.UseFrameOffset(BSParam.LinkConstraintUseFrameOffset);
            constrain.TranslationalLimitMotor(BSParam.LinkConstraintEnableTransMotor,
                                              BSParam.LinkConstraintTransMotorMaxVel,
                                              BSParam.LinkConstraintTransMotorMaxForce);
            constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
            if (BSParam.LinkConstraintSolverIterations != 0f)
            {
                constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
            }
            return(constrain);
        }