aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
diff options
context:
space:
mode:
authorRobert Adams2012-12-10 15:35:53 -0800
committerRobert Adams2012-12-10 15:35:53 -0800
commit9df85eadf4b3719a898fda8769313ae023962c25 (patch)
treeaf055fb53368d75c236959bfde56d43f23e6f741 /OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
parentBulletSim: some comments about rebuilding linksets (having to recompute and r... (diff)
downloadopensim-SC_OLD-9df85eadf4b3719a898fda8769313ae023962c25.zip
opensim-SC_OLD-9df85eadf4b3719a898fda8769313ae023962c25.tar.gz
opensim-SC_OLD-9df85eadf4b3719a898fda8769313ae023962c25.tar.bz2
opensim-SC_OLD-9df85eadf4b3719a898fda8769313ae023962c25.tar.xz
BulletSim: Fix crash on the destruction of physical linksets.
While fixing the above, add methods to physical body and shape pointer wrapper so routines won't have to know that IntPtr.Zero means no physical instance. Fix problem with physical linksets failing after a few sits and unsits by properly restoring child prom positions for compound linksets after multiple selection and deselections.
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs113
1 files changed, 96 insertions, 17 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index bc9f9be..fe5b5e3 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)
@@ -108,7 +134,7 @@ public sealed class BSLinksetCompound : BSLinkset
108 { 134 {
109 // The non-physical children can come back to life. 135 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 136 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay. 137 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false); 138 BulletSimAPI.Activate2(child.PhysBody.ptr, false);
113 ret = true; 139 ret = true;
114 } 140 }
@@ -146,6 +172,10 @@ public sealed class BSLinksetCompound : BSLinkset
146 172
147 if (!IsRoot(child)) 173 if (!IsRoot(child))
148 { 174 {
175 // Because it is a convenient time, recompute child world position and rotation based on
176 // its position in the linkset.
177 RecomputeChildWorldPosition(child, true);
178
149 // Cause the current shape to be freed and the new one to be built. 179 // Cause the current shape to be freed and the new one to be built.
150 InternalRefresh(LinksetRoot); 180 InternalRefresh(LinksetRoot);
151 ret = true; 181 ret = true;
@@ -154,6 +184,42 @@ public sealed class BSLinksetCompound : BSLinkset
154 return ret; 184 return ret;
155 } 185 }
156 186
187 // When the linkset is built, the child shape is added
188 // to the compound shape relative to the root shape. The linkset then moves around but
189 // this does not move the actual child prim. The child prim's location must be recomputed
190 // based on the location of the root shape.
191 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
192 {
193 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
194 if (lci != null)
195 {
196 if (inTaintTime)
197 {
198 OMV.Vector3 oldPos = child.RawPosition;
199 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos;
200 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
201 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
202 child.LocalID, oldPos, lci, child.RawPosition);
203 }
204 else
205 {
206 // TaintedObject is not used here so the raw position is set now and not at taint-time.
207 child.Position = LinksetRoot.RawPosition + lci.OffsetPos;
208 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
209 }
210 }
211 else
212 {
213 // This happens when children have been added to the linkset but the linkset
214 // has not been constructed yet. So like, at taint time, adding children to a linkset
215 // and then changing properties of the children (makePhysical, for instance)
216 // but the post-print action of actually rebuilding the linkset has not yet happened.
217 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
218 // LogHeader, child.LocalID);
219 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
220 }
221 }
222
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 223 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
158 // this routine will restore the removed constraints. 224 // this routine will restore the removed constraints.
159 // Called at taint-time!! 225 // Called at taint-time!!
@@ -192,8 +258,7 @@ public sealed class BSLinksetCompound : BSLinkset
192 child.LocalID, child.PhysBody.ptr.ToString("X")); 258 child.LocalID, child.PhysBody.ptr.ToString("X"));
193 259
194 // Cause the child's body to be rebuilt and thus restored to normal operation 260 // Cause the child's body to be rebuilt and thus restored to normal operation
195 // TODO: position and rotation must be restored because the child could have moved 261 RecomputeChildWorldPosition(child, false);
196 // based on the linkset.
197 child.ForceBodyShapeRebuild(false); 262 child.ForceBodyShapeRebuild(false);
198 263
199 if (!HasAnyChildren) 264 if (!HasAnyChildren)
@@ -228,43 +293,57 @@ public sealed class BSLinksetCompound : BSLinkset
228 { 293 {
229 if (!IsRoot(cPrim)) 294 if (!IsRoot(cPrim))
230 { 295 {
231 // Each child position and rotation is given relative to the root. 296 // Compute the displacement of the child from the root of the linkset.
232 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); 297 // This info is saved in the child prim so the relationship does not
233 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; 298 // change over time and the new child position can be computed
234 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; 299 // when the linkset is being disassembled (the linkset may have moved).
300 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
301 if (lci == null)
302 {
303 // Each child position and rotation is given relative to the root.
304 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
305 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
306 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
307
308 // Save relative position for recomputing child's world position after moving linkset.
309 lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
310 cPrim.LinksetInfo = lci;
311 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
312 }
235 313
236 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", 314 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
237 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); 315 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
238 316
239 if (cPrim.PhysShape.isNativeShape) 317 if (cPrim.PhysShape.isNativeShape)
240 { 318 {
241 // A native shape is turning into a null collision shape because native 319 // A native shape is turning into a hull collision shape because native
242 // shapes are not shared so we have to hullify it so it will be tracked 320 // shapes are not shared so we have to hullify it so it will be tracked
243 // and freed at the correct time. This also solves the scaling problem 321 // and freed at the correct time. This also solves the scaling problem
244 // (native shapes scaled but hull/meshes are assumed to not be). 322 // (native shapes scaled but hull/meshes are assumed to not be).
323 // TODO: decide of the native shape can just be used in the compound shape.
324 // Use call to CreateGeomNonSpecial().
245 BulletShape saveShape = cPrim.PhysShape; 325 BulletShape saveShape = cPrim.PhysShape;
246 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape 326 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
327 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
247 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); 328 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
248 BulletShape newShape = cPrim.PhysShape; 329 BulletShape newShape = cPrim.PhysShape;
249 cPrim.PhysShape = saveShape; 330 cPrim.PhysShape = saveShape;
250 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot); 331 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos , lci.OffsetRot);
251 } 332 }
252 else 333 else
253 { 334 {
254 // For the shared shapes (meshes and hulls), just use the shape in the child. 335 // For the shared shapes (meshes and hulls), just use the shape in the child.
336 // The reference count added here will be decremented when the compound shape
337 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
255 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) 338 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
256 { 339 {
257 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", 340 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
258 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); 341 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
259 } 342 }
260 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); 343 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos , lci.OffsetRot);
261 } 344 }
262 } 345 }
263 346
264 // TODO: need to phantomize the child prims left behind.
265 // Maybe just destroy the children bodies and shapes and have them rebuild on unlink.
266 // Selection/deselection might cause way too many build/destructions esp. for LARGE linksets.
267
268 return false; // 'false' says to move onto the next child in the list 347 return false; // 'false' says to move onto the next child in the list
269 }); 348 });
270 349