aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs406
1 files changed, 311 insertions, 95 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index b9c2cf9..27d8ad0 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -28,22 +28,79 @@ using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Text; 29using System.Text;
30 30
31using OpenSim.Framework;
32
31using OMV = OpenMetaverse; 33using OMV = OpenMetaverse;
32 34
33namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
34{ 36{
37
38// When a child is linked, the relationship position of the child to the parent
39// is remembered so the child's world position can be recomputed when it is
40// removed from the linkset.
41sealed class BSLinksetCompoundInfo : BSLinksetInfo
42{
43 public int Index;
44 public OMV.Vector3 OffsetFromRoot;
45 public OMV.Vector3 OffsetFromCenterOfMass;
46 public OMV.Quaternion OffsetRot;
47 public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r)
48 {
49 Index = indx;
50 OffsetFromRoot = p;
51 OffsetFromCenterOfMass = p;
52 OffsetRot = r;
53 }
54 // 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape)
55 public BSLinksetCompoundInfo(int indx, BSPhysObject root, BSPhysObject child, OMV.Vector3 centerDisplacement)
56 {
57 // Each child position and rotation is given relative to the center-of-mass.
58 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation);
59 OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation;
60 OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement;
61 OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation;
62
63 // Save relative position for recomputing child's world position after moving linkset.
64 Index = indx;
65 OffsetFromRoot = displacementFromRoot;
66 OffsetFromCenterOfMass = displacementFromCOM;
67 OffsetRot = displacementRot;
68 }
69 public override void Clear()
70 {
71 Index = 0;
72 OffsetFromRoot = OMV.Vector3.Zero;
73 OffsetFromCenterOfMass = OMV.Vector3.Zero;
74 OffsetRot = OMV.Quaternion.Identity;
75 }
76 public override string ToString()
77 {
78 StringBuilder buff = new StringBuilder();
79 buff.Append("<i=");
80 buff.Append(Index.ToString());
81 buff.Append(",p=");
82 buff.Append(OffsetFromRoot.ToString());
83 buff.Append(",m=");
84 buff.Append(OffsetFromCenterOfMass.ToString());
85 buff.Append(",r=");
86 buff.Append(OffsetRot.ToString());
87 buff.Append(">");
88 return buff.ToString();
89 }
90};
91
35public sealed class BSLinksetCompound : BSLinkset 92public sealed class BSLinksetCompound : BSLinkset
36{ 93{
37 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; 94 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
38 95
39 public BSLinksetCompound(BSScene scene, BSPhysObject parent) 96 public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 { 97 {
41 base.Initialize(scene, parent);
42 } 98 }
43 99
44 // For compound implimented linksets, if there are children, use compound shape for the root. 100 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 101 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
46 { 102 {
103 // Returning 'unknown' means we don't have a preference.
47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 104 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren) 105 if (IsRoot(requestor) && HasAnyChildren)
49 { 106 {
@@ -55,27 +112,33 @@ public sealed class BSLinksetCompound : BSLinkset
55 112
56 // When physical properties are changed the linkset needs to recalculate 113 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties. 114 // 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) 115 public override void Refresh(BSPhysObject requestor)
61 { 116 {
62 // External request for Refresh (from BSPrim) is not necessary 117 base.Refresh(requestor);
63 // InternalRefresh(requestor); 118
119 // Something changed so do the rebuilding thing
120 // ScheduleRebuild();
64 } 121 }
65 122
66 private void InternalRefresh(BSPhysObject requestor) 123 // Schedule a refresh to happen after all the other taint processing.
124 private void ScheduleRebuild(BSPhysObject requestor)
67 { 125 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); 126 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
69 // Queue to happen after all the other taint processing 127 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() 128 // When rebuilding, it is possible to set properties that would normally require a rebuild.
129 // If already rebuilding, don't request another rebuild.
130 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
131 if (!Rebuilding && HasAnyChildren)
71 { 132 {
72 if (IsRoot(requestor) && HasAnyChildren) 133 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
73 RecomputeLinksetCompound(); 134 {
74 }); 135 if (HasAnyChildren)
136 RecomputeLinksetCompound();
137 });
138 }
75 } 139 }
76 140
77 // The object is going dynamic (physical). Do any setup necessary 141 // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset.
78 // for a dynamic linkset.
79 // Only the state of the passed object can be modified. The rest of the linkset 142 // Only the state of the passed object can be modified. The rest of the linkset
80 // has not yet been fully constructed. 143 // has not yet been fully constructed.
81 // Return 'true' if any properties updated on the passed object. 144 // Return 'true' if any properties updated on the passed object.
@@ -84,12 +147,22 @@ public sealed class BSLinksetCompound : BSLinkset
84 { 147 {
85 bool ret = false; 148 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 149 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child)) 150 if (IsRoot(child))
151 {
152 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
153 ScheduleRebuild(LinksetRoot);
154 }
155 else
88 { 156 {
89 // Physical children are removed from the world as the shape ofthe root compound 157 // The origional prims are removed from the world as the shape of the root compound
90 // shape takes over. 158 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 159 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 160 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
161 // We don't want collisions from the old linkset children.
162 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
163
164 child.PhysBody.collisionType = CollisionType.LinksetChild;
165
93 ret = true; 166 ret = true;
94 } 167 }
95 return ret; 168 return ret;
@@ -104,33 +177,92 @@ public sealed class BSLinksetCompound : BSLinkset
104 { 177 {
105 bool ret = false; 178 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 179 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child)) 180 if (IsRoot(child))
181 {
182 ScheduleRebuild(LinksetRoot);
183 }
184 else
108 { 185 {
109 // The non-physical children can come back to life. 186 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 187 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay. 188
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false); 189 child.PhysBody.collisionType = CollisionType.LinksetChild;
190
191 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
192 PhysicsScene.PE.Activate(child.PhysBody, false);
113 ret = true; 193 ret = true;
114 } 194 }
115 return ret; 195 return ret;
116 } 196 }
117 197
118 // Called at taint-time!! 198 // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
119 public override void UpdateProperties(BSPhysObject updated) 199 // Called at taint-time.
120 { 200 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPhysObject updated)
121 // Nothing to do for constraints on property updates
122 }
123
124 // The children move around in relationship to the root.
125 // Just grab the current values of wherever it is right now.
126 public override OMV.Vector3 Position(BSPhysObject member)
127 { 201 {
128 return BulletSimAPI.GetPosition2(member.PhysBody.ptr); 202 // The user moving a child around requires the rebuilding of the linkset compound shape
129 } 203 // One problem is this happens when a border is crossed -- the simulator implementation
130 204 // stores the position into the group which causes the move of the object
131 public override OMV.Quaternion Orientation(BSPhysObject member) 205 // but it also means all the child positions get updated.
132 { 206 // What would cause an unnecessary rebuild so we make sure the linkset is in a
133 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); 207 // region before bothering to do a rebuild.
208 if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
209 {
210 // If a child of the linkset is updating only the position or rotation, that can be done
211 // without rebuilding the linkset.
212 // If a handle for the child can be fetch, we update the child here. If a rebuild was
213 // scheduled by someone else, the rebuild will just replace this setting.
214
215 bool updatedChild = false;
216 // Anything other than updating position or orientation usually means a physical update
217 // and that is caused by us updating the object.
218 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
219 {
220 // Gather the child info. It might not be there if the linkset is in transition.
221 BSLinksetCompoundInfo lsi = updated.LinksetInfo as BSLinksetCompoundInfo;
222 if (LinksetRoot.PhysShape.HasPhysicalShape && lsi != null)
223 {
224 if (PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape))
225 {
226 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, lsi.Index);
227 if (linksetChildShape.HasPhysicalShape)
228 {
229 // Compute the offset from the center-of-gravity
230 BSLinksetCompoundInfo newLsi = new BSLinksetCompoundInfo(lsi.Index, LinksetRoot, updated, LinksetRoot.PositionDisplacement);
231 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, lsi.Index,
232 newLsi.OffsetFromCenterOfMass,
233 newLsi.OffsetRot,
234 true /* shouldRecalculateLocalAabb */);
235 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1}newLsi={2}",
236 updated.LocalID, whichUpdated, newLsi);
237 updated.LinksetInfo = newLsi;
238 updatedChild = true;
239 }
240 else // DEBUG DEBUG
241 { // DEBUG DEBUG
242 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
243 updated.LocalID, linksetChildShape);
244 } // DEBUG DEBUG
245 }
246 else // DEBUG DEBUG
247 { // DEBUG DEBUG
248 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,notCompound", updated.LocalID);
249 } // DEBUG DEBUG
250 }
251 else // DEBUG DEBUG
252 { // DEBUG DEBUG
253 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,rootPhysShape={1},lsi={2}",
254 updated.LocalID, LinksetRoot.PhysShape, lsi == null ? "NULL" : lsi.ToString());
255 } // DEBUG DEBUG
256 if (!updatedChild)
257 {
258 // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
259 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
260 updated.LocalID, whichUpdated);
261 updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed.
262 ScheduleRebuild(updated);
263 }
264 }
265 }
134 } 266 }
135 267
136 // Routine called when rebuilding the body of some member of the linkset. 268 // Routine called when rebuilding the body of some member of the linkset.
@@ -142,24 +274,62 @@ public sealed class BSLinksetCompound : BSLinkset
142 bool ret = false; 274 bool ret = false;
143 275
144 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", 276 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
145 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child)); 277 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, IsRoot(child));
146 278
147 if (!IsRoot(child)) 279 if (!IsRoot(child))
148 { 280 {
149 // Cause the current shape to be freed and the new one to be built. 281 // Because it is a convenient time, recompute child world position and rotation based on
150 InternalRefresh(LinksetRoot); 282 // its position in the linkset.
151 ret = true; 283 RecomputeChildWorldPosition(child, true);
152 } 284 }
153 285
286 // Cannot schedule a refresh/rebuild here because this routine is called when
287 // the linkset is being rebuilt.
288 // InternalRefresh(LinksetRoot);
289
154 return ret; 290 return ret;
155 } 291 }
156 292
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 293 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
158 // this routine will restore the removed constraints. 294 // this routine will restore the removed constraints.
159 // Called at taint-time!! 295 // Called at taint-time!!
160 public override void RestoreBodyDependencies(BSPrim child) 296 public override void RestoreBodyDependencies(BSPrim child)
161 { 297 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. 298 }
299
300 // When the linkset is built, the child shape is added to the compound shape relative to the
301 // root shape. The linkset then moves around but this does not move the actual child
302 // prim. The child prim's location must be recomputed based on the location of the root shape.
303 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
304 {
305 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
306 if (lci != null)
307 {
308 if (inTaintTime)
309 {
310 OMV.Vector3 oldPos = child.RawPosition;
311 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot;
312 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
313 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
314 child.LocalID, oldPos, lci, child.RawPosition);
315 }
316 else
317 {
318 // TaintedObject is not used here so the raw position is set now and not at taint-time.
319 child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot;
320 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
321 }
322 }
323 else
324 {
325 // This happens when children have been added to the linkset but the linkset
326 // has not been constructed yet. So like, at taint time, adding children to a linkset
327 // and then changing properties of the children (makePhysical, for instance)
328 // but the post-print action of actually rebuilding the linkset has not yet happened.
329 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
330 // LogHeader, child.LocalID);
331 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
332 }
163 } 333 }
164 334
165 // ================================================================ 335 // ================================================================
@@ -174,24 +344,25 @@ public sealed class BSLinksetCompound : BSLinkset
174 344
175 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); 345 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
176 346
177 // Cause constraints and assorted properties to be recomputed before the next simulation step. 347 // Rebuild the compound shape with the new child shape included
178 InternalRefresh(LinksetRoot); 348 ScheduleRebuild(child);
179 } 349 }
180 return; 350 return;
181 } 351 }
182 352
183 // Remove the specified child from the linkset. 353 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset. 354 // Safe to call even if the child is not really in the linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child) 355 protected override void RemoveChildFromLinkset(BSPhysObject child)
186 { 356 {
187 if (m_children.Remove(child)) 357 if (m_children.Remove(child))
188 { 358 {
189 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 359 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
190 child.LocalID, 360 child.LocalID,
191 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), 361 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
192 child.LocalID, child.PhysBody.ptr.ToString("X")); 362 child.LocalID, child.PhysBody.AddrString);
193 363
194 // Cause the child's body to be rebuilt and thus restored to normal operation 364 // Cause the child's body to be rebuilt and thus restored to normal operation
365 RecomputeChildWorldPosition(child, false);
195 child.ForceBodyShapeRebuild(false); 366 child.ForceBodyShapeRebuild(false);
196 367
197 if (!HasAnyChildren) 368 if (!HasAnyChildren)
@@ -201,8 +372,8 @@ public sealed class BSLinksetCompound : BSLinkset
201 } 372 }
202 else 373 else
203 { 374 {
204 // Schedule a rebuild of the linkset before the next simulation tick. 375 // Rebuild the compound shape with the child removed
205 InternalRefresh(LinksetRoot); 376 ScheduleRebuild(LinksetRoot);
206 } 377 }
207 } 378 }
208 return; 379 return;
@@ -213,63 +384,108 @@ public sealed class BSLinksetCompound : BSLinkset
213 // Constraint linksets are rebuilt every time. 384 // Constraint linksets are rebuilt every time.
214 // Note that this works for rebuilding just the root after a linkset is taken apart. 385 // Note that this works for rebuilding just the root after a linkset is taken apart.
215 // Called at taint time!! 386 // Called at taint time!!
387 private bool disableCOM = true; // disable until we get this debugged
216 private void RecomputeLinksetCompound() 388 private void RecomputeLinksetCompound()
217 { 389 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it 390 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 { 391 {
227 if (!IsRoot(cPrim)) 392 // Suppress rebuilding while rebuilding
393 Rebuilding = true;
394
395 // Cause the root shape to be rebuilt as a compound object with just the root in it
396 LinksetRoot.ForceBodyShapeRebuild(true);
397
398 // The center of mass for the linkset is the geometric center of the group.
399 // Compute a displacement for each component so it is relative to the center-of-mass.
400 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
401 OMV.Vector3 centerOfMass;
402 OMV.Vector3 centerDisplacement = OMV.Vector3.Zero;
403 if (disableCOM) // DEBUG DEBUG
404 { // DEBUG DEBUG
405 centerOfMass = LinksetRoot.RawPosition; // DEBUG DEBUG
406 LinksetRoot.PositionDisplacement = OMV.Vector3.Zero;
407 } // DEBUG DEBUG
408 else
228 { 409 {
229 // Each child position and rotation is given relative to the root. 410 centerOfMass = ComputeLinksetGeometricCenter();
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); 411 centerDisplacement = centerOfMass - LinksetRoot.RawPosition;
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
233 412
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", 413 // Since we're displacing the center of the shape, we need to move the body in the world
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); 414 LinksetRoot.PositionDisplacement = centerDisplacement;
236 415
237 if (cPrim.PhysShape.isNativeShape) 416 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0, -centerDisplacement, OMV.Quaternion.Identity, false);
238 { 417 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
239 // Native shapes are not shared so we need to create a new one. 418 LinksetRoot.LocalID, centerOfMass, LinksetRoot.RawPosition, centerDisplacement);
240 // A mesh or hull is created because scale is not available on a native shape. 419 }
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) 420
242 BulletShape saveShape = cPrim.PhysShape; 421 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
243 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape 422 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
244 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); 423
245 BulletShape newShape = cPrim.PhysShape; 424 // Add a shape for each of the other children in the linkset
246 cPrim.PhysShape = saveShape; 425 int memberIndex = 1;
247 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot); 426 ForEachMember(delegate(BSPhysObject cPrim)
248 } 427 {
249 else 428 if (!IsRoot(cPrim))
250 { 429 {
251 // For the shared shapes (meshes and hulls), just use the shape in the child. 430 // Compute the displacement of the child from the root of the linkset.
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) 431 // This info is saved in the child prim so the relationship does not
432 // change over time and the new child position can be computed
433 // when the linkset is being disassembled (the linkset may have moved).
434 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
435 if (lci == null)
253 { 436 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", 437 lci = new BSLinksetCompoundInfo(memberIndex, LinksetRoot, cPrim, centerDisplacement);
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); 438 cPrim.LinksetInfo = lci;
439 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
256 } 440 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
258 }
259 }
260 return false; // 'false' says to move onto the next child in the list
261 });
262 441
263 // With all of the linkset packed into the root prim, it has the mass of everyone. 442 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},lci={3}",
264 float linksetMass = LinksetMass; 443 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci);
265 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
266 444
267 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); 445 if (cPrim.PhysShape.isNativeShape)
446 {
447 // A native shape is turning into a hull collision shape because native
448 // shapes are not shared so we have to hullify it so it will be tracked
449 // and freed at the correct time. This also solves the scaling problem
450 // (native shapes scaled but hull/meshes are assumed to not be).
451 // TODO: decide of the native shape can just be used in the compound shape.
452 // Use call to CreateGeomNonSpecial().
453 BulletShape saveShape = cPrim.PhysShape;
454 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
455 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
456 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
457 BulletShape newShape = cPrim.PhysShape;
458 cPrim.PhysShape = saveShape;
459 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetFromCenterOfMass, lci.OffsetRot);
460 }
461 else
462 {
463 // For the shared shapes (meshes and hulls), just use the shape in the child.
464 // The reference count added here will be decremented when the compound shape
465 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
466 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
467 {
468 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
469 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
470 }
471 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetFromCenterOfMass, lci.OffsetRot);
472 }
473 lci.Index = memberIndex;
474 memberIndex++;
475 }
476 return false; // 'false' says to move onto the next child in the list
477 });
268 478
269 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. 479 // With all of the linkset packed into the root prim, it has the mass of everyone.
270 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, 480 LinksetMass = ComputeLinksetMass();
271 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); 481 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
482 }
483 finally
484 {
485 Rebuilding = false;
486 }
272 487
488 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
273 } 489 }
274} 490}
275} \ No newline at end of file 491} \ No newline at end of file