aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs296
1 files changed, 153 insertions, 143 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 6b90661..7fce8c9 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -36,6 +36,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSShapeCollection : IDisposable 37public class BSShapeCollection : IDisposable
38{ 38{
39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40
39 protected BSScene PhysicsScene { get; set; } 41 protected BSScene PhysicsScene { get; set; }
40 42
41 private Object m_collectionActivityLock = new Object(); 43 private Object m_collectionActivityLock = new Object();
@@ -43,24 +45,23 @@ public class BSShapeCollection : IDisposable
43 // Description of a Mesh 45 // Description of a Mesh
44 private struct MeshDesc 46 private struct MeshDesc
45 { 47 {
46 public IntPtr Ptr; 48 public IntPtr ptr;
47 public int referenceCount; 49 public int referenceCount;
48 public DateTime lastReferenced; 50 public DateTime lastReferenced;
49 public IMesh meshData;
50 } 51 }
51 52
52 // Description of a hull. 53 // Description of a hull.
53 // 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 physical objects
54 private struct HullDesc 55 private struct HullDesc
55 { 56 {
56 public IntPtr Ptr; 57 public IntPtr ptr;
57 public int referenceCount; 58 public int referenceCount;
58 public DateTime lastReferenced; 59 public DateTime lastReferenced;
59 } 60 }
60 61
61 private struct BodyDesc 62 private struct BodyDesc
62 { 63 {
63 public IntPtr Ptr; 64 public IntPtr ptr;
64 // Bodies are only used once so reference count is always either one or zero 65 // Bodies are only used once so reference count is always either one or zero
65 public int referenceCount; 66 public int referenceCount;
66 public DateTime lastReferenced; 67 public DateTime lastReferenced;
@@ -93,14 +94,16 @@ public class BSShapeCollection : IDisposable
93 lock (m_collectionActivityLock) 94 lock (m_collectionActivityLock)
94 { 95 {
95 // Do we have the correct geometry for this type of object? 96 // Do we have the correct geometry for this type of object?
97 // Updates prim.BSShape with information/pointers to requested shape
96 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs); 98 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs);
97 // If we had to select a new shape geometry for the object, 99 // If we had to select a new shape geometry for the object,
98 // rebuild the body around it. 100 // rebuild the body around it.
101 // Updates prim.BSBody with information/pointers to requested body
99 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, prim.BSShape, shapeData); 102 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, prim.BSShape, shapeData);
100 ret = newGeom || newBody; 103 ret = newGeom || newBody;
101 } 104 }
102 DetailLog("{0},BSShapeCollection.GetBodyAndShape,force-{1},ret={2},body={3},shape={4}", 105 DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}",
103 prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape); 106 prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape);
104 107
105 return ret; 108 return ret;
106 } 109 }
@@ -120,7 +123,8 @@ public class BSShapeCollection : IDisposable
120 } 123 }
121 else 124 else
122 { 125 {
123 bodyDesc.Ptr = shape.ptr; 126 // New entry
127 bodyDesc.ptr = shape.ptr;
124 bodyDesc.referenceCount = 1; 128 bodyDesc.referenceCount = 1;
125 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", shape.ID, bodyDesc.referenceCount); 129 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", shape.ID, bodyDesc.referenceCount);
126 } 130 }
@@ -130,7 +134,7 @@ public class BSShapeCollection : IDisposable
130} 134}
131 135
132 // Release the usage of a body. 136 // Release the usage of a body.
133 // Not that this will also delete the body in BUllet if the body is now unused (reference count = 0). 137 // Called when releasing use of a BSBody. BSShape is handled separately.
134 public void DereferenceBody(BulletBody shape, bool inTaintTime) 138 public void DereferenceBody(BulletBody shape, bool inTaintTime)
135 { 139 {
136 if (shape.ptr == IntPtr.Zero) 140 if (shape.ptr == IntPtr.Zero)
@@ -146,15 +150,17 @@ public class BSShapeCollection : IDisposable
146 Bodies[shape.ID] = bodyDesc; 150 Bodies[shape.ID] = bodyDesc;
147 DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", shape.ID, bodyDesc.referenceCount); 151 DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", shape.ID, bodyDesc.referenceCount);
148 152
153 // If body is no longer being used, free it -- bodies are never shared.
149 if (bodyDesc.referenceCount == 0) 154 if (bodyDesc.referenceCount == 0)
150 { 155 {
151 Bodies.Remove(shape.ID); 156 Bodies.Remove(shape.ID);
152 BSScene.TaintCallback removeOperation = delegate() 157 BSScene.TaintCallback removeOperation = delegate()
153 { 158 {
154 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. Ptr={1:X}", shape.ID, shape.ptr); 159 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}",
155 // zero any reference to the shape so it is not freed when the body is deleted 160 shape.ID, shape.ptr.ToString("X"));
161 // Zero any reference to the shape so it is not freed when the body is deleted.
156 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, shape.ptr, IntPtr.Zero); 162 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, shape.ptr, IntPtr.Zero);
157 // It may have already been removed from the world in which case the next is a NOOP 163 // It may have already been removed from the world in which case the next is a NOOP.
158 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, shape.ptr); 164 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, shape.ptr);
159 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, shape.ptr); 165 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, shape.ptr);
160 }; 166 };
@@ -172,19 +178,13 @@ public class BSShapeCollection : IDisposable
172 } 178 }
173 } 179 }
174 180
175 // Track another user of the shape
176 private bool ReferenceShape(BulletShape shape)
177 {
178 return ReferenceShape(shape, null);
179 }
180
181 // Track the datastructures and use count for a shape. 181 // Track the datastructures and use count for a shape.
182 // When creating a hull, this is called first to reference the mesh 182 // When creating a hull, this is called first to reference the mesh
183 // and then again to reference the hull. 183 // and then again to reference the hull.
184 // Meshes and hulls for the same shape have the same hash key. 184 // Meshes and hulls for the same shape have the same hash key.
185 // NOTE that native shapes are not added to the mesh list or removed. 185 // NOTE that native shapes are not added to the mesh list or removed.
186 // Returns 'true' if this is the initial reference to the shape. Otherwise reused. 186 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
187 private bool ReferenceShape(BulletShape shape, IMesh meshData) 187 private bool ReferenceShape(BulletShape shape)
188 { 188 {
189 bool ret = false; 189 bool ret = false;
190 switch (shape.type) 190 switch (shape.type)
@@ -196,16 +196,16 @@ public class BSShapeCollection : IDisposable
196 // There is an existing instance of this mesh. 196 // There is an existing instance of this mesh.
197 meshDesc.referenceCount++; 197 meshDesc.referenceCount++;
198 DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}", 198 DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}",
199 BSScene.DetailLogZero, shape.shapeKey, meshDesc.referenceCount); 199 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
200 } 200 }
201 else 201 else
202 { 202 {
203 // This is a new reference to a mesh 203 // This is a new reference to a mesh
204 meshDesc.Ptr = shape.ptr; 204 meshDesc.ptr = shape.ptr;
205 meshDesc.meshData = meshData; 205 // We keep a reference to the underlying IMesh data so a hull can be built
206 meshDesc.referenceCount = 1; 206 meshDesc.referenceCount = 1;
207 DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}", 207 DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}",
208 BSScene.DetailLogZero, shape.shapeKey, meshDesc.referenceCount); 208 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
209 ret = true; 209 ret = true;
210 } 210 }
211 meshDesc.lastReferenced = System.DateTime.Now; 211 meshDesc.lastReferenced = System.DateTime.Now;
@@ -215,18 +215,18 @@ public class BSShapeCollection : IDisposable
215 HullDesc hullDesc; 215 HullDesc hullDesc;
216 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) 216 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
217 { 217 {
218 // There is an existing instance of this mesh. 218 // There is an existing instance of this hull.
219 hullDesc.referenceCount++; 219 hullDesc.referenceCount++;
220 DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}", 220 DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}",
221 BSScene.DetailLogZero, shape.shapeKey, hullDesc.referenceCount); 221 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
222 } 222 }
223 else 223 else
224 { 224 {
225 // This is a new reference to a hull 225 // This is a new reference to a hull
226 hullDesc.Ptr = shape.ptr; 226 hullDesc.ptr = shape.ptr;
227 hullDesc.referenceCount = 1; 227 hullDesc.referenceCount = 1;
228 DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}", 228 DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}",
229 BSScene.DetailLogZero, shape.shapeKey, hullDesc.referenceCount); 229 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
230 ret = true; 230 ret = true;
231 231
232 } 232 }
@@ -242,7 +242,8 @@ public class BSShapeCollection : IDisposable
242 return ret; 242 return ret;
243 } 243 }
244 244
245 // Release the usage of a shape 245 // Release the usage of a shape.
246 // The collisionObject is released since it is a copy of the real collision shape.
246 private void DereferenceShape(BulletShape shape, bool atTaintTime) 247 private void DereferenceShape(BulletShape shape, bool atTaintTime)
247 { 248 {
248 if (shape.ptr == IntPtr.Zero) 249 if (shape.ptr == IntPtr.Zero)
@@ -254,8 +255,6 @@ public class BSShapeCollection : IDisposable
254 { 255 {
255 case ShapeData.PhysicsShapeType.SHAPE_HULL: 256 case ShapeData.PhysicsShapeType.SHAPE_HULL:
256 DereferenceHull(shape); 257 DereferenceHull(shape);
257 // Hulls also include a mesh
258 DereferenceMesh(shape);
259 break; 258 break;
260 case ShapeData.PhysicsShapeType.SHAPE_MESH: 259 case ShapeData.PhysicsShapeType.SHAPE_MESH:
261 DereferenceMesh(shape); 260 DereferenceMesh(shape);
@@ -266,15 +265,24 @@ public class BSShapeCollection : IDisposable
266 // Native shapes are not tracked and are released immediately 265 // Native shapes are not tracked and are released immediately
267 if (shape.ptr != IntPtr.Zero & shape.isNativeShape) 266 if (shape.ptr != IntPtr.Zero & shape.isNativeShape)
268 { 267 {
268 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
269 BSScene.DetailLogZero, shape.ptr.ToString("X"), atTaintTime);
269 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 270 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
270 } 271 }
271 break; 272 break;
272 } 273 }
273 }; 274 };
274 if (atTaintTime) 275 if (atTaintTime)
275 dereferenceOperation(); 276 {
277 lock (m_collectionActivityLock)
278 {
279 dereferenceOperation();
280 }
281 }
276 else 282 else
283 {
277 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation); 284 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation);
285 }
278 } 286 }
279 287
280 // Count down the reference count for a mesh shape 288 // Count down the reference count for a mesh shape
@@ -288,8 +296,8 @@ public class BSShapeCollection : IDisposable
288 // TODO: release the Bullet storage 296 // TODO: release the Bullet storage
289 meshDesc.lastReferenced = System.DateTime.Now; 297 meshDesc.lastReferenced = System.DateTime.Now;
290 Meshes[shape.shapeKey] = meshDesc; 298 Meshes[shape.shapeKey] = meshDesc;
291 DetailLog("{0},BSShapeColliction.DereferenceMesh,key={1},cnt={2}", 299 DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}",
292 BSScene.DetailLogZero, shape.shapeKey, meshDesc.referenceCount); 300 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
293 301
294 } 302 }
295 } 303 }
@@ -305,8 +313,8 @@ public class BSShapeCollection : IDisposable
305 // TODO: release the Bullet storage (aging old entries?) 313 // TODO: release the Bullet storage (aging old entries?)
306 hullDesc.lastReferenced = System.DateTime.Now; 314 hullDesc.lastReferenced = System.DateTime.Now;
307 Hulls[shape.shapeKey] = hullDesc; 315 Hulls[shape.shapeKey] = hullDesc;
308 DetailLog("{0},BSShapeColliction.DereferenceHull,key={1},cnt={2}", 316 DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}",
309 BSScene.DetailLogZero, shape.shapeKey, hullDesc.referenceCount); 317 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
310 } 318 }
311 } 319 }
312 320
@@ -322,8 +330,6 @@ public class BSShapeCollection : IDisposable
322 bool haveShape = false; 330 bool haveShape = false;
323 bool nativeShapePossible = true; 331 bool nativeShapePossible = true;
324 332
325 BulletShape newShape = new BulletShape(IntPtr.Zero);
326
327 // If the prim attributes are simple, this could be a simple Bullet native shape 333 // If the prim attributes are simple, this could be a simple Bullet native shape
328 if (nativeShapePossible 334 if (nativeShapePossible
329 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) 335 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
@@ -340,137 +346,117 @@ public class BSShapeCollection : IDisposable
340 haveShape = true; 346 haveShape = true;
341 if (forceRebuild || (prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE)) 347 if (forceRebuild || (prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE))
342 { 348 {
343 newShape = AddNativeShapeToPrim( 349 ret = GetReferenceToNativeShape(prim, shapeData,
344 prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE, ShapeData.FixedShapeKey.KEY_SPHERE); 350 ShapeData.PhysicsShapeType.SHAPE_SPHERE, ShapeData.FixedShapeKey.KEY_SPHERE);
345 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", 351 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
346 prim.LocalID, forceRebuild,prim.BSShape); 352 prim.LocalID, forceRebuild, prim.BSShape);
347
348 ret = true;
349 } 353 }
350 } 354 }
351 else 355 else
352 { 356 {
353 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size);
354 haveShape = true; 357 haveShape = true;
355 if (forceRebuild || (prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX)) 358 if (forceRebuild || (prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX))
356 { 359 {
357 newShape = AddNativeShapeToPrim( 360 ret = GetReferenceToNativeShape(
358 prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX, ShapeData.FixedShapeKey.KEY_BOX); 361 prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX, ShapeData.FixedShapeKey.KEY_BOX);
359 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", 362 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
360 prim.LocalID, forceRebuild,prim.BSShape); 363 prim.LocalID, forceRebuild, prim.BSShape);
361
362 ret = true;
363 } 364 }
364 } 365 }
365 } 366 }
366 // If a simple shape is not happening, create a mesh and possibly a hull 367 // If a simple shape is not happening, create a mesh and possibly a hull.
367 // Note that if it's a native shape, the check for physical/non-physical is not 368 // Note that if it's a native shape, the check for physical/non-physical is not
368 // made. Native shapes are best used in either case. 369 // made. Native shapes are best used in either case.
369 if (!haveShape) 370 if (!haveShape)
370 { 371 {
371 if (prim.IsPhysical) 372 if (prim.IsPhysical)
372 { 373 {
373 if (forceRebuild || !Hulls.ContainsKey(shapeData.HullKey)) 374 // Update prim.BSShape to reference a hull of this shape.
374 { 375 ret = GetReferenceToHull(prim, shapeData, pbs);
375 // physical objects require a hull for interaction. 376 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
376 // This also creates the mesh if it doesn't already exist. 377 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
377 ret = CreateGeomHull(prim, shapeData, pbs);
378 }
379 else
380 {
381 prim.BSShape = new BulletShape(Hulls[shapeData.HullKey].Ptr,
382 ShapeData.PhysicsShapeType.SHAPE_HULL);
383 prim.BSShape.shapeKey = shapeData.HullKey;
384 // Another user of this shape.
385 ReferenceShape(prim.BSShape);
386 ret = true;
387 }
388 } 378 }
389 else 379 else
390 { 380 {
391 if (forceRebuild || !Meshes.ContainsKey(prim.BSShape.shapeKey)) 381 ret = GetReferenceToMesh(prim, shapeData, pbs);
392 { 382 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
393 // Static (non-physical) objects only need a mesh for bumping into 383 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
394 // Returning 'true' means prim.BShape was changed.
395 ret = CreateGeomMesh(prim, shapeData, pbs);
396 }
397 else
398 {
399 prim.BSShape = new BulletShape(Hulls[shapeData.MeshKey].Ptr,
400 ShapeData.PhysicsShapeType.SHAPE_MESH);
401 prim.BSShape.shapeKey = shapeData.MeshKey;
402 ReferenceShape(prim.BSShape);
403 ret = true;
404 }
405 } 384 }
406 } 385 }
407 return ret; 386 return ret;
408 } 387 }
409 388
410 // Creates a native shape and assignes it to prim.BSShape 389 // Creates a native shape and assignes it to prim.BSShape
411 private BulletShape AddNativeShapeToPrim( 390 private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData,
412 BSPrim prim, ShapeData shapeData, ShapeData.PhysicsShapeType shapeType, 391 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey)
413 ShapeData.FixedShapeKey shapeKey)
414 { 392 {
415 BulletShape newShape; 393 BulletShape newShape;
416 394
395 shapeData.Type = shapeType;
417 // Bullet native objects are scaled by the Bullet engine so pass the size in 396 // Bullet native objects are scaled by the Bullet engine so pass the size in
418 prim.Scale = shapeData.Size; 397 prim.Scale = shapeData.Size;
419 shapeData.Type = shapeType; 398 shapeData.Scale = shapeData.Size;
420 shapeData.Scale = prim.Scale;
421 399
422 // release any previous shape 400 // release any previous shape
423 DereferenceShape(prim.BSShape, true); 401 DereferenceShape(prim.BSShape, true);
424 402
425 // Shape of this discriptioin is not allocated. Create new. 403 // Native shapes are always built independently.
426 newShape = new BulletShape( 404 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
427 BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
428 newShape.shapeKey = (ulong)shapeKey; 405 newShape.shapeKey = (ulong)shapeKey;
429 newShape.isNativeShape = true; 406 newShape.isNativeShape = true;
430 407
431 // Don't to a 'ReferenceShape()' here because native shapes are not tracked. 408 // Don't need to do a 'ReferenceShape()' here because native shapes are not tracked.
409 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape);
432 410
433 prim.BSShape = newShape; 411 prim.BSShape = newShape;
434 return newShape; 412 return true;
435 } 413 }
436 414
437 // Returns 'true' of a mesh was actually rebuild. 415 // Builds a mesh shape in the physical world and updates prim.BSShape.
416 // Dereferences previous shape in BSShape and adds a reference for this new shape.
417 // Returns 'true' of a mesh was actually built. Otherwise .
438 // Called at taint-time! 418 // Called at taint-time!
439 private bool CreateGeomMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs) 419 private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs)
440 { 420 {
441 BulletShape newShape = new BulletShape(IntPtr.Zero); 421 BulletShape newShape = new BulletShape(IntPtr.Zero);
442 422
443 // level of detail based on size and type of the object 423 float lod;
444 float lod = PhysicsScene.MeshLOD; 424 ulong newMeshKey = ComputeShapeKey(shapeData, pbs, out lod);
445 if (pbs.SculptEntry)
446 lod = PhysicsScene.SculptLOD;
447
448 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
449 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
450 lod = PhysicsScene.MeshMegaPrimLOD;
451
452 ulong newMeshKey = (ulong)pbs.GetMeshKey(shapeData.Size, lod);
453 425
454 // if this new shape is the same as last time, don't recreate the mesh 426 // if this new shape is the same as last time, don't recreate the mesh
455 if (prim.BSShape.shapeKey == newMeshKey) return false; 427 if (prim.BSShape.shapeKey == newMeshKey) return false;
456 428
457 DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,key={1}", prim.LocalID, newMeshKey); 429 DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}",
430 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
458 431
459 // Since we're recreating new, get rid of the reference to the previous shape 432 // Since we're recreating new, get rid of the reference to the previous shape
460 DereferenceShape(prim.BSShape, true); 433 DereferenceShape(prim.BSShape, true);
461 434
435 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
436
437 ReferenceShape(newShape);
438
439 // meshes are already scaled by the meshmerizer
440 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
441 prim.BSShape = newShape;
442
443 return true; // 'true' means a new shape has been added to this prim
444 }
445
446 private BulletShape CreatePhysicalMesh(string objName, ulong newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
447 {
462 IMesh meshData = null; 448 IMesh meshData = null;
463 IntPtr meshPtr; 449 IntPtr meshPtr;
464 MeshDesc meshDesc; 450 MeshDesc meshDesc;
465 if (Meshes.TryGetValue(newMeshKey, out meshDesc)) 451 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
466 { 452 {
467 // If the mesh has already been built just use it. 453 // If the mesh has already been built just use it.
468 meshPtr = meshDesc.Ptr; 454 meshPtr = meshDesc.ptr;
469 } 455 }
470 else 456 else
471 { 457 {
472 // always pass false for physicalness as this creates some sort of bounding box which we don't need 458 // Pass false for physicalness as this creates some sort of bounding box which we don't need
473 meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, shapeData.Size, lod, false); 459 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
474 460
475 int[] indices = meshData.getIndexListAsInt(); 461 int[] indices = meshData.getIndexListAsInt();
476 List<OMV.Vector3> vertices = meshData.getVertexList(); 462 List<OMV.Vector3> vertices = meshData.getVertexList();
@@ -490,56 +476,62 @@ public class BSShapeCollection : IDisposable
490 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 476 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
491 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 477 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
492 } 478 }
493 newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); 479 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
494 newShape.shapeKey = newMeshKey; 480 newShape.shapeKey = newMeshKey;
495 481
496 ReferenceShape(newShape, meshData); 482 return newShape;
497
498 // meshes are already scaled by the meshmerizer
499 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
500 prim.BSShape = newShape;
501 return true; // 'true' means a new shape has been added to this prim
502 } 483 }
503 484
504 // Returns 'true' of a mesh was actually rebuild (we could also have one of these specs). 485 // See that hull shape exists in the physical world and update prim.BSShape.
505 List<ConvexResult> m_hulls; 486 // We could be creating the hull because scale changed or whatever.
506 private bool CreateGeomHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs) 487 private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs)
507 { 488 {
508 BulletShape newShape; 489 BulletShape newShape;
509 490
510 // Level of detail for the mesh can be different for sculpties and regular meshes. 491 float lod;
511 float lod = pbs.SculptEntry ? PhysicsScene.SculptLOD : PhysicsScene.MeshLOD; 492 ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
512
513 ulong newHullKey = (ulong)pbs.GetMeshKey(shapeData.Size, lod);
514 493
515 // if the hull hasn't changed, don't rebuild it 494 // if the hull hasn't changed, don't rebuild it
516 if (newHullKey == prim.BSShape.shapeKey) return false; 495 if (newHullKey == prim.BSShape.shapeKey) return false;
517 496
518 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", prim.LocalID, newHullKey, newHullKey); 497 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
498 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
519 499
520 // Remove references to the previous shape. Also removes reference to underlying mesh. 500 // Remove usage of the previous shape. Also removes reference to underlying mesh if it is a hull.
521 DereferenceShape(prim.BSShape, true); 501 DereferenceShape(prim.BSShape, true);
522 502
523 // Do not let the mesh dereference itself again. Was done in the above DerefereceShape(). 503 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
524 prim.BSShape.type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; 504
525 505 if (!ReferenceShape(newShape))
526 // Make sure the underlying mesh exists and is correct. 506 {
527 // Since we're in the hull code, we know CreateGeomMesh() will not create a native shape. 507 PhysicsScene.Logger.ErrorFormat("{0} Created new hull shape but one already exists: id={1}, key={2}, refCnt={3}",
528 CreateGeomMesh(prim, shapeData, pbs); 508 LogHeader, shapeData.ID, newHullKey.ToString("X"), Hulls[newHullKey].referenceCount);
529 MeshDesc meshDesc = Meshes[newHullKey]; 509 }
510 // hulls are already scaled by the meshmerizer
511 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
512 prim.BSShape = newShape;
513 return true; // 'true' means a new shape has been added to this prim
514 }
515
516 List<ConvexResult> m_hulls;
517 private BulletShape CreatePhysicalHull(string objName, ulong newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
518 {
530 519
531 IntPtr hullPtr; 520 IntPtr hullPtr;
532 HullDesc hullDesc; 521 HullDesc hullDesc;
533 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 522 if (Hulls.TryGetValue(newHullKey, out hullDesc))
534 { 523 {
535 // If the hull shape already is created, just use it. 524 // If the hull shape already is created, just use it.
536 hullPtr = hullDesc.Ptr; 525 hullPtr = hullDesc.ptr;
537 } 526 }
538 else 527 else
539 { 528 {
540 // Build a new hull in the physical world 529 // Build a new hull in the physical world
541 int[] indices = meshDesc.meshData.getIndexListAsInt(); 530 // Pass false for physicalness as this creates some sort of bounding box which we don't need
542 List<OMV.Vector3> vertices = meshDesc.meshData.getVertexList(); 531 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
532
533 int[] indices = meshData.getIndexListAsInt();
534 List<OMV.Vector3> vertices = meshData.getVertexList();
543 535
544 //format conversion from IMesh format to DecompDesc format 536 //format conversion from IMesh format to DecompDesc format
545 List<int> convIndices = new List<int>(); 537 List<int> convIndices = new List<int>();
@@ -616,20 +608,13 @@ public class BSShapeCollection : IDisposable
616 } 608 }
617 } 609 }
618 // create the hull data structure in Bullet 610 // create the hull data structure in Bullet
619 // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, LocalID, _hullKey, hullCount);
620 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); 611 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
621 } 612 }
622 613
623 newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); 614 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
624 newShape.shapeKey = newHullKey; 615 newShape.shapeKey = newHullKey;
625 newShape.meshPtr = meshDesc.Ptr;
626
627 ReferenceShape(newShape);
628 616
629 // meshes and hulls are already scaled by the meshmerizer 617 return newShape; // 'true' means a new shape has been added to this prim
630 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
631 prim.BSShape = newShape;
632 return true; // 'true' means a new shape has been added to this prim
633 } 618 }
634 619
635 // Callback from convex hull creater with a newly created hull. 620 // Callback from convex hull creater with a newly created hull.
@@ -640,7 +625,30 @@ public class BSShapeCollection : IDisposable
640 return; 625 return;
641 } 626 }
642 627
643 // Create an object in Bullet if it has not already been created. 628 // Create a hash of all the shape parameters to be used as a key
629 // for this particular shape.
630 private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
631 {
632 // level of detail based on size and type of the object
633 float lod = PhysicsScene.MeshLOD;
634 if (pbs.SculptEntry)
635 lod = PhysicsScene.SculptLOD;
636
637 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
638 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
639 lod = PhysicsScene.MeshMegaPrimLOD;
640
641 retLod = lod;
642 return (ulong)pbs.GetMeshKey(shapeData.Size, lod);
643 }
644 // For those who don't want the LOD
645 private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
646 {
647 float lod;
648 return ComputeShapeKey(shapeData, pbs, out lod);
649 }
650
651 // Create a body object in Bullet.
644 // Updates prim.BSBody with the information about the new body if one is created. 652 // Updates prim.BSBody with the information about the new body if one is created.
645 // Returns 'true' if an object was actually created. 653 // Returns 'true' if an object was actually created.
646 // Called at taint-time. 654 // Called at taint-time.
@@ -665,7 +673,7 @@ public class BSShapeCollection : IDisposable
665 673
666 } 674 }
667 675
668 if (mustRebuild) 676 if (mustRebuild || forceRebuild)
669 { 677 {
670 DereferenceBody(prim.BSBody, true); 678 DereferenceBody(prim.BSBody, true);
671 679
@@ -673,13 +681,15 @@ public class BSShapeCollection : IDisposable
673 IntPtr bodyPtr = IntPtr.Zero; 681 IntPtr bodyPtr = IntPtr.Zero;
674 if (prim.IsSolid) 682 if (prim.IsSolid)
675 { 683 {
676 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, shapeData.Position, shapeData.Rotation); 684 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
677 DetailLog("{0},BSShapeCollection.CreateObject,mesh,ptr={1:X}", prim.LocalID, bodyPtr); 685 shapeData.ID, shapeData.Position, shapeData.Rotation);
686 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
678 } 687 }
679 else 688 else
680 { 689 {
681 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, shapeData.Position, shapeData.Rotation); 690 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
682 DetailLog("{0},BSShapeCollection.CreateObject,ghost,ptr={1:X}", prim.LocalID, bodyPtr); 691 shapeData.ID, shapeData.Position, shapeData.Rotation);
692 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
683 } 693 }
684 aBody = new BulletBody(shapeData.ID, bodyPtr); 694 aBody = new BulletBody(shapeData.ID, bodyPtr);
685 695