public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2,
                 Vector3 pivotInA, Vector3 pivotInB,
                 Vector3 axisInA, Vector3 axisInB,
                 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
 {
     m_world = world;
     m_body1 = obj1;
     m_body2 = obj2;
     m_constraint = new BulletConstraint(
                         BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
                             pivotInA, pivotInB,
                             axisInA, axisInB,
                             useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
     m_enabled = true;
 }
 // Create a btGeneric6DofConstraint
 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
                 Vector3 frame1, Quaternion frame1rot,
                 Vector3 frame2, Quaternion frame2rot,
                 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
 {
     m_world = world;
     m_body1 = obj1;
     m_body2 = obj2;
     m_constraint = new BulletConstraint(
                         BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
                             frame1, frame1rot,
                             frame2, frame2rot,
                             useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
     m_enabled = true;
     world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
                         BSScene.DetailLogZero, world.worldID,
                         obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString());
 }
    // Get the constraint between two bodies. There can be only one.
    // Return 'true' if a constraint was found.
    public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint)
    {
        bool found = false;
        BSConstraint foundConstraint = null;

        uint lookingID1 = body1.ID;
        uint lookingID2 = body2.ID;
        lock (m_constraints)
        {
            foreach (BSConstraint constrain in m_constraints)
            {
                if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2)
                    || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1))
                {
                    foundConstraint = constrain;
                    found = true;
                    break;
                }
            }
        }
        returnConstraint = foundConstraint;
        return found;
    }
 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
                 Vector3 joinPoint,
                 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
 {
     m_world = world;
     m_body1 = obj1;
     m_body2 = obj2;
     if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
     {
         world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
                         BSScene.DetailLogZero, world.worldID,
                         obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString());
         world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
                         LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString());
         m_enabled = false;
     }
     else
     {
         m_constraint = new BulletConstraint(
                             BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
                                 joinPoint,
                                 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
         world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
                             BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString(),
                             obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString());
         if (!m_constraint.HasPhysicalConstraint)
         {
             world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
                             LogHeader, obj1.ID, obj2.ID);
             m_enabled = false;
         }
         else
         {
             m_enabled = true;
         }
     }
 }
 // Remove all constraints that reference the passed body.
 // Return 'true' if any constraints were destroyed.
 public bool RemoveAndDestroyConstraint(BulletBody body1)
 {
     List<BSConstraint> toRemove = new List<BSConstraint>();
     uint lookingID = body1.ID;
     lock (m_constraints)
     {
         foreach (BSConstraint constrain in m_constraints)
         {
             if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID)
             {
                 toRemove.Add(constrain);
             }
         }
         foreach (BSConstraint constrain in toRemove)
         {
             m_constraints.Remove(constrain);
             constrain.Dispose();
         }
     }
     return (toRemove.Count > 0);
 }
    // Remove any constraint between the passed bodies.
    // Presumed there is only one such constraint possible.
    // Return 'true' if a constraint was found and destroyed.
    public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2)
    {
        bool ret = false;
        lock (m_constraints)
        {
            BSConstraint constrain;
            if (this.TryGetConstraint(body1, body2, out constrain))
            {
                // remove the constraint from our collection
                RemoveAndDestroyConstraint(constrain);
                ret = true;
            }
        }

        return ret;
    }
    // Create the initial instance of terrain and the underlying ground plane.
    // This is called from the initialization routine so we presume it is
    //    safe to call Bullet in real time. We hope no one is moving prims around yet.
    public void CreateInitialGroundPlaneAndTerrain()
    {
        // The ground plane is here to catch things that are trying to drop to negative infinity
        BulletShape groundPlaneShape = new BulletShape(
                    BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, 
                                    BSParam.TerrainCollisionMargin),
                    BSPhysicsShapeType.SHAPE_GROUNDPLANE);
        m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
                        BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
                                                            Vector3.Zero, Quaternion.Identity));
        BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr, Vector3.Zero, Quaternion.Identity);
        BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
        // Ground plane does not move
        BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
        // Everything collides with the ground plane.
        m_groundPlane.collisionType = CollisionType.Groundplane;
        m_groundPlane.ApplyCollisionMask();

        // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
        BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
        m_terrains.Add(Vector3.Zero, initialTerrain);
    }
    // Create terrain mesh from a heightmap.
    public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, 
                                                    Vector3 minCoords, Vector3 maxCoords)
        : base(physicsScene, regionBase, id)
    {
        int indicesCount;
        int[] indices;
        int verticesCount;
        float[] vertices;

        m_savedHeightMap = initialMap;

        m_sizeX = (int)(maxCoords.X - minCoords.X);
        m_sizeY = (int)(maxCoords.Y - minCoords.Y);

        if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap,
                            m_sizeX, m_sizeY,
                            (float)m_sizeX, (float)m_sizeY,
                            Vector3.Zero, 1.0f,
                            out indicesCount, out indices, out verticesCount, out vertices))
        {
            // DISASTER!!
            PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID);
            PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
            // Something is very messed up and a crash is in our future.
            return;
        }
        PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", 
                                ID, indicesCount, indices.Length, verticesCount, vertices.Length);

        m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
                                                    indicesCount, indices, verticesCount, vertices),
                                        BSPhysicsShapeType.SHAPE_MESH);
        if (!m_terrainShape.HasPhysicalShape)
        {
            // DISASTER!!
            PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
            physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
            // Something is very messed up and a crash is in our future.
            return;
        }

        Vector3 pos = regionBase;
        Quaternion rot = Quaternion.Identity;

        m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot));
        if (!m_terrainBody.HasPhysicalBody)
        {
            // DISASTER!!
            physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
            // Something is very messed up and a crash is in our future.
            return;
        }

        // Set current terrain attributes
        BulletSimAPI.SetFriction2(m_terrainBody.ptr, BSParam.TerrainFriction);
        BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, BSParam.TerrainHitFraction);
        BulletSimAPI.SetRestitution2(m_terrainBody.ptr, BSParam.TerrainRestitution);
        BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);

        // Static objects are not very massive.
        BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);

        // Put the new terrain to the world of physical objects
        BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr, pos, rot);

        // Redo its bounding box now that it is in the world
        BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);

        m_terrainBody.collisionType = CollisionType.Terrain;
        m_terrainBody.ApplyCollisionMask();

        // Make it so the terrain will not move or be considered for movement.
        BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
    }
    // Create a body object in Bullet.
    // Updates prim.BSBody with the information about the new body if one is created.
    // Returns 'true' if an object was actually created.
    // Called at taint-time.
    private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape,
                            BodyDestructionCallback bodyCallback)
    {
        bool ret = false;

        // the mesh, hull or native shape must have already been created in Bullet
        bool mustRebuild = !prim.PhysBody.HasPhysicalBody;

        // If there is an existing body, verify it's of an acceptable type.
        // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
        if (!mustRebuild)
        {
            CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr);
            if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
                || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
            {
                // If the collisionObject is not the correct type for solidness, rebuild what's there
                mustRebuild = true;
            }
        }

        if (mustRebuild || forceRebuild)
        {
            // Free any old body
            DereferenceBody(prim.PhysBody, true, bodyCallback);

            BulletBody aBody;
            Object bodyPtr = null;
            if (prim.IsSolid)
            {
                bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
                                        prim.LocalID, prim.RawPosition, prim.RawOrientation);
                if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString());
            }
            else
            {
                bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
                                        prim.LocalID, prim.RawPosition, prim.RawOrientation);
                if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString());
            }
            aBody = new BulletBody(prim.LocalID, bodyPtr);

            ReferenceBody(aBody, true);

            prim.PhysBody = aBody;

            ret = true;
        }

        return ret;
    }
    // Release the usage of a body.
    // Called when releasing use of a BSBody. BSShape is handled separately.
    public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
    {
        if (!body.HasPhysicalBody)
            return;

        lock (m_collectionActivityLock)
        {
            PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
            {
                if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
                                            body.ID, body, inTaintTime);
                // If the caller needs to know the old body is going away, pass the event up.
                if (bodyCallback != null) bodyCallback(body);

                if (BulletSimAPI.IsInWorld2(PhysicsScene.World.ptr, body.ptr))
                {
                    BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
                    if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
                }

                // Zero any reference to the shape so it is not freed when the body is deleted.
                BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, null);
                BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
            });
        }
    }
 // Track another user of a body.
 // We presume the caller has allocated the body.
 // Bodies only have one user so the body is just put into the world if not already there.
 public void ReferenceBody(BulletBody body, bool inTaintTime)
 {
     lock (m_collectionActivityLock)
     {
         if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
         PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
         {
             if (!BulletSimAPI.IsInWorld2(PhysicsScene.World.ptr, body.ptr))
             {
                 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
                 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
             }
         });
     }
 }