diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | 152 |
1 files changed, 117 insertions, 35 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index e131919..107befe 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -122,18 +122,14 @@ public sealed class BSShapeCollection : IDisposable | |||
122 | lock (m_collectionActivityLock) | 122 | lock (m_collectionActivityLock) |
123 | { | 123 | { |
124 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body); | 124 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body); |
125 | BSScene.TaintCallback createOperation = delegate() | 125 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() |
126 | { | 126 | { |
127 | if (!BulletSimAPI.IsInWorld2(body.ptr)) | 127 | if (!BulletSimAPI.IsInWorld2(body.ptr)) |
128 | { | 128 | { |
129 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); | 129 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); |
130 | DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | 130 | DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); |
131 | } | 131 | } |
132 | }; | 132 | }); |
133 | if (inTaintTime) | ||
134 | createOperation(); | ||
135 | else | ||
136 | PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation); | ||
137 | } | 133 | } |
138 | } | 134 | } |
139 | 135 | ||
@@ -146,7 +142,7 @@ public sealed class BSShapeCollection : IDisposable | |||
146 | 142 | ||
147 | lock (m_collectionActivityLock) | 143 | lock (m_collectionActivityLock) |
148 | { | 144 | { |
149 | BSScene.TaintCallback removeOperation = delegate() | 145 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() |
150 | { | 146 | { |
151 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}", | 147 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}", |
152 | body.ID, body.ptr.ToString("X"), inTaintTime); | 148 | body.ID, body.ptr.ToString("X"), inTaintTime); |
@@ -159,12 +155,7 @@ public sealed class BSShapeCollection : IDisposable | |||
159 | // Zero any reference to the shape so it is not freed when the body is deleted. | 155 | // Zero any reference to the shape so it is not freed when the body is deleted. |
160 | BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); | 156 | BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); |
161 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); | 157 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); |
162 | }; | 158 | }); |
163 | // If already in taint-time, do the operations now. Otherwise queue for later. | ||
164 | if (inTaintTime) | ||
165 | removeOperation(); | ||
166 | else | ||
167 | PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation); | ||
168 | } | 159 | } |
169 | } | 160 | } |
170 | 161 | ||
@@ -238,7 +229,7 @@ public sealed class BSShapeCollection : IDisposable | |||
238 | if (shape.ptr == IntPtr.Zero) | 229 | if (shape.ptr == IntPtr.Zero) |
239 | return; | 230 | return; |
240 | 231 | ||
241 | BSScene.TaintCallback dereferenceOperation = delegate() | 232 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() |
242 | { | 233 | { |
243 | if (shape.ptr != IntPtr.Zero) | 234 | if (shape.ptr != IntPtr.Zero) |
244 | { | 235 | { |
@@ -270,18 +261,7 @@ public sealed class BSShapeCollection : IDisposable | |||
270 | } | 261 | } |
271 | } | 262 | } |
272 | } | 263 | } |
273 | }; | 264 | }); |
274 | if (inTaintTime) | ||
275 | { | ||
276 | lock (m_collectionActivityLock) | ||
277 | { | ||
278 | dereferenceOperation(); | ||
279 | } | ||
280 | } | ||
281 | else | ||
282 | { | ||
283 | PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation); | ||
284 | } | ||
285 | } | 265 | } |
286 | 266 | ||
287 | // Count down the reference count for a mesh shape | 267 | // Count down the reference count for a mesh shape |
@@ -311,7 +291,10 @@ public sealed class BSShapeCollection : IDisposable | |||
311 | { | 291 | { |
312 | hullDesc.referenceCount--; | 292 | hullDesc.referenceCount--; |
313 | // TODO: release the Bullet storage (aging old entries?) | 293 | // TODO: release the Bullet storage (aging old entries?) |
294 | |||
295 | // Tell upper layers that, if they have dependencies on this shape, this link is going away | ||
314 | if (shapeCallback != null) shapeCallback(shape); | 296 | if (shapeCallback != null) shapeCallback(shape); |
297 | |||
315 | hullDesc.lastReferenced = System.DateTime.Now; | 298 | hullDesc.lastReferenced = System.DateTime.Now; |
316 | Hulls[shape.shapeKey] = hullDesc; | 299 | Hulls[shape.shapeKey] = hullDesc; |
317 | DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}", | 300 | DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}", |
@@ -320,10 +303,48 @@ public sealed class BSShapeCollection : IDisposable | |||
320 | } | 303 | } |
321 | 304 | ||
322 | // Remove a reference to a compound shape. | 305 | // Remove a reference to a compound shape. |
306 | // Taking a compound shape apart is a little tricky because if you just delete the | ||
307 | // physical object, it will free all the underlying children. We can't do that because | ||
308 | // they could be shared. So, this removes each of the children from the compound and | ||
309 | // dereferences them separately before destroying the compound collision object itself. | ||
323 | // Called at taint-time. | 310 | // Called at taint-time. |
324 | private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) | 311 | private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) |
325 | { | 312 | { |
326 | // Compound shape is made of a bunch of meshes and natives. | 313 | if (!BulletSimAPI.IsCompound2(shape.ptr)) |
314 | { | ||
315 | // Failed the sanity check!! | ||
316 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | ||
317 | LogHeader, shape.type, shape.ptr.ToString("X")); | ||
318 | DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | ||
319 | BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); | ||
320 | return; | ||
321 | } | ||
322 | int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); | ||
323 | for (int ii = 0; ii < numChildren; ii++) | ||
324 | { | ||
325 | IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); | ||
326 | DereferenceAnonCollisionShape(childShape); | ||
327 | } | ||
328 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | ||
329 | } | ||
330 | |||
331 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | ||
332 | // Figure out type and call the correct dereference routine. | ||
333 | // This is coming from a compound shape that we created so we know it is either native or mesh. | ||
334 | // Called at taint-time. | ||
335 | private void DereferenceAnonCollisionShape(IntPtr cShape) | ||
336 | { | ||
337 | BulletShape shapeInfo = new BulletShape(cShape, ShapeData.PhysicsShapeType.SHAPE_MESH); | ||
338 | if (BulletSimAPI.IsCompound2(cShape)) | ||
339 | shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_COMPOUND; | ||
340 | |||
341 | if (BulletSimAPI.IsNativeShape2(cShape)) | ||
342 | { | ||
343 | shapeInfo.isNativeShape = true; | ||
344 | shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) | ||
345 | } | ||
346 | |||
347 | DereferenceShape(shapeInfo, true, null); | ||
327 | } | 348 | } |
328 | 349 | ||
329 | // Create the geometry information in Bullet for later use. | 350 | // Create the geometry information in Bullet for later use. |
@@ -338,10 +359,8 @@ public sealed class BSShapeCollection : IDisposable | |||
338 | { | 359 | { |
339 | bool ret = false; | 360 | bool ret = false; |
340 | bool haveShape = false; | 361 | bool haveShape = false; |
341 | bool nativeShapePossible = true; | ||
342 | PrimitiveBaseShape pbs = prim.BaseShape; | ||
343 | 362 | ||
344 | if (prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | 363 | if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_AVATAR) |
345 | { | 364 | { |
346 | // an avatar capsule is close to a native shape (it is not shared) | 365 | // an avatar capsule is close to a native shape (it is not shared) |
347 | ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_AVATAR, | 366 | ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_AVATAR, |
@@ -350,6 +369,31 @@ public sealed class BSShapeCollection : IDisposable | |||
350 | ret = true; | 369 | ret = true; |
351 | haveShape = true; | 370 | haveShape = true; |
352 | } | 371 | } |
372 | |||
373 | // Compound shapes are handled special as they are rebuilt from scratch. | ||
374 | // This isn't too great a hardship since most of the child shapes will already been created. | ||
375 | if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_COMPOUND) | ||
376 | { | ||
377 | ret = GetReferenceToCompoundShape(prim, shapeCallback); | ||
378 | DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); | ||
379 | haveShape = true; | ||
380 | } | ||
381 | |||
382 | if (!haveShape) | ||
383 | { | ||
384 | ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback); | ||
385 | } | ||
386 | |||
387 | return ret; | ||
388 | } | ||
389 | |||
390 | private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
391 | { | ||
392 | bool ret = false; | ||
393 | bool haveShape = false; | ||
394 | bool nativeShapePossible = true; | ||
395 | PrimitiveBaseShape pbs = prim.BaseShape; | ||
396 | |||
353 | // If the prim attributes are simple, this could be a simple Bullet native shape | 397 | // If the prim attributes are simple, this could be a simple Bullet native shape |
354 | if (!haveShape | 398 | if (!haveShape |
355 | && pbs != null | 399 | && pbs != null |
@@ -363,6 +407,7 @@ public sealed class BSShapeCollection : IDisposable | |||
363 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | 407 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 |
364 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | 408 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) |
365 | { | 409 | { |
410 | // It doesn't look like Bullet scales spheres so make sure the scales are all equal | ||
366 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | 411 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) |
367 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) | 412 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) |
368 | { | 413 | { |
@@ -378,7 +423,7 @@ public sealed class BSShapeCollection : IDisposable | |||
378 | prim.LocalID, forceRebuild, prim.PhysShape); | 423 | prim.LocalID, forceRebuild, prim.PhysShape); |
379 | } | 424 | } |
380 | } | 425 | } |
381 | if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | 426 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) |
382 | { | 427 | { |
383 | haveShape = true; | 428 | haveShape = true; |
384 | if (forceRebuild | 429 | if (forceRebuild |
@@ -393,9 +438,10 @@ public sealed class BSShapeCollection : IDisposable | |||
393 | } | 438 | } |
394 | } | 439 | } |
395 | } | 440 | } |
441 | |||
396 | // If a simple shape is not happening, create a mesh and possibly a hull. | 442 | // If a simple shape is not happening, create a mesh and possibly a hull. |
397 | // Note that if it's a native shape, the check for physical/non-physical is not | 443 | // Note that if it's a native shape, the check for physical/non-physical is not |
398 | // made. Native shapes are best used in either case. | 444 | // made. Native shapes work in either case. |
399 | if (!haveShape && pbs != null) | 445 | if (!haveShape && pbs != null) |
400 | { | 446 | { |
401 | if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) | 447 | if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) |
@@ -487,7 +533,7 @@ public sealed class BSShapeCollection : IDisposable | |||
487 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) | 533 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) |
488 | return false; | 534 | return false; |
489 | 535 | ||
490 | DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}", | 536 | DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", |
491 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); | 537 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); |
492 | 538 | ||
493 | // Since we're recreating new, get rid of the reference to the previous shape | 539 | // Since we're recreating new, get rid of the reference to the previous shape |
@@ -535,7 +581,7 @@ public sealed class BSShapeCollection : IDisposable | |||
535 | verticesAsFloats[vi++] = vv.Z; | 581 | verticesAsFloats[vi++] = vv.Z; |
536 | } | 582 | } |
537 | 583 | ||
538 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | 584 | // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", |
539 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | 585 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); |
540 | 586 | ||
541 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 587 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, |
@@ -561,7 +607,7 @@ public sealed class BSShapeCollection : IDisposable | |||
561 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) | 607 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) |
562 | return false; | 608 | return false; |
563 | 609 | ||
564 | DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", | 610 | DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", |
565 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | 611 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); |
566 | 612 | ||
567 | // Remove usage of the previous shape. | 613 | // Remove usage of the previous shape. |
@@ -693,6 +739,42 @@ public sealed class BSShapeCollection : IDisposable | |||
693 | return; | 739 | return; |
694 | } | 740 | } |
695 | 741 | ||
742 | // Compound shapes are always built from scratch. | ||
743 | // This shouldn't be to bad since most of the parts will be meshes that had been built previously. | ||
744 | private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
745 | { | ||
746 | BulletShape cShape = new BulletShape( | ||
747 | BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr), ShapeData.PhysicsShapeType.SHAPE_COMPOUND); | ||
748 | |||
749 | // The prim's linkset is the source of the children. | ||
750 | // TODO: there is too much knowledge here about the internals of linksets and too much | ||
751 | // dependency on the relationship of compound shapes and linksets (what if we want to use | ||
752 | // compound shapes for something else?). Think through this and clean up so the | ||
753 | // appropriate knowledge is used at the correct software levels. | ||
754 | |||
755 | // Recreate the geometry of the root prim (might have been a linkset root in the past) | ||
756 | CreateGeomNonSpecial(true, prim, null); | ||
757 | |||
758 | BSPhysObject rootPrim = prim.Linkset.LinksetRoot; | ||
759 | |||
760 | prim.Linkset.ForEachMember(delegate(BSPhysObject cPrim) | ||
761 | { | ||
762 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(rootPrim.RawOrientation); | ||
763 | OMV.Vector3 displacementPos = (cPrim.RawPosition - rootPrim.RawPosition) * invRootOrientation; | ||
764 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
765 | |||
766 | DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", | ||
767 | prim.LocalID, cPrim.LocalID, cPrim.PhysShape.ptr.ToString("X"), displacementPos, displacementRot); | ||
768 | |||
769 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); | ||
770 | return false; | ||
771 | }); | ||
772 | |||
773 | prim.PhysShape = cShape; | ||
774 | |||
775 | return true; | ||
776 | } | ||
777 | |||
696 | // Create a hash of all the shape parameters to be used as a key | 778 | // Create a hash of all the shape parameters to be used as a key |
697 | // for this particular shape. | 779 | // for this particular shape. |
698 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) | 780 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) |