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