aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs238
1 files changed, 175 insertions, 63 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index 1f7c398..2189468 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -32,18 +32,43 @@ using OMV = OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35
36// When a child is linked, the relationship position of the child to the parent
37// is remembered so the child's world position can be recomputed when it is
38// removed from the linkset.
39sealed class BSLinksetCompoundInfo : BSLinksetInfo
40{
41 public OMV.Vector3 OffsetPos;
42 public OMV.Quaternion OffsetRot;
43 public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r)
44 {
45 OffsetPos = p;
46 OffsetRot = r;
47 }
48 public override string ToString()
49 {
50 StringBuilder buff = new StringBuilder();
51 buff.Append("<p=");
52 buff.Append(OffsetPos.ToString());
53 buff.Append(",r=");
54 buff.Append(OffsetRot.ToString());
55 buff.Append(">");
56 return buff.ToString();
57 }
58};
59
35public sealed class BSLinksetCompound : BSLinkset 60public sealed class BSLinksetCompound : BSLinkset
36{ 61{
37 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; 62 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
38 63
39 public BSLinksetCompound(BSScene scene, BSPhysObject parent) 64 public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 { 65 {
41 base.Initialize(scene, parent);
42 } 66 }
43 67
44 // For compound implimented linksets, if there are children, use compound shape for the root. 68 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 69 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
46 { 70 {
71 // Returning 'unknown' means we don't have a preference.
47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 72 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren) 73 if (IsRoot(requestor) && HasAnyChildren)
49 { 74 {
@@ -55,23 +80,27 @@ public sealed class BSLinksetCompound : BSLinkset
55 80
56 // When physical properties are changed the linkset needs to recalculate 81 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties. 82 // its internal properties.
58 // This is queued in the 'post taint' queue so the
59 // refresh will happen once after all the other taints are applied.
60 public override void Refresh(BSPhysObject requestor) 83 public override void Refresh(BSPhysObject requestor)
61 { 84 {
62 // External request for Refresh (from BSPrim) doesn't need to do anything 85 // External request for Refresh (from BSPrim) doesn't need to do anything
63 // InternalRefresh(requestor); 86 // InternalRefresh(requestor);
64 } 87 }
65 88
89 // Schedule a refresh to happen after all the other taint processing.
66 private void InternalRefresh(BSPhysObject requestor) 90 private void InternalRefresh(BSPhysObject requestor)
67 { 91 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); 92 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1},rebuilding={2}",
69 // Queue to happen after all the other taint processing 93 LinksetRoot.LocalID, requestor.LocalID, Rebuilding);
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() 94 // When rebuilding, it is possible to set properties that would normally require a rebuild.
95 // If already rebuilding, don't request another rebuild.
96 if (!Rebuilding)
71 { 97 {
72 if (IsRoot(requestor) && HasAnyChildren) 98 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate()
73 RecomputeLinksetCompound(); 99 {
74 }); 100 if (IsRoot(requestor) && HasAnyChildren)
101 RecomputeLinksetCompound();
102 });
103 }
75 } 104 }
76 105
77 // The object is going dynamic (physical). Do any setup necessary 106 // The object is going dynamic (physical). Do any setup necessary
@@ -84,12 +113,24 @@ public sealed class BSLinksetCompound : BSLinkset
84 { 113 {
85 bool ret = false; 114 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 115 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child)) 116 if (IsRoot(child))
117 {
118 // The root is going dynamic. Make sure mass is properly set.
119 m_mass = ComputeLinksetMass();
120 if (HasAnyChildren)
121 InternalRefresh(LinksetRoot);
122 }
123 else
88 { 124 {
89 // The origional prims are removed from the world as the shape of the root compound 125 // The origional prims are removed from the world as the shape of the root compound
90 // shape takes over. 126 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 127 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 128 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
129 // We don't want collisions from the old linkset children.
130 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
131
132 child.PhysBody.collisionType = CollisionType.LinksetChild;
133
93 ret = true; 134 ret = true;
94 } 135 }
95 return ret; 136 return ret;
@@ -104,11 +145,19 @@ public sealed class BSLinksetCompound : BSLinkset
104 { 145 {
105 bool ret = false; 146 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 147 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child)) 148 if (IsRoot(child))
149 {
150 if (HasAnyChildren)
151 InternalRefresh(LinksetRoot);
152 }
153 else
108 { 154 {
109 // The non-physical children can come back to life. 155 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 156 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay. 157
158 child.PhysBody.collisionType = CollisionType.LinksetChild;
159
160 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false); 161 BulletSimAPI.Activate2(child.PhysBody.ptr, false);
113 ret = true; 162 ret = true;
114 } 163 }
@@ -146,20 +195,58 @@ public sealed class BSLinksetCompound : BSLinkset
146 195
147 if (!IsRoot(child)) 196 if (!IsRoot(child))
148 { 197 {
149 // Cause the current shape to be freed and the new one to be built. 198 // Because it is a convenient time, recompute child world position and rotation based on
150 InternalRefresh(LinksetRoot); 199 // its position in the linkset.
151 ret = true; 200 RecomputeChildWorldPosition(child, true);
152 } 201 }
153 202
203 // Cannot schedule a refresh/rebuild here because this routine is called when
204 // the linkset is being rebuilt.
205 // InternalRefresh(LinksetRoot);
206
154 return ret; 207 return ret;
155 } 208 }
156 209
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 210 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
158 // this routine will restore the removed constraints. 211 // this routine will restore the removed constraints.
159 // Called at taint-time!! 212 // Called at taint-time!!
160 public override void RestoreBodyDependencies(BSPrim child) 213 public override void RestoreBodyDependencies(BSPrim child)
161 { 214 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. 215 }
216
217 // When the linkset is built, the child shape is added to the compound shape relative to the
218 // root shape. The linkset then moves around but this does not move the actual child
219 // prim. The child prim's location must be recomputed based on the location of the root shape.
220 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
221 {
222 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
223 if (lci != null)
224 {
225 if (inTaintTime)
226 {
227 OMV.Vector3 oldPos = child.RawPosition;
228 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos;
229 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
230 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
231 child.LocalID, oldPos, lci, child.RawPosition);
232 }
233 else
234 {
235 // TaintedObject is not used here so the raw position is set now and not at taint-time.
236 child.Position = LinksetRoot.RawPosition + lci.OffsetPos;
237 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
238 }
239 }
240 else
241 {
242 // This happens when children have been added to the linkset but the linkset
243 // has not been constructed yet. So like, at taint time, adding children to a linkset
244 // and then changing properties of the children (makePhysical, for instance)
245 // but the post-print action of actually rebuilding the linkset has not yet happened.
246 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
247 // LogHeader, child.LocalID);
248 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
249 }
163 } 250 }
164 251
165 // ================================================================ 252 // ================================================================
@@ -181,7 +268,7 @@ public sealed class BSLinksetCompound : BSLinkset
181 } 268 }
182 269
183 // Remove the specified child from the linkset. 270 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset. 271 // Safe to call even if the child is not really in the linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child) 272 protected override void RemoveChildFromLinkset(BSPhysObject child)
186 { 273 {
187 if (m_children.Remove(child)) 274 if (m_children.Remove(child))
@@ -192,6 +279,7 @@ public sealed class BSLinksetCompound : BSLinkset
192 child.LocalID, child.PhysBody.ptr.ToString("X")); 279 child.LocalID, child.PhysBody.ptr.ToString("X"));
193 280
194 // Cause the child's body to be rebuilt and thus restored to normal operation 281 // Cause the child's body to be rebuilt and thus restored to normal operation
282 RecomputeChildWorldPosition(child, false);
195 child.ForceBodyShapeRebuild(false); 283 child.ForceBodyShapeRebuild(false);
196 284
197 if (!HasAnyChildren) 285 if (!HasAnyChildren)
@@ -215,59 +303,83 @@ public sealed class BSLinksetCompound : BSLinkset
215 // Called at taint time!! 303 // Called at taint time!!
216 private void RecomputeLinksetCompound() 304 private void RecomputeLinksetCompound()
217 { 305 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it 306 try
219 LinksetRoot.ForceBodyShapeRebuild(true);
220
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
223
224 // Add a shape for each of the other children in the linkset
225 ForEachMember(delegate(BSPhysObject cPrim)
226 { 307 {
227 if (!IsRoot(cPrim)) 308 // Suppress rebuilding while rebuilding
228 { 309 Rebuilding = true;
229 // Each child position and rotation is given relative to the root.
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
233 310
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", 311 // Cause the root shape to be rebuilt as a compound object with just the root in it
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); 312 LinksetRoot.ForceBodyShapeRebuild(true);
236 313
237 if (cPrim.PhysShape.isNativeShape) 314 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
238 { 315 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
239 // Native shapes are not shared so we need to create a new one. 316
240 // A mesh or hull is created because scale is not available on a native shape. 317 // Add a shape for each of the other children in the linkset
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) 318 ForEachMember(delegate(BSPhysObject cPrim)
242 BulletShape saveShape = cPrim.PhysShape; 319 {
243 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape 320 if (!IsRoot(cPrim))
244 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
245 BulletShape newShape = cPrim.PhysShape;
246 cPrim.PhysShape = saveShape;
247 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot);
248 }
249 else
250 { 321 {
251 // For the shared shapes (meshes and hulls), just use the shape in the child. 322 // Compute the displacement of the child from the root of the linkset.
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) 323 // This info is saved in the child prim so the relationship does not
324 // change over time and the new child position can be computed
325 // when the linkset is being disassembled (the linkset may have moved).
326 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
327 if (lci == null)
253 { 328 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", 329 // Each child position and rotation is given relative to the root.
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); 330 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
331 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
332 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
333
334 // Save relative position for recomputing child's world position after moving linkset.
335 lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
336 cPrim.LinksetInfo = lci;
337 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
256 } 338 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
258 }
259 }
260 339
261 // TODO: need to phantomize the child prims left behind. 340 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
262 // Maybe just destroy the children bodies and shapes and have them rebuild on unlink. 341 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
263 // Selection/deselection might cause way too many build/destructions esp. for LARGE linksets.
264 342
265 return false; // 'false' says to move onto the next child in the list 343 if (cPrim.PhysShape.isNativeShape)
266 }); 344 {
345 // A native shape is turning into a hull collision shape because native
346 // shapes are not shared so we have to hullify it so it will be tracked
347 // and freed at the correct time. This also solves the scaling problem
348 // (native shapes scaled but hull/meshes are assumed to not be).
349 // TODO: decide of the native shape can just be used in the compound shape.
350 // Use call to CreateGeomNonSpecial().
351 BulletShape saveShape = cPrim.PhysShape;
352 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
353 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
354 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
355 BulletShape newShape = cPrim.PhysShape;
356 cPrim.PhysShape = saveShape;
357 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot);
358 }
359 else
360 {
361 // For the shared shapes (meshes and hulls), just use the shape in the child.
362 // The reference count added here will be decremented when the compound shape
363 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
364 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
365 {
366 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
367 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
368 }
369 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot);
370 }
371 }
372 return false; // 'false' says to move onto the next child in the list
373 });
267 374
268 // With all of the linkset packed into the root prim, it has the mass of everyone. 375 // With all of the linkset packed into the root prim, it has the mass of everyone.
269 float linksetMass = LinksetMass; 376 float linksetMass = LinksetMass;
270 LinksetRoot.UpdatePhysicalMassProperties(linksetMass); 377 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
378 }
379 finally
380 {
381 Rebuilding = false;
382 }
271 383
272 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); 384 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr);
273 385