aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
diff options
context:
space:
mode:
authorubit2013-04-28 20:40:11 +0200
committerubit2013-04-28 20:40:11 +0200
commit61ea7ee5a94e5e3d33fc77c1c316318850309c42 (patch)
tree1e589fc3b448b580d1cc25b52215ef5ce2d7ae78 /OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
parentMerge branch 'ubitwork' of ssh://3dhosting.de/var/git/careminster into ubitwork (diff)
parentController module for dynamic floaters (WIP) (diff)
downloadopensim-SC_OLD-61ea7ee5a94e5e3d33fc77c1c316318850309c42.zip
opensim-SC_OLD-61ea7ee5a94e5e3d33fc77c1c316318850309c42.tar.gz
opensim-SC_OLD-61ea7ee5a94e5e3d33fc77c1c316318850309c42.tar.bz2
opensim-SC_OLD-61ea7ee5a94e5e3d33fc77c1c316318850309c42.tar.xz
Merge branch 'ubitwork' of ssh://3dhosting.de/var/git/careminster into ubitwork
Conflicts: bin/Regions/Regions.ini.example
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs439
1 files changed, 339 insertions, 100 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index b9c2cf9..e05562a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -28,22 +28,80 @@ 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, BSPrimLinkable root, BSPrimLinkable 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, BSPrimLinkable parent)
97 : base(scene, parent)
40 { 98 {
41 base.Initialize(scene, parent);
42 } 99 }
43 100
44 // For compound implimented linksets, if there are children, use compound shape for the root. 101 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 102 public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
46 { 103 {
104 // Returning 'unknown' means we don't have a preference.
47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 105 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren) 106 if (IsRoot(requestor) && HasAnyChildren)
49 { 107 {
@@ -55,41 +113,57 @@ public sealed class BSLinksetCompound : BSLinkset
55 113
56 // When physical properties are changed the linkset needs to recalculate 114 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties. 115 // its internal properties.
58 // This is queued in the 'post taint' queue so the 116 public override void Refresh(BSPrimLinkable requestor)
59 // refresh will happen once after all the other taints are applied.
60 public override void Refresh(BSPhysObject requestor)
61 { 117 {
62 // External request for Refresh (from BSPrim) is not necessary 118 base.Refresh(requestor);
63 // InternalRefresh(requestor); 119
120 // Something changed so do the rebuilding thing
121 // ScheduleRebuild();
64 } 122 }
65 123
66 private void InternalRefresh(BSPhysObject requestor) 124 // Schedule a refresh to happen after all the other taint processing.
125 private void ScheduleRebuild(BSPrimLinkable requestor)
67 { 126 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); 127 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
69 // Queue to happen after all the other taint processing 128 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() 129 // When rebuilding, it is possible to set properties that would normally require a rebuild.
130 // If already rebuilding, don't request another rebuild.
131 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
132 if (!Rebuilding && HasAnyChildren)
71 { 133 {
72 if (IsRoot(requestor) && HasAnyChildren) 134 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
73 RecomputeLinksetCompound(); 135 {
74 }); 136 if (HasAnyChildren)
137 RecomputeLinksetCompound();
138 });
139 }
75 } 140 }
76 141
77 // The object is going dynamic (physical). Do any setup necessary 142 // 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 143 // Only the state of the passed object can be modified. The rest of the linkset
80 // has not yet been fully constructed. 144 // has not yet been fully constructed.
81 // Return 'true' if any properties updated on the passed object. 145 // Return 'true' if any properties updated on the passed object.
82 // Called at taint-time! 146 // Called at taint-time!
83 public override bool MakeDynamic(BSPhysObject child) 147 public override bool MakeDynamic(BSPrimLinkable child)
84 { 148 {
85 bool ret = false; 149 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 150 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child)) 151 if (IsRoot(child))
152 {
153 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
154 ScheduleRebuild(LinksetRoot);
155 }
156 else
88 { 157 {
89 // Physical children are removed from the world as the shape ofthe root compound 158 // The origional prims are removed from the world as the shape of the root compound
90 // shape takes over. 159 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 160 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 161 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
162 // We don't want collisions from the old linkset children.
163 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
164
165 child.PhysBody.collisionType = CollisionType.LinksetChild;
166
93 ret = true; 167 ret = true;
94 } 168 }
95 return ret; 169 return ret;
@@ -100,73 +174,181 @@ public sealed class BSLinksetCompound : BSLinkset
100 // This doesn't normally happen -- OpenSim removes the objects from the physical 174 // This doesn't normally happen -- OpenSim removes the objects from the physical
101 // world if it is a static linkset. 175 // world if it is a static linkset.
102 // Called at taint-time! 176 // Called at taint-time!
103 public override bool MakeStatic(BSPhysObject child) 177 public override bool MakeStatic(BSPrimLinkable child)
104 { 178 {
105 bool ret = false; 179 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 180 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child)) 181 if (IsRoot(child))
182 {
183 ScheduleRebuild(LinksetRoot);
184 }
185 else
108 { 186 {
109 // The non-physical children can come back to life. 187 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 188 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay. 189
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false); 190 child.PhysBody.collisionType = CollisionType.LinksetChild;
191
192 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
193 PhysicsScene.PE.Activate(child.PhysBody, false);
113 ret = true; 194 ret = true;
114 } 195 }
115 return ret; 196 return ret;
116 } 197 }
117 198
118 // Called at taint-time!! 199 // '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) 200 // Called at taint-time.
120 { 201 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable 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 { 202 {
128 return BulletSimAPI.GetPosition2(member.PhysBody.ptr); 203 // The user moving a child around requires the rebuilding of the linkset compound shape
129 } 204 // One problem is this happens when a border is crossed -- the simulator implementation
205 // stores the position into the group which causes the move of the object
206 // but it also means all the child positions get updated.
207 // What would cause an unnecessary rebuild so we make sure the linkset is in a
208 // region before bothering to do a rebuild.
209 if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
210 {
211 // If a child of the linkset is updating only the position or rotation, that can be done
212 // without rebuilding the linkset.
213 // If a handle for the child can be fetch, we update the child here. If a rebuild was
214 // scheduled by someone else, the rebuild will just replace this setting.
215
216 bool updatedChild = false;
217 // Anything other than updating position or orientation usually means a physical update
218 // and that is caused by us updating the object.
219 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
220 {
221 // Find the physical instance of the child
222 if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape))
223 {
224 // It is possible that the linkset is still under construction and the child is not yet
225 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
226 // build the whole thing with the new position or rotation.
227 // The index must be checked because Bullet references the child array but does no validity
228 // checking of the child index passed.
229 int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape);
230 if (updated.LinksetChildIndex < numLinksetChildren)
231 {
232 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex);
233 if (linksetChildShape.HasPhysicalShape)
234 {
235 // Found the child shape within the compound shape
236 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex,
237 updated.RawPosition - LinksetRoot.RawPosition,
238 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
239 true /* shouldRecalculateLocalAabb */);
240 updatedChild = true;
241 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
242 updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
243 }
244 else // DEBUG DEBUG
245 { // DEBUG DEBUG
246 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
247 updated.LocalID, linksetChildShape);
248 } // DEBUG DEBUG
249 }
250 else // DEBUG DEBUG
251 { // DEBUG DEBUG
252 // the child is not yet in the compound shape. This is non-fatal.
253 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
254 updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
255 } // DEBUG DEBUG
256 }
257 else // DEBUG DEBUG
258 { // DEBUG DEBUG
259 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
260 } // DEBUG DEBUG
130 261
131 public override OMV.Quaternion Orientation(BSPhysObject member) 262 if (!updatedChild)
132 { 263 {
133 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); 264 // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
265 // Note: there are several ways through this code that will not update the child if
266 // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since
267 // there will already be a rebuild scheduled.
268 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
269 updated.LocalID, whichUpdated);
270 updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed.
271 ScheduleRebuild(updated);
272 }
273 }
274 }
134 } 275 }
135 276
136 // Routine called when rebuilding the body of some member of the linkset. 277 // Routine called when rebuilding the body of some member of the linkset.
137 // Since we don't keep in world relationships, do nothing unless it's a child changing. 278 // Since we don't keep in world relationships, do nothing unless it's a child changing.
138 // Returns 'true' of something was actually removed and would need restoring 279 // Returns 'true' of something was actually removed and would need restoring
139 // Called at taint-time!! 280 // Called at taint-time!!
140 public override bool RemoveBodyDependencies(BSPrim child) 281 public override bool RemoveBodyDependencies(BSPrimLinkable child)
141 { 282 {
142 bool ret = false; 283 bool ret = false;
143 284
144 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", 285 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
145 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child)); 286 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
146 287
147 if (!IsRoot(child)) 288 if (!IsRoot(child))
148 { 289 {
149 // Cause the current shape to be freed and the new one to be built. 290 // Because it is a convenient time, recompute child world position and rotation based on
150 InternalRefresh(LinksetRoot); 291 // its position in the linkset.
151 ret = true; 292 RecomputeChildWorldPosition(child, true /* inTaintTime */);
293 child.LinksetInfo = null;
152 } 294 }
153 295
296 // Cannot schedule a refresh/rebuild here because this routine is called when
297 // the linkset is being rebuilt.
298 // InternalRefresh(LinksetRoot);
299
154 return ret; 300 return ret;
155 } 301 }
156 302
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 303 // When the linkset is built, the child shape is added to the compound shape relative to the
158 // this routine will restore the removed constraints. 304 // root shape. The linkset then moves around but this does not move the actual child
159 // Called at taint-time!! 305 // prim. The child prim's location must be recomputed based on the location of the root shape.
160 public override void RestoreBodyDependencies(BSPrim child) 306 private void RecomputeChildWorldPosition(BSPrimLinkable child, bool inTaintTime)
161 { 307 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. 308 // For the moment (20130201), disable this computation (converting the child physical addr back to
309 // a region address) until we have a good handle on center-of-mass offsets and what the physics
310 // engine moving a child actually means.
311 // The simulator keeps track of where children should be as the linkset moves. Setting
312 // the pos/rot here does not effect that knowledge as there is no good way for the
313 // physics engine to send the simulator an update for a child.
314
315 /*
316 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
317 if (lci != null)
318 {
319 if (inTaintTime)
320 {
321 OMV.Vector3 oldPos = child.RawPosition;
322 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot;
323 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
324 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
325 child.LocalID, oldPos, lci, child.RawPosition);
326 }
327 else
328 {
329 // TaintedObject is not used here so the raw position is set now and not at taint-time.
330 child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot;
331 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
332 }
333 }
334 else
335 {
336 // This happens when children have been added to the linkset but the linkset
337 // has not been constructed yet. So like, at taint time, adding children to a linkset
338 // and then changing properties of the children (makePhysical, for instance)
339 // but the post-print action of actually rebuilding the linkset has not yet happened.
340 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
341 // LogHeader, child.LocalID);
342 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
343 }
344 */
163 } 345 }
164 346
165 // ================================================================ 347 // ================================================================
166 348
167 // Add a new child to the linkset. 349 // Add a new child to the linkset.
168 // Called while LinkActivity is locked. 350 // Called while LinkActivity is locked.
169 protected override void AddChildToLinkset(BSPhysObject child) 351 protected override void AddChildToLinkset(BSPrimLinkable child)
170 { 352 {
171 if (!HasChild(child)) 353 if (!HasChild(child))
172 { 354 {
@@ -174,24 +356,28 @@ public sealed class BSLinksetCompound : BSLinkset
174 356
175 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); 357 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
176 358
177 // Cause constraints and assorted properties to be recomputed before the next simulation step. 359 // Rebuild the compound shape with the new child shape included
178 InternalRefresh(LinksetRoot); 360 ScheduleRebuild(child);
179 } 361 }
180 return; 362 return;
181 } 363 }
182 364
183 // Remove the specified child from the linkset. 365 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset. 366 // Safe to call even if the child is not really in the linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child) 367 protected override void RemoveChildFromLinkset(BSPrimLinkable child)
186 { 368 {
369 child.ClearDisplacement();
370
187 if (m_children.Remove(child)) 371 if (m_children.Remove(child))
188 { 372 {
189 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 373 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
190 child.LocalID, 374 child.LocalID,
191 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), 375 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
192 child.LocalID, child.PhysBody.ptr.ToString("X")); 376 child.LocalID, child.PhysBody.AddrString);
193 377
194 // Cause the child's body to be rebuilt and thus restored to normal operation 378 // Cause the child's body to be rebuilt and thus restored to normal operation
379 RecomputeChildWorldPosition(child, false);
380 child.LinksetInfo = null;
195 child.ForceBodyShapeRebuild(false); 381 child.ForceBodyShapeRebuild(false);
196 382
197 if (!HasAnyChildren) 383 if (!HasAnyChildren)
@@ -201,8 +387,8 @@ public sealed class BSLinksetCompound : BSLinkset
201 } 387 }
202 else 388 else
203 { 389 {
204 // Schedule a rebuild of the linkset before the next simulation tick. 390 // Rebuild the compound shape with the child removed
205 InternalRefresh(LinksetRoot); 391 ScheduleRebuild(LinksetRoot);
206 } 392 }
207 } 393 }
208 return; 394 return;
@@ -213,63 +399,116 @@ public sealed class BSLinksetCompound : BSLinkset
213 // Constraint linksets are rebuilt every time. 399 // Constraint linksets are rebuilt every time.
214 // Note that this works for rebuilding just the root after a linkset is taken apart. 400 // Note that this works for rebuilding just the root after a linkset is taken apart.
215 // Called at taint time!! 401 // Called at taint time!!
402 private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged
216 private void RecomputeLinksetCompound() 403 private void RecomputeLinksetCompound()
217 { 404 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it 405 try
219 LinksetRoot.ForceBodyShapeRebuild(true); 406 {
407 // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.)
408 Rebuilding = true;
220 409
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", 410 // Cause the root shape to be rebuilt as a compound object with just the root in it
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); 411 LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */);
223 412
224 // Add a shape for each of the other children in the linkset 413 // The center of mass for the linkset is the geometric center of the group.
225 ForEachMember(delegate(BSPhysObject cPrim) 414 // Compute a displacement for each component so it is relative to the center-of-mass.
226 { 415 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
227 if (!IsRoot(cPrim)) 416 OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition;
417 if (!disableCOM) // DEBUG DEBUG
228 { 418 {
229 // Each child position and rotation is given relative to the root. 419 // Compute a center-of-mass in world coordinates.
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); 420 centerOfMassW = ComputeLinksetCenterOfMass();
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; 421 }
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; 422
423 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
424
425 // 'centerDisplacement' is the value to subtract from children to give physical offset position
426 OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
427 LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement);
233 428
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", 429 // This causes the physical position of the root prim to be offset to accomodate for the displacements
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); 430 LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
236 431
237 if (cPrim.PhysShape.isNativeShape) 432 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM
433 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */,
434 -centerDisplacement,
435 OMV.Quaternion.Identity, // LinksetRoot.RawOrientation,
436 false /* shouldRecalculateLocalAabb (is done later after linkset built) */);
437
438 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
439 LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement);
440
441 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
442 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
443
444 // Add a shape for each of the other children in the linkset
445 int memberIndex = 1;
446 ForEachMember(delegate(BSPrimLinkable cPrim)
447 {
448 if (IsRoot(cPrim))
238 { 449 {
239 // Native shapes are not shared so we need to create a new one. 450 cPrim.LinksetChildIndex = 0;
240 // A mesh or hull is created because scale is not available on a native shape.
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?)
242 BulletShape saveShape = cPrim.PhysShape;
243 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape
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 } 451 }
249 else 452 else
250 { 453 {
251 // For the shared shapes (meshes and hulls), just use the shape in the child. 454 cPrim.LinksetChildIndex = memberIndex;
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) 455
456 if (cPrim.PhysShape.isNativeShape)
253 { 457 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", 458 // A native shape is turned into a hull collision shape because native
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); 459 // shapes are not shared so we have to hullify it so it will be tracked
460 // and freed at the correct time. This also solves the scaling problem
461 // (native shapes scale but hull/meshes are assumed to not be).
462 // TODO: decide of the native shape can just be used in the compound shape.
463 // Use call to CreateGeomNonSpecial().
464 BulletShape saveShape = cPrim.PhysShape;
465 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
466 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
467 BulletShape newShape = cPrim.PhysShape;
468 cPrim.PhysShape = saveShape;
469
470 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
471 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
472 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
473 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
474 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
256 } 475 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); 476 else
258 } 477 {
259 } 478 // For the shared shapes (meshes and hulls), just use the shape in the child.
260 return false; // 'false' says to move onto the next child in the list 479 // The reference count added here will be decremented when the compound shape
261 }); 480 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
481 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
482 {
483 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
484 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
485 }
486 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
487 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
488 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
489 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
490 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
262 491
263 // With all of the linkset packed into the root prim, it has the mass of everyone. 492 }
264 float linksetMass = LinksetMass; 493 memberIndex++;
265 LinksetRoot.UpdatePhysicalMassProperties(linksetMass); 494 }
495 return false; // 'false' says to move onto the next child in the list
496 });
266 497
267 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); 498 // With all of the linkset packed into the root prim, it has the mass of everyone.
499 LinksetMass = ComputeLinksetMass();
500 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
268 501
269 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. 502 // Enable the physical position updator to return the position and rotation of the root shape
270 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, 503 PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
271 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); 504 }
505 finally
506 {
507 Rebuilding = false;
508 }
272 509
510 // See that the Aabb surrounds the new shape
511 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
273 } 512 }
274} 513}
275} \ No newline at end of file 514} \ No newline at end of file