From 2b8efa24dd816fda23fe3aed5822af1d50febf5d Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Sun, 16 Dec 2012 21:18:32 -0800
Subject: BulletSim: add parameter to UpdateProperties call into the linkset so
 changes from the physics engine can be differentiated from changes made by
 the user. This eliminates a linkset rebuild loop. Also add logic to not
 rebuild or freak out when the object/linkset crosses a terrain boundry.

---
 OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs  |  3 +-
 .../Physics/BulletSPlugin/BSLinksetCompound.cs     | 48 +++++++++++++---------
 .../Physics/BulletSPlugin/BSLinksetConstraints.cs  |  2 +-
 .../Region/Physics/BulletSPlugin/BSPhysObject.cs   |  9 ++--
 OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs     | 29 +++++++++----
 OpenSim/Region/Physics/BulletSPlugin/BSScene.cs    | 10 +++--
 6 files changed, 65 insertions(+), 36 deletions(-)

(limited to 'OpenSim')

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 2486be5..2017fa5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -252,8 +252,9 @@ public abstract class BSLinkset
 
     // Called when a parameter update comes from the physics engine for any object
     //      of the linkset is received.
+    // Passed flag is update came from physics engine (true) or the user (false).
     // Called at taint-time!!
-    public abstract void UpdateProperties(BSPhysObject physObject);
+    public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate);
 
     // Routine used when rebuilding the body of the root of the linkset
     // Destroy all the constraints have have been made to root.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index 8359607..4d4f712 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -28,6 +28,8 @@ using System;
 using System.Collections.Generic;
 using System.Text;
 
+using OpenSim.Framework;
+
 using OMV = OpenMetaverse;
 
 namespace OpenSim.Region.Physics.BulletSPlugin
@@ -87,25 +89,22 @@ public sealed class BSLinksetCompound : BSLinkset
     //   its internal properties.
     public override void Refresh(BSPhysObject requestor)
     {
-        if (!IsRoot(requestor))
-        {
-        }
         // Something changed so do the rebuilding thing
-        InternalRefresh(requestor);
+        // ScheduleRebuild();
     }
 
     // Schedule a refresh to happen after all the other taint processing.
-    private void InternalRefresh(BSPhysObject requestor)
+    private void ScheduleRebuild()
     {
-        DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1},rebuilding={2}", 
-                            LinksetRoot.LocalID, requestor.LocalID, Rebuilding);
+        DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,rebuilding={1}", 
+                            LinksetRoot.LocalID, Rebuilding);
         // When rebuilding, it is possible to set properties that would normally require a rebuild.
         //    If already rebuilding, don't request another rebuild.
         if (!Rebuilding)
         {
-            PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate()
+            PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", LinksetRoot.LocalID, delegate()
             {
-                if (IsRoot(requestor) && HasAnyChildren)
+                if (HasAnyChildren)
                     RecomputeLinksetCompound();
             });
         }
@@ -125,8 +124,7 @@ public sealed class BSLinksetCompound : BSLinkset
         {
             // The root is going dynamic. Make sure mass is properly set.
             m_mass = ComputeLinksetMass();
-            if (HasAnyChildren)
-                InternalRefresh(LinksetRoot);
+            ScheduleRebuild();
         }
         else
         {
@@ -155,8 +153,7 @@ public sealed class BSLinksetCompound : BSLinkset
         DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
         if (IsRoot(child))
         {
-            if (HasAnyChildren)
-                InternalRefresh(LinksetRoot);
+            ScheduleRebuild();
         }
         else
         {
@@ -172,10 +169,21 @@ public sealed class BSLinksetCompound : BSLinkset
         return ret;
     }
 
-    // Called at taint-time!!
-    public override void UpdateProperties(BSPhysObject updated)
+    public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate)
     {
-        // Nothing to do for compound linksets on property updates
+        // The user moving a child around requires the rebuilding of the linkset compound shape
+        // One problem is this happens when a border is crossed -- the simulator implementation
+        //    is to store the position into the group which causes the move of the object
+        //    but it also means all the child positions get updated.
+        //    What would cause an unnecessary rebuild so we make sure the linkset is in a
+        //    region before bothering to do a rebuild.
+        if (!IsRoot(updated) 
+                && !physicalUpdate 
+                && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
+        {
+            updated.LinksetInfo = null;
+            ScheduleRebuild();
+        }
     }
 
     // Routine called when rebuilding the body of some member of the linkset.
@@ -257,8 +265,8 @@ public sealed class BSLinksetCompound : BSLinkset
 
             DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
 
-            // Cause constraints and assorted properties to be recomputed before the next simulation step.
-            InternalRefresh(LinksetRoot);
+            // Rebuild the compound shape with the new child shape included
+            ScheduleRebuild();
         }
         return;
     }
