aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs444
1 files changed, 248 insertions, 196 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index d189f1d..d3ba273 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -51,7 +51,7 @@ public class BSShapeCollection : IDisposable
51 } 51 }
52 52
53 // Description of a hull. 53 // Description of a hull.
54 // Meshes and hulls have the same shape hash key but we only need hulls for efficient physical objects 54 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
55 private struct HullDesc 55 private struct HullDesc
56 { 56 {
57 public IntPtr ptr; 57 public IntPtr ptr;
@@ -59,17 +59,9 @@ public class BSShapeCollection : IDisposable
59 public DateTime lastReferenced; 59 public DateTime lastReferenced;
60 } 60 }
61 61
62 private struct BodyDesc 62 // The sharable set of meshes and hulls. Indexed by their shape hash.
63 {
64 public IntPtr ptr;
65 // Bodies are only used once so reference count is always either one or zero
66 public int referenceCount;
67 public DateTime lastReferenced;
68 }
69
70 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); 63 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
71 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); 64 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
72 private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
73 65
74 public BSShapeCollection(BSScene physScene) 66 public BSShapeCollection(BSScene physScene)
75 { 67 {
@@ -92,8 +84,12 @@ public class BSShapeCollection : IDisposable
92 // First checks the shape and updates that if necessary then makes 84 // First checks the shape and updates that if necessary then makes
93 // sure the body is of the right type. 85 // sure the body is of the right type.
94 // Return 'true' if either the body or the shape changed. 86 // Return 'true' if either the body or the shape changed.
87 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before
88 // the current shape or body is destroyed. This allows the caller to remove any
89 // higher level dependencies on the shape or body. Mostly used for LinkSets to
90 // remove the physical constraints before the body is destroyed.
95 // Called at taint-time!! 91 // Called at taint-time!!
96 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim, 92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
97 ShapeData shapeData, PrimitiveBaseShape pbs, 93 ShapeData shapeData, PrimitiveBaseShape pbs,
98 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 94 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
99 { 95 {
@@ -103,7 +99,8 @@ public class BSShapeCollection : IDisposable
103 lock (m_collectionActivityLock) 99 lock (m_collectionActivityLock)
104 { 100 {
105 // Do we have the correct geometry for this type of object? 101 // Do we have the correct geometry for this type of object?
106 // Updates prim.BSShape with information/pointers to requested shape 102 // Updates prim.BSShape with information/pointers to shape.
103 // CreateGeom returns 'true' of BSShape as changed to a new shape.
107 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback); 104 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
108 // If we had to select a new shape geometry for the object, 105 // If we had to select a new shape geometry for the object,
109 // rebuild the body around it. 106 // rebuild the body around it.
@@ -120,40 +117,24 @@ public class BSShapeCollection : IDisposable
120 117
121 // Track another user of a body 118 // Track another user of a body
122 // We presume the caller has allocated the body. 119 // We presume the caller has allocated the body.
123 // Bodies only have one user so the reference count is either 1 or 0. 120 // Bodies only have one user so the body is just put into the world if not already there.
124 public void ReferenceBody(BulletBody body, bool inTaintTime) 121 public void ReferenceBody(BulletBody body, bool inTaintTime)
125 { 122 {
126 lock (m_collectionActivityLock) 123 lock (m_collectionActivityLock)
127 { 124 {
128 BodyDesc bodyDesc; 125 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body);
129 if (Bodies.TryGetValue(body.ID, out bodyDesc)) 126 BSScene.TaintCallback createOperation = delegate()
130 { 127 {
131 bodyDesc.referenceCount++; 128 if (!BulletSimAPI.IsInWorld2(body.ptr))
132 DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,body={1},ref={2}", body.ID, body, bodyDesc.referenceCount);
133 }
134 else
135 {
136 // New entry
137 bodyDesc.ptr = body.ptr;
138 bodyDesc.referenceCount = 1;
139 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={2}",
140 body.ID, body, bodyDesc.referenceCount);
141 BSScene.TaintCallback createOperation = delegate()
142 { 129 {
143 if (!BulletSimAPI.IsInWorld2(body.ptr)) 130 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
144 { 131 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
145 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 132 }
146 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", 133 };
147 body.ID, body); 134 if (inTaintTime)
148 } 135 createOperation();
149 }; 136 else
150 if (inTaintTime) 137 PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
151 createOperation();
152 else
153 PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
154 }
155 bodyDesc.lastReferenced = System.DateTime.Now;
156 Bodies[body.ID] = bodyDesc;
157 } 138 }
158 } 139 }
159 140
@@ -166,43 +147,25 @@ public class BSShapeCollection : IDisposable
166 147
167 lock (m_collectionActivityLock) 148 lock (m_collectionActivityLock)
168 { 149 {
169 BodyDesc bodyDesc; 150 BSScene.TaintCallback removeOperation = delegate()
170 if (Bodies.TryGetValue(body.ID, out bodyDesc))
171 { 151 {
172 bodyDesc.referenceCount--; 152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
173 bodyDesc.lastReferenced = System.DateTime.Now; 153 body.ID, body.ptr.ToString("X"), inTaintTime);
174 Bodies[body.ID] = bodyDesc; 154 // If the caller needs to know the old body is going away, pass the event up.
175 DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount); 155 if (bodyCallback != null) bodyCallback(body);
176 156
177 // If body is no longer being used, free it -- bodies can never be shared. 157 // It may have already been removed from the world in which case the next is a NOOP.
178 if (bodyDesc.referenceCount == 0) 158 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
179 { 159
180 Bodies.Remove(body.ID); 160 // Zero any reference to the shape so it is not freed when the body is deleted.
181 BSScene.TaintCallback removeOperation = delegate() 161 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
182 { 162 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
183 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}", 163 };
184 body.ID, body.ptr.ToString("X"), inTaintTime); 164 // If already in taint-time, do the operations now. Otherwise queue for later.
185 // If the caller needs to know the old body is going away, pass the event up. 165 if (inTaintTime)
186 if (bodyCallback != null) bodyCallback(body); 166 removeOperation();
187
188 // It may have already been removed from the world in which case the next is a NOOP.
189 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
190
191 // Zero any reference to the shape so it is not freed when the body is deleted.
192 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
193 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
194 };
195 // If already in taint-time, do the operations now. Otherwise queue for later.
196 if (inTaintTime)
197 removeOperation();
198 else
199 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
200 }
201 }
202 else 167 else
203 { 168 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
204 DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount);
205 }
206 } 169 }
207 } 170 }
208 171
@@ -271,7 +234,6 @@ public class BSShapeCollection : IDisposable
271 } 234 }
272 235
273 // Release the usage of a shape. 236 // Release the usage of a shape.
274 // The collisionObject is released since it is a copy of the real collision shape.
275 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) 237 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
276 { 238 {
277 if (shape.ptr == IntPtr.Zero) 239 if (shape.ptr == IntPtr.Zero)
@@ -279,26 +241,32 @@ public class BSShapeCollection : IDisposable
279 241
280 BSScene.TaintCallback dereferenceOperation = delegate() 242 BSScene.TaintCallback dereferenceOperation = delegate()
281 { 243 {
282 switch (shape.type) 244 if (shape.ptr != IntPtr.Zero)
283 { 245 {
284 case ShapeData.PhysicsShapeType.SHAPE_HULL: 246 if (shape.isNativeShape)
285 DereferenceHull(shape, shapeCallback); 247 {
286 break;
287 case ShapeData.PhysicsShapeType.SHAPE_MESH:
288 DereferenceMesh(shape, shapeCallback);
289 break;
290 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
291 break;
292 default:
293 // Native shapes are not tracked and are released immediately 248 // Native shapes are not tracked and are released immediately
294 if (shape.ptr != IntPtr.Zero & shape.isNativeShape) 249 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
250 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
251 if (shapeCallback != null) shapeCallback(shape);
252 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
253 }
254 else
255 {
256 switch (shape.type)
295 { 257 {
296 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", 258 case ShapeData.PhysicsShapeType.SHAPE_HULL:
297 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); 259 DereferenceHull(shape, shapeCallback);
298 if (shapeCallback != null) shapeCallback(shape); 260 break;
299 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 261 case ShapeData.PhysicsShapeType.SHAPE_MESH:
262 DereferenceMesh(shape, shapeCallback);
263 break;
264 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
265 break;
266 default:
267 break;
300 } 268 }
301 break; 269 }
302 } 270 }
303 }; 271 };
304 if (inTaintTime) 272 if (inTaintTime)
@@ -351,19 +319,31 @@ public class BSShapeCollection : IDisposable
351 319
352 // Create the geometry information in Bullet for later use. 320 // Create the geometry information in Bullet for later use.
353 // The objects needs a hull if it's physical otherwise a mesh is enough. 321 // The objects needs a hull if it's physical otherwise a mesh is enough.
354 // No locking here because this is done when we know physics is not simulating. 322 // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
355 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used. 323 // shared geometries will be used. If the parameters of the existing shape are the same
324 // as this request, the shape is not rebuilt.
325 // Info in prim.BSShape is updated to the new shape.
356 // Returns 'true' if the geometry was rebuilt. 326 // Returns 'true' if the geometry was rebuilt.
357 // Called at taint-time! 327 // Called at taint-time!
358 private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData, 328 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
359 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback) 329 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
360 { 330 {
361 bool ret = false; 331 bool ret = false;
362 bool haveShape = false; 332 bool haveShape = false;
363 bool nativeShapePossible = true; 333 bool nativeShapePossible = true;
364 334
335 if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
336 {
337 // an avatar capsule is close to a native shape (it is not shared)
338 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
339 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
340 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
341 haveShape = true;
342 }
365 // If the prim attributes are simple, this could be a simple Bullet native shape 343 // If the prim attributes are simple, this could be a simple Bullet native shape
366 if (nativeShapePossible 344 if (!haveShape
345 && pbs != null
346 && nativeShapePossible
367 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) 347 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
368 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 348 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
369 && pbs.ProfileHollow == 0 349 && pbs.ProfileHollow == 0
@@ -406,7 +386,7 @@ public class BSShapeCollection : IDisposable
406 // If a simple shape is not happening, create a mesh and possibly a hull. 386 // If a simple shape is not happening, create a mesh and possibly a hull.
407 // Note that if it's a native shape, the check for physical/non-physical is not 387 // Note that if it's a native shape, the check for physical/non-physical is not
408 // made. Native shapes are best used in either case. 388 // made. Native shapes are best used in either case.
409 if (!haveShape) 389 if (!haveShape && pbs != null)
410 { 390 {
411 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 391 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
412 { 392 {
@@ -425,12 +405,12 @@ public class BSShapeCollection : IDisposable
425 return ret; 405 return ret;
426 } 406 }
427 407
428 // Creates a native shape and assignes it to prim.BSShape 408 // Creates a native shape and assignes it to prim.BSShape.
429 private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData, 409 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
410 private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData,
430 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, 411 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
431 ShapeDestructionCallback shapeCallback) 412 ShapeDestructionCallback shapeCallback)
432 { 413 {
433 BulletShape newShape;
434 414
435 shapeData.Type = shapeType; 415 shapeData.Type = shapeType;
436 // Bullet native objects are scaled by the Bullet engine so pass the size in 416 // Bullet native objects are scaled by the Bullet engine so pass the size in
@@ -440,23 +420,42 @@ public class BSShapeCollection : IDisposable
440 // release any previous shape 420 // release any previous shape
441 DereferenceShape(prim.BSShape, true, shapeCallback); 421 DereferenceShape(prim.BSShape, true, shapeCallback);
442 422
443 // Native shapes are always built independently. 423 BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
444 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
445 newShape.shapeKey = (System.UInt64)shapeKey;
446 newShape.isNativeShape = true;
447 424
448 // Don't need to do a 'ReferenceShape()' here because native shapes are not tracked. 425 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
449 // DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape); 426 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
427 shapeData.ID, newShape, shapeData.Scale);
450 428
451 prim.BSShape = newShape; 429 prim.BSShape = newShape;
452 return true; 430 return true;
453 } 431 }
454 432
433 private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
434 ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
435 {
436 BulletShape newShape;
437
438 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
439 {
440 newShape = new BulletShape(
441 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale),
442 shapeType);
443 }
444 else
445 {
446 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
447 }
448 newShape.shapeKey = (System.UInt64)shapeKey;
449 newShape.isNativeShape = true;
450
451 return newShape;
452 }
453
455 // Builds a mesh shape in the physical world and updates prim.BSShape. 454 // Builds a mesh shape in the physical world and updates prim.BSShape.
456 // Dereferences previous shape in BSShape and adds a reference for this new shape. 455 // Dereferences previous shape in BSShape and adds a reference for this new shape.
457 // Returns 'true' of a mesh was actually built. Otherwise . 456 // Returns 'true' of a mesh was actually built. Otherwise .
458 // Called at taint-time! 457 // Called at taint-time!
459 private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs, 458 private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
460 ShapeDestructionCallback shapeCallback) 459 ShapeDestructionCallback shapeCallback)
461 { 460 {
462 BulletShape newShape = new BulletShape(IntPtr.Zero); 461 BulletShape newShape = new BulletShape(IntPtr.Zero);
@@ -475,6 +474,8 @@ public class BSShapeCollection : IDisposable
475 DereferenceShape(prim.BSShape, true, shapeCallback); 474 DereferenceShape(prim.BSShape, true, shapeCallback);
476 475
477 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); 476 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
477 // Take evasive action if the mesh was not constructed.
478 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
478 479
479 ReferenceShape(newShape); 480 ReferenceShape(newShape);
480 481
@@ -488,7 +489,7 @@ public class BSShapeCollection : IDisposable
488 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 489 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
489 { 490 {
490 IMesh meshData = null; 491 IMesh meshData = null;
491 IntPtr meshPtr; 492 IntPtr meshPtr = IntPtr.Zero;
492 MeshDesc meshDesc; 493 MeshDesc meshDesc;
493 if (Meshes.TryGetValue(newMeshKey, out meshDesc)) 494 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
494 { 495 {
@@ -500,23 +501,26 @@ public class BSShapeCollection : IDisposable
500 // Pass false for physicalness as this creates some sort of bounding box which we don't need 501 // Pass false for physicalness as this creates some sort of bounding box which we don't need
501 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 502 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
502 503
503 int[] indices = meshData.getIndexListAsInt(); 504 if (meshData != null)
504 List<OMV.Vector3> vertices = meshData.getVertexList();
505
506 float[] verticesAsFloats = new float[vertices.Count * 3];
507 int vi = 0;
508 foreach (OMV.Vector3 vv in vertices)
509 { 505 {
510 verticesAsFloats[vi++] = vv.X; 506 int[] indices = meshData.getIndexListAsInt();
511 verticesAsFloats[vi++] = vv.Y; 507 List<OMV.Vector3> vertices = meshData.getVertexList();
512 verticesAsFloats[vi++] = vv.Z;
513 }
514 508
515 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 509 float[] verticesAsFloats = new float[vertices.Count * 3];
516 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 510 int vi = 0;
511 foreach (OMV.Vector3 vv in vertices)
512 {
513 verticesAsFloats[vi++] = vv.X;
514 verticesAsFloats[vi++] = vv.Y;
515 verticesAsFloats[vi++] = vv.Z;
516 }
517 517
518 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 518 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
519 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 519 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
520
521 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
522 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
523 }
520 } 524 }
521 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); 525 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
522 newShape.shapeKey = newMeshKey; 526 newShape.shapeKey = newMeshKey;
@@ -526,7 +530,7 @@ public class BSShapeCollection : IDisposable
526 530
527 // See that hull shape exists in the physical world and update prim.BSShape. 531 // See that hull shape exists in the physical world and update prim.BSShape.
528 // We could be creating the hull because scale changed or whatever. 532 // We could be creating the hull because scale changed or whatever.
529 private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs, 533 private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
530 ShapeDestructionCallback shapeCallback) 534 ShapeDestructionCallback shapeCallback)
531 { 535 {
532 BulletShape newShape; 536 BulletShape newShape;
@@ -545,6 +549,7 @@ public class BSShapeCollection : IDisposable
545 DereferenceShape(prim.BSShape, true, shapeCallback); 549 DereferenceShape(prim.BSShape, true, shapeCallback);
546 550
547 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); 551 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
552 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
548 553
549 ReferenceShape(newShape); 554 ReferenceShape(newShape);
550 555
@@ -558,7 +563,7 @@ public class BSShapeCollection : IDisposable
558 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 563 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
559 { 564 {
560 565
561 IntPtr hullPtr; 566 IntPtr hullPtr = IntPtr.Zero;
562 HullDesc hullDesc; 567 HullDesc hullDesc;
563 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 568 if (Hulls.TryGetValue(newHullKey, out hullDesc))
564 { 569 {
@@ -570,86 +575,89 @@ public class BSShapeCollection : IDisposable
570 // Build a new hull in the physical world 575 // Build a new hull in the physical world
571 // Pass false for physicalness as this creates some sort of bounding box which we don't need 576 // Pass false for physicalness as this creates some sort of bounding box which we don't need
572 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 577 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
573 578 if (meshData != null)
574 int[] indices = meshData.getIndexListAsInt();
575 List<OMV.Vector3> vertices = meshData.getVertexList();
576
577 //format conversion from IMesh format to DecompDesc format
578 List<int> convIndices = new List<int>();
579 List<float3> convVertices = new List<float3>();
580 for (int ii = 0; ii < indices.GetLength(0); ii++)
581 { 579 {
582 convIndices.Add(indices[ii]);
583 }
584 foreach (OMV.Vector3 vv in vertices)
585 {
586 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
587 }
588 580
589 // setup and do convex hull conversion 581 int[] indices = meshData.getIndexListAsInt();
590 m_hulls = new List<ConvexResult>(); 582 List<OMV.Vector3> vertices = meshData.getVertexList();
591 DecompDesc dcomp = new DecompDesc();
592 dcomp.mIndices = convIndices;
593 dcomp.mVertices = convVertices;
594 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
595 // create the hull into the _hulls variable
596 convexBuilder.process(dcomp);
597
598 // Convert the vertices and indices for passing to unmanaged.
599 // The hull information is passed as a large floating point array.
600 // The format is:
601 // convHulls[0] = number of hulls
602 // convHulls[1] = number of vertices in first hull
603 // convHulls[2] = hull centroid X coordinate
604 // convHulls[3] = hull centroid Y coordinate
605 // convHulls[4] = hull centroid Z coordinate
606 // convHulls[5] = first hull vertex X
607 // convHulls[6] = first hull vertex Y
608 // convHulls[7] = first hull vertex Z
609 // convHulls[8] = second hull vertex X
610 // ...
611 // convHulls[n] = number of vertices in second hull
612 // convHulls[n+1] = second hull centroid X coordinate
613 // ...
614 //
615 // TODO: is is very inefficient. Someday change the convex hull generator to return
616 // data structures that do not need to be converted in order to pass to Bullet.
617 // And maybe put the values directly into pinned memory rather than marshaling.
618 int hullCount = m_hulls.Count;
619 int totalVertices = 1; // include one for the count of the hulls
620 foreach (ConvexResult cr in m_hulls)
621 {
622 totalVertices += 4; // add four for the vertex count and centroid
623 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
624 }
625 float[] convHulls = new float[totalVertices];
626 583
627 convHulls[0] = (float)hullCount; 584 //format conversion from IMesh format to DecompDesc format
628 int jj = 1; 585 List<int> convIndices = new List<int>();
629 foreach (ConvexResult cr in m_hulls) 586 List<float3> convVertices = new List<float3>();
630 { 587 for (int ii = 0; ii < indices.GetLength(0); ii++)
631 // copy vertices for index access 588 {
632 float3[] verts = new float3[cr.HullVertices.Count]; 589 convIndices.Add(indices[ii]);
633 int kk = 0; 590 }
634 foreach (float3 ff in cr.HullVertices) 591 foreach (OMV.Vector3 vv in vertices)
635 { 592 {
636 verts[kk++] = ff; 593 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
637 } 594 }
638 595
639 // add to the array one hull's worth of data 596 // setup and do convex hull conversion
640 convHulls[jj++] = cr.HullIndices.Count; 597 m_hulls = new List<ConvexResult>();
641 convHulls[jj++] = 0f; // centroid x,y,z 598 DecompDesc dcomp = new DecompDesc();
642 convHulls[jj++] = 0f; 599 dcomp.mIndices = convIndices;
643 convHulls[jj++] = 0f; 600 dcomp.mVertices = convVertices;
644 foreach (int ind in cr.HullIndices) 601 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
602 // create the hull into the _hulls variable
603 convexBuilder.process(dcomp);
604
605 // Convert the vertices and indices for passing to unmanaged.
606 // The hull information is passed as a large floating point array.
607 // The format is:
608 // convHulls[0] = number of hulls
609 // convHulls[1] = number of vertices in first hull
610 // convHulls[2] = hull centroid X coordinate
611 // convHulls[3] = hull centroid Y coordinate
612 // convHulls[4] = hull centroid Z coordinate
613 // convHulls[5] = first hull vertex X
614 // convHulls[6] = first hull vertex Y
615 // convHulls[7] = first hull vertex Z
616 // convHulls[8] = second hull vertex X
617 // ...
618 // convHulls[n] = number of vertices in second hull
619 // convHulls[n+1] = second hull centroid X coordinate
620 // ...
621 //
622 // TODO: is is very inefficient. Someday change the convex hull generator to return
623 // data structures that do not need to be converted in order to pass to Bullet.
624 // And maybe put the values directly into pinned memory rather than marshaling.
625 int hullCount = m_hulls.Count;
626 int totalVertices = 1; // include one for the count of the hulls
627 foreach (ConvexResult cr in m_hulls)
645 { 628 {
646 convHulls[jj++] = verts[ind].x; 629 totalVertices += 4; // add four for the vertex count and centroid
647 convHulls[jj++] = verts[ind].y; 630 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
648 convHulls[jj++] = verts[ind].z;
649 } 631 }
632 float[] convHulls = new float[totalVertices];
633
634 convHulls[0] = (float)hullCount;
635 int jj = 1;
636 foreach (ConvexResult cr in m_hulls)
637 {
638 // copy vertices for index access
639 float3[] verts = new float3[cr.HullVertices.Count];
640 int kk = 0;
641 foreach (float3 ff in cr.HullVertices)
642 {
643 verts[kk++] = ff;
644 }
645
646 // add to the array one hull's worth of data
647 convHulls[jj++] = cr.HullIndices.Count;
648 convHulls[jj++] = 0f; // centroid x,y,z
649 convHulls[jj++] = 0f;
650 convHulls[jj++] = 0f;
651 foreach (int ind in cr.HullIndices)
652 {
653 convHulls[jj++] = verts[ind].x;
654 convHulls[jj++] = verts[ind].y;
655 convHulls[jj++] = verts[ind].z;
656 }
657 }
658 // create the hull data structure in Bullet
659 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
650 } 660 }
651 // create the hull data structure in Bullet
652 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
653 } 661 }
654 662
655 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); 663 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
@@ -690,11 +698,55 @@ public class BSShapeCollection : IDisposable
690 return ComputeShapeKey(shapeData, pbs, out lod); 698 return ComputeShapeKey(shapeData, pbs, out lod);
691 } 699 }
692 700
701 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
702 {
703 // If the shape was successfully created, nothing more to do
704 if (newShape.ptr != IntPtr.Zero)
705 return newShape;
706
707 // The most common reason for failure is that an underlying asset is not available
708
709 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
710 if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
711 {
712 prim.LastAssetBuildFailed = true;
713 BSPhysObject xprim = prim;
714 Util.FireAndForget(delegate
715 {
716 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
717 if (assetProvider != null)
718 {
719 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
720 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
721 {
722 if (!yprim.BaseShape.SculptEntry)
723 return;
724 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
725 return;
726
727 yprim.BaseShape.SculptData = new byte[asset.Data.Length];
728 asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
729 // This will cause the prim to see that the filler shape is not the right
730 // one and try again to build the object.
731 yprim.ForceBodyShapeRebuild(false);
732
733 });
734 }
735 });
736 }
737
738 // While we figure out the real problem, stick a simple native shape on the object.
739 BulletShape fillinShape =
740 BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE);
741
742 return fillinShape;
743 }
744
693 // Create a body object in Bullet. 745 // Create a body object in Bullet.
694 // Updates prim.BSBody with the information about the new body if one is created. 746 // Updates prim.BSBody with the information about the new body if one is created.
695 // Returns 'true' if an object was actually created. 747 // Returns 'true' if an object was actually created.
696 // Called at taint-time. 748 // Called at taint-time.
697 private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape, 749 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
698 ShapeData shapeData, BodyDestructionCallback bodyCallback) 750 ShapeData shapeData, BodyDestructionCallback bodyCallback)
699 { 751 {
700 bool ret = false; 752 bool ret = false;