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