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.cs386
1 files changed, 211 insertions, 175 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index bd03d31..350a5d1 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -35,59 +35,74 @@ using OMV = OpenMetaverse;
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37 37
38 /*
38// When a child is linked, the relationship position of the child to the parent 39// 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// is remembered so the child's world position can be recomputed when it is
40// removed from the linkset. 41// removed from the linkset.
41sealed class BSLinksetCompoundInfo : BSLinksetInfo 42sealed class BSLinksetCompoundInfo : BSLinksetInfo
42{ 43{
43 public OMV.Vector3 OffsetPos; 44 public int Index;
45 public OMV.Vector3 OffsetFromRoot;
46 public OMV.Vector3 OffsetFromCenterOfMass;
44 public OMV.Quaternion OffsetRot; 47 public OMV.Quaternion OffsetRot;
45 public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r) 48 public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r)
46 { 49 {
47 OffsetPos = p; 50 Index = indx;
51 OffsetFromRoot = p;
52 OffsetFromCenterOfMass = p;
48 OffsetRot = r; 53 OffsetRot = r;
49 } 54 }
55 // 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape)
56 public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement)
57 {
58 // Each child position and rotation is given relative to the center-of-mass.
59 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation);
60 OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation;
61 OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement;
62 OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation;
63
64 // Save relative position for recomputing child's world position after moving linkset.
65 Index = indx;
66 OffsetFromRoot = displacementFromRoot;
67 OffsetFromCenterOfMass = displacementFromCOM;
68 OffsetRot = displacementRot;
69 }
50 public override void Clear() 70 public override void Clear()
51 { 71 {
52 OffsetPos = OMV.Vector3.Zero; 72 Index = 0;
73 OffsetFromRoot = OMV.Vector3.Zero;
74 OffsetFromCenterOfMass = OMV.Vector3.Zero;
53 OffsetRot = OMV.Quaternion.Identity; 75 OffsetRot = OMV.Quaternion.Identity;
54 } 76 }
55 public override string ToString() 77 public override string ToString()
56 { 78 {
57 StringBuilder buff = new StringBuilder(); 79 StringBuilder buff = new StringBuilder();
58 buff.Append("<p="); 80 buff.Append("<i=");
59 buff.Append(OffsetPos.ToString()); 81 buff.Append(Index.ToString());
82 buff.Append(",p=");
83 buff.Append(OffsetFromRoot.ToString());
84 buff.Append(",m=");
85 buff.Append(OffsetFromCenterOfMass.ToString());
60 buff.Append(",r="); 86 buff.Append(",r=");
61 buff.Append(OffsetRot.ToString()); 87 buff.Append(OffsetRot.ToString());
62 buff.Append(">"); 88 buff.Append(">");
63 return buff.ToString(); 89 return buff.ToString();
64 } 90 }
65}; 91};
92 */
66 93
67public sealed class BSLinksetCompound : BSLinkset 94public sealed class BSLinksetCompound : BSLinkset
68{ 95{
69 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; 96 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
70 97
71 public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent) 98 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
99 : base(scene, parent)
72 { 100 {
73 } 101 }
74 102
75 // For compound implimented linksets, if there are children, use compound shape for the root.
76 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
77 {
78 // Returning 'unknown' means we don't have a preference.
79 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
80 if (IsRoot(requestor) && HasAnyChildren)
81 {
82 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
83 }
84 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
85 return ret;
86 }
87
88 // When physical properties are changed the linkset needs to recalculate 103 // When physical properties are changed the linkset needs to recalculate
89 // its internal properties. 104 // its internal properties.
90 public override void Refresh(BSPhysObject requestor) 105 public override void Refresh(BSPrimLinkable requestor)
91 { 106 {
92 base.Refresh(requestor); 107 base.Refresh(requestor);
93 108
@@ -96,16 +111,16 @@ public sealed class BSLinksetCompound : BSLinkset
96 } 111 }
97 112
98 // Schedule a refresh to happen after all the other taint processing. 113 // Schedule a refresh to happen after all the other taint processing.
99 private void ScheduleRebuild(BSPhysObject requestor) 114 private void ScheduleRebuild(BSPrimLinkable requestor)
100 { 115 {
101 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2}", 116 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
102 requestor.LocalID, Rebuilding, HasAnyChildren); 117 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
103 // When rebuilding, it is possible to set properties that would normally require a rebuild. 118 // When rebuilding, it is possible to set properties that would normally require a rebuild.
104 // If already rebuilding, don't request another rebuild. 119 // If already rebuilding, don't request another rebuild.
105 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. 120 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
106 if (!Rebuilding && HasAnyChildren) 121 if (!Rebuilding && HasAnyChildren)
107 { 122 {
108 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() 123 m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
109 { 124 {
110 if (HasAnyChildren) 125 if (HasAnyChildren)
111 RecomputeLinksetCompound(); 126 RecomputeLinksetCompound();
@@ -118,7 +133,7 @@ public sealed class BSLinksetCompound : BSLinkset
118 // has not yet been fully constructed. 133 // has not yet been fully constructed.
119 // Return 'true' if any properties updated on the passed object. 134 // Return 'true' if any properties updated on the passed object.
120 // Called at taint-time! 135 // Called at taint-time!
121 public override bool MakeDynamic(BSPhysObject child) 136 public override bool MakeDynamic(BSPrimLinkable child)
122 { 137 {
123 bool ret = false; 138 bool ret = false;
124 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 139 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
@@ -127,138 +142,131 @@ public sealed class BSLinksetCompound : BSLinkset
127 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. 142 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
128 ScheduleRebuild(LinksetRoot); 143 ScheduleRebuild(LinksetRoot);
129 } 144 }
130 else
131 {
132 // The origional prims are removed from the world as the shape of the root compound
133 // shape takes over.
134 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
135 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
136 // We don't want collisions from the old linkset children.
137 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
138
139 child.PhysBody.collisionType = CollisionType.LinksetChild;
140
141 ret = true;
142 }
143 return ret; 145 return ret;
144 } 146 }
145 147
146 // The object is going static (non-physical). Do any setup necessary for a static linkset. 148 // The object is going static (non-physical). We do not do anything for static linksets.
147 // Return 'true' if any properties updated on the passed object. 149 // Return 'true' if any properties updated on the passed object.
148 // This doesn't normally happen -- OpenSim removes the objects from the physical
149 // world if it is a static linkset.
150 // Called at taint-time! 150 // Called at taint-time!
151 public override bool MakeStatic(BSPhysObject child) 151 public override bool MakeStatic(BSPrimLinkable child)
152 { 152 {
153 bool ret = false; 153 bool ret = false;
154 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 154 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
155 if (IsRoot(child)) 155 if (IsRoot(child))
156 { 156 {
157 // Schedule a rebuild to verify that the root shape is set to the real shape.
157 ScheduleRebuild(LinksetRoot); 158 ScheduleRebuild(LinksetRoot);
158 } 159 }
159 else
160 {
161 // The non-physical children can come back to life.
162 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
163
164 child.PhysBody.collisionType = CollisionType.LinksetChild;
165
166 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
167 PhysicsScene.PE.Activate(child.PhysBody, false);
168 ret = true;
169 }
170 return ret; 160 return ret;
171 } 161 }
172 162
173 public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate) 163 // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
164 // Called at taint-time.
165 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
174 { 166 {
167 if (!LinksetRoot.IsPhysicallyActive)
168 {
169 // No reason to do this physical stuff for static linksets.
170 DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID);
171 return;
172 }
173
175 // The user moving a child around requires the rebuilding of the linkset compound shape 174 // The user moving a child around requires the rebuilding of the linkset compound shape
176 // One problem is this happens when a border is crossed -- the simulator implementation 175 // One problem is this happens when a border is crossed -- the simulator implementation
177 // is to store the position into the group which causes the move of the object 176 // stores the position into the group which causes the move of the object
178 // but it also means all the child positions get updated. 177 // but it also means all the child positions get updated.
179 // What would cause an unnecessary rebuild so we make sure the linkset is in a 178 // What would cause an unnecessary rebuild so we make sure the linkset is in a
180 // region before bothering to do a rebuild. 179 // region before bothering to do a rebuild.
181 if (!IsRoot(updated) 180 if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
182 && !physicalUpdate
183 && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
184 { 181 {
185 updated.LinksetInfo = null; 182 // If a child of the linkset is updating only the position or rotation, that can be done
186 ScheduleRebuild(updated); 183 // without rebuilding the linkset.
184 // If a handle for the child can be fetch, we update the child here. If a rebuild was
185 // scheduled by someone else, the rebuild will just replace this setting.
186
187 bool updatedChild = false;
188 // Anything other than updating position or orientation usually means a physical update
189 // and that is caused by us updating the object.
190 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
191 {
192 // Find the physical instance of the child
193 if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
194 {
195 // It is possible that the linkset is still under construction and the child is not yet
196 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
197 // build the whole thing with the new position or rotation.
198 // The index must be checked because Bullet references the child array but does no validity
199 // checking of the child index passed.
200 int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
201 if (updated.LinksetChildIndex < numLinksetChildren)
202 {
203 BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
204 if (linksetChildShape.HasPhysicalShape)
205 {
206 // Found the child shape within the compound shape
207 m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
208 updated.RawPosition - LinksetRoot.RawPosition,
209 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
210 true /* shouldRecalculateLocalAabb */);
211 updatedChild = true;
212 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
213 updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
214 }
215 else // DEBUG DEBUG
216 { // DEBUG DEBUG
217 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
218 updated.LocalID, linksetChildShape);
219 } // DEBUG DEBUG
220 }
221 else // DEBUG DEBUG
222 { // DEBUG DEBUG
223 // the child is not yet in the compound shape. This is non-fatal.
224 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
225 updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
226 } // DEBUG DEBUG
227 }
228 else // DEBUG DEBUG
229 { // DEBUG DEBUG
230 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
231 } // DEBUG DEBUG
232
233 if (!updatedChild)
234 {
235 // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
236 // Note: there are several ways through this code that will not update the child if
237 // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since
238 // there will already be a rebuild scheduled.
239 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
240 updated.LocalID, whichUpdated);
241 updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed.
242 ScheduleRebuild(updated);
243 }
244 }
187 } 245 }
188 } 246 }
189 247
190 // Routine called when rebuilding the body of some member of the linkset. 248 // Routine called when rebuilding the body of some member of the linkset.
191 // Since we don't keep in world relationships, do nothing unless it's a child changing. 249 // If one of the bodies is being changed, the linkset needs rebuilding.
250 // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated.
192 // Returns 'true' of something was actually removed and would need restoring 251 // Returns 'true' of something was actually removed and would need restoring
193 // Called at taint-time!! 252 // Called at taint-time!!
194 public override bool RemoveBodyDependencies(BSPrim child) 253 public override bool RemoveDependencies(BSPrimLinkable child)
195 { 254 {
196 bool ret = false; 255 bool ret = false;
197 256
198 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", 257 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
199 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, IsRoot(child)); 258 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
200 259
201 if (!IsRoot(child)) 260 ScheduleRebuild(child);
202 {
203 // Because it is a convenient time, recompute child world position and rotation based on
204 // its position in the linkset.
205 RecomputeChildWorldPosition(child, true);
206 }
207
208 // Cannot schedule a refresh/rebuild here because this routine is called when
209 // the linkset is being rebuilt.
210 // InternalRefresh(LinksetRoot);
211 261
212 return ret; 262 return ret;
213 } 263 }
214 264
215 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
216 // this routine will restore the removed constraints.
217 // Called at taint-time!!
218 public override void RestoreBodyDependencies(BSPrim child)
219 {
220 }
221
222 // When the linkset is built, the child shape is added to the compound shape relative to the
223 // root shape. The linkset then moves around but this does not move the actual child
224 // prim. The child prim's location must be recomputed based on the location of the root shape.
225 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
226 {
227 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
228 if (lci != null)
229 {
230 if (inTaintTime)
231 {
232 OMV.Vector3 oldPos = child.RawPosition;
233 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos;
234 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
235 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
236 child.LocalID, oldPos, lci, child.RawPosition);
237 }
238 else
239 {
240 // TaintedObject is not used here so the raw position is set now and not at taint-time.
241 child.Position = LinksetRoot.RawPosition + lci.OffsetPos;
242 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
243 }
244 }
245 else
246 {
247 // This happens when children have been added to the linkset but the linkset
248 // has not been constructed yet. So like, at taint time, adding children to a linkset
249 // and then changing properties of the children (makePhysical, for instance)
250 // but the post-print action of actually rebuilding the linkset has not yet happened.
251 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
252 // LogHeader, child.LocalID);
253 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
254 }
255 }
256
257 // ================================================================ 265 // ================================================================
258 266
259 // Add a new child to the linkset. 267 // Add a new child to the linkset.
260 // Called while LinkActivity is locked. 268 // Called while LinkActivity is locked.
261 protected override void AddChildToLinkset(BSPhysObject child) 269 protected override void AddChildToLinkset(BSPrimLinkable child)
262 { 270 {
263 if (!HasChild(child)) 271 if (!HasChild(child))
264 { 272 {
@@ -274,8 +282,10 @@ public sealed class BSLinksetCompound : BSLinkset
274 282
275 // Remove the specified child from the linkset. 283 // Remove the specified child from the linkset.
276 // Safe to call even if the child is not really in the linkset. 284 // Safe to call even if the child is not really in the linkset.
277 protected override void RemoveChildFromLinkset(BSPhysObject child) 285 protected override void RemoveChildFromLinkset(BSPrimLinkable child)
278 { 286 {
287 child.ClearDisplacement();
288
279 if (m_children.Remove(child)) 289 if (m_children.Remove(child))
280 { 290 {
281 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 291 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
@@ -284,7 +294,7 @@ public sealed class BSLinksetCompound : BSLinkset
284 child.LocalID, child.PhysBody.AddrString); 294 child.LocalID, child.PhysBody.AddrString);
285 295
286 // Cause the child's body to be rebuilt and thus restored to normal operation 296 // Cause the child's body to be rebuilt and thus restored to normal operation
287 RecomputeChildWorldPosition(child, false); 297 child.LinksetInfo = null;
288 child.ForceBodyShapeRebuild(false); 298 child.ForceBodyShapeRebuild(false);
289 299
290 if (!HasAnyChildren) 300 if (!HasAnyChildren)
@@ -295,7 +305,7 @@ public sealed class BSLinksetCompound : BSLinkset
295 else 305 else
296 { 306 {
297 // Rebuild the compound shape with the child removed 307 // Rebuild the compound shape with the child removed
298 ScheduleRebuild(child); 308 ScheduleRebuild(LinksetRoot);
299 } 309 }
300 } 310 }
301 return; 311 return;
@@ -306,87 +316,113 @@ public sealed class BSLinksetCompound : BSLinkset
306 // Constraint linksets are rebuilt every time. 316 // Constraint linksets are rebuilt every time.
307 // Note that this works for rebuilding just the root after a linkset is taken apart. 317 // Note that this works for rebuilding just the root after a linkset is taken apart.
308 // Called at taint time!! 318 // Called at taint time!!
319 private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape
320 private bool disableCOM = true; // For basic linkset debugging, turn off the center-of-mass setting
309 private void RecomputeLinksetCompound() 321 private void RecomputeLinksetCompound()
310 { 322 {
311 try 323 try
312 { 324 {
313 // Suppress rebuilding while rebuilding
314 Rebuilding = true; 325 Rebuilding = true;
315 326
316 // Cause the root shape to be rebuilt as a compound object with just the root in it 327 // No matter what is being done, force the root prim's PhysBody and PhysShape to get set
328 // to what they should be as if the root was not in a linkset.
329 // Not that bad since we only get into this routine if there are children in the linkset and
330 // something has been updated/changed.
317 LinksetRoot.ForceBodyShapeRebuild(true); 331 LinksetRoot.ForceBodyShapeRebuild(true);
318 332
319 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", 333 // There is no reason to build all this physical stuff for a non-physical linkset.
320 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); 334 if (!LinksetRoot.IsPhysicallyActive)
335 {
336 // Clean up any old linkset shape and make sure the root shape is set to the root object.
337 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID);
338
339 return; // Note the 'finally' clause at the botton which will get executed.
340 }
341
342 // Get a new compound shape to build the linkset shape in.
343 BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene);
321 344
322 // Add a shape for each of the other children in the linkset 345 // The center of mass for the linkset is the geometric center of the group.
323 ForEachMember(delegate(BSPhysObject cPrim) 346 // Compute a displacement for each component so it is relative to the center-of-mass.
347 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
348 OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass();
349
350 OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation));
351
352 // 'centerDisplacement' is the value to subtract from children to give physical offset position
353 OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
354 if (UseBulletSimRootOffsetHack || disableCOM)
324 { 355 {
356 centerDisplacementV = OMV.Vector3.Zero;
357 LinksetRoot.ClearDisplacement();
358 }
359 else
360 {
361 LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV);
362 }
363 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}",
364 LinksetRoot.LocalID, LinksetRoot.RawPosition, centerOfMassW, centerDisplacementV);
365
366 // Add the shapes of all the components of the linkset
367 int memberIndex = 1;
368 ForEachMember(delegate(BSPrimLinkable cPrim)
369 {
370 // Root shape is always index zero.
371 cPrim.LinksetChildIndex = IsRoot(cPrim) ? 0 : memberIndex;
372
373 // Get a reference to the shape of the child and add that shape to the linkset compound shape
374 BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim);
375 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacementV;
376 OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation;
377 m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot);
378 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}",
379 LinksetRoot.LocalID, memberIndex, childShape, offsetPos, offsetRot);
380
381 // Since we are borrowing the shape of the child, disable the origional child body
325 if (!IsRoot(cPrim)) 382 if (!IsRoot(cPrim))
326 { 383 {
327 // Compute the displacement of the child from the root of the linkset. 384 m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
328 // This info is saved in the child prim so the relationship does not 385 m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION);
329 // change over time and the new child position can be computed 386 // We don't want collisions from the old linkset children.
330 // when the linkset is being disassembled (the linkset may have moved). 387 m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
331 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; 388 cPrim.PhysBody.collisionType = CollisionType.LinksetChild;
332 if (lci == null) 389 }
333 {
334 // Each child position and rotation is given relative to the root.
335 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
336 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
337 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
338
339 // Save relative position for recomputing child's world position after moving linkset.
340 lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
341 cPrim.LinksetInfo = lci;
342 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
343 }
344 390
345 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", 391 memberIndex++;
346 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
347 392
348 if (cPrim.PhysShape.isNativeShape)
349 {
350 // A native shape is turning into a hull collision shape because native
351 // shapes are not shared so we have to hullify it so it will be tracked
352 // and freed at the correct time. This also solves the scaling problem
353 // (native shapes scaled but hull/meshes are assumed to not be).
354 // TODO: decide of the native shape can just be used in the compound shape.
355 // Use call to CreateGeomNonSpecial().
356 BulletShape saveShape = cPrim.PhysShape;
357 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
358 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
359 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
360 BulletShape newShape = cPrim.PhysShape;
361 cPrim.PhysShape = saveShape;
362 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetPos, lci.OffsetRot);
363 }
364 else
365 {
366 // For the shared shapes (meshes and hulls), just use the shape in the child.
367 // The reference count added here will be decremented when the compound shape
368 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
369 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
370 {
371 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
372 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
373 }
374 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
375 }
376 }
377 return false; // 'false' says to move onto the next child in the list 393 return false; // 'false' says to move onto the next child in the list
378 }); 394 });
379 395
396 // Replace the root shape with the built compound shape.
397 // Object removed and added to world to get collision cache rebuilt for new shape.
398 LinksetRoot.PhysShape.Dereference(m_physicsScene);
399 LinksetRoot.PhysShape = linksetShape;
400 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody);
401 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo);
402 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
403 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
404 LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
405
380 // With all of the linkset packed into the root prim, it has the mass of everyone. 406 // With all of the linkset packed into the root prim, it has the mass of everyone.
381 LinksetMass = ComputeLinksetMass(); 407 LinksetMass = ComputeLinksetMass();
382 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); 408 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
409
410 if (UseBulletSimRootOffsetHack)
411 {
412 // Enable the physical position updator to return the position and rotation of the root shape.
413 // This enables a feature in the C++ code to return the world coordinates of the first shape in the
414 // compound shape. This eleviates the need to offset the returned physical position by the
415 // center-of-mass offset.
416 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
417 }
383 } 418 }
384 finally 419 finally
385 { 420 {
386 Rebuilding = false; 421 Rebuilding = false;
387 } 422 }
388 423
389 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); 424 // See that the Aabb surrounds the new shape
425 m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
390 } 426 }
391} 427}
392} \ No newline at end of file 428} \ No newline at end of file