@@ -285,8 +293,8 @@ public sealed class BSLinksetCompound : BSLinkset
             }
             else
             {
-                // Schedule a rebuild of the linkset  before the next simulation tick.
-                InternalRefresh(LinksetRoot);
+                // Rebuild the compound shape with the child removed
+                ScheduleRebuild();
             }
         }
         return;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index 7076ab4..8c36c31 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -78,7 +78,7 @@ public sealed class BSLinksetConstraints : BSLinkset
     }
 
     // Called at taint-time!!
-    public override void UpdateProperties(BSPhysObject updated)
+    public override void UpdateProperties(BSPhysObject updated, bool inTaintTime)
     {
         // Nothing to do for constraints on property updates
     }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 6539b43..92a5f2f 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -214,7 +214,7 @@ public abstract class BSPhysObject : PhysicsActor
     {
         bool ret = true;
         // If the 'no collision' call, force it to happen right now so quick collision_end
-        bool force = CollisionCollection.Count == 0;
+        bool force = (CollisionCollection.Count == 0);
 
         // throttle the collisions to the number of milliseconds specified in the subscription
         if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
@@ -232,8 +232,10 @@ public abstract class BSPhysObject : PhysicsActor
             // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
             base.SendCollisionUpdate(CollisionCollection);
 
-            // The collisionCollection structure is passed around in the simulator.
+            // The CollisionCollection instance is passed around in the simulator.
             // Make sure we don't have a handle to that one and that a new one is used for next time.
+            //    This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, 
+            //    a race condition is created for the other users of this instance.
             CollisionCollection = new CollisionEventUpdate();
         }
         return ret;
@@ -251,7 +253,8 @@ public abstract class BSPhysObject : PhysicsActor
 
             PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
             {
-                CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
+                if (PhysBody.HasPhysicalBody)
+                    CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
             });
         }
         else
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 53be2e3..758d92b 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -300,6 +300,10 @@ public sealed class BSPrim : BSPhysObject
             }
             _position = value;
             PositionSanityCheck(false);
+
+            // A linkset might need to know if a component information changed.
+            Linkset.UpdateProperties(this, false);
+
             PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
             {
                 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
@@ -329,6 +333,14 @@ public sealed class BSPrim : BSPhysObject
     {
         bool ret = false;
 
+        if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
+        {
+            // The physical object is out of the known/simulated area.
+            // Upper levels of code will handle the transition to other areas so, for
+            //     the time, we just ignore the position.
+            return ret;
+        }
+
         float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
         OMV.Vector3 upForce = OMV.Vector3.Zero;
         if (RawPosition.Z < terrainHeight)
@@ -352,8 +364,6 @@ public sealed class BSPrim : BSPhysObject
             }
         }
 
-        // TODO: check for out of bounds
-
         // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
         // TODO: This should be intergrated with a geneal physics action mechanism.
         // TODO: This should be moderated with PID'ness.
@@ -567,7 +577,10 @@ public sealed class BSPrim : BSPhysObject
             if (_orientation == value)
                 return;
             _orientation = value;
-            // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
+
+            // A linkset might need to know if a component information changed.
+            Linkset.UpdateProperties(this, false);
+
             PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
             {
                 if (PhysBody.HasPhysicalBody)
@@ -1432,14 +1445,14 @@ public sealed class BSPrim : BSPhysObject
                 entprop.Velocity = _velocity;
             }
 
-            // remember the current and last set values
-            LastEntityProperties = CurrentEntityProperties;
-            CurrentEntityProperties = entprop;
-
             OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;   // DEBUG DEBUG DEBUG
             DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
                     LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
 
+            // remember the current and last set values
+            LastEntityProperties = CurrentEntityProperties;
+            CurrentEntityProperties = entprop;
+
             base.RequestPhysicsterseUpdate();
         }
             /*
@@ -1453,7 +1466,7 @@ public sealed class BSPrim : BSPhysObject
              */
 
         // The linkset implimentation might want to know about this.
-        Linkset.UpdateProperties(this);
+        Linkset.UpdateProperties(this, true);
     }
 }
 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index ac99777..7b44574 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -517,8 +517,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
                         out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
 
             if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
-            DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
-                        DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
+            DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
+                                    DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, 
+                                    updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
             if (VehiclePhysicalLoggingEnabled) DumpVehicles();  // DEBUG
         }
         catch (Exception e)
@@ -573,6 +574,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 
         // Objects that are done colliding are removed from the ObjectsWithCollisions list.
         // Not done above because it is inside an iteration of ObjectWithCollisions.
+        // This complex collision processing is required to create an empty collision
+        //     event call after all collisions have happened on an object. This enables
+        //     the simulator to generate the 'collision end' event.
         if (ObjectsWithNoMoreCollisions.Count > 0)
         {
             foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
@@ -597,7 +601,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 
         ProcessPostStepTaints();
 
-        // This causes the unmanaged code to output ALL the values found in ALL the objects in the world.
+        // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
         // Only enable this in a limited test world with few objects.
         // BulletSimAPI.DumpAllInfo2(World.ptr);    // DEBUG DEBUG DEBUG
 
-- 
cgit v1.1