aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorRobert Adams2013-04-28 14:44:21 -0700
committerRobert Adams2013-04-29 07:38:40 -0700
commite5582939fd8d78b61c6f1eeda6de45d94f4b4926 (patch)
tree1f990ab6f73f4e787566031af35c7c59c89968aa
parentBulletSim: complete BSShape classes. (diff)
downloadopensim-SC_OLD-e5582939fd8d78b61c6f1eeda6de45d94f4b4926.zip
opensim-SC_OLD-e5582939fd8d78b61c6f1eeda6de45d94f4b4926.tar.gz
opensim-SC_OLD-e5582939fd8d78b61c6f1eeda6de45d94f4b4926.tar.bz2
opensim-SC_OLD-e5582939fd8d78b61c6f1eeda6de45d94f4b4926.tar.xz
BulletSim: massive refactor of shape classes. Removed shape specific code from BSShapeCollection. Using BSShape* classes to hold references to shape. Simplified shape dependency callbacks. Remove 'PreferredShape' methods and have each class specify shape type. Disable compound shape linkset for a later commit that will simplify linkset implementation.
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs6
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActors.cs6
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs19
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs9
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs35
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs11
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs34
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs9
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs966
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs203
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs6
20 files changed, 290 insertions, 1050 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
index fdf2cb9..8a22bc7 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
@@ -79,7 +79,7 @@ private sealed class BulletShapeUnman : BulletShape
79 : base() 79 : base()
80 { 80 {
81 ptr = xx; 81 ptr = xx;
82 type = typ; 82 shapeType = typ;
83 } 83 }
84 public override bool HasPhysicalShape 84 public override bool HasPhysicalShape
85 { 85 {
@@ -91,7 +91,7 @@ private sealed class BulletShapeUnman : BulletShape
91 } 91 }
92 public override BulletShape Clone() 92 public override BulletShape Clone()
93 { 93 {
94 return new BulletShapeUnman(ptr, type); 94 return new BulletShapeUnman(ptr, shapeType);
95 } 95 }
96 public override bool ReferenceSame(BulletShape other) 96 public override bool ReferenceSame(BulletShape other)
97 { 97 {
@@ -375,7 +375,7 @@ public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletSha
375{ 375{
376 BulletWorldUnman worldu = world as BulletWorldUnman; 376 BulletWorldUnman worldu = world as BulletWorldUnman;
377 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; 377 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
378 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type); 378 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType);
379} 379}
380 380
381public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) 381public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
index b37265a..1ef8b17 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
@@ -85,7 +85,7 @@ private sealed class BulletShapeXNA : BulletShape
85 : base() 85 : base()
86 { 86 {
87 shape = xx; 87 shape = xx;
88 type = typ; 88 shapeType = typ;
89 } 89 }
90 public override bool HasPhysicalShape 90 public override bool HasPhysicalShape
91 { 91 {
@@ -97,7 +97,7 @@ private sealed class BulletShapeXNA : BulletShape
97 } 97 }
98 public override BulletShape Clone() 98 public override BulletShape Clone()
99 { 99 {
100 return new BulletShapeXNA(shape, type); 100 return new BulletShapeXNA(shape, shapeType);
101 } 101 }
102 public override bool ReferenceSame(BulletShape other) 102 public override bool ReferenceSame(BulletShape other)
103 { 103 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
index bd5ee0b1..ac05979 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
@@ -87,8 +87,8 @@ public class BSActorAvatarMove : BSActor
87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
88 // Register a prestep action to restore physical requirements before the next simulation step. 88 // Register a prestep action to restore physical requirements before the next simulation step.
89 // Called at taint-time. 89 // Called at taint-time.
90 // BSActor.RemoveBodyDependencies() 90 // BSActor.RemoveDependencies()
91 public override void RemoveBodyDependencies() 91 public override void RemoveDependencies()
92 { 92 {
93 // Nothing to do for the hoverer since it is all software at pre-step action time. 93 // Nothing to do for the hoverer since it is all software at pre-step action time.
94 } 94 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs
index 92ace66..3630ca8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs
@@ -87,8 +87,8 @@ public class BSActorHover : BSActor
87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
88 // Register a prestep action to restore physical requirements before the next simulation step. 88 // Register a prestep action to restore physical requirements before the next simulation step.
89 // Called at taint-time. 89 // Called at taint-time.
90 // BSActor.RemoveBodyDependencies() 90 // BSActor.RemoveDependencies()
91 public override void RemoveBodyDependencies() 91 public override void RemoveDependencies()
92 { 92 {
93 // Nothing to do for the hoverer since it is all software at pre-step action time. 93 // Nothing to do for the hoverer since it is all software at pre-step action time.
94 } 94 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs
index 09ee32b..6059af5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs
@@ -85,8 +85,8 @@ public class BSActorLockAxis : BSActor
85 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 85 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
86 // Register a prestep action to restore physical requirements before the next simulation step. 86 // Register a prestep action to restore physical requirements before the next simulation step.
87 // Called at taint-time. 87 // Called at taint-time.
88 // BSActor.RemoveBodyDependencies() 88 // BSActor.RemoveDependencies()
89 public override void RemoveBodyDependencies() 89 public override void RemoveDependencies()
90 { 90 {
91 if (LockAxisConstraint != null) 91 if (LockAxisConstraint != null)
92 { 92 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs
index 56aacc5..1b598fd 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs
@@ -88,8 +88,8 @@ public class BSActorMoveToTarget : BSActor
88 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 88 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
89 // Register a prestep action to restore physical requirements before the next simulation step. 89 // Register a prestep action to restore physical requirements before the next simulation step.
90 // Called at taint-time. 90 // Called at taint-time.
91 // BSActor.RemoveBodyDependencies() 91 // BSActor.RemoveDependencies()
92 public override void RemoveBodyDependencies() 92 public override void RemoveDependencies()
93 { 93 {
94 // Nothing to do for the moveToTarget since it is all software at pre-step action time. 94 // Nothing to do for the moveToTarget since it is all software at pre-step action time.
95 } 95 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs
index 3ad138d..c0f40fd 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs
@@ -89,8 +89,8 @@ public class BSActorSetForce : BSActor
89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
90 // Register a prestep action to restore physical requirements before the next simulation step. 90 // Register a prestep action to restore physical requirements before the next simulation step.
91 // Called at taint-time. 91 // Called at taint-time.
92 // BSActor.RemoveBodyDependencies() 92 // BSActor.RemoveDependencies()
93 public override void RemoveBodyDependencies() 93 public override void RemoveDependencies()
94 { 94 {
95 // Nothing to do for the hoverer since it is all software at pre-step action time. 95 // Nothing to do for the hoverer since it is all software at pre-step action time.
96 } 96 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs
index 7a791ec..b3806e1 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs
@@ -89,8 +89,8 @@ public class BSActorSetTorque : BSActor
89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
90 // Register a prestep action to restore physical requirements before the next simulation step. 90 // Register a prestep action to restore physical requirements before the next simulation step.
91 // Called at taint-time. 91 // Called at taint-time.
92 // BSActor.RemoveBodyDependencies() 92 // BSActor.RemoveDependencies()
93 public override void RemoveBodyDependencies() 93 public override void RemoveDependencies()
94 { 94 {
95 // Nothing to do for the hoverer since it is all software at pre-step action time. 95 // Nothing to do for the hoverer since it is all software at pre-step action time.
96 } 96 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
index 12a8817..5e3f1c4 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
@@ -106,9 +106,9 @@ public class BSActorCollection
106 { 106 {
107 ForEachActor(a => a.Refresh()); 107 ForEachActor(a => a.Refresh());
108 } 108 }
109 public void RemoveBodyDependencies() 109 public void RemoveDependencies()
110 { 110 {
111 ForEachActor(a => a.RemoveBodyDependencies()); 111 ForEachActor(a => a.RemoveDependencies());
112 } 112 }
113} 113}
114 114
@@ -154,7 +154,7 @@ public abstract class BSActor
154 public abstract void Refresh(); 154 public abstract void Refresh();
155 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 155 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
156 // Register a prestep action to restore physical requirements before the next simulation step. 156 // Register a prestep action to restore physical requirements before the next simulation step.
157 public abstract void RemoveBodyDependencies(); 157 public abstract void RemoveDependencies();
158 158
159} 159}
160} 160}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index a0d58d3..da23a262 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -123,8 +123,8 @@ public sealed class BSCharacter : BSPhysObject
123 { 123 {
124 PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); 124 PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
125 PhysBody.Clear(); 125 PhysBody.Clear();
126 PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */); 126 PhysShape.Dereference(PhysicsScene);
127 PhysShape.Clear(); 127 PhysShape = new BSShapeNull();
128 }); 128 });
129 } 129 }
130 130
@@ -146,8 +146,8 @@ public sealed class BSCharacter : BSPhysObject
146 Flying = _flying; 146 Flying = _flying;
147 147
148 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); 148 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
149 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); 149 PhysicsScene.PE.SetMargin(PhysShape.physShapeInfo, PhysicsScene.Params.collisionMargin);
150 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 150 PhysicsScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
151 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 151 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
152 if (BSParam.CcdMotionThreshold > 0f) 152 if (BSParam.CcdMotionThreshold > 0f)
153 { 153 {
@@ -205,9 +205,9 @@ public sealed class BSCharacter : BSPhysObject
205 205
206 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 206 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
207 { 207 {
208 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) 208 if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
209 { 209 {
210 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 210 PhysicsScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
211 UpdatePhysicalMassProperties(RawMass, true); 211 UpdatePhysicalMassProperties(RawMass, true);
212 // Make sure this change appears as a property update event 212 // Make sure this change appears as a property update event
213 PhysicsScene.PE.PushUpdate(PhysBody); 213 PhysicsScene.PE.PushUpdate(PhysBody);
@@ -221,11 +221,6 @@ public sealed class BSCharacter : BSPhysObject
221 { 221 {
222 set { BaseShape = value; } 222 set { BaseShape = value; }
223 } 223 }
224 // I want the physics engine to make an avatar capsule
225 public override BSPhysicsShapeType PreferredPhysicalShape
226 {
227 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
228 }
229 224
230 public override bool Grabbed { 225 public override bool Grabbed {
231 set { _grabbed = value; } 226 set { _grabbed = value; }
@@ -381,7 +376,7 @@ public sealed class BSCharacter : BSPhysObject
381 } 376 }
382 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) 377 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
383 { 378 {
384 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 379 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
385 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); 380 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia);
386 } 381 }
387 382
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 612c68b..e2e807e 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -625,7 +625,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
625 // Vehicles report collision events so we know when it's on the ground 625 // Vehicles report collision events so we know when it's on the ground
626 m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); 626 m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
627 627
628 ControllingPrim.Inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape, m_vehicleMass); 628 ControllingPrim.Inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
629 m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); 629 m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
630 m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); 630 m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
631 631
@@ -649,7 +649,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
649 } 649 }
650 650
651 // BSActor.RemoveBodyDependencies 651 // BSActor.RemoveBodyDependencies
652 public override void RemoveBodyDependencies() 652 public override void RemoveDependencies()
653 { 653 {
654 Refresh(); 654 Refresh();
655 } 655 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 4ece1eb..df1dd34 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -93,13 +93,6 @@ public abstract class BSLinkset
93 // to the physical representation is done via the tainting mechenism. 93 // to the physical representation is done via the tainting mechenism.
94 protected object m_linksetActivityLock = new Object(); 94 protected object m_linksetActivityLock = new Object();
95 95
96 // Some linksets have a preferred physical shape.
97 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
98 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
99 {
100 return BSPhysicsShapeType.SHAPE_UNKNOWN;
101 }
102
103 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 96 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
104 public float LinksetMass { get; protected set; } 97 public float LinksetMass { get; protected set; }
105 98
@@ -263,7 +256,7 @@ public abstract class BSLinkset
263 // This is called when the root body is changing. 256 // This is called when the root body is changing.
264 // Returns 'true' of something was actually removed and would need restoring 257 // Returns 'true' of something was actually removed and would need restoring
265 // Called at taint-time!! 258 // Called at taint-time!!
266 public abstract bool RemoveBodyDependencies(BSPrimLinkable child); 259 public abstract bool RemoveDependencies(BSPrimLinkable child);
267 260
268 // ================================================================ 261 // ================================================================
269 protected virtual float ComputeLinksetMass() 262 protected virtual float ComputeLinksetMass()
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index e05562a..a20bbc3 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -98,19 +98,6 @@ public sealed class BSLinksetCompound : BSLinkset
98 { 98 {
99 } 99 }
100 100
101 // For compound implimented linksets, if there are children, use compound shape for the root.
102 public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
103 {
104 // Returning 'unknown' means we don't have a preference.
105 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
106 if (IsRoot(requestor) && HasAnyChildren)
107 {
108 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
109 }
110 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
111 return ret;
112 }
113
114 // When physical properties are changed the linkset needs to recalculate 101 // When physical properties are changed the linkset needs to recalculate
115 // its internal properties. 102 // its internal properties.
116 public override void Refresh(BSPrimLinkable requestor) 103 public override void Refresh(BSPrimLinkable requestor)
@@ -218,22 +205,22 @@ public sealed class BSLinksetCompound : BSLinkset
218 // and that is caused by us updating the object. 205 // and that is caused by us updating the object.
219 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) 206 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
220 { 207 {
221 // Find the physical instance of the child 208 // Find the physical instance of the child
222 if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) 209 if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
223 { 210 {
224 // It is possible that the linkset is still under construction and the child is not yet 211 // It is possible that the linkset is still under construction and the child is not yet
225 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will 212 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
226 // build the whole thing with the new position or rotation. 213 // build the whole thing with the new position or rotation.
227 // The index must be checked because Bullet references the child array but does no validity 214 // The index must be checked because Bullet references the child array but does no validity
228 // checking of the child index passed. 215 // checking of the child index passed.
229 int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape); 216 int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
230 if (updated.LinksetChildIndex < numLinksetChildren) 217 if (updated.LinksetChildIndex < numLinksetChildren)
231 { 218 {
232 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex); 219 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
233 if (linksetChildShape.HasPhysicalShape) 220 if (linksetChildShape.HasPhysicalShape)
234 { 221 {
235 // Found the child shape within the compound shape 222 // Found the child shape within the compound shape
236 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex, 223 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
237 updated.RawPosition - LinksetRoot.RawPosition, 224 updated.RawPosition - LinksetRoot.RawPosition,
238 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), 225 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
239 true /* shouldRecalculateLocalAabb */); 226 true /* shouldRecalculateLocalAabb */);
@@ -278,7 +265,7 @@ public sealed class BSLinksetCompound : BSLinkset
278 // Since we don't keep in world relationships, do nothing unless it's a child changing. 265 // Since we don't keep in world relationships, do nothing unless it's a child changing.
279 // Returns 'true' of something was actually removed and would need restoring 266 // Returns 'true' of something was actually removed and would need restoring
280 // Called at taint-time!! 267 // Called at taint-time!!
281 public override bool RemoveBodyDependencies(BSPrimLinkable child) 268 public override bool RemoveDependencies(BSPrimLinkable child)
282 { 269 {
283 bool ret = false; 270 bool ret = false;
284 271
@@ -404,11 +391,12 @@ public sealed class BSLinksetCompound : BSLinkset
404 { 391 {
405 try 392 try
406 { 393 {
394 /*
407 // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.) 395 // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.)
408 Rebuilding = true; 396 Rebuilding = true;
409 397
410 // Cause the root shape to be rebuilt as a compound object with just the root in it 398 // Cause the root shape to be rebuilt as a compound object with just the root in it
411 LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */); 399 LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime );
412 400
413 // The center of mass for the linkset is the geometric center of the group. 401 // The center of mass for the linkset is the geometric center of the group.
414 // Compute a displacement for each component so it is relative to the center-of-mass. 402 // Compute a displacement for each component so it is relative to the center-of-mass.
@@ -430,10 +418,10 @@ public sealed class BSLinksetCompound : BSLinkset
430 LinksetRoot.ForcePosition = LinksetRoot.RawPosition; 418 LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
431 419
432 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM 420 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM
433 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */, 421 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, 0 /* childIndex ,
434 -centerDisplacement, 422 -centerDisplacement,
435 OMV.Quaternion.Identity, // LinksetRoot.RawOrientation, 423 OMV.Quaternion.Identity, // LinksetRoot.RawOrientation,
436 false /* shouldRecalculateLocalAabb (is done later after linkset built) */); 424 false /* shouldRecalculateLocalAabb (is done later after linkset built) );
437 425
438 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", 426 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
439 LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement); 427 LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement);
@@ -501,6 +489,7 @@ public sealed class BSLinksetCompound : BSLinkset
501 489
502 // Enable the physical position updator to return the position and rotation of the root shape 490 // Enable the physical position updator to return the position and rotation of the root shape
503 PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); 491 PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
492 */
504 } 493 }
505 finally 494 finally
506 { 495 {
@@ -508,7 +497,7 @@ public sealed class BSLinksetCompound : BSLinkset
508 } 497 }
509 498
510 // See that the Aabb surrounds the new shape 499 // See that the Aabb surrounds the new shape
511 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); 500 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
512 } 501 }
513} 502}
514} \ No newline at end of file 503} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index 6d252ca..1811772 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -93,11 +93,11 @@ public sealed class BSLinksetConstraints : BSLinkset
93 // up to rebuild the constraints before the next simulation step. 93 // up to rebuild the constraints before the next simulation step.
94 // Returns 'true' of something was actually removed and would need restoring 94 // Returns 'true' of something was actually removed and would need restoring
95 // Called at taint-time!! 95 // Called at taint-time!!
96 public override bool RemoveBodyDependencies(BSPrimLinkable child) 96 public override bool RemoveDependencies(BSPrimLinkable child)
97 { 97 {
98 bool ret = false; 98 bool ret = false;
99 99
100 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", 100 DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}",
101 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); 101 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
102 102
103 lock (m_linksetActivityLock) 103 lock (m_linksetActivityLock)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 309d004..b6eb619 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -88,7 +88,7 @@ public abstract class BSPhysObject : PhysicsActor
88 88
89 // We don't have any physical representation yet. 89 // We don't have any physical representation yet.
90 PhysBody = new BulletBody(localID); 90 PhysBody = new BulletBody(localID);
91 PhysShape = new BulletShape(); 91 PhysShape = new BSShapeNull();
92 92
93 PrimAssetState = PrimAssetCondition.Unknown; 93 PrimAssetState = PrimAssetCondition.Unknown;
94 94
@@ -138,7 +138,7 @@ public abstract class BSPhysObject : PhysicsActor
138 // Reference to the physical body (btCollisionObject) of this object 138 // Reference to the physical body (btCollisionObject) of this object
139 public BulletBody PhysBody; 139 public BulletBody PhysBody;
140 // Reference to the physical shape (btCollisionShape) of this object 140 // Reference to the physical shape (btCollisionShape) of this object
141 public BulletShape PhysShape; 141 public BSShape PhysShape;
142 142
143 // The physical representation of the prim might require an asset fetch. 143 // The physical representation of the prim might require an asset fetch.
144 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. 144 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
@@ -151,13 +151,6 @@ public abstract class BSPhysObject : PhysicsActor
151 // The objects base shape information. Null if not a prim type shape. 151 // The objects base shape information. Null if not a prim type shape.
152 public PrimitiveBaseShape BaseShape { get; protected set; } 152 public PrimitiveBaseShape BaseShape { get; protected set; }
153 153
154 // Some types of objects have preferred physical representations.
155 // Returns SHAPE_UNKNOWN if there is no preference.
156 public virtual BSPhysicsShapeType PreferredPhysicalShape
157 {
158 get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
159 }
160
161 // When the physical properties are updated, an EntityProperty holds the update values. 154 // When the physical properties are updated, an EntityProperty holds the update values.
162 // Keep the current and last EntityProperties to enable computation of differences 155 // Keep the current and last EntityProperties to enable computation of differences
163 // between the current update and the previous values. 156 // between the current update and the previous values.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 4bc266b..5d12338 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -134,8 +134,8 @@ public class BSPrim : BSPhysObject
134 // If there are physical body and shape, release my use of same. 134 // If there are physical body and shape, release my use of same.
135 PhysicsScene.Shapes.DereferenceBody(PhysBody, null); 135 PhysicsScene.Shapes.DereferenceBody(PhysBody, null);
136 PhysBody.Clear(); 136 PhysBody.Clear();
137 PhysicsScene.Shapes.DereferenceShape(PhysShape, null); 137 PhysShape.Dereference(PhysicsScene);
138 PhysShape.Clear(); 138 PhysShape = new BSShapeNull();
139 }); 139 });
140 } 140 }
141 141
@@ -161,25 +161,13 @@ public class BSPrim : BSPhysObject
161 ForceBodyShapeRebuild(false); 161 ForceBodyShapeRebuild(false);
162 } 162 }
163 } 163 }
164 // 'unknown' says to choose the best type
165 public override BSPhysicsShapeType PreferredPhysicalShape
166 { get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } }
167
168 public override bool ForceBodyShapeRebuild(bool inTaintTime) 164 public override bool ForceBodyShapeRebuild(bool inTaintTime)
169 { 165 {
170 if (inTaintTime) 166 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
171 { 167 {
172 _mass = CalculateMass(); // changing the shape changes the mass 168 _mass = CalculateMass(); // changing the shape changes the mass
173 CreateGeomAndObject(true); 169 CreateGeomAndObject(true);
174 } 170 });
175 else
176 {
177 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate()
178 {
179 _mass = CalculateMass(); // changing the shape changes the mass
180 CreateGeomAndObject(true);
181 });
182 }
183 return true; 171 return true;
184 } 172 }
185 public override bool Grabbed { 173 public override bool Grabbed {
@@ -462,7 +450,7 @@ public class BSPrim : BSPhysObject
462 Gravity = ComputeGravity(Buoyancy); 450 Gravity = ComputeGravity(Buoyancy);
463 PhysicsScene.PE.SetGravity(PhysBody, Gravity); 451 PhysicsScene.PE.SetGravity(PhysBody, Gravity);
464 452
465 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 453 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
466 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); 454 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia);
467 PhysicsScene.PE.UpdateInertiaTensor(PhysBody); 455 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
468 456
@@ -805,7 +793,8 @@ public class BSPrim : BSPhysObject
805 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 793 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
806 794
807 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", 795 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
808 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); 796 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
797 CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
809 } 798 }
810 799
811 // "Making dynamic" means changing to and from static. 800 // "Making dynamic" means changing to and from static.
@@ -1463,12 +1452,13 @@ public class BSPrim : BSPhysObject
1463 // Create the correct physical representation for this type of object. 1452 // Create the correct physical representation for this type of object.
1464 // Updates base.PhysBody and base.PhysShape with the new information. 1453 // Updates base.PhysBody and base.PhysShape with the new information.
1465 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. 1454 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1466 PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) 1455 PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1467 { 1456 {
1468 // Called if the current prim body is about to be destroyed. 1457 // Called if the current prim body is about to be destroyed.
1469 // Remove all the physical dependencies on the old body. 1458 // Remove all the physical dependencies on the old body.
1470 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) 1459 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1471 RemoveBodyDependencies(); 1460 // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1461 RemoveDependencies();
1472 }); 1462 });
1473 1463
1474 // Make sure the properties are set on the new object 1464 // Make sure the properties are set on the new object
@@ -1477,9 +1467,9 @@ public class BSPrim : BSPhysObject
1477 } 1467 }
1478 1468
1479 // Called at taint-time 1469 // Called at taint-time
1480 protected virtual void RemoveBodyDependencies() 1470 protected virtual void RemoveDependencies()
1481 { 1471 {
1482 PhysicalActors.RemoveBodyDependencies(); 1472 PhysicalActors.RemoveDependencies();
1483 } 1473 }
1484 1474
1485 // The physics engine says that properties have updated. Update same and inform 1475 // The physics engine says that properties have updated. Update same and inform
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
index 28242d4..81104ec 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
@@ -61,9 +61,6 @@ public class BSPrimLinkable : BSPrimDisplaced
61 base.Destroy(); 61 base.Destroy();
62 } 62 }
63 63
64 public override BSPhysicsShapeType PreferredPhysicalShape
65 { get { return Linkset.PreferredPhysicalShape(this); } }
66
67 public override void link(Manager.PhysicsActor obj) 64 public override void link(Manager.PhysicsActor obj)
68 { 65 {
69 BSPrimLinkable parent = obj as BSPrimLinkable; 66 BSPrimLinkable parent = obj as BSPrimLinkable;
@@ -149,10 +146,10 @@ public class BSPrimLinkable : BSPrimDisplaced
149 } 146 }
150 147
151 // Body is being taken apart. Remove physical dependencies and schedule a rebuild. 148 // Body is being taken apart. Remove physical dependencies and schedule a rebuild.
152 protected override void RemoveBodyDependencies() 149 protected override void RemoveDependencies()
153 { 150 {
154 Linkset.RemoveBodyDependencies(this); 151 Linkset.RemoveDependencies(this);
155 base.RemoveBodyDependencies(); 152 base.RemoveDependencies();
156 } 153 }
157 154
158 public override void UpdateProperties(EntityProperties entprop) 155 public override void UpdateProperties(EntityProperties entprop)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 0f9b3c3..3c23509 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -38,38 +38,15 @@ public sealed class BSShapeCollection : IDisposable
38{ 38{
39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; 39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40 40
41 private BSScene PhysicsScene { get; set; } 41 private BSScene m_physicsScene { get; set; }
42 42
43 private Object m_collectionActivityLock = new Object(); 43 private Object m_collectionActivityLock = new Object();
44 44
45 // Description of a Mesh
46 private struct MeshDesc
47 {
48 public BulletShape shape;
49 public int referenceCount;
50 public DateTime lastReferenced;
51 public UInt64 shapeKey;
52 }
53
54 // Description of a hull.
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc
57 {
58 public BulletShape shape;
59 public int referenceCount;
60 public DateTime lastReferenced;
61 public UInt64 shapeKey;
62 }
63
64 // The sharable set of meshes and hulls. Indexed by their shape hash.
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67
68 private bool DDetail = false; 45 private bool DDetail = false;
69 46
70 public BSShapeCollection(BSScene physScene) 47 public BSShapeCollection(BSScene physScene)
71 { 48 {
72 PhysicsScene = physScene; 49 m_physicsScene = physScene;
73 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) 50 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
74 // While detailed debugging is still active, this is better than commenting out all the 51 // While detailed debugging is still active, this is better than commenting out all the
75 // DetailLog statements. When debugging slows down, this and the protected logging 52 // DetailLog statements. When debugging slows down, this and the protected logging
@@ -86,22 +63,18 @@ public sealed class BSShapeCollection : IDisposable
86 // Mostly used for changing bodies out from under Linksets. 63 // Mostly used for changing bodies out from under Linksets.
87 // Useful for other cases where parameters need saving. 64 // Useful for other cases where parameters need saving.
88 // Passing 'null' says no callback. 65 // Passing 'null' says no callback.
89 public delegate void ShapeDestructionCallback(BulletShape shape); 66 public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape);
90 public delegate void BodyDestructionCallback(BulletBody body);
91 67
92 // Called to update/change the body and shape for an object. 68 // Called to update/change the body and shape for an object.
93 // First checks the shape and updates that if necessary then makes 69 // The object has some shape and body on it. Here we decide if that is the correct shape
94 // sure the body is of the right type. 70 // for the current state of the object (static/dynamic/...).
71 // If bodyCallback is not null, it is called if either the body or the shape are changed
72 // so dependencies (like constraints) can be removed before the physical object is dereferenced.
95 // Return 'true' if either the body or the shape changed. 73 // Return 'true' if either the body or the shape changed.
96 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before 74 // Called at taint-time.
97 // the current shape or body is destroyed. This allows the caller to remove any 75 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback)
98 // higher level dependencies on the shape or body. Mostly used for LinkSets to
99 // remove the physical constraints before the body is destroyed.
100 // Called at taint-time!!
101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim,
102 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
103 { 76 {
104 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); 77 m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
105 78
106 bool ret = false; 79 bool ret = false;
107 80
@@ -111,12 +84,12 @@ public sealed class BSShapeCollection : IDisposable
111 // Do we have the correct geometry for this type of object? 84 // Do we have the correct geometry for this type of object?
112 // Updates prim.BSShape with information/pointers to shape. 85 // Updates prim.BSShape with information/pointers to shape.
113 // Returns 'true' of BSShape is changed to a new shape. 86 // Returns 'true' of BSShape is changed to a new shape.
114 bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback); 87 bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback);
115 // If we had to select a new shape geometry for the object, 88 // If we had to select a new shape geometry for the object,
116 // rebuild the body around it. 89 // rebuild the body around it.
117 // Updates prim.BSBody with information/pointers to requested body 90 // Updates prim.BSBody with information/pointers to requested body
118 // Returns 'true' if BSBody was changed. 91 // Returns 'true' if BSBody was changed.
119 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, bodyCallback); 92 bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback);
120 ret = newGeom || newBody; 93 ret = newGeom || newBody;
121 } 94 }
122 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", 95 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
@@ -127,271 +100,20 @@ public sealed class BSShapeCollection : IDisposable
127 100
128 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) 101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
129 { 102 {
130 return GetBodyAndShape(forceRebuild, sim, prim, null, null); 103 return GetBodyAndShape(forceRebuild, sim, prim, null);
131 }
132
133 // Track another user of a body.
134 // We presume the caller has allocated the body.
135 // Bodies only have one user so the body is just put into the world if not already there.
136 private void ReferenceBody(BulletBody body)
137 {
138 lock (m_collectionActivityLock)
139 {
140 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
141 if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
142 {
143 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
144 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
145 }
146 }
147 }
148
149 // Release the usage of a body.
150 // Called when releasing use of a BSBody. BSShape is handled separately.
151 // Called in taint time.
152 public void DereferenceBody(BulletBody body, BodyDestructionCallback bodyCallback )
153 {
154 if (!body.HasPhysicalBody)
155 return;
156
157 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
158
159 lock (m_collectionActivityLock)
160 {
161 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
162 // If the caller needs to know the old body is going away, pass the event up.
163 if (bodyCallback != null) bodyCallback(body);
164
165 // Removing an object not in the world is a NOOP
166 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
167
168 // Zero any reference to the shape so it is not freed when the body is deleted.
169 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
170 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
171 }
172 }
173
174 // Track the datastructures and use count for a shape.
175 // When creating a hull, this is called first to reference the mesh
176 // and then again to reference the hull.
177 // Meshes and hulls for the same shape have the same hash key.
178 // NOTE that native shapes are not added to the mesh list or removed.
179 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
180 public bool ReferenceShape(BulletShape shape)
181 {
182 bool ret = false;
183 switch (shape.type)
184 {
185 case BSPhysicsShapeType.SHAPE_MESH:
186 MeshDesc meshDesc;
187 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
188 {
189 // There is an existing instance of this mesh.
190 meshDesc.referenceCount++;
191 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
192 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
193 }
194 else
195 {
196 // This is a new reference to a mesh
197 meshDesc.shape = shape.Clone();
198 meshDesc.shapeKey = shape.shapeKey;
199 // We keep a reference to the underlying IMesh data so a hull can be built
200 meshDesc.referenceCount = 1;
201 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
202 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
203 ret = true;
204 }
205 meshDesc.lastReferenced = System.DateTime.Now;
206 Meshes[shape.shapeKey] = meshDesc;
207 break;
208 case BSPhysicsShapeType.SHAPE_HULL:
209 HullDesc hullDesc;
210 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
211 {
212 // There is an existing instance of this hull.
213 hullDesc.referenceCount++;
214 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
215 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
216 }
217 else
218 {
219 // This is a new reference to a hull
220 hullDesc.shape = shape.Clone();
221 hullDesc.shapeKey = shape.shapeKey;
222 hullDesc.referenceCount = 1;
223 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
224 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
225 ret = true;
226
227 }
228 hullDesc.lastReferenced = System.DateTime.Now;
229 Hulls[shape.shapeKey] = hullDesc;
230 break;
231 case BSPhysicsShapeType.SHAPE_UNKNOWN:
232 break;
233 default:
234 // Native shapes are not tracked and they don't go into any list
235 break;
236 }
237 return ret;
238 }
239
240 // Release the usage of a shape.
241 public void DereferenceShape(BulletShape shape, ShapeDestructionCallback shapeCallback)
242 {
243 if (!shape.HasPhysicalShape)
244 return;
245
246 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceShape");
247
248 if (shape.HasPhysicalShape)
249 {
250 if (shape.isNativeShape)
251 {
252 // Native shapes are not tracked and are released immediately
253 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1}",
254 BSScene.DetailLogZero, shape.AddrString);
255 if (shapeCallback != null) shapeCallback(shape);
256 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
257 }
258 else
259 {
260 switch (shape.type)
261 {
262 case BSPhysicsShapeType.SHAPE_HULL:
263 DereferenceHull(shape, shapeCallback);
264 break;
265 case BSPhysicsShapeType.SHAPE_MESH:
266 DereferenceMesh(shape, shapeCallback);
267 break;
268 case BSPhysicsShapeType.SHAPE_COMPOUND:
269 DereferenceCompound(shape, shapeCallback);
270 break;
271 case BSPhysicsShapeType.SHAPE_UNKNOWN:
272 break;
273 default:
274 break;
275 }
276 }
277 }
278 }
279
280 // Count down the reference count for a mesh shape
281 // Called at taint-time.
282 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
283 {
284 MeshDesc meshDesc;
285 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
286 {
287 meshDesc.referenceCount--;
288 // TODO: release the Bullet storage
289 if (shapeCallback != null) shapeCallback(shape);
290 meshDesc.lastReferenced = System.DateTime.Now;
291 Meshes[shape.shapeKey] = meshDesc;
292 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
293 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
294
295 }
296 } 104 }
297 105
298 // Count down the reference count for a hull shape 106 // If the existing prim's shape is to be replaced, remove the tie to the existing shape
299 // Called at taint-time. 107 // before replacing it.
300 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback) 108 private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
301 { 109 {
302 HullDesc hullDesc; 110 if (prim.PhysShape.HasPhysicalShape)
303 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
304 { 111 {
305 hullDesc.referenceCount--; 112 if (shapeCallback != null)
306 // TODO: release the Bullet storage (aging old entries?) 113 shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo);
307 114 prim.PhysShape.Dereference(m_physicsScene);
308 // Tell upper layers that, if they have dependencies on this shape, this link is going away
309 if (shapeCallback != null) shapeCallback(shape);
310
311 hullDesc.lastReferenced = System.DateTime.Now;
312 Hulls[shape.shapeKey] = hullDesc;
313 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
314 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
315 }
316 }
317
318 // Remove a reference to a compound shape.
319 // Taking a compound shape apart is a little tricky because if you just delete the
320 // physical shape, it will free all the underlying children. We can't do that because
321 // they could be shared. So, this removes each of the children from the compound and
322 // dereferences them separately before destroying the compound collision object itself.
323 // Called at taint-time.
324 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
325 {
326 if (!PhysicsScene.PE.IsCompound(shape))
327 {
328 // Failed the sanity check!!
329 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
330 LogHeader, shape.type, shape.AddrString);
331 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
332 BSScene.DetailLogZero, shape.type, shape.AddrString);
333 return;
334 }
335
336 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
337 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
338
339 for (int ii = numChildren - 1; ii >= 0; ii--)
340 {
341 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
342 DereferenceAnonCollisionShape(childShape);
343 }
344 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
345 }
346
347 // Sometimes we have a pointer to a collision shape but don't know what type it is.
348 // Figure out type and call the correct dereference routine.
349 // Called at taint-time.
350 private void DereferenceAnonCollisionShape(BulletShape shapeInfo)
351 {
352 MeshDesc meshDesc;
353 HullDesc hullDesc;
354
355 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
356 {
357 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
358 shapeInfo.shapeKey = meshDesc.shapeKey;
359 }
360 else
361 {
362 if (TryGetHullByPtr(shapeInfo, out hullDesc))
363 {
364 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
365 shapeInfo.shapeKey = hullDesc.shapeKey;
366 }
367 else
368 {
369 if (PhysicsScene.PE.IsCompound(shapeInfo))
370 {
371 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
372 }
373 else
374 {
375 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
376 {
377 shapeInfo.isNativeShape = true;
378 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
379 }
380 }
381 }
382 }
383
384 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
385
386 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
387 {
388 DereferenceShape(shapeInfo, null);
389 }
390 else
391 {
392 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
393 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString);
394 } 115 }
116 prim.PhysShape = new BSShapeNull();
395 } 117 }
396 118
397 // Create the geometry information in Bullet for later use. 119 // Create the geometry information in Bullet for later use.
@@ -402,40 +124,7 @@ public sealed class BSShapeCollection : IDisposable
402 // Info in prim.BSShape is updated to the new shape. 124 // Info in prim.BSShape is updated to the new shape.
403 // Returns 'true' if the geometry was rebuilt. 125 // Returns 'true' if the geometry was rebuilt.
404 // Called at taint-time! 126 // Called at taint-time!
405 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 127 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
406 {
407 bool ret = false;
408 bool haveShape = false;
409
410 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
411 {
412 // an avatar capsule is close to a native shape (it is not shared)
413 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback);
414 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
415 ret = true;
416 haveShape = true;
417 }
418
419 // Compound shapes are handled special as they are rebuilt from scratch.
420 // This isn't too great a hardship since most of the child shapes will have already been created.
421 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
422 {
423 ret = GetReferenceToCompoundShape(prim, shapeCallback);
424 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
425 haveShape = true;
426 }
427
428 if (!haveShape)
429 {
430 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
431 }
432
433 return ret;
434 }
435
436 // Create a mesh, hull or native shape.
437 // Return 'true' if the prim's shape was changed.
438 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
439 { 128 {
440 bool ret = false; 129 bool ret = false;
441 bool haveShape = false; 130 bool haveShape = false;
@@ -443,19 +132,21 @@ public sealed class BSShapeCollection : IDisposable
443 PrimitiveBaseShape pbs = prim.BaseShape; 132 PrimitiveBaseShape pbs = prim.BaseShape;
444 133
445 // If the prim attributes are simple, this could be a simple Bullet native shape 134 // If the prim attributes are simple, this could be a simple Bullet native shape
135 // Native shapes work whether to object is static or physical.
446 if (!haveShape 136 if (!haveShape
447 && nativeShapePossible 137 && nativeShapePossible
448 && pbs != null 138 && pbs != null
449 && !pbs.SculptEntry 139 && PrimHasNoCuts(pbs)
450 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) ) 140 && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) )
141 )
451 { 142 {
452 // Get the scale of any existing shape so we can see if the new shape is same native type and same size. 143 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
453 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; 144 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
454 if (prim.PhysShape.HasPhysicalShape) 145 if (prim.PhysShape.HasPhysicalShape)
455 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape); 146 scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo);
456 147
457 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", 148 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
458 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); 149 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType);
459 150
460 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal 151 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
461 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 152 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
@@ -463,26 +154,28 @@ public sealed class BSShapeCollection : IDisposable
463 { 154 {
464 haveShape = true; 155 haveShape = true;
465 if (forceRebuild 156 if (forceRebuild
466 || prim.Scale != scaleOfExistingShape 157 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE
467 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 158 )
468 )
469 { 159 {
470 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 160 DereferenceExistingShape(prim, shapeCallback);
471 FixedShapeKey.KEY_SPHERE, shapeCallback); 161 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
162 BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE);
472 } 163 }
473 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", 164 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
474 prim.LocalID, forceRebuild, ret, prim.PhysShape); 165 prim.LocalID, forceRebuild, ret, prim.PhysShape);
475 } 166 }
167 // If we didn't make a sphere, maybe a box will work.
476 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 168 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
477 { 169 {
478 haveShape = true; 170 haveShape = true;
479 if (forceRebuild 171 if (forceRebuild
480 || prim.Scale != scaleOfExistingShape 172 || prim.Scale != scaleOfExistingShape
481 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 173 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX
482 ) 174 )
483 { 175 {
484 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 176 DereferenceExistingShape(prim, shapeCallback);
485 FixedShapeKey.KEY_BOX, shapeCallback); 177 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
178 BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
486 } 179 }
487 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", 180 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
488 prim.LocalID, forceRebuild, ret, prim.PhysShape); 181 prim.LocalID, forceRebuild, ret, prim.PhysShape);
@@ -511,7 +204,7 @@ public sealed class BSShapeCollection : IDisposable
511 } 204 }
512 205
513 // return 'true' if the prim's shape was changed. 206 // return 'true' if the prim's shape was changed.
514 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 207 private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
515 { 208 {
516 209
517 bool ret = false; 210 bool ret = false;
@@ -520,537 +213,70 @@ public sealed class BSShapeCollection : IDisposable
520 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) 213 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
521 { 214 {
522 // Update prim.BSShape to reference a hull of this shape. 215 // Update prim.BSShape to reference a hull of this shape.
523 ret = GetReferenceToHull(prim, shapeCallback); 216 DereferenceExistingShape(prim, shapeCallback);
217 prim.PhysShape = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
524 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 218 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
525 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 219 prim.LocalID, prim.PhysShape, prim.PhysShape.physShapeInfo.shapeKey.ToString("X"));
526 } 220 }
527 else 221 else
528 { 222 {
529 ret = GetReferenceToMesh(prim, shapeCallback); 223 // Update prim.BSShape to reference a mesh of this shape.
224 DereferenceExistingShape(prim, shapeCallback);
225 prim.PhysShape = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
530 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 226 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
531 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 227 prim.LocalID, prim.PhysShape, prim.PhysShape.physShapeInfo.shapeKey.ToString("X"));
532 } 228 }
533 return ret; 229 return ret;
534 } 230 }
535 231
536 // Creates a native shape and assignes it to prim.BSShape. 232 // Track another user of a body.
537 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). 233 // We presume the caller has allocated the body.
538 private bool GetReferenceToNativeShape(BSPhysObject prim, 234 // Bodies only have one user so the body is just put into the world if not already there.
539 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey, 235 private void ReferenceBody(BulletBody body)
540 ShapeDestructionCallback shapeCallback)
541 {
542 // release any previous shape
543 DereferenceShape(prim.PhysShape, shapeCallback);
544
545 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
546
547 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
548 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
549 prim.LocalID, newShape, prim.Scale);
550
551 // native shapes are scaled by Bullet
552 prim.PhysShape = newShape;
553 return true;
554 }
555
556 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
557 FixedShapeKey shapeKey)
558 {
559 BulletShape newShape;
560 // Need to make sure the passed shape information is for the native type.
561 ShapeData nativeShapeData = new ShapeData();
562 nativeShapeData.Type = shapeType;
563 nativeShapeData.ID = prim.LocalID;
564 nativeShapeData.Scale = prim.Scale;
565 nativeShapeData.Size = prim.Scale; // unneeded, I think.
566 nativeShapeData.MeshKey = (ulong)shapeKey;
567 nativeShapeData.HullKey = (ulong)shapeKey;
568
569 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
570 {
571
572 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale);
573 if (DDetail) DetailLog("{0},BSShapeCollection.BuildPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
574 }
575 else
576 {
577 // Native shapes are scaled in Bullet so set the scaling to the size
578 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData);
579
580 }
581 if (!newShape.HasPhysicalShape)
582 {
583 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
584 LogHeader, prim.LocalID, shapeType);
585 }
586 newShape.shapeKey = (System.UInt64)shapeKey;
587 newShape.isNativeShape = true;
588
589 return newShape;
590 }
591
592 // Builds a mesh shape in the physical world and updates prim.BSShape.
593 // Dereferences previous shape in BSShape and adds a reference for this new shape.
594 // Returns 'true' of a mesh was actually built. Otherwise .
595 // Called at taint-time!
596 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
597 {
598 BulletShape newShape = new BulletShape();
599
600 float lod;
601 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
602
603 // if this new shape is the same as last time, don't recreate the mesh
604 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
605 return false;
606
607 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2},size={3},lod={4}",
608 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod);
609
610 // Since we're recreating new, get rid of the reference to the previous shape
611 DereferenceShape(prim.PhysShape, shapeCallback);
612
613 newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod);
614 // Take evasive action if the mesh was not constructed.
615 newShape = VerifyMeshCreated(PhysicsScene, newShape, prim);
616
617 ReferenceShape(newShape);
618
619 prim.PhysShape = newShape;
620
621 return true; // 'true' means a new shape has been added to this prim
622 }
623
624 private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
625 { 236 {
626 BulletShape newShape = new BulletShape(); 237 lock (m_collectionActivityLock)
627
628 MeshDesc meshDesc;
629 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
630 {
631 // If the mesh has already been built just use it.
632 newShape = meshDesc.shape.Clone();
633 }
634 else
635 { 238 {
636 IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, 239 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
637 false, // say it is not physical so a bounding box is not built 240 if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body))
638 false // do not cache the mesh and do not use previously built versions
639 );
640
641 if (meshData != null)
642 { 241 {
643 242 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body);
644 int[] indices = meshData.getIndexListAsInt(); 243 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
645 int realIndicesIndex = indices.Length;
646 float[] verticesAsFloats = meshData.getVertexListAsFloat();
647
648 if (BSParam.ShouldRemoveZeroWidthTriangles)
649 {
650 // Remove degenerate triangles. These are triangles with two of the vertices
651 // are the same. This is complicated by the problem that vertices are not
652 // made unique in sculpties so we have to compare the values in the vertex.
653 realIndicesIndex = 0;
654 for (int tri = 0; tri < indices.Length; tri += 3)
655 {
656 // Compute displacements into vertex array for each vertex of the triangle
657 int v1 = indices[tri + 0] * 3;
658 int v2 = indices[tri + 1] * 3;
659 int v3 = indices[tri + 2] * 3;
660 // Check to see if any two of the vertices are the same
661 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
662 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
663 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
664 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
665 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
666 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
667 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
668 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
669 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
670 )
671 {
672 // None of the vertices of the triangles are the same. This is a good triangle;
673 indices[realIndicesIndex + 0] = indices[tri + 0];
674 indices[realIndicesIndex + 1] = indices[tri + 1];
675 indices[realIndicesIndex + 2] = indices[tri + 2];
676 realIndicesIndex += 3;
677 }
678 }
679 }
680 DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}",
681 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
682
683 if (realIndicesIndex != 0)
684 {
685 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
686 realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
687 }
688 else
689 {
690 PhysicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
691 LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name);
692 }
693 } 244 }
694 } 245 }
695 newShape.shapeKey = newMeshKey;
696
697 return newShape;
698 }
699
700 // See that hull shape exists in the physical world and update prim.BSShape.
701 // We could be creating the hull because scale changed or whatever.
702 // Return 'true' if a new hull was built. Otherwise, returning a shared hull instance.
703 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
704 {
705 BulletShape newShape;
706
707 float lod;
708 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
709
710 // if the hull hasn't changed, don't rebuild it
711 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
712 return false;
713
714 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
715 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
716
717 // Remove usage of the previous shape.
718 DereferenceShape(prim.PhysShape, shapeCallback);
719
720 newShape = CreatePhysicalHull(prim, newHullKey, prim.BaseShape, prim.Size, lod);
721 // It might not have been created if we're waiting for an asset.
722 newShape = VerifyMeshCreated(PhysicsScene, newShape, prim);
723
724 ReferenceShape(newShape);
725
726 prim.PhysShape = newShape;
727 return true; // 'true' means a new shape has been added to this prim
728 } 246 }
729 247
730 List<ConvexResult> m_hulls; 248 // Release the usage of a body.
731 private BulletShape CreatePhysicalHull(BSPhysObject prim, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 249 // Called when releasing use of a BSBody. BSShape is handled separately.
250 // Called in taint time.
251 public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback )
732 { 252 {
253 if (!body.HasPhysicalBody)
254 return;
733 255
734 BulletShape newShape = new BulletShape(); 256 m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
735 IntPtr hullPtr = IntPtr.Zero;
736 257
737 HullDesc hullDesc; 258 lock (m_collectionActivityLock)
738 if (Hulls.TryGetValue(newHullKey, out hullDesc))
739 {
740 // If the hull shape already has been created, just use the one shared instance.
741 newShape = hullDesc.shape.Clone();
742 }
743 else
744 { 259 {
745 if (BSParam.ShouldUseBulletHACD) 260 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
746 { 261 // If the caller needs to know the old body is going away, pass the event up.
747 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID); 262 if (bodyCallback != null)
748 MeshDesc meshDesc; 263 bodyCallback(body, null);
749 if (!Meshes.TryGetValue(newHullKey, out meshDesc))
750 {
751 // That's odd because the mesh should have been created before the hull
752 // but, since it doesn't exist, create it.
753 newShape = CreatePhysicalMesh(prim, newHullKey, prim.BaseShape, prim.Size, lod);
754 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,noMeshBuiltNew,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
755
756 if (newShape.HasPhysicalShape)
757 {
758 ReferenceShape(newShape);
759 Meshes.TryGetValue(newHullKey, out meshDesc);
760 }
761 }
762 if (meshDesc.shape.HasPhysicalShape)
763 {
764 HACDParams parms;
765 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
766 parms.minClusters = BSParam.BHullMinClusters;
767 parms.compacityWeight = BSParam.BHullCompacityWeight;
768 parms.volumeWeight = BSParam.BHullVolumeWeight;
769 parms.concavity = BSParam.BHullConcavity;
770 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
771 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
772 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
773 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
774
775 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
776 newShape = PhysicsScene.PE.BuildHullShapeFromMesh(PhysicsScene.World, meshDesc.shape, parms);
777 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
778 }
779 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
780 }
781 if (!newShape.HasPhysicalShape)
782 {
783 // Build a new hull in the physical world.
784 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
785 IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
786 if (meshData != null)
787 {
788 int[] indices = meshData.getIndexListAsInt();
789 List<OMV.Vector3> vertices = meshData.getVertexList();
790
791 //format conversion from IMesh format to DecompDesc format
792 List<int> convIndices = new List<int>();
793 List<float3> convVertices = new List<float3>();
794 for (int ii = 0; ii < indices.GetLength(0); ii++)
795 {
796 convIndices.Add(indices[ii]);
797 }
798 foreach (OMV.Vector3 vv in vertices)
799 {
800 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
801 }
802
803 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
804 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
805 {
806 // Simple primitive shapes we know are convex so they are better implemented with
807 // fewer hulls.
808 // Check for simple shape (prim without cuts) and reduce split parameter if so.
809 if (PrimHasNoCuts(pbs))
810 {
811 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
812 }
813 }
814
815 // setup and do convex hull conversion
816 m_hulls = new List<ConvexResult>();
817 DecompDesc dcomp = new DecompDesc();
818 dcomp.mIndices = convIndices;
819 dcomp.mVertices = convVertices;
820 dcomp.mDepth = maxDepthSplit;
821 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
822 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
823 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
824 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
825 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
826 // create the hull into the _hulls variable
827 convexBuilder.process(dcomp);
828
829 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
830 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
831
832 // Convert the vertices and indices for passing to unmanaged.
833 // The hull information is passed as a large floating point array.
834 // The format is:
835 // convHulls[0] = number of hulls
836 // convHulls[1] = number of vertices in first hull
837 // convHulls[2] = hull centroid X coordinate
838 // convHulls[3] = hull centroid Y coordinate
839 // convHulls[4] = hull centroid Z coordinate
840 // convHulls[5] = first hull vertex X
841 // convHulls[6] = first hull vertex Y
842 // convHulls[7] = first hull vertex Z
843 // convHulls[8] = second hull vertex X
844 // ...
845 // convHulls[n] = number of vertices in second hull
846 // convHulls[n+1] = second hull centroid X coordinate
847 // ...
848 //
849 // TODO: is is very inefficient. Someday change the convex hull generator to return
850 // data structures that do not need to be converted in order to pass to Bullet.
851 // And maybe put the values directly into pinned memory rather than marshaling.
852 int hullCount = m_hulls.Count;
853 int totalVertices = 1; // include one for the count of the hulls
854 foreach (ConvexResult cr in m_hulls)
855 {
856 totalVertices += 4; // add four for the vertex count and centroid
857 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
858 }
859 float[] convHulls = new float[totalVertices];
860
861 convHulls[0] = (float)hullCount;
862 int jj = 1;
863 foreach (ConvexResult cr in m_hulls)
864 {
865 // copy vertices for index access
866 float3[] verts = new float3[cr.HullVertices.Count];
867 int kk = 0;
868 foreach (float3 ff in cr.HullVertices)
869 {
870 verts[kk++] = ff;
871 }
872
873 // add to the array one hull's worth of data
874 convHulls[jj++] = cr.HullIndices.Count;
875 convHulls[jj++] = 0f; // centroid x,y,z
876 convHulls[jj++] = 0f;
877 convHulls[jj++] = 0f;
878 foreach (int ind in cr.HullIndices)
879 {
880 convHulls[jj++] = verts[ind].x;
881 convHulls[jj++] = verts[ind].y;
882 convHulls[jj++] = verts[ind].z;
883 }
884 }
885 // create the hull data structure in Bullet
886 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
887 }
888 }
889 newShape.shapeKey = newHullKey;
890 }
891
892 return newShape;
893 }
894
895 // Callback from convex hull creater with a newly created hull.
896 // Just add it to our collection of hulls for this shape.
897 private void HullReturn(ConvexResult result)
898 {
899 m_hulls.Add(result);
900 return;
901 }
902
903 // Compound shapes are always built from scratch.
904 // This shouldn't be to bad since most of the parts will be meshes that had been built previously.
905 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
906 {
907 // Remove reference to the old shape
908 // Don't need to do this as the shape is freed when the new root shape is created below.
909 // DereferenceShape(prim.PhysShape, true, shapeCallback);
910
911 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false);
912
913 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
914 CreateGeomMeshOrHull(prim, shapeCallback);
915 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
916 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
917 prim.LocalID, cShape, prim.PhysShape);
918
919 prim.PhysShape = cShape;
920
921 return true;
922 }
923
924 // Create a hash of all the shape parameters to be used as a key
925 // for this particular shape.
926 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
927 {
928 // level of detail based on size and type of the object
929 float lod = BSParam.MeshLOD;
930
931 // prims with curvy internal cuts need higher lod
932 if (pbs.HollowShape == HollowShape.Circle)
933 lod = BSParam.MeshCircularLOD;
934
935 if (pbs.SculptEntry)
936 lod = BSParam.SculptLOD;
937
938 // Mega prims usually get more detail because one can interact with shape approximations at this size.
939 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
940 if (maxAxis > BSParam.MeshMegaPrimThreshold)
941 lod = BSParam.MeshMegaPrimLOD;
942
943 retLod = lod;
944 return pbs.GetMeshKey(size, lod);
945 }
946 // For those who don't want the LOD
947 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
948 {
949 float lod;
950 return ComputeShapeKey(size, pbs, out lod);
951 }
952
953 // The creation of a mesh or hull can fail if an underlying asset is not available.
954 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
955 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
956 // The first case causes the asset to be fetched. The second case requires
957 // us to not loop forever.
958 // Called after creating a physical mesh or hull. If the physical shape was created,
959 // just return.
960 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
961 {
962 // If the shape was successfully created, nothing more to do
963 if (newShape.HasPhysicalShape)
964 return newShape;
965 264
966 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been 265 // Removing an object not in the world is a NOOP
967 // fetched but we end up here again, the meshing of the asset must have failed. 266 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body);
968 // Prevent trying to keep fetching the mesh by declaring failure.
969 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
970 {
971 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
972 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
973 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
974 }
975 else
976 {
977 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
978 if (prim.BaseShape.SculptEntry
979 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
980 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
981 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
982 )
983 {
984 physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
985 // Multiple requestors will know we're waiting for this asset
986 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
987 267
988 BSPhysObject xprim = prim; 268 // Zero any reference to the shape so it is not freed when the body is deleted.
989 Util.FireAndForget(delegate 269 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null);
990 {
991 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
992 if (assetProvider != null)
993 {
994 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
995 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
996 {
997 bool assetFound = false;
998 string mismatchIDs = String.Empty; // DEBUG DEBUG
999 if (asset != null && yprim.BaseShape.SculptEntry)
1000 {
1001 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
1002 {
1003 yprim.BaseShape.SculptData = asset.Data;
1004 // This will cause the prim to see that the filler shape is not the right
1005 // one and try again to build the object.
1006 // No race condition with the normal shape setting since the rebuild is at taint time.
1007 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
1008 assetFound = true;
1009 }
1010 else
1011 {
1012 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
1013 }
1014 }
1015 if (assetFound)
1016 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
1017 else
1018 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
1019 physicsScene.DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
1020 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
1021 270
1022 }); 271 m_physicsScene.PE.DestroyObject(m_physicsScene.World, body);
1023 }
1024 else
1025 {
1026 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
1027 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
1028 LogHeader, physicsScene.Name);
1029 }
1030 });
1031 }
1032 else
1033 {
1034 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
1035 {
1036 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
1037 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
1038 }
1039 }
1040 } 272 }
1041
1042 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
1043 BulletShape fillinShape = physicsScene.Shapes.BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
1044 physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID);
1045
1046 return fillinShape;
1047 } 273 }
1048 274
1049 // Create a body object in Bullet. 275 // Create a body object in Bullet.
1050 // Updates prim.BSBody with the information about the new body if one is created. 276 // Updates prim.BSBody with the information about the new body if one is created.
1051 // Returns 'true' if an object was actually created. 277 // Returns 'true' if an object was actually created.
1052 // Called at taint-time. 278 // Called at taint-time.
1053 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BodyDestructionCallback bodyCallback) 279 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback)
1054 { 280 {
1055 bool ret = false; 281 bool ret = false;
1056 282
@@ -1061,7 +287,7 @@ public sealed class BSShapeCollection : IDisposable
1061 // If not a solid object, body is a GhostObject. Otherwise a RigidBody. 287 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
1062 if (!mustRebuild) 288 if (!mustRebuild)
1063 { 289 {
1064 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody); 290 CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody);
1065 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 291 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
1066 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 292 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
1067 { 293 {
@@ -1079,12 +305,12 @@ public sealed class BSShapeCollection : IDisposable
1079 BulletBody aBody; 305 BulletBody aBody;
1080 if (prim.IsSolid) 306 if (prim.IsSolid)
1081 { 307 {
1082 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); 308 aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
1083 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); 309 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody);
1084 } 310 }
1085 else 311 else
1086 { 312 {
1087 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); 313 aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
1088 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); 314 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
1089 } 315 }
1090 316
@@ -1098,46 +324,10 @@ public sealed class BSShapeCollection : IDisposable
1098 return ret; 324 return ret;
1099 } 325 }
1100 326
1101 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
1102 {
1103 bool ret = false;
1104 MeshDesc foundDesc = new MeshDesc();
1105 foreach (MeshDesc md in Meshes.Values)
1106 {
1107 if (md.shape.ReferenceSame(shape))
1108 {
1109 foundDesc = md;
1110 ret = true;
1111 break;
1112 }
1113
1114 }
1115 outDesc = foundDesc;
1116 return ret;
1117 }
1118
1119 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
1120 {
1121 bool ret = false;
1122 HullDesc foundDesc = new HullDesc();
1123 foreach (HullDesc hd in Hulls.Values)
1124 {
1125 if (hd.shape.ReferenceSame(shape))
1126 {
1127 foundDesc = hd;
1128 ret = true;
1129 break;
1130 }
1131
1132 }
1133 outDesc = foundDesc;
1134 return ret;
1135 }
1136
1137 private void DetailLog(string msg, params Object[] args) 327 private void DetailLog(string msg, params Object[] args)
1138 { 328 {
1139 if (PhysicsScene.PhysicsLogging.Enabled) 329 if (m_physicsScene.PhysicsLogging.Enabled)
1140 PhysicsScene.DetailLog(msg, args); 330 m_physicsScene.DetailLog(msg, args);
1141 } 331 }
1142} 332}
1143} 333}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
index e427dbc..a7b3f02 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -39,6 +39,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
39{ 39{
40public abstract class BSShape 40public abstract class BSShape
41{ 41{
42 private static string LogHeader = "[BULLETSIM SHAPE]";
43
42 public int referenceCount { get; set; } 44 public int referenceCount { get; set; }
43 public DateTime lastReferenced { get; set; } 45 public DateTime lastReferenced { get; set; }
44 public BulletShape physShapeInfo { get; set; } 46 public BulletShape physShapeInfo { get; set; }
@@ -56,49 +58,6 @@ public abstract class BSShape
56 physShapeInfo = pShape; 58 physShapeInfo = pShape;
57 } 59 }
58 60
59 // Get a reference to a physical shape. Create if it doesn't exist
60 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
61 {
62 BSShape ret = null;
63
64 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
65 {
66 // an avatar capsule is close to a native shape (it is not shared)
67 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
68 FixedShapeKey.KEY_CAPSULE);
69 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
70 }
71
72 // Compound shapes are handled special as they are rebuilt from scratch.
73 // This isn't too great a hardship since most of the child shapes will have already been created.
74 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
75 {
76 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
77 ret = BSShapeCompound.GetReference(physicsScene, prim);
78 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
79 }
80
81 // Avatars have their own unique shape
82 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR)
83 {
84 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
85 ret = BSShapeAvatar.GetReference(prim);
86 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret);
87 }
88
89 if (ret == null)
90 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
91
92 return ret;
93 }
94 private static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
95 {
96 // TODO: work needed here!!
97 BSShapeMesh.GetReference(physicsScene, forceRebuild, prim);
98 BSShapeHull.GetReference(physicsScene, forceRebuild, prim);
99 return null;
100 }
101
102 // Called when this shape is being used again. 61 // Called when this shape is being used again.
103 public virtual void IncrementReference() 62 public virtual void IncrementReference()
104 { 63 {
@@ -116,6 +75,27 @@ public abstract class BSShape
116 // Release the use of a physical shape. 75 // Release the use of a physical shape.
117 public abstract void Dereference(BSScene physicsScene); 76 public abstract void Dereference(BSScene physicsScene);
118 77
78 // Return 'true' if there is an allocated physics physical shape under this class instance.
79 public virtual bool HasPhysicalShape
80 {
81 get
82 {
83 if (physShapeInfo != null)
84 return physShapeInfo.HasPhysicalShape;
85 return false;
86 }
87 }
88 public virtual BSPhysicsShapeType ShapeType
89 {
90 get
91 {
92 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
93 if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
94 ret = physShapeInfo.shapeType;
95 return ret;
96 }
97 }
98
119 // Returns a string for debugging that uniquily identifies the memory used by this instance 99 // Returns a string for debugging that uniquily identifies the memory used by this instance
120 public virtual string AddrString 100 public virtual string AddrString
121 { 101 {
@@ -132,6 +112,119 @@ public abstract class BSShape
132 buff.Append(">"); 112 buff.Append(">");
133 return buff.ToString(); 113 return buff.ToString();
134 } 114 }
115
116 // Create a hash of all the shape parameters to be used as a key for this particular shape.
117 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
118 {
119 // level of detail based on size and type of the object
120 float lod = BSParam.MeshLOD;
121 if (pbs.SculptEntry)
122 lod = BSParam.SculptLOD;
123
124 // Mega prims usually get more detail because one can interact with shape approximations at this size.
125 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
126 if (maxAxis > BSParam.MeshMegaPrimThreshold)
127 lod = BSParam.MeshMegaPrimLOD;
128
129 retLod = lod;
130 return pbs.GetMeshKey(size, lod);
131 }
132
133 // The creation of a mesh or hull can fail if an underlying asset is not available.
134 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
135 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
136 // The first case causes the asset to be fetched. The second case requires
137 // us to not loop forever.
138 // Called after creating a physical mesh or hull. If the physical shape was created,
139 // just return.
140 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
141 {
142 // If the shape was successfully created, nothing more to do
143 if (newShape.HasPhysicalShape)
144 return newShape;
145
146 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
147 // fetched but we end up here again, the meshing of the asset must have failed.
148 // Prevent trying to keep fetching the mesh by declaring failure.
149 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
150 {
151 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
152 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
153 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
154 }
155 else
156 {
157 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
158 if (prim.BaseShape.SculptEntry
159 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
160 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
161 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
162 )
163 {
164 physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
165 // Multiple requestors will know we're waiting for this asset
166 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
167
168 BSPhysObject xprim = prim;
169 Util.FireAndForget(delegate
170 {
171 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
172 if (assetProvider != null)
173 {
174 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
175 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
176 {
177 bool assetFound = false;
178 string mismatchIDs = String.Empty; // DEBUG DEBUG
179 if (asset != null && yprim.BaseShape.SculptEntry)
180 {
181 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
182 {
183 yprim.BaseShape.SculptData = asset.Data;
184 // This will cause the prim to see that the filler shape is not the right
185 // one and try again to build the object.
186 // No race condition with the normal shape setting since the rebuild is at taint time.
187 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
188 assetFound = true;
189 }
190 else
191 {
192 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
193 }
194 }
195 if (assetFound)
196 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
197 else
198 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
199 physicsScene.DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
200 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
201 });
202 }
203 else
204 {
205 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
206 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
207 LogHeader, physicsScene.Name);
208 }
209 });
210 }
211 else
212 {
213 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
214 {
215 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
216 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
217 }
218 }
219 }
220
221 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
222 BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
223 physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID);
224
225 return fillShape.physShapeInfo;
226 }
227
135} 228}
136 229
137// ============================================================================================================ 230// ============================================================================================================
@@ -199,7 +292,7 @@ public class BSShapeNative : BSShape
199 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 292 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
200 LogHeader, prim.LocalID, shapeType); 293 LogHeader, prim.LocalID, shapeType);
201 } 294 }
202 newShape.type = shapeType; 295 newShape.shapeType = shapeType;
203 newShape.isNativeShape = true; 296 newShape.isNativeShape = true;
204 newShape.shapeKey = (UInt64)shapeKey; 297 newShape.shapeKey = (UInt64)shapeKey;
205 return newShape; 298 return newShape;
@@ -219,10 +312,11 @@ public class BSShapeMesh : BSShape
219 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 312 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
220 { 313 {
221 float lod; 314 float lod;
222 System.UInt64 newMeshKey = BSShapeCollection.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 315 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
223 316
224 physicsScene.DetailLog("{0},BSShapeMesh,getReference,oldKey={1},newKey={2},size={3},lod={4}", 317 physicsScene.DetailLog("{0},BSShapeMesh,getReference,oldKey={1},newKey={2},size={3},lod={4}",
225 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod); 318 prim.LocalID, prim.PhysShape.physShapeInfo.shapeKey.ToString("X"),
319 newMeshKey.ToString("X"), prim.Size, lod);
226 320
227 BSShapeMesh retMesh = new BSShapeMesh(new BulletShape()); 321 BSShapeMesh retMesh = new BSShapeMesh(new BulletShape());
228 lock (Meshes) 322 lock (Meshes)
@@ -238,8 +332,8 @@ public class BSShapeMesh : BSShape
238 BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); 332 BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
239 333
240 // Check to see if mesh was created (might require an asset). 334 // Check to see if mesh was created (might require an asset).
241 newShape = BSShapeCollection.VerifyMeshCreated(physicsScene, newShape, prim); 335 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
242 if (newShape.type == BSPhysicsShapeType.SHAPE_MESH) 336 if (newShape.shapeType == BSPhysicsShapeType.SHAPE_MESH)
243 { 337 {
244 // If a mesh was what was created, remember the built shape for later sharing. 338 // If a mesh was what was created, remember the built shape for later sharing.
245 Meshes.Add(newMeshKey, retMesh); 339 Meshes.Add(newMeshKey, retMesh);
@@ -360,10 +454,10 @@ public class BSShapeHull : BSShape
360 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 454 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
361 { 455 {
362 float lod; 456 float lod;
363 System.UInt64 newHullKey = BSShapeCollection.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 457 System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
364 458
365 physicsScene.DetailLog("{0},BSShapeHull,getReference,oldKey={1},newKey={2},size={3},lod={4}", 459 physicsScene.DetailLog("{0},BSShapeHull,getReference,oldKey={1},newKey={2},size={3},lod={4}",
366 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"), prim.Size, lod); 460 prim.LocalID, prim.PhysShape.physShapeInfo.shapeKey.ToString("X"), newHullKey.ToString("X"), prim.Size, lod);
367 461
368 BSShapeHull retHull = new BSShapeHull(new BulletShape()); 462 BSShapeHull retHull = new BSShapeHull(new BulletShape());
369 lock (Hulls) 463 lock (Hulls)
@@ -379,8 +473,8 @@ public class BSShapeHull : BSShape
379 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod); 473 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
380 474
381 // Check to see if mesh was created (might require an asset). 475 // Check to see if mesh was created (might require an asset).
382 newShape = BSShapeCollection.VerifyMeshCreated(physicsScene, newShape, prim); 476 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
383 if (newShape.type == BSPhysicsShapeType.SHAPE_MESH) 477 if (newShape.shapeType == BSPhysicsShapeType.SHAPE_MESH)
384 { 478 {
385 // If a mesh was what was created, remember the built shape for later sharing. 479 // If a mesh was what was created, remember the built shape for later sharing.
386 Hulls.Add(newHullKey, retHull); 480 Hulls.Add(newHullKey, retHull);
@@ -569,7 +663,6 @@ public class BSShapeHull : BSShape
569 } 663 }
570} 664}
571 665
572
573// ============================================================================================================ 666// ============================================================================================================
574public class BSShapeCompound : BSShape 667public class BSShapeCompound : BSShape
575{ 668{
@@ -589,9 +682,9 @@ public class BSShapeCompound : BSShape
589 { 682 {
590 // Failed the sanity check!! 683 // Failed the sanity check!!
591 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", 684 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
592 LogHeader, physShapeInfo.type, physShapeInfo.AddrString); 685 LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
593 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", 686 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
594 BSScene.DetailLogZero, physShapeInfo.type, physShapeInfo.AddrString); 687 BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
595 return; 688 return;
596 } 689 }
597 690
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
index 8012d91..906e4f9 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
@@ -104,11 +104,11 @@ public class BulletShape
104{ 104{
105 public BulletShape() 105 public BulletShape()
106 { 106 {
107 type = BSPhysicsShapeType.SHAPE_UNKNOWN; 107 shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; 108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false; 109 isNativeShape = false;
110 } 110 }
111 public BSPhysicsShapeType type; 111 public BSPhysicsShapeType shapeType;
112 public System.UInt64 shapeKey; 112 public System.UInt64 shapeKey;
113 public bool isNativeShape; 113 public bool isNativeShape;
114 114
@@ -133,7 +133,7 @@ public class BulletShape
133 buff.Append("<p="); 133 buff.Append("<p=");
134 buff.Append(AddrString); 134 buff.Append(AddrString);
135 buff.Append(",s="); 135 buff.Append(",s=");
136 buff.Append(type.ToString()); 136 buff.Append(shapeType.ToString());
137 buff.Append(",k="); 137 buff.Append(",k=");
138 buff.Append(shapeKey.ToString("X")); 138 buff.Append(shapeKey.ToString("X"));
139 buff.Append(",n="); 139 buff.Append(",n=");