diff options
Diffstat (limited to '')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | 296 |
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 | { |
37 | public class BSShapeCollection : IDisposable | 37 | public 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 | ||