aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2012-10-24 02:04:26 +0100
committerJustin Clark-Casey (justincc)2012-10-24 02:04:26 +0100
commit326f1507fac61d1f50470eebd0b873f8c2360338 (patch)
treee8c650707f20fd454c3d18187b063a9cb29349a7 /OpenSim/Region/Physics
parentminor: Move co-ordinate related help to object commands to common ConsoleUtil... (diff)
parentBulletSim: update binaries with small change that insures that manual positio... (diff)
downloadopensim-SC_OLD-326f1507fac61d1f50470eebd0b873f8c2360338.zip
opensim-SC_OLD-326f1507fac61d1f50470eebd0b873f8c2360338.tar.gz
opensim-SC_OLD-326f1507fac61d1f50470eebd0b873f8c2360338.tar.bz2
opensim-SC_OLD-326f1507fac61d1f50470eebd0b873f8c2360338.tar.xz
Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
Diffstat (limited to 'OpenSim/Region/Physics')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs35
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs6
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs15
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs368
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs385
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs8
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs20
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs10
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs69
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs8
10 files changed, 534 insertions, 390 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 623ac8f..a041ba8 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -105,7 +105,7 @@ public class BSCharacter : BSPhysObject
105 shapeData.Position = _position; 105 shapeData.Position = _position;
106 shapeData.Rotation = _orientation; 106 shapeData.Rotation = _orientation;
107 shapeData.Velocity = _velocity; 107 shapeData.Velocity = _velocity;
108 shapeData.Size = Scale; 108 shapeData.Size = Scale; // capsule is a native shape but scale is not just <1,1,1>
109 shapeData.Scale = Scale; 109 shapeData.Scale = Scale;
110 shapeData.Mass = _mass; 110 shapeData.Mass = _mass;
111 shapeData.Buoyancy = _buoyancy; 111 shapeData.Buoyancy = _buoyancy;
@@ -144,7 +144,9 @@ public class BSCharacter : BSPhysObject
144 ForcePosition = _position; 144 ForcePosition = _position;
145 // Set the velocity and compute the proper friction 145 // Set the velocity and compute the proper friction
146 ForceVelocity = _velocity; 146 ForceVelocity = _velocity;
147
147 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution); 148 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution);
149 BulletSimAPI.SetMargin2(BSShape.ptr, PhysicsScene.Params.collisionMargin);
148 BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale); 150 BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
149 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 151 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
150 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 152 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
@@ -156,16 +158,20 @@ public class BSCharacter : BSPhysObject
156 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw); 158 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
157 BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia); 159 BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
158 160
161 // Make so capsule does not fall over
162 BulletSimAPI.SetAngularFactorV2(BSBody.ptr, OMV.Vector3.Zero);
163
159 BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); 164 BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
160 165
161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr); 166 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
162 167
163 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); 168 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
169 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_DEACTIVATION);
164 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr); 170 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
165 171
166 // Do this after the object has been added to the world 172 // Do this after the object has been added to the world
167 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, 173 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
168 (uint)CollisionFilterGroups.AvatarFilter, 174 (uint)CollisionFilterGroups.AvatarFilter,
169 (uint)CollisionFilterGroups.AvatarMask); 175 (uint)CollisionFilterGroups.AvatarMask);
170 } 176 }
171 177
@@ -175,11 +181,13 @@ public class BSCharacter : BSPhysObject
175 } 181 }
176 // No one calls this method so I don't know what it could possibly mean 182 // No one calls this method so I don't know what it could possibly mean
177 public override bool Stopped { get { return false; } } 183 public override bool Stopped { get { return false; } }
184
178 public override OMV.Vector3 Size { 185 public override OMV.Vector3 Size {
179 get 186 get
180 { 187 {
181 // Avatar capsule size is kept in the scale parameter. 188 // Avatar capsule size is kept in the scale parameter.
182 return _size; 189 // return _size;
190 return new OMV.Vector3(Scale.X * 2f, Scale.Y * 2f, Scale.Z);
183 } 191 }
184 192
185 set { 193 set {
@@ -199,7 +207,9 @@ public class BSCharacter : BSPhysObject
199 207
200 } 208 }
201 } 209 }
210
202 public override OMV.Vector3 Scale { get; set; } 211 public override OMV.Vector3 Scale { get; set; }
212
203 public override PrimitiveBaseShape Shape 213 public override PrimitiveBaseShape Shape
204 { 214 {
205 set { BaseShape = value; } 215 set { BaseShape = value; }
@@ -264,12 +274,12 @@ public class BSCharacter : BSPhysObject
264 274
265 275
266 // Check that the current position is sane and, if not, modify the position to make it so. 276 // Check that the current position is sane and, if not, modify the position to make it so.
267 // Check for being below terrain and being out of bounds. 277 // Check for being below terrain or on water.
268 // Returns 'true' of the position was made sane by some action. 278 // Returns 'true' of the position was made sane by some action.
269 private bool PositionSanityCheck() 279 private bool PositionSanityCheck()
270 { 280 {
271 bool ret = false; 281 bool ret = false;
272 282
273 // If below the ground, move the avatar up 283 // If below the ground, move the avatar up
274 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 284 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
275 if (Position.Z < terrainHeight) 285 if (Position.Z < terrainHeight)
@@ -335,7 +345,7 @@ public class BSCharacter : BSPhysObject
335 } 345 }
336 346
337 // Avatars don't do vehicles 347 // Avatars don't do vehicles
338 public override int VehicleType { get { return 0; } set { return; } } 348 public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
339 public override void VehicleFloatParam(int param, float value) { } 349 public override void VehicleFloatParam(int param, float value) { }
340 public override void VehicleVectorParam(int param, OMV.Vector3 value) {} 350 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
341 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } 351 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
@@ -413,7 +423,7 @@ public class BSCharacter : BSPhysObject
413 }); 423 });
414 } 424 }
415 } 425 }
416 // Go directly to Bullet to get/set the value. 426 // Go directly to Bullet to get/set the value.
417 public override OMV.Quaternion ForceOrientation 427 public override OMV.Quaternion ForceOrientation
418 { 428 {
419 get 429 get
@@ -478,7 +488,7 @@ public class BSCharacter : BSPhysObject
478 set { _collidingObj = value; } 488 set { _collidingObj = value; }
479 } 489 }
480 public override bool FloatOnWater { 490 public override bool FloatOnWater {
481 set { 491 set {
482 _floatOnWater = value; 492 _floatOnWater = value;
483 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 493 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
484 { 494 {
@@ -588,9 +598,8 @@ public class BSCharacter : BSPhysObject
588 newScale.X = PhysicsScene.Params.avatarCapsuleRadius; 598 newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
589 newScale.Y = PhysicsScene.Params.avatarCapsuleRadius; 599 newScale.Y = PhysicsScene.Params.avatarCapsuleRadius;
590 600
591 // From the total height, remote the capsule half spheres that are at each end 601 // From the total height, remove the capsule half spheres that are at each end
592 newScale.Z = (size.Z * 2f) - Math.Min(newScale.X, newScale.Y); 602 newScale.Z = size.Z- (newScale.X + newScale.Y);
593 // newScale.Z = (size.Z * 2f);
594 Scale = newScale; 603 Scale = newScale;
595 } 604 }
596 605
@@ -636,7 +645,7 @@ public class BSCharacter : BSPhysObject
636 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel); 645 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel);
637 } 646 }
638 647
639 // Tell the linkset about this 648 // Tell the linkset about value changes
640 Linkset.UpdateProperties(this); 649 Linkset.UpdateProperties(this);
641 650
642 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 651 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index a20be3a..f017cdd 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -34,6 +34,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
34 34
35public abstract class BSConstraint : IDisposable 35public abstract class BSConstraint : IDisposable
36{ 36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38
37 protected BulletSim m_world; 39 protected BulletSim m_world;
38 protected BulletBody m_body1; 40 protected BulletBody m_body1;
39 protected BulletBody m_body2; 41 protected BulletBody m_body2;
@@ -53,7 +55,7 @@ public abstract class BSConstraint : IDisposable
53 { 55 {
54 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); 56 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
55 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", 57 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
56 BSScene.DetailLogZero, 58 BSScene.DetailLogZero,
57 m_body1.ID, m_body1.ptr.ToString("X"), 59 m_body1.ID, m_body1.ptr.ToString("X"),
58 m_body2.ID, m_body2.ptr.ToString("X"), 60 m_body2.ID, m_body2.ptr.ToString("X"),
59 success); 61 success);
@@ -124,7 +126,7 @@ public abstract class BSConstraint : IDisposable
124 } 126 }
125 else 127 else
126 { 128 {
127 m_world.physicsScene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID); 129 m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
128 } 130 }
129 } 131 }
130 return ret; 132 return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 56342b8..117c878 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -23,7 +23,7 @@
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 *
27 27
28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to 28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
29 * call the BulletSim system. 29 * call the BulletSim system.
@@ -352,7 +352,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
352 // m_bankingMix = 1; 352 // m_bankingMix = 1;
353 // m_bankingTimescale = 1; 353 // m_bankingTimescale = 1;
354 // m_referenceFrame = Quaternion.Identity; 354 // m_referenceFrame = Quaternion.Identity;
355 m_flags |= (VehicleFlag.NO_DEFLECTION_UP 355 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
356 | VehicleFlag.LIMIT_ROLL_ONLY 356 | VehicleFlag.LIMIT_ROLL_ONLY
357 | VehicleFlag.LIMIT_MOTOR_UP); 357 | VehicleFlag.LIMIT_MOTOR_UP);
358 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); 358 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
@@ -382,7 +382,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
382 // m_bankingTimescale = 1; 382 // m_bankingTimescale = 1;
383 // m_referenceFrame = Quaternion.Identity; 383 // m_referenceFrame = Quaternion.Identity;
384 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY 384 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
385 | VehicleFlag.HOVER_GLOBAL_HEIGHT 385 | VehicleFlag.HOVER_GLOBAL_HEIGHT
386 | VehicleFlag.LIMIT_ROLL_ONLY 386 | VehicleFlag.LIMIT_ROLL_ONLY
387 | VehicleFlag.HOVER_UP_ONLY); 387 | VehicleFlag.HOVER_UP_ONLY);
388 m_flags |= (VehicleFlag.NO_DEFLECTION_UP 388 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
@@ -458,14 +458,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
458 // Do any updating needed for a vehicle 458 // Do any updating needed for a vehicle
459 public void Refresh() 459 public void Refresh()
460 { 460 {
461 if (!IsActive) 461 if (!IsActive)
462 return; 462 return;
463 463
464 // Set the prim's inertia to zero. The vehicle code handles that and this 464 // Set the prim's inertia to zero. The vehicle code handles that and this
465 // removes the motion and torque actions introduced by Bullet. 465 // removes the motion and torque actions introduced by Bullet.
466 Vector3 inertia = Vector3.Zero; 466 Vector3 inertia = Vector3.Zero;
467 BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia); 467 // comment out for DEBUG test
468 BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr); 468 // BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
469 // BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
469 } 470 }
470 471
471 // One step of the vehicle properties for the next 'pTimestep' seconds. 472 // One step of the vehicle properties for the next 'pTimestep' seconds.
@@ -791,7 +792,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
791 792
792 // Sum velocities 793 // Sum velocities
793 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection 794 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
794 795
795 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 796 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
796 { 797 {
797 m_lastAngularVelocity.X = 0; 798 m_lastAngularVelocity.X = 0;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 43b1262..c984824 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -32,10 +32,27 @@ using OMV = OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35public class BSLinkset 35public abstract class BSLinkset
36{ 36{
37 // private static string LogHeader = "[BULLETSIM LINKSET]"; 37 // private static string LogHeader = "[BULLETSIM LINKSET]";
38 38
39 // Create the correct type of linkset for this child
40 public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
41 {
42 BSLinkset ret = null;
43 /*
44 if (parent.IsPhysical)
45 ret = new BSLinksetConstraints(physScene, parent);
46 else
47 ret = new BSLinksetManual(physScene, parent);
48 */
49
50 // at the moment, there is only one
51 ret = new BSLinksetConstraints(physScene, parent);
52
53 return ret;
54 }
55
39 public BSPhysObject LinksetRoot { get; protected set; } 56 public BSPhysObject LinksetRoot { get; protected set; }
40 57
41 public BSScene PhysicsScene { get; private set; } 58 public BSScene PhysicsScene { get; private set; }
@@ -52,16 +69,16 @@ public class BSLinkset
52 // the physical 'taint' children separately. 69 // the physical 'taint' children separately.
53 // After taint processing and before the simulation step, these 70 // After taint processing and before the simulation step, these
54 // two lists must be the same. 71 // two lists must be the same.
55 private HashSet<BSPhysObject> m_children; 72 protected HashSet<BSPhysObject> m_children;
56 private HashSet<BSPhysObject> m_taintChildren; 73 protected HashSet<BSPhysObject> m_taintChildren;
57 74
58 // We lock the diddling of linkset classes to prevent any badness. 75 // We lock the diddling of linkset classes to prevent any badness.
59 // This locks the modification of the instances of this class. Changes 76 // This locks the modification of the instances of this class. Changes
60 // to the physical representation is done via the tainting mechenism. 77 // to the physical representation is done via the tainting mechenism.
61 private object m_linksetActivityLock = new Object(); 78 protected object m_linksetActivityLock = new Object();
62 79
63 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 80 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
64 private float m_mass; 81 protected float m_mass;
65 public float LinksetMass 82 public float LinksetMass
66 { 83 {
67 get 84 get
@@ -81,7 +98,7 @@ public class BSLinkset
81 get { return ComputeLinksetGeometricCenter(); } 98 get { return ComputeLinksetGeometricCenter(); }
82 } 99 }
83 100
84 public BSLinkset(BSScene scene, BSPhysObject parent) 101 protected void Initialize(BSScene scene, BSPhysObject parent)
85 { 102 {
86 // A simple linkset of one (no children) 103 // A simple linkset of one (no children)
87 LinksetID = m_nextLinksetID++; 104 LinksetID = m_nextLinksetID++;
@@ -128,7 +145,7 @@ public class BSLinkset
128 } 145 }
129 146
130 // The child is down to a linkset of just itself 147 // The child is down to a linkset of just itself
131 return new BSLinkset(PhysicsScene, child); 148 return BSLinkset.Factory(PhysicsScene, child);
132 } 149 }
133 150
134 // Return 'true' if the passed object is the root object of this linkset 151 // Return 'true' if the passed object is the root object of this linkset
@@ -148,6 +165,9 @@ public class BSLinkset
148 bool ret = false; 165 bool ret = false;
149 lock (m_linksetActivityLock) 166 lock (m_linksetActivityLock)
150 { 167 {
168 if (m_children.Contains(child))
169 ret = true;
170 /*
151 foreach (BSPhysObject bp in m_children) 171 foreach (BSPhysObject bp in m_children)
152 { 172 {
153 if (child.LocalID == bp.LocalID) 173 if (child.LocalID == bp.LocalID)
@@ -156,6 +176,7 @@ public class BSLinkset
156 break; 176 break;
157 } 177 }
158 } 178 }
179 */
159 } 180 }
160 return ret; 181 return ret;
161 } 182 }
@@ -163,24 +184,7 @@ public class BSLinkset
163 // When physical properties are changed the linkset needs to recalculate 184 // When physical properties are changed the linkset needs to recalculate
164 // its internal properties. 185 // its internal properties.
165 // May be called at runtime or taint-time (just pass the appropriate flag). 186 // May be called at runtime or taint-time (just pass the appropriate flag).
166 public void Refresh(BSPhysObject requestor, bool inTaintTime) 187 public abstract void Refresh(BSPhysObject requestor, bool inTaintTime);
167 {
168 // If there are no children, not physical or not root, I am not the one that recomputes the constraints
169 // (For the moment, static linksets do create constraints so remove the test for physical.)
170 if (!HasAnyChildren || /*!requestor.IsPhysical ||*/ !IsRoot(requestor))
171 return;
172
173 BSScene.TaintCallback refreshOperation = delegate()
174 {
175 RecomputeLinksetConstraintVariables();
176 DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
177 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
178 };
179 if (inTaintTime)
180 refreshOperation();
181 else
182 PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
183 }
184 188
185 // The object is going dynamic (physical). Do any setup necessary 189 // The object is going dynamic (physical). Do any setup necessary
186 // for a dynamic linkset. 190 // for a dynamic linkset.
@@ -188,102 +192,35 @@ public class BSLinkset
188 // has not yet been fully constructed. 192 // has not yet been fully constructed.
189 // Return 'true' if any properties updated on the passed object. 193 // Return 'true' if any properties updated on the passed object.
190 // Called at taint-time! 194 // Called at taint-time!
191 public bool MakeDynamic(BSPhysObject child) 195 public abstract bool MakeDynamic(BSPhysObject child);
192 {
193 // What is done for each object in BSPrim is what we want.
194 return false;
195 }
196 196
197 // The object is going static (non-physical). Do any setup necessary 197 // The object is going static (non-physical). Do any setup necessary
198 // for a static linkset. 198 // for a static linkset.
199 // Return 'true' if any properties updated on the passed object. 199 // Return 'true' if any properties updated on the passed object.
200 // Called at taint-time! 200 // Called at taint-time!
201 public bool MakeStatic(BSPhysObject child) 201 public abstract bool MakeStatic(BSPhysObject child);
202 {
203 // What is done for each object in BSPrim is what we want.
204 return false;
205 }
206 202
207 // If the software is handling the movement of all the objects in a linkset 203 // Called when a parameter update comes from the physics engine for any object
208 // (like if one doesn't use constraints for static linksets), this is called 204 // of the linkset is received.
209 // when an update for the root of the linkset is received.
210 // Called at taint-time!! 205 // Called at taint-time!!
211 public void UpdateProperties(BSPhysObject physObject) 206 public abstract void UpdateProperties(BSPhysObject physObject);
212 {
213 // The root local properties have been updated. Apply to the children if appropriate.
214 if (IsRoot(physObject) && HasAnyChildren)
215 {
216 if (!physObject.IsPhysical)
217 {
218 // TODO: implement software linkset update for static object linksets
219 }
220 }
221 }
222 207
223 // Routine used when rebuilding the body of the root of the linkset 208 // Routine used when rebuilding the body of the root of the linkset
224 // Destroy all the constraints have have been made to root. 209 // Destroy all the constraints have have been made to root.
225 // This is called when the root body is changing. 210 // This is called when the root body is changing.
226 // Returns 'true' of something eas actually removed and would need restoring 211 // Returns 'true' of something was actually removed and would need restoring
227 // Called at taint-time!! 212 // Called at taint-time!!
228 public bool RemoveBodyDependencies(BSPrim child) 213 public abstract bool RemoveBodyDependencies(BSPrim child);
229 {
230 bool ret = false;
231
232 lock (m_linksetActivityLock)
233 {
234 if (IsRoot(child))
235 {
236 // If the one with the dependency is root, must undo all children
237 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
238 child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
239
240 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
241 }
242 else
243 {
244 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
245 child.LocalID,
246 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
247 child.LocalID, child.BSBody.ptr.ToString("X"));
248 // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
249 // Despite the function name, this removes any link to the specified object.
250 ret = PhysicallyUnlinkAllChildrenFromRoot(child);
251 }
252 }
253 return ret;
254 }
255 214
256 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 215 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
257 // this routine will restore the removed constraints. 216 // this routine will restore the removed constraints.
258 // Called at taint-time!! 217 // Called at taint-time!!
259 public void RestoreBodyDependencies(BSPrim child) 218 public abstract void RestoreBodyDependencies(BSPrim child);
260 {
261 lock (m_linksetActivityLock)
262 {
263 if (IsRoot(child))
264 {
265 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
266 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
267 foreach (BSPhysObject bpo in m_taintChildren)
268 {
269 PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
270 }
271 }
272 else
273 {
274 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
275 LinksetRoot.LocalID,
276 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
277 child.LocalID, child.BSBody.ptr.ToString("X"));
278 PhysicallyLinkAChildToRoot(LinksetRoot, child);
279 }
280 }
281 }
282 219
283 // ================================================================ 220 // ================================================================
284 // Below this point is internal magic 221 // Below this point is internal magic
285 222
286 private float ComputeLinksetMass() 223 protected virtual float ComputeLinksetMass()
287 { 224 {
288 float mass; 225 float mass;
289 lock (m_linksetActivityLock) 226 lock (m_linksetActivityLock)
@@ -297,7 +234,7 @@ public class BSLinkset
297 return mass; 234 return mass;
298 } 235 }
299 236
300 private OMV.Vector3 ComputeLinksetCenterOfMass() 237 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
301 { 238 {
302 OMV.Vector3 com; 239 OMV.Vector3 com;
303 lock (m_linksetActivityLock) 240 lock (m_linksetActivityLock)
@@ -317,7 +254,7 @@ public class BSLinkset
317 return com; 254 return com;
318 } 255 }
319 256
320 private OMV.Vector3 ComputeLinksetGeometricCenter() 257 protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
321 { 258 {
322 OMV.Vector3 com; 259 OMV.Vector3 com;
323 lock (m_linksetActivityLock) 260 lock (m_linksetActivityLock)
@@ -336,236 +273,21 @@ public class BSLinkset
336 273
337 // I am the root of a linkset and a new child is being added 274 // I am the root of a linkset and a new child is being added
338 // Called while LinkActivity is locked. 275 // Called while LinkActivity is locked.
339 private void AddChildToLinkset(BSPhysObject child) 276 protected abstract void AddChildToLinkset(BSPhysObject child);
340 {
341 if (!HasChild(child))
342 {
343 m_children.Add(child);
344
345 BSPhysObject rootx = LinksetRoot; // capture the root as of now
346 BSPhysObject childx = child;
347
348 DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
349
350 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
351 {
352 DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
353 rootx.LocalID,
354 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
355 childx.LocalID, childx.BSBody.ptr.ToString("X"));
356 // Since this is taint-time, the body and shape could have changed for the child
357 rootx.ForcePosition = rootx.Position; // DEBUG
358 childx.ForcePosition = childx.Position; // DEBUG
359 PhysicallyLinkAChildToRoot(rootx, childx);
360 m_taintChildren.Add(child);
361 });
362 }
363 return;
364 }
365 277
366 // Forcefully removing a child from a linkset. 278 // Forcefully removing a child from a linkset.
367 // This is not being called by the child so we have to make sure the child doesn't think 279 // This is not being called by the child so we have to make sure the child doesn't think
368 // it's still connected to the linkset. 280 // it's still connected to the linkset.
369 // Normal OpenSimulator operation will never do this because other SceneObjectPart information 281 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
370 // also has to be updated (like pointer to prim's parent). 282 // also has to be updated (like pointer to prim's parent).
371 private void RemoveChildFromOtherLinkset(BSPhysObject pchild) 283 protected abstract void RemoveChildFromOtherLinkset(BSPhysObject pchild);
372 {
373 pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
374 RemoveChildFromLinkset(pchild);
375 }
376 284
377 // I am the root of a linkset and one of my children is being removed. 285 // I am the root of a linkset and one of my children is being removed.
378 // Safe to call even if the child is not really in my linkset. 286 // Safe to call even if the child is not really in my linkset.
379 private void RemoveChildFromLinkset(BSPhysObject child) 287 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
380 {
381 if (m_children.Remove(child))
382 {
383 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
384 BSPhysObject childx = child;
385
386 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
387 childx.LocalID,
388 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
389 childx.LocalID, childx.BSBody.ptr.ToString("X"));
390
391 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
392 {
393 m_taintChildren.Remove(child);
394 PhysicallyUnlinkAChildFromRoot(rootx, childx);
395 RecomputeLinksetConstraintVariables();
396 });
397
398 }
399 else
400 {
401 // This will happen if we remove the root of the linkset first. Non-fatal occurance.
402 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
403 }
404 return;
405 }
406
407 // Create a constraint between me (root of linkset) and the passed prim (the child).
408 // Called at taint time!
409 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
410 {
411 // Zero motion for children so they don't interpolate
412 childPrim.ZeroMotion();
413
414 // Relative position normalized to the root prim
415 // Essentually a vector pointing from center of rootPrim to center of childPrim
416 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
417
418 // real world coordinate of midpoint between the two objects
419 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
420
421 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
422 rootPrim.LocalID,
423 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
424 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
425 rootPrim.Position, childPrim.Position, midPoint);
426
427 // create a constraint that allows no freedom of movement between the two objects
428 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
429
430 BS6DofConstraint constrain = new BS6DofConstraint(
431 PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
432
433 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
434 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
435 * of the objects.
436 * Code left as a warning to future programmers.
437 // ==================================================================================
438 // relative position normalized to the root prim
439 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
440 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
441
442 // relative rotation of the child to the parent
443 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
444 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
445
446 // create a constraint that allows no freedom of movement between the two objects
447 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
448 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
449 BS6DofConstraint constrain = new BS6DofConstraint(
450 PhysicsScene.World, rootPrim.Body, childPrim.Body,
451 OMV.Vector3.Zero,
452 OMV.Quaternion.Inverse(rootPrim.Orientation),
453 OMV.Vector3.Zero,
454 OMV.Quaternion.Inverse(childPrim.Orientation),
455 // A point half way between the parent and child
456 // childRelativePosition/2,
457 // childRelativeRotation,
458 // childRelativePosition/2,
459 // inverseChildRelativeRotation,
460 true,
461 true
462 );
463 // ==================================================================================
464 */
465
466 PhysicsScene.Constraints.AddConstraint(constrain);
467
468 // zero linear and angular limits makes the objects unable to move in relation to each other
469 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
470 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
471
472 // tweek the constraint to increase stability
473 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
474 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
475 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
476 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
477 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
478 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
479 {
480 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
481 }
482 }
483
484 // Remove linkage between myself and a particular child
485 // The root and child bodies are passed in because we need to remove the constraint between
486 // the bodies that were at unlink time.
487 // Called at taint time!
488 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
489 {
490 bool ret = false;
491 DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
492 rootPrim.LocalID,
493 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
494 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
495
496 // Find the constraint for this link and get rid of it from the overall collection and from my list
497 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
498 {
499 // Make the child refresh its location
500 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
501 ret = true;
502 }
503
504 return ret;
505 }
506
507 // Remove linkage between myself and any possible children I might have.
508 // Called at taint time!
509 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
510 {
511 DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
512 bool ret = false;
513
514 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
515 {
516 ret = true;
517 }
518 return ret;
519 }
520
521 // Call each of the constraints that make up this linkset and recompute the
522 // various transforms and variables. Used when objects are added or removed
523 // from a linkset to make sure the constraints know about the new mass and
524 // geometry.
525 // Must only be called at taint time!!
526 private void RecomputeLinksetConstraintVariables()
527 {
528 float linksetMass = LinksetMass;
529 foreach (BSPhysObject child in m_taintChildren)
530 {
531 BSConstraint constrain;
532 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
533 {
534 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
535 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
536 constrain.RecomputeConstraintVariables(linksetMass);
537 }
538 else
539 {
540 // Non-fatal error that happens when children are being added to the linkset but
541 // their constraints have not been created yet.
542 break;
543 }
544 }
545
546 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
547 if (m_children.Count == m_taintChildren.Count)
548 {
549 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
550 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
551 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
552 centerOfMass, OMV.Quaternion.Identity);
553 DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
554 LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
555 foreach (BSPhysObject child in m_taintChildren)
556 {
557 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
558 centerOfMass, OMV.Quaternion.Identity);
559 }
560
561 // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
562 }
563 return;
564 }
565
566 288
567 // Invoke the detailed logger and output something if it's enabled. 289 // Invoke the detailed logger and output something if it's enabled.
568 private void DetailLog(string msg, params Object[] args) 290 protected void DetailLog(string msg, params Object[] args)
569 { 291 {
570 if (PhysicsScene.PhysicsLogging.Enabled) 292 if (PhysicsScene.PhysicsLogging.Enabled)
571 PhysicsScene.DetailLog(msg, args); 293 PhysicsScene.DetailLog(msg, args);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
new file mode 100755
index 0000000..8a750b5
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -0,0 +1,385 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public class BSLinksetConstraints : BSLinkset
36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent)
40 {
41 base.Initialize(scene, parent);
42 }
43
44 // When physical properties are changed the linkset needs to recalculate
45 // its internal properties.
46 // May be called at runtime or taint-time (just pass the appropriate flag).
47 public override void Refresh(BSPhysObject requestor, bool inTaintTime)
48 {
49 // If there are no children or not root, I am not the one that recomputes the constraints
50 if (!HasAnyChildren || !IsRoot(requestor))
51 return;
52
53 BSScene.TaintCallback refreshOperation = delegate()
54 {
55 RecomputeLinksetConstraintVariables();
56 DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
57 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
58 };
59 if (inTaintTime)
60 refreshOperation();
61 else
62 PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
63 }
64
65 // The object is going dynamic (physical). Do any setup necessary
66 // for a dynamic linkset.
67 // Only the state of the passed object can be modified. The rest of the linkset
68 // has not yet been fully constructed.
69 // Return 'true' if any properties updated on the passed object.
70 // Called at taint-time!
71 public override bool MakeDynamic(BSPhysObject child)
72 {
73 // What is done for each object in BSPrim is what we want.
74 return false;
75 }
76
77 // The object is going static (non-physical). Do any setup necessary
78 // for a static linkset.
79 // Return 'true' if any properties updated on the passed object.
80 // Called at taint-time!
81 public override bool MakeStatic(BSPhysObject child)
82 {
83 // What is done for each object in BSPrim is what we want.
84 return false;
85 }
86
87 // Called at taint-time!!
88 public override void UpdateProperties(BSPhysObject updated)
89 {
90 // Nothing to do for constraints on property updates
91 }
92
93 // Routine used when rebuilding the body of the root of the linkset
94 // Destroy all the constraints have have been made to root.
95 // This is called when the root body is changing.
96 // Returns 'true' of something eas actually removed and would need restoring
97 // Called at taint-time!!
98 public override bool RemoveBodyDependencies(BSPrim child)
99 {
100 bool ret = false;
101
102 lock (m_linksetActivityLock)
103 {
104 if (IsRoot(child))
105 {
106 // If the one with the dependency is root, must undo all children
107 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
108 child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
109
110 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
111 }
112 else
113 {
114 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
115 child.LocalID,
116 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
117 child.LocalID, child.BSBody.ptr.ToString("X"));
118 // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
119 // Despite the function name, this removes any link to the specified object.
120 ret = PhysicallyUnlinkAllChildrenFromRoot(child);
121 }
122 }
123 return ret;
124 }
125
126 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
127 // this routine will restore the removed constraints.
128 // Called at taint-time!!
129 public override void RestoreBodyDependencies(BSPrim child)
130 {
131 lock (m_linksetActivityLock)
132 {
133 if (IsRoot(child))
134 {
135 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
136 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
137 foreach (BSPhysObject bpo in m_taintChildren)
138 {
139 PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
140 }
141 }
142 else
143 {
144 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
145 LinksetRoot.LocalID,
146 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
147 child.LocalID, child.BSBody.ptr.ToString("X"));
148 PhysicallyLinkAChildToRoot(LinksetRoot, child);
149 }
150 }
151 }
152
153 // ================================================================
154 // Below this point is internal magic
155
156 // I am the root of a linkset and a new child is being added
157 // Called while LinkActivity is locked.
158 protected override void AddChildToLinkset(BSPhysObject child)
159 {
160 if (!HasChild(child))
161 {
162 m_children.Add(child);
163
164 BSPhysObject rootx = LinksetRoot; // capture the root as of now
165 BSPhysObject childx = child;
166
167 DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
168
169 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
170 {
171 DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
172 rootx.LocalID,
173 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
174 childx.LocalID, childx.BSBody.ptr.ToString("X"));
175 // Since this is taint-time, the body and shape could have changed for the child
176 rootx.ForcePosition = rootx.Position; // DEBUG
177 childx.ForcePosition = childx.Position; // DEBUG
178 PhysicallyLinkAChildToRoot(rootx, childx);
179 m_taintChildren.Add(child);
180 });
181 }
182 return;
183 }
184
185 // Forcefully removing a child from a linkset.
186 // This is not being called by the child so we have to make sure the child doesn't think
187 // it's still connected to the linkset.
188 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
189 // also has to be updated (like pointer to prim's parent).
190 protected override void RemoveChildFromOtherLinkset(BSPhysObject pchild)
191 {
192 pchild.Linkset = BSLinkset.Factory(PhysicsScene, pchild);
193 RemoveChildFromLinkset(pchild);
194 }
195
196 // I am the root of a linkset and one of my children is being removed.
197 // Safe to call even if the child is not really in my linkset.
198 protected override void RemoveChildFromLinkset(BSPhysObject child)
199 {
200 if (m_children.Remove(child))
201 {
202 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
203 BSPhysObject childx = child;
204
205 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
206 childx.LocalID,
207 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
208 childx.LocalID, childx.BSBody.ptr.ToString("X"));
209
210 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
211 {
212 m_taintChildren.Remove(child);
213 PhysicallyUnlinkAChildFromRoot(rootx, childx);
214 RecomputeLinksetConstraintVariables();
215 });
216
217 }
218 else
219 {
220 // This will happen if we remove the root of the linkset first. Non-fatal occurance.
221 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
222 }
223 return;
224 }
225
226 // Create a constraint between me (root of linkset) and the passed prim (the child).
227 // Called at taint time!
228 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
229 {
230 // Zero motion for children so they don't interpolate
231 childPrim.ZeroMotion();
232
233 // Relative position normalized to the root prim
234 // Essentually a vector pointing from center of rootPrim to center of childPrim
235 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
236
237 // real world coordinate of midpoint between the two objects
238 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
239
240 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
241 rootPrim.LocalID,
242 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
243 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
244 rootPrim.Position, childPrim.Position, midPoint);
245
246 // create a constraint that allows no freedom of movement between the two objects
247 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
248
249 BS6DofConstraint constrain = new BS6DofConstraint(
250 PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
251
252 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
253 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
254 * of the objects.
255 * Code left as a warning to future programmers.
256 // ==================================================================================
257 // relative position normalized to the root prim
258 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
259 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
260
261 // relative rotation of the child to the parent
262 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
263 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
264
265 // create a constraint that allows no freedom of movement between the two objects
266 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
267 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
268 BS6DofConstraint constrain = new BS6DofConstraint(
269 PhysicsScene.World, rootPrim.Body, childPrim.Body,
270 OMV.Vector3.Zero,
271 OMV.Quaternion.Inverse(rootPrim.Orientation),
272 OMV.Vector3.Zero,
273 OMV.Quaternion.Inverse(childPrim.Orientation),
274 // A point half way between the parent and child
275 // childRelativePosition/2,
276 // childRelativeRotation,
277 // childRelativePosition/2,
278 // inverseChildRelativeRotation,
279 true,
280 true
281 );
282 // ==================================================================================
283 */
284
285 PhysicsScene.Constraints.AddConstraint(constrain);
286
287 // zero linear and angular limits makes the objects unable to move in relation to each other
288 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
289 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
290
291 // tweek the constraint to increase stability
292 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
293 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
294 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
295 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
296 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
297 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
298 {
299 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
300 }
301 }
302
303 // Remove linkage between myself and a particular child
304 // The root and child bodies are passed in because we need to remove the constraint between
305 // the bodies that were at unlink time.
306 // Called at taint time!
307 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
308 {
309 bool ret = false;
310 DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
311 rootPrim.LocalID,
312 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
313 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
314
315 // Find the constraint for this link and get rid of it from the overall collection and from my list
316 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
317 {
318 // Make the child refresh its location
319 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
320 ret = true;
321 }
322
323 return ret;
324 }
325
326 // Remove linkage between myself and any possible children I might have.
327 // Called at taint time!
328 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
329 {
330 DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
331 bool ret = false;
332
333 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
334 {
335 ret = true;
336 }
337 return ret;
338 }
339
340 // Call each of the constraints that make up this linkset and recompute the
341 // various transforms and variables. Used when objects are added or removed
342 // from a linkset to make sure the constraints know about the new mass and
343 // geometry.
344 // Must only be called at taint time!!
345 private void RecomputeLinksetConstraintVariables()
346 {
347 float linksetMass = LinksetMass;
348 foreach (BSPhysObject child in m_taintChildren)
349 {
350 BSConstraint constrain;
351 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
352 {
353 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
354 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
355 constrain.RecomputeConstraintVariables(linksetMass);
356 }
357 else
358 {
359 // Non-fatal error that happens when children are being added to the linkset but
360 // their constraints have not been created yet.
361 break;
362 }
363 }
364
365 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
366 if (m_children.Count == m_taintChildren.Count)
367 {
368 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
369 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
370 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
371 centerOfMass, OMV.Quaternion.Identity);
372 DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
373 LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
374 foreach (BSPhysObject child in m_taintChildren)
375 {
376 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
377 centerOfMass, OMV.Quaternion.Identity);
378 }
379
380 // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
381 }
382 return;
383 }
384}
385}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index ead6a08..538f905 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -46,7 +46,7 @@ public abstract class BSPhysObject : PhysicsActor
46 PhysObjectName = name; 46 PhysObjectName = name;
47 TypeName = typeName; 47 TypeName = typeName;
48 48
49 Linkset = new BSLinkset(PhysicsScene, this); 49 Linkset = BSLinkset.Factory(PhysicsScene, this);
50 LastAssetBuildFailed = false; 50 LastAssetBuildFailed = false;
51 51
52 CollisionCollection = new CollisionEventUpdate(); 52 CollisionCollection = new CollisionEventUpdate();
@@ -78,7 +78,7 @@ public abstract class BSPhysObject : PhysicsActor
78 public PrimitiveBaseShape BaseShape { get; protected set; } 78 public PrimitiveBaseShape BaseShape { get; protected set; }
79 79
80 // When the physical properties are updated, an EntityProperty holds the update values. 80 // When the physical properties are updated, an EntityProperty holds the update values.
81 // Keep the current and last EntityProperties to enable computation of differences 81 // Keep the current and last EntityProperties to enable computation of differences
82 // between the current update and the previous values. 82 // between the current update and the previous values.
83 public EntityProperties CurrentEntityProperties { get; set; } 83 public EntityProperties CurrentEntityProperties { get; set; }
84 public EntityProperties LastEntityProperties { get; set; } 84 public EntityProperties LastEntityProperties { get; set; }
@@ -213,7 +213,7 @@ public abstract class BSPhysObject : PhysicsActor
213 UnSubscribeEvents(); 213 UnSubscribeEvents();
214 } 214 }
215 } 215 }
216 public override void UnSubscribeEvents() { 216 public override void UnSubscribeEvents() {
217 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); 217 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
218 SubscribedEventsMs = 0; 218 SubscribedEventsMs = 0;
219 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 219 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
@@ -222,7 +222,7 @@ public abstract class BSPhysObject : PhysicsActor
222 }); 222 });
223 } 223 }
224 // Return 'true' if the simulator wants collision events 224 // Return 'true' if the simulator wants collision events
225 public override bool SubscribedEvents() { 225 public override bool SubscribedEvents() {
226 return (SubscribedEventsMs > 0); 226 return (SubscribedEventsMs > 0);
227 } 227 }
228 228
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index aeeb4dd..38ab3de 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -173,6 +173,7 @@ public sealed class BSPrim : BSPhysObject
173 } 173 }
174 public override bool ForceBodyShapeRebuild(bool inTaintTime) 174 public override bool ForceBodyShapeRebuild(bool inTaintTime)
175 { 175 {
176 LastAssetBuildFailed = false;
176 BSScene.TaintCallback rebuildOperation = delegate() 177 BSScene.TaintCallback rebuildOperation = delegate()
177 { 178 {
178 _mass = CalculateMass(); // changing the shape changes the mass 179 _mass = CalculateMass(); // changing the shape changes the mass
@@ -295,7 +296,7 @@ public sealed class BSPrim : BSPhysObject
295 private bool PositionSanityCheck() 296 private bool PositionSanityCheck()
296 { 297 {
297 bool ret = false; 298 bool ret = false;
298 299
299 // If totally below the ground, move the prim up 300 // If totally below the ground, move the prim up
300 // TODO: figure out the right solution for this... only for dynamic objects? 301 // TODO: figure out the right solution for this... only for dynamic objects?
301 /* 302 /*
@@ -398,7 +399,7 @@ public sealed class BSPrim : BSPhysObject
398 { 399 {
399 // Done at taint time so we're sure the physics engine is not using the variables 400 // Done at taint time so we're sure the physics engine is not using the variables
400 // Vehicle code changes the parameters for this vehicle type. 401 // Vehicle code changes the parameters for this vehicle type.
401 this._vehicle.ProcessTypeChange(type); 402 _vehicle.ProcessTypeChange(type);
402 }); 403 });
403 } 404 }
404 } 405 }
@@ -510,7 +511,7 @@ public sealed class BSPrim : BSPhysObject
510 }); 511 });
511 } 512 }
512 } 513 }
513 // Go directly to Bullet to get/set the value. 514 // Go directly to Bullet to get/set the value.
514 public override OMV.Quaternion ForceOrientation 515 public override OMV.Quaternion ForceOrientation
515 { 516 {
516 get 517 get
@@ -768,7 +769,7 @@ public sealed class BSPrim : BSPhysObject
768 } 769 }
769 } 770 }
770 public override bool FloatOnWater { 771 public override bool FloatOnWater {
771 set { 772 set {
772 _floatOnWater = value; 773 _floatOnWater = value;
773 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 774 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
774 { 775 {
@@ -971,7 +972,7 @@ public sealed class BSPrim : BSPhysObject
971 if (hollowAmount > 0.0) 972 if (hollowAmount > 0.0)
972 { 973 {
973 hollowVolume *= hollowAmount; 974 hollowVolume *= hollowAmount;
974 975
975 switch (BaseShape.HollowShape) 976 switch (BaseShape.HollowShape)
976 { 977 {
977 case HollowShape.Square: 978 case HollowShape.Square:
@@ -1245,13 +1246,14 @@ public sealed class BSPrim : BSPhysObject
1245 FillShapeInfo(out shapeData); 1246 FillShapeInfo(out shapeData);
1246 1247
1247 // If this prim is part of a linkset, we must remove and restore the physical 1248 // If this prim is part of a linkset, we must remove and restore the physical
1248 // links of the body is rebuilt. 1249 // links if the body is rebuilt.
1249 bool needToRestoreLinkset = false; 1250 bool needToRestoreLinkset = false;
1250 1251
1251 // Create the correct physical representation for this type of object. 1252 // Create the correct physical representation for this type of object.
1252 // Updates BSBody and BSShape with the new information. 1253 // Updates BSBody and BSShape with the new information.
1253 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1254 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1254 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape, 1255 // Returns 'true' if either the body or the shape was changed.
1256 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
1255 null, delegate(BulletBody dBody) 1257 null, delegate(BulletBody dBody)
1256 { 1258 {
1257 // Called if the current prim body is about to be destroyed. 1259 // Called if the current prim body is about to be destroyed.
@@ -1354,7 +1356,7 @@ public sealed class BSPrim : BSPhysObject
1354 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1356 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1355 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1357 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1356 1358
1357 // BulletSimAPI.DumpRigidBody2(Scene.World.Ptr, BSBody.Ptr); 1359 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
1358 1360
1359 base.RequestPhysicsterseUpdate(); 1361 base.RequestPhysicsterseUpdate();
1360 } 1362 }
@@ -1367,8 +1369,8 @@ public sealed class BSPrim : BSPhysObject
1367 entprop.Acceleration, entprop.RotationalVelocity); 1369 entprop.Acceleration, entprop.RotationalVelocity);
1368 } 1370 }
1369 */ 1371 */
1370 // The linkset implimentation might want to know about this.
1371 1372
1373 // The linkset implimentation might want to know about this.
1372 Linkset.UpdateProperties(this); 1374 Linkset.UpdateProperties(this);
1373 } 1375 }
1374} 1376}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 6621d39..db0c99e 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -320,7 +320,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
320 { 320 {
321 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 321 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
322 } 322 }
323 323
324 // Called directly from unmanaged code so don't do much 324 // Called directly from unmanaged code so don't do much
325 private void BulletLoggerPhysLog(string msg) 325 private void BulletLoggerPhysLog(string msg)
326 { 326 {
@@ -545,7 +545,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
545 } 545 }
546 546
547 // This is a kludge to get avatar movement updates. 547 // This is a kludge to get avatar movement updates.
548 // The simulator expects collisions for avatars even if there are have been no collisions. 548 // The simulator expects collisions for avatars even if there are have been no collisions.
549 // The event updates avatar animations and stuff. 549 // The event updates avatar animations and stuff.
550 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. 550 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
551 foreach (BSPhysObject bsp in m_avatars) 551 foreach (BSPhysObject bsp in m_avatars)
@@ -692,7 +692,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
692 { 692 {
693 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process 693 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
694 { 694 {
695 // swizzle a new list into the list location so we can process what's there
696 int taintCount = m_taintsToProcessPerStep; 695 int taintCount = m_taintsToProcessPerStep;
697 TaintCallbackEntry oneCallback = new TaintCallbackEntry(); 696 TaintCallbackEntry oneCallback = new TaintCallbackEntry();
698 while (_taintedObjects.Count > 0 && taintCount-- > 0) 697 while (_taintedObjects.Count > 0 && taintCount-- > 0)
@@ -711,11 +710,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
711 { 710 {
712 try 711 try
713 { 712 {
714 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG 713 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident);
715 oneCallback.callback(); 714 oneCallback.callback();
716 } 715 }
717 catch (Exception e) 716 catch (Exception e)
718 { 717 {
718 DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
719 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e); 719 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
720 } 720 }
721 } 721 }
@@ -1333,7 +1333,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1333 // Add the Flush() if debugging crashes to get all the messages written out. 1333 // Add the Flush() if debugging crashes to get all the messages written out.
1334 // PhysicsLogging.Flush(); 1334 // PhysicsLogging.Flush();
1335 } 1335 }
1336 // used to fill in the LocalID when there isn't one 1336 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1337 public const string DetailLogZero = "0000000000"; 1337 public const string DetailLogZero = "0000000000";
1338 1338
1339} 1339}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index d3ba273..30fa50a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -36,7 +36,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSShapeCollection : IDisposable 37public class BSShapeCollection : IDisposable
38{ 38{
39 // private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; 39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40 40
41 protected BSScene PhysicsScene { get; set; } 41 protected BSScene PhysicsScene { get; set; }
42 42
@@ -89,7 +89,7 @@ public class BSShapeCollection : IDisposable
89 // higher level dependencies on the shape or body. Mostly used for LinkSets to 89 // higher level dependencies on the shape or body. Mostly used for LinkSets to
90 // remove the physical constraints before the body is destroyed. 90 // remove the physical constraints before the body is destroyed.
91 // Called at taint-time!! 91 // Called at taint-time!!
92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, 92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
93 ShapeData shapeData, PrimitiveBaseShape pbs, 93 ShapeData shapeData, PrimitiveBaseShape pbs,
94 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 94 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
95 { 95 {
@@ -105,7 +105,7 @@ public class BSShapeCollection : IDisposable
105 // If we had to select a new shape geometry for the object, 105 // If we had to select a new shape geometry for the object,
106 // rebuild the body around it. 106 // rebuild the body around it.
107 // Updates prim.BSBody with information/pointers to requested body 107 // Updates prim.BSBody with information/pointers to requested body
108 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, 108 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
109 prim.BSShape, shapeData, bodyCallback); 109 prim.BSShape, shapeData, bodyCallback);
110 ret = newGeom || newBody; 110 ret = newGeom || newBody;
111 } 111 }
@@ -325,7 +325,7 @@ public class BSShapeCollection : IDisposable
325 // Info in prim.BSShape is updated to the new shape. 325 // Info in prim.BSShape is updated to the new shape.
326 // Returns 'true' if the geometry was rebuilt. 326 // Returns 'true' if the geometry was rebuilt.
327 // Called at taint-time! 327 // Called at taint-time!
328 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData, 328 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
329 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback) 329 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
330 { 330 {
331 bool ret = false; 331 bool ret = false;
@@ -335,9 +335,10 @@ public class BSShapeCollection : IDisposable
335 if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 335 if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
336 { 336 {
337 // an avatar capsule is close to a native shape (it is not shared) 337 // an avatar capsule is close to a native shape (it is not shared)
338 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR, 338 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
339 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback); 339 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
340 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape); 340 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
341 ret = true;
341 haveShape = true; 342 haveShape = true;
342 } 343 }
343 // If the prim attributes are simple, this could be a simple Bullet native shape 344 // If the prim attributes are simple, this could be a simple Bullet native shape
@@ -362,7 +363,7 @@ public class BSShapeCollection : IDisposable
362 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE 363 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
363 ) 364 )
364 { 365 {
365 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE, 366 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
366 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback); 367 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
367 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", 368 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
368 prim.LocalID, forceRebuild, prim.BSShape); 369 prim.LocalID, forceRebuild, prim.BSShape);
@@ -376,7 +377,7 @@ public class BSShapeCollection : IDisposable
376 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX 377 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
377 ) 378 )
378 { 379 {
379 ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX, 380 ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX,
380 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback); 381 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
381 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", 382 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
382 prim.LocalID, forceRebuild, prim.BSShape); 383 prim.LocalID, forceRebuild, prim.BSShape);
@@ -411,39 +412,49 @@ public class BSShapeCollection : IDisposable
411 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, 412 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
412 ShapeDestructionCallback shapeCallback) 413 ShapeDestructionCallback shapeCallback)
413 { 414 {
415 // release any previous shape
416 DereferenceShape(prim.BSShape, true, shapeCallback);
414 417
415 shapeData.Type = shapeType; 418 shapeData.Type = shapeType;
416 // Bullet native objects are scaled by the Bullet engine so pass the size in 419 // Bullet native objects are scaled by the Bullet engine so pass the size in
417 prim.Scale = shapeData.Size; 420 prim.Scale = shapeData.Size;
418 shapeData.Scale = shapeData.Size; 421 shapeData.Scale = shapeData.Size;
419 422
420 // release any previous shape
421 DereferenceShape(prim.BSShape, true, shapeCallback);
422
423 BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey); 423 BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
424 424
425 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 425 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
426 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 426 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
427 shapeData.ID, newShape, shapeData.Scale); 427 shapeData.ID, newShape, shapeData.Scale);
428 428
429 prim.BSShape = newShape; 429 prim.BSShape = newShape;
430 return true; 430 return true;
431 } 431 }
432 432
433 private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType, 433 private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
434 ShapeData shapeData, ShapeData.FixedShapeKey shapeKey) 434 ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
435 { 435 {
436 BulletShape newShape; 436 BulletShape newShape;
437 // Need to make sure the passed shape information is for the native type.
438 ShapeData nativeShapeData = shapeData;
439 nativeShapeData.Type = shapeType;
440 nativeShapeData.MeshKey = (ulong)shapeKey;
441 nativeShapeData.HullKey = (ulong)shapeKey;
437 442
438 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 443 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
439 { 444 {
440 newShape = new BulletShape( 445 newShape = new BulletShape(
441 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale), 446 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, nativeShapeData.Scale)
442 shapeType); 447 , shapeType);
448 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", nativeShapeData.ID, nativeShapeData.Scale);
443 } 449 }
444 else 450 else
445 { 451 {
446 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); 452 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
453 }
454 if (newShape.ptr == IntPtr.Zero)
455 {
456 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
457 LogHeader, nativeShapeData.ID, nativeShapeData.Type);
447 } 458 }
448 newShape.shapeKey = (System.UInt64)shapeKey; 459 newShape.shapeKey = (System.UInt64)shapeKey;
449 newShape.isNativeShape = true; 460 newShape.isNativeShape = true;
@@ -698,19 +709,26 @@ public class BSShapeCollection : IDisposable
698 return ComputeShapeKey(shapeData, pbs, out lod); 709 return ComputeShapeKey(shapeData, pbs, out lod);
699 } 710 }
700 711
712 // The creation of a mesh or hull can fail if an underlying asset is not available.
713 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
714 // and 2) the asset cannot be converted (like decompressing JPEG2000s).
715 // The first case causes the asset to be fetched. The second case just requires
716 // us to not loop forever.
717 // Called after creating a physical mesh or hull. If the physical shape was created,
718 // just return.
701 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs) 719 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
702 { 720 {
703 // If the shape was successfully created, nothing more to do 721 // If the shape was successfully created, nothing more to do
704 if (newShape.ptr != IntPtr.Zero) 722 if (newShape.ptr != IntPtr.Zero)
705 return newShape; 723 return newShape;
706 724
707 // The most common reason for failure is that an underlying asset is not available
708
709 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 725 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
710 if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero) 726 if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
711 { 727 {
712 prim.LastAssetBuildFailed = true; 728 prim.LastAssetBuildFailed = true;
713 BSPhysObject xprim = prim; 729 BSPhysObject xprim = prim;
730 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
731 LogHeader, shapeData.ID.ToString("X"), prim.LastAssetBuildFailed);
714 Util.FireAndForget(delegate 732 Util.FireAndForget(delegate
715 { 733 {
716 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; 734 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
@@ -724,20 +742,28 @@ public class BSShapeCollection : IDisposable
724 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) 742 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
725 return; 743 return;
726 744
727 yprim.BaseShape.SculptData = new byte[asset.Data.Length]; 745 yprim.BaseShape.SculptData = asset.Data;
728 asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
729 // This will cause the prim to see that the filler shape is not the right 746 // This will cause the prim to see that the filler shape is not the right
730 // one and try again to build the object. 747 // one and try again to build the object.
748 // No race condition with the native sphere setting since the rebuild is at taint time.
731 yprim.ForceBodyShapeRebuild(false); 749 yprim.ForceBodyShapeRebuild(false);
732 750
733 }); 751 });
734 } 752 }
735 }); 753 });
736 } 754 }
755 else
756 {
757 if (prim.LastAssetBuildFailed)
758 {
759 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
760 LogHeader, shapeData.ID, pbs.SculptTexture);
761 }
762 }
737 763
738 // While we figure out the real problem, stick a simple native shape on the object. 764 // While we figure out the real problem, stick a simple native shape on the object.
739 BulletShape fillinShape = 765 BulletShape fillinShape =
740 BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE); 766 BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_BOX, shapeData, ShapeData.FixedShapeKey.KEY_BOX);
741 767
742 return fillinShape; 768 return fillinShape;
743 } 769 }
@@ -746,7 +772,7 @@ public class BSShapeCollection : IDisposable
746 // Updates prim.BSBody with the information about the new body if one is created. 772 // Updates prim.BSBody with the information about the new body if one is created.
747 // Returns 'true' if an object was actually created. 773 // Returns 'true' if an object was actually created.
748 // Called at taint-time. 774 // Called at taint-time.
749 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, 775 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
750 ShapeData shapeData, BodyDestructionCallback bodyCallback) 776 ShapeData shapeData, BodyDestructionCallback bodyCallback)
751 { 777 {
752 bool ret = false; 778 bool ret = false;
@@ -765,7 +791,6 @@ public class BSShapeCollection : IDisposable
765 // If the collisionObject is not the correct type for solidness, rebuild what's there 791 // If the collisionObject is not the correct type for solidness, rebuild what's there
766 mustRebuild = true; 792 mustRebuild = true;
767 } 793 }
768
769 } 794 }
770 795
771 if (mustRebuild || forceRebuild) 796 if (mustRebuild || forceRebuild)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 4106534..880859a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -201,9 +201,7 @@ public class BSTerrainManager
201 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new 201 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
202 // terrain shape is created and added to the body. 202 // terrain shape is created and added to the body.
203 // This call is most often used to update the heightMap and parameters of the terrain. 203 // This call is most often used to update the heightMap and parameters of the terrain.
204 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when 204 // (The above does suggest that some simplification/refactoring is in order.)
205 // calling this routine from initialization or taint-time routines) or whether to delay
206 // all the unmanaged activities to taint-time.
207 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 205 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
208 { 206 {
209 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}", 207 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
@@ -335,8 +333,8 @@ public class BSTerrainManager
335 333
336 // Make sure the new shape is processed. 334 // Make sure the new shape is processed.
337 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true); 335 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
338 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING); 336 // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
339 // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 337 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
340 338
341 m_terrainModified = true; 339 m_terrainModified = true;
342 }; 340 };