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.cs558
1 files changed, 334 insertions, 224 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 892c34b..220fbbc 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -45,7 +45,7 @@ public sealed class BSShapeCollection : IDisposable
45 // Description of a Mesh 45 // Description of a Mesh
46 private struct MeshDesc 46 private struct MeshDesc
47 { 47 {
48 public IntPtr ptr; 48 public BulletShape shape;
49 public int referenceCount; 49 public int referenceCount;
50 public DateTime lastReferenced; 50 public DateTime lastReferenced;
51 public UInt64 shapeKey; 51 public UInt64 shapeKey;
@@ -55,7 +55,7 @@ public sealed class BSShapeCollection : IDisposable
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. 55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc 56 private struct HullDesc
57 { 57 {
58 public IntPtr ptr; 58 public BulletShape shape;
59 public int referenceCount; 59 public int referenceCount;
60 public DateTime lastReferenced; 60 public DateTime lastReferenced;
61 public UInt64 shapeKey; 61 public UInt64 shapeKey;
@@ -65,9 +65,16 @@ public sealed class BSShapeCollection : IDisposable
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); 65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); 66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67 67
68 private bool DDetail = false;
69
68 public BSShapeCollection(BSScene physScene) 70 public BSShapeCollection(BSScene physScene)
69 { 71 {
70 PhysicsScene = physScene; 72 PhysicsScene = physScene;
73 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
74 // While detailed debugging is still active, this is better than commenting out all the
75 // DetailLog statements. When debugging slows down, this and the protected logging
76 // statements can be commented/removed.
77 DDetail = true;
71 } 78 }
72 79
73 public void Dispose() 80 public void Dispose()
@@ -91,7 +98,7 @@ public sealed class BSShapeCollection : IDisposable
91 // higher level dependencies on the shape or body. Mostly used for LinkSets to 98 // higher level dependencies on the shape or body. Mostly used for LinkSets to
92 // remove the physical constraints before the body is destroyed. 99 // remove the physical constraints before the body is destroyed.
93 // Called at taint-time!! 100 // Called at taint-time!!
94 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, 101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim,
95 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 102 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
96 { 103 {
97 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); 104 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
@@ -109,8 +116,7 @@ public sealed class BSShapeCollection : IDisposable
109 // rebuild the body around it. 116 // rebuild the body around it.
110 // Updates prim.BSBody with information/pointers to requested body 117 // Updates prim.BSBody with information/pointers to requested body
111 // Returns 'true' if BSBody was changed. 118 // Returns 'true' if BSBody was changed.
112 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, 119 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, bodyCallback);
113 prim.PhysShape, bodyCallback);
114 ret = newGeom || newBody; 120 ret = newGeom || newBody;
115 } 121 }
116 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", 122 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
@@ -119,51 +125,52 @@ public sealed class BSShapeCollection : IDisposable
119 return ret; 125 return ret;
120 } 126 }
121 127
128 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
129 {
130 return GetBodyAndShape(forceRebuild, sim, prim, null, null);
131 }
132
122 // Track another user of a body. 133 // Track another user of a body.
123 // We presume the caller has allocated the body. 134 // We presume the caller has allocated the body.
124 // Bodies only have one user so the body is just put into the world if not already there. 135 // Bodies only have one user so the body is just put into the world if not already there.
125 public void ReferenceBody(BulletBody body, bool inTaintTime) 136 private void ReferenceBody(BulletBody body)
126 { 137 {
127 lock (m_collectionActivityLock) 138 lock (m_collectionActivityLock)
128 { 139 {
129 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); 140 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
130 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() 141 if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
131 { 142 {
132 if (!BulletSimAPI.IsInWorld2(body.ptr)) 143 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
133 { 144 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
134 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 145 }
135 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
136 }
137 });
138 } 146 }
139 } 147 }
140 148
141 // Release the usage of a body. 149 // Release the usage of a body.
142 // Called when releasing use of a BSBody. BSShape is handled separately. 150 // Called when releasing use of a BSBody. BSShape is handled separately.
143 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) 151 // Called in taint time.
152 public void DereferenceBody(BulletBody body, BodyDestructionCallback bodyCallback )
144 { 153 {
145 if (body.ptr == IntPtr.Zero) 154 if (!body.HasPhysicalBody)
146 return; 155 return;
147 156
157 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
158
148 lock (m_collectionActivityLock) 159 lock (m_collectionActivityLock)
149 { 160 {
150 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() 161 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
151 { 162 // If the caller needs to know the old body is going away, pass the event up.
152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", 163 if (bodyCallback != null) bodyCallback(body);
153 body.ID, body, inTaintTime);
154 // If the caller needs to know the old body is going away, pass the event up.
155 if (bodyCallback != null) bodyCallback(body);
156 164
157 if (BulletSimAPI.IsInWorld2(body.ptr)) 165 if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
158 { 166 {
159 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); 167 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
160 DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); 168 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
161 } 169 }
162 170
163 // Zero any reference to the shape so it is not freed when the body is deleted. 171 // Zero any reference to the shape so it is not freed when the body is deleted.
164 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); 172 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
165 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); 173 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
166 });
167 } 174 }
168 } 175 }
169 176
@@ -184,17 +191,17 @@ public sealed class BSShapeCollection : IDisposable
184 { 191 {
185 // There is an existing instance of this mesh. 192 // There is an existing instance of this mesh.
186 meshDesc.referenceCount++; 193 meshDesc.referenceCount++;
187 DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", 194 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
188 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 195 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
189 } 196 }
190 else 197 else
191 { 198 {
192 // This is a new reference to a mesh 199 // This is a new reference to a mesh
193 meshDesc.ptr = shape.ptr; 200 meshDesc.shape = shape.Clone();
194 meshDesc.shapeKey = shape.shapeKey; 201 meshDesc.shapeKey = shape.shapeKey;
195 // We keep a reference to the underlying IMesh data so a hull can be built 202 // We keep a reference to the underlying IMesh data so a hull can be built
196 meshDesc.referenceCount = 1; 203 meshDesc.referenceCount = 1;
197 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", 204 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
198 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 205 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
199 ret = true; 206 ret = true;
200 } 207 }
@@ -207,16 +214,16 @@ public sealed class BSShapeCollection : IDisposable
207 { 214 {
208 // There is an existing instance of this hull. 215 // There is an existing instance of this hull.
209 hullDesc.referenceCount++; 216 hullDesc.referenceCount++;
210 DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", 217 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
211 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 218 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
212 } 219 }
213 else 220 else
214 { 221 {
215 // This is a new reference to a hull 222 // This is a new reference to a hull
216 hullDesc.ptr = shape.ptr; 223 hullDesc.shape = shape.Clone();
217 hullDesc.shapeKey = shape.shapeKey; 224 hullDesc.shapeKey = shape.shapeKey;
218 hullDesc.referenceCount = 1; 225 hullDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", 226 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 227 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
221 ret = true; 228 ret = true;
222 229
@@ -234,44 +241,43 @@ public sealed class BSShapeCollection : IDisposable
234 } 241 }
235 242
236 // Release the usage of a shape. 243 // Release the usage of a shape.
237 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) 244 public void DereferenceShape(BulletShape shape, ShapeDestructionCallback shapeCallback)
238 { 245 {
239 if (shape.ptr == IntPtr.Zero) 246 if (!shape.HasPhysicalShape)
240 return; 247 return;
241 248
242 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() 249 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceShape");
250
251 if (shape.HasPhysicalShape)
243 { 252 {
244 if (shape.ptr != IntPtr.Zero) 253 if (shape.isNativeShape)
245 { 254 {
246 if (shape.isNativeShape) 255 // Native shapes are not tracked and are released immediately
247 { 256 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1}",
248 // Native shapes are not tracked and are released immediately 257 BSScene.DetailLogZero, shape.AddrString);
249 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", 258 if (shapeCallback != null) shapeCallback(shape);
250 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); 259 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
251 if (shapeCallback != null) shapeCallback(shape); 260 }
252 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 261 else
253 } 262 {
254 else 263 switch (shape.type)
255 { 264 {
256 switch (shape.type) 265 case BSPhysicsShapeType.SHAPE_HULL:
257 { 266 DereferenceHull(shape, shapeCallback);
258 case BSPhysicsShapeType.SHAPE_HULL: 267 break;
259 DereferenceHull(shape, shapeCallback); 268 case BSPhysicsShapeType.SHAPE_MESH:
260 break; 269 DereferenceMesh(shape, shapeCallback);
261 case BSPhysicsShapeType.SHAPE_MESH: 270 break;
262 DereferenceMesh(shape, shapeCallback); 271 case BSPhysicsShapeType.SHAPE_COMPOUND:
263 break; 272 DereferenceCompound(shape, shapeCallback);
264 case BSPhysicsShapeType.SHAPE_COMPOUND: 273 break;
265 DereferenceCompound(shape, shapeCallback); 274 case BSPhysicsShapeType.SHAPE_UNKNOWN:
266 break; 275 break;
267 case BSPhysicsShapeType.SHAPE_UNKNOWN: 276 default:
268 break; 277 break;
269 default:
270 break;
271 }
272 } 278 }
273 } 279 }
274 }); 280 }
275 } 281 }
276 282
277 // Count down the reference count for a mesh shape 283 // Count down the reference count for a mesh shape
@@ -286,7 +292,7 @@ public sealed class BSShapeCollection : IDisposable
286 if (shapeCallback != null) shapeCallback(shape); 292 if (shapeCallback != null) shapeCallback(shape);
287 meshDesc.lastReferenced = System.DateTime.Now; 293 meshDesc.lastReferenced = System.DateTime.Now;
288 Meshes[shape.shapeKey] = meshDesc; 294 Meshes[shape.shapeKey] = meshDesc;
289 DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", 295 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
290 BSScene.DetailLogZero, shape, meshDesc.referenceCount); 296 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
291 297
292 } 298 }
@@ -307,7 +313,7 @@ public sealed class BSShapeCollection : IDisposable
307 313
308 hullDesc.lastReferenced = System.DateTime.Now; 314 hullDesc.lastReferenced = System.DateTime.Now;
309 Hulls[shape.shapeKey] = hullDesc; 315 Hulls[shape.shapeKey] = hullDesc;
310 DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", 316 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
311 BSScene.DetailLogZero, shape, hullDesc.referenceCount); 317 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
312 } 318 }
313 } 319 }
@@ -320,57 +326,56 @@ public sealed class BSShapeCollection : IDisposable
320 // Called at taint-time. 326 // Called at taint-time.
321 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) 327 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
322 { 328 {
323 if (!BulletSimAPI.IsCompound2(shape.ptr)) 329 if (!PhysicsScene.PE.IsCompound(shape))
324 { 330 {
325 // Failed the sanity check!! 331 // Failed the sanity check!!
326 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", 332 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
327 LogHeader, shape.type, shape.ptr.ToString("X")); 333 LogHeader, shape.type, shape.AddrString);
328 DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", 334 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
329 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); 335 BSScene.DetailLogZero, shape.type, shape.AddrString);
330 return; 336 return;
331 } 337 }
332 338
333 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); 339 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
334 DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); 340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
335 341
336 for (int ii = numChildren - 1; ii >= 0; ii--) 342 for (int ii = numChildren - 1; ii >= 0; ii--)
337 { 343 {
338 IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); 344 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
339 DereferenceAnonCollisionShape(childShape); 345 DereferenceAnonCollisionShape(childShape);
340 } 346 }
341 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 347 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
342 } 348 }
343 349
344 // Sometimes we have a pointer to a collision shape but don't know what type it is. 350 // Sometimes we have a pointer to a collision shape but don't know what type it is.
345 // Figure out type and call the correct dereference routine. 351 // Figure out type and call the correct dereference routine.
346 // Called at taint-time. 352 // Called at taint-time.
347 private void DereferenceAnonCollisionShape(IntPtr cShape) 353 private void DereferenceAnonCollisionShape(BulletShape shapeInfo)
348 { 354 {
349 MeshDesc meshDesc; 355 MeshDesc meshDesc;
350 HullDesc hullDesc; 356 HullDesc hullDesc;
351 357
352 BulletShape shapeInfo = new BulletShape(cShape); 358 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
353 if (TryGetMeshByPtr(cShape, out meshDesc))
354 { 359 {
355 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; 360 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
356 shapeInfo.shapeKey = meshDesc.shapeKey; 361 shapeInfo.shapeKey = meshDesc.shapeKey;
357 } 362 }
358 else 363 else
359 { 364 {
360 if (TryGetHullByPtr(cShape, out hullDesc)) 365 if (TryGetHullByPtr(shapeInfo, out hullDesc))
361 { 366 {
362 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; 367 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
363 shapeInfo.shapeKey = hullDesc.shapeKey; 368 shapeInfo.shapeKey = hullDesc.shapeKey;
364 } 369 }
365 else 370 else
366 { 371 {
367 if (BulletSimAPI.IsCompound2(cShape)) 372 if (PhysicsScene.PE.IsCompound(shapeInfo))
368 { 373 {
369 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; 374 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
370 } 375 }
371 else 376 else
372 { 377 {
373 if (BulletSimAPI.IsNativeShape2(cShape)) 378 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
374 { 379 {
375 shapeInfo.isNativeShape = true; 380 shapeInfo.isNativeShape = true;
376 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) 381 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
@@ -379,16 +384,16 @@ public sealed class BSShapeCollection : IDisposable
379 } 384 }
380 } 385 }
381 386
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); 387 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383 388
384 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) 389 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
385 { 390 {
386 DereferenceShape(shapeInfo, true, null); 391 DereferenceShape(shapeInfo, null);
387 } 392 }
388 else 393 else
389 { 394 {
390 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", 395 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
391 LogHeader, PhysicsScene.RegionName, cShape.ToString("X")); 396 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString);
392 } 397 }
393 } 398 }
394 399
@@ -408,19 +413,18 @@ public sealed class BSShapeCollection : IDisposable
408 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 413 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
409 { 414 {
410 // an avatar capsule is close to a native shape (it is not shared) 415 // an avatar capsule is close to a native shape (it is not shared)
411 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, 416 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback);
412 FixedShapeKey.KEY_CAPSULE, shapeCallback); 417 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
413 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
414 ret = true; 418 ret = true;
415 haveShape = true; 419 haveShape = true;
416 } 420 }
417 421
418 // Compound shapes are handled special as they are rebuilt from scratch. 422 // Compound shapes are handled special as they are rebuilt from scratch.
419 // This isn't too great a hardship since most of the child shapes will already been created. 423 // This isn't too great a hardship since most of the child shapes will have already been created.
420 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) 424 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
421 { 425 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback); 426 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); 427 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
424 haveShape = true; 428 haveShape = true;
425 } 429 }
426 430
@@ -432,8 +436,9 @@ public sealed class BSShapeCollection : IDisposable
432 return ret; 436 return ret;
433 } 437 }
434 438
435 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. 439 // Create a mesh, hull or native shape.
436 private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 440 // Return 'true' if the prim's shape was changed.
441 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
437 { 442 {
438 bool ret = false; 443 bool ret = false;
439 bool haveShape = false; 444 bool haveShape = false;
@@ -442,46 +447,48 @@ public sealed class BSShapeCollection : IDisposable
442 447
443 // If the prim attributes are simple, this could be a simple Bullet native shape 448 // If the prim attributes are simple, this could be a simple Bullet native shape
444 if (!haveShape 449 if (!haveShape
445 && pbs != null
446 && nativeShapePossible 450 && nativeShapePossible
447 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) 451 && pbs != null
448 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 452 && !pbs.SculptEntry
449 && pbs.ProfileHollow == 0 453 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) )
450 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 454 {
451 && pbs.PathBegin == 0 && pbs.PathEnd == 0 455 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
452 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 456 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
453 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 457 if (prim.PhysShape.HasPhysicalShape)
454 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 458 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape);
455 { 459
456 // It doesn't look like Bullet scales spheres so make sure the scales are all equal 460 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
461 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
462
463 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
457 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 464 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
458 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) 465 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
459 { 466 {
460 haveShape = true; 467 haveShape = true;
461 if (forceRebuild 468 if (forceRebuild
462 || prim.Scale != prim.Size 469 || prim.Scale != scaleOfExistingShape
463 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 470 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
464 ) 471 )
465 { 472 {
466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 473 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
467 FixedShapeKey.KEY_SPHERE, shapeCallback); 474 FixedShapeKey.KEY_SPHERE, shapeCallback);
468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
469 prim.LocalID, forceRebuild, prim.PhysShape);
470 } 475 }
476 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
477 prim.LocalID, forceRebuild, ret, prim.PhysShape);
471 } 478 }
472 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 479 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
473 { 480 {
474 haveShape = true; 481 haveShape = true;
475 if (forceRebuild 482 if (forceRebuild
476 || prim.Scale != prim.Size 483 || prim.Scale != scaleOfExistingShape
477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 484 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
478 ) 485 )
479 { 486 {
480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 487 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
481 FixedShapeKey.KEY_BOX, shapeCallback); 488 FixedShapeKey.KEY_BOX, shapeCallback);
482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
483 prim.LocalID, forceRebuild, prim.PhysShape);
484 } 489 }
490 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
491 prim.LocalID, forceRebuild, ret, prim.PhysShape);
485 } 492 }
486 } 493 }
487 494
@@ -494,23 +501,36 @@ public sealed class BSShapeCollection : IDisposable
494 return ret; 501 return ret;
495 } 502 }
496 503
504 // return 'true' if this shape description does not include any cutting or twisting.
505 private bool PrimHasNoCuts(PrimitiveBaseShape pbs)
506 {
507 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
508 && pbs.ProfileHollow == 0
509 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
510 && pbs.PathBegin == 0 && pbs.PathEnd == 0
511 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
512 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
513 && pbs.PathShearX == 0 && pbs.PathShearY == 0;
514 }
515
516 // return 'true' if the prim's shape was changed.
497 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 517 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
498 { 518 {
499 519
500 bool ret = false; 520 bool ret = false;
501 // Note that if it's a native shape, the check for physical/non-physical is not 521 // Note that if it's a native shape, the check for physical/non-physical is not
502 // made. Native shapes work in either case. 522 // made. Native shapes work in either case.
503 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 523 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
504 { 524 {
505 // Update prim.BSShape to reference a hull of this shape. 525 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback); 526 ret = GetReferenceToHull(prim, shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 527 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 528 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 } 529 }
510 else 530 else
511 { 531 {
512 ret = GetReferenceToMesh(prim, shapeCallback); 532 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 533 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 534 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
515 } 535 }
516 return ret; 536 return ret;
@@ -523,14 +543,15 @@ public sealed class BSShapeCollection : IDisposable
523 ShapeDestructionCallback shapeCallback) 543 ShapeDestructionCallback shapeCallback)
524 { 544 {
525 // release any previous shape 545 // release any previous shape
526 DereferenceShape(prim.PhysShape, true, shapeCallback); 546 DereferenceShape(prim.PhysShape, shapeCallback);
527 547
528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); 548 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
529 549
530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 550 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
531 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 551 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
532 prim.LocalID, newShape, prim.Scale); 552 prim.LocalID, newShape, prim.Scale);
533 553
554 // native shapes are scaled by Bullet
534 prim.PhysShape = newShape; 555 prim.PhysShape = newShape;
535 return true; 556 return true;
536 } 557 }
@@ -550,20 +571,17 @@ public sealed class BSShapeCollection : IDisposable
550 571
551 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 572 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
552 { 573 {
553 // The proper scale has been calculated in the prim. 574
554 newShape = new BulletShape( 575 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale);
555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) 576 if (DDetail) DetailLog("{0},BSShapeCollection.BuildPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
556 , shapeType);
557 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
558 } 577 }
559 else 578 else
560 { 579 {
561 // Native shapes are scaled in Bullet so set the scaling to the size 580 // Native shapes are scaled in Bullet so set the scaling to the size
562 prim.Scale = prim.Size; 581 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData);
563 nativeShapeData.Scale = prim.Scale; 582
564 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
565 } 583 }
566 if (newShape.ptr == IntPtr.Zero) 584 if (!newShape.HasPhysicalShape)
567 { 585 {
568 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 586 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
569 LogHeader, prim.LocalID, shapeType); 587 LogHeader, prim.LocalID, shapeType);
@@ -580,7 +598,7 @@ public sealed class BSShapeCollection : IDisposable
580 // Called at taint-time! 598 // Called at taint-time!
581 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 599 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
582 { 600 {
583 BulletShape newShape = new BulletShape(IntPtr.Zero); 601 BulletShape newShape = new BulletShape();
584 602
585 float lod; 603 float lod;
586 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 604 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
@@ -589,62 +607,96 @@ public sealed class BSShapeCollection : IDisposable
589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) 607 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
590 return false; 608 return false;
591 609
592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", 610 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2},size={3},lod={4}",
593 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); 611 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod);
594 612
595 // Since we're recreating new, get rid of the reference to the previous shape 613 // Since we're recreating new, get rid of the reference to the previous shape
596 DereferenceShape(prim.PhysShape, true, shapeCallback); 614 DereferenceShape(prim.PhysShape, shapeCallback);
597 615
598 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); 616 newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod);
599 // Take evasive action if the mesh was not constructed. 617 // Take evasive action if the mesh was not constructed.
600 newShape = VerifyMeshCreated(newShape, prim); 618 newShape = VerifyMeshCreated(newShape, prim);
601 619
602 ReferenceShape(newShape); 620 ReferenceShape(newShape);
603 621
604 // meshes are already scaled by the meshmerizer
605 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
606 prim.PhysShape = newShape; 622 prim.PhysShape = newShape;
607 623
608 return true; // 'true' means a new shape has been added to this prim 624 return true; // 'true' means a new shape has been added to this prim
609 } 625 }
610 626
611 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 627 private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
612 { 628 {
613 IMesh meshData = null; 629 BulletShape newShape = new BulletShape();
614 IntPtr meshPtr = IntPtr.Zero; 630
615 MeshDesc meshDesc; 631 MeshDesc meshDesc;
616 if (Meshes.TryGetValue(newMeshKey, out meshDesc)) 632 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
617 { 633 {
618 // If the mesh has already been built just use it. 634 // If the mesh has already been built just use it.
619 meshPtr = meshDesc.ptr; 635 newShape = meshDesc.shape.Clone();
620 } 636 }
621 else 637 else
622 { 638 {
623 // Pass false for physicalness as this creates some sort of bounding box which we don't need 639 IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
624 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 640 true,
641 false, // say it is not physical so a bounding box is not built
642 false, // do not cache the mesh and do not use previously built versions
643 false // It's NOT for ODE
644 );
625 645
626 if (meshData != null) 646 if (meshData != null)
627 { 647 {
648
628 int[] indices = meshData.getIndexListAsInt(); 649 int[] indices = meshData.getIndexListAsInt();
629 List<OMV.Vector3> vertices = meshData.getVertexList(); 650 int realIndicesIndex = indices.Length;
651 float[] verticesAsFloats = meshData.getVertexListAsFloat();
630 652
631 float[] verticesAsFloats = new float[vertices.Count * 3]; 653 if (BSParam.ShouldRemoveZeroWidthTriangles)
632 int vi = 0;
633 foreach (OMV.Vector3 vv in vertices)
634 { 654 {
635 verticesAsFloats[vi++] = vv.X; 655 // Remove degenerate triangles. These are triangles with two of the vertices
636 verticesAsFloats[vi++] = vv.Y; 656 // are the same. This is complicated by the problem that vertices are not
637 verticesAsFloats[vi++] = vv.Z; 657 // made unique in sculpties so we have to compare the values in the vertex.
658 realIndicesIndex = 0;
659 for (int tri = 0; tri < indices.Length; tri += 3)
660 {
661 // Compute displacements into vertex array for each vertex of the triangle
662 int v1 = indices[tri + 0] * 3;
663 int v2 = indices[tri + 1] * 3;
664 int v3 = indices[tri + 2] * 3;
665 // Check to see if any two of the vertices are the same
666 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
667 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
668 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
669 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
670 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
671 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
672 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
673 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
674 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
675 )
676 {
677 // None of the vertices of the triangles are the same. This is a good triangle;
678 indices[realIndicesIndex + 0] = indices[tri + 0];
679 indices[realIndicesIndex + 1] = indices[tri + 1];
680 indices[realIndicesIndex + 2] = indices[tri + 2];
681 realIndicesIndex += 3;
682 }
683 }
638 } 684 }
685 DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}",
686 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
639 687
640 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 688 if (realIndicesIndex != 0)
641 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 689 {
642 690 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
643 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 691 realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
644 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 692 }
693 else
694 {
695 PhysicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
696 LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name);
697 }
645 } 698 }
646 } 699 }
647 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
648 newShape.shapeKey = newMeshKey; 700 newShape.shapeKey = newMeshKey;
649 701
650 return newShape; 702 return newShape;
@@ -652,6 +704,7 @@ public sealed class BSShapeCollection : IDisposable
652 704
653 // See that hull shape exists in the physical world and update prim.BSShape. 705 // See that hull shape exists in the physical world and update prim.BSShape.
654 // We could be creating the hull because scale changed or whatever. 706 // We could be creating the hull because scale changed or whatever.
707 // Return 'true' if a new hull was built. Otherwise, returning a shared hull instance.
655 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 708 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
656 { 709 {
657 BulletShape newShape; 710 BulletShape newShape;
@@ -663,19 +716,18 @@ public sealed class BSShapeCollection : IDisposable
663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) 716 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
664 return false; 717 return false;
665 718
666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", 719 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
667 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 720 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
668 721
669 // Remove usage of the previous shape. 722 // Remove usage of the previous shape.
670 DereferenceShape(prim.PhysShape, true, shapeCallback); 723 DereferenceShape(prim.PhysShape, shapeCallback);
671 724
672 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); 725 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
726 // It might not have been created if we're waiting for an asset.
673 newShape = VerifyMeshCreated(newShape, prim); 727 newShape = VerifyMeshCreated(newShape, prim);
674 728
675 ReferenceShape(newShape); 729 ReferenceShape(newShape);
676 730
677 // hulls are already scaled by the meshmerizer
678 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
679 prim.PhysShape = newShape; 731 prim.PhysShape = newShape;
680 return true; // 'true' means a new shape has been added to this prim 732 return true; // 'true' means a new shape has been added to this prim
681 } 733 }
@@ -684,18 +736,20 @@ public sealed class BSShapeCollection : IDisposable
684 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 736 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
685 { 737 {
686 738
739 BulletShape newShape = new BulletShape();
687 IntPtr hullPtr = IntPtr.Zero; 740 IntPtr hullPtr = IntPtr.Zero;
741
688 HullDesc hullDesc; 742 HullDesc hullDesc;
689 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 743 if (Hulls.TryGetValue(newHullKey, out hullDesc))
690 { 744 {
691 // If the hull shape already is created, just use it. 745 // If the hull shape already has been created, just use the one shared instance.
692 hullPtr = hullDesc.ptr; 746 newShape = hullDesc.shape.Clone();
693 } 747 }
694 else 748 else
695 { 749 {
696 // Build a new hull in the physical world 750 // Build a new hull in the physical world.
697 // Pass false for physicalness as this creates some sort of bounding box which we don't need 751 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
698 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 752 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
699 if (meshData != null) 753 if (meshData != null)
700 { 754 {
701 755
@@ -714,15 +768,35 @@ public sealed class BSShapeCollection : IDisposable
714 convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); 768 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
715 } 769 }
716 770
771 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
772 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
773 {
774 // Simple primitive shapes we know are convex so they are better implemented with
775 // fewer hulls.
776 // Check for simple shape (prim without cuts) and reduce split parameter if so.
777 if (PrimHasNoCuts(pbs))
778 {
779 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
780 }
781 }
782
717 // setup and do convex hull conversion 783 // setup and do convex hull conversion
718 m_hulls = new List<ConvexResult>(); 784 m_hulls = new List<ConvexResult>();
719 DecompDesc dcomp = new DecompDesc(); 785 DecompDesc dcomp = new DecompDesc();
720 dcomp.mIndices = convIndices; 786 dcomp.mIndices = convIndices;
721 dcomp.mVertices = convVertices; 787 dcomp.mVertices = convVertices;
788 dcomp.mDepth = maxDepthSplit;
789 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
790 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
791 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
792 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
722 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); 793 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
723 // create the hull into the _hulls variable 794 // create the hull into the _hulls variable
724 convexBuilder.process(dcomp); 795 convexBuilder.process(dcomp);
725 796
797 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
798 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
799
726 // Convert the vertices and indices for passing to unmanaged. 800 // Convert the vertices and indices for passing to unmanaged.
727 // The hull information is passed as a large floating point array. 801 // The hull information is passed as a large floating point array.
728 // The format is: 802 // The format is:
@@ -777,14 +851,13 @@ public sealed class BSShapeCollection : IDisposable
777 } 851 }
778 } 852 }
779 // create the hull data structure in Bullet 853 // create the hull data structure in Bullet
780 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); 854 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
781 } 855 }
782 } 856 }
783 857
784 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
785 newShape.shapeKey = newHullKey; 858 newShape.shapeKey = newHullKey;
786 859
787 return newShape; // 'true' means a new shape has been added to this prim 860 return newShape;
788 } 861 }
789 862
790 // Callback from convex hull creater with a newly created hull. 863 // Callback from convex hull creater with a newly created hull.
@@ -803,13 +876,12 @@ public sealed class BSShapeCollection : IDisposable
803 // Don't need to do this as the shape is freed when the new root shape is created below. 876 // Don't need to do this as the shape is freed when the new root shape is created below.
804 // DereferenceShape(prim.PhysShape, true, shapeCallback); 877 // DereferenceShape(prim.PhysShape, true, shapeCallback);
805 878
806 BulletShape cShape = new BulletShape( 879 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false);
807 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND);
808 880
809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. 881 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
810 CreateGeomMeshOrHull(prim, shapeCallback); 882 CreateGeomMeshOrHull(prim, shapeCallback);
811 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); 883 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
812 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", 884 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
813 prim.LocalID, cShape, prim.PhysShape); 885 prim.LocalID, cShape, prim.PhysShape);
814 886
815 prim.PhysShape = cShape; 887 prim.PhysShape = cShape;
@@ -822,14 +894,19 @@ public sealed class BSShapeCollection : IDisposable
822 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) 894 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
823 { 895 {
824 // level of detail based on size and type of the object 896 // level of detail based on size and type of the object
825 float lod = PhysicsScene.MeshLOD; 897 float lod = BSParam.MeshLOD;
898
899 // prims with curvy internal cuts need higher lod
900 if (pbs.HollowShape == HollowShape.Circle)
901 lod = BSParam.MeshCircularLOD;
902
826 if (pbs.SculptEntry) 903 if (pbs.SculptEntry)
827 lod = PhysicsScene.SculptLOD; 904 lod = BSParam.SculptLOD;
828 905
829 // Mega prims usually get more detail because one can interact with shape approximations at this size. 906 // Mega prims usually get more detail because one can interact with shape approximations at this size.
830 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); 907 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
831 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) 908 if (maxAxis > BSParam.MeshMegaPrimThreshold)
832 lod = PhysicsScene.MeshMegaPrimLOD; 909 lod = BSParam.MeshMegaPrimLOD;
833 910
834 retLod = lod; 911 retLod = lod;
835 return pbs.GetMeshKey(size, lod); 912 return pbs.GetMeshKey(size, lod);
@@ -851,51 +928,88 @@ public sealed class BSShapeCollection : IDisposable
851 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) 928 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
852 { 929 {
853 // If the shape was successfully created, nothing more to do 930 // If the shape was successfully created, nothing more to do
854 if (newShape.ptr != IntPtr.Zero) 931 if (newShape.HasPhysicalShape)
855 return newShape; 932 return newShape;
856 933
857 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 934 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
858 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) 935 // fetched but we end up here again, the meshing of the asset must have failed.
936 // Prevent trying to keep fetching the mesh by declaring failure.
937 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
859 { 938 {
860 prim.LastAssetBuildFailed = true; 939 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
861 BSPhysObject xprim = prim; 940 PhysicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
862 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", 941 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
863 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
864 Util.FireAndForget(delegate
865 {
866 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
867 if (assetProvider != null)
868 {
869 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
870 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
871 {
872 if (!yprim.BaseShape.SculptEntry)
873 return;
874 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
875 return;
876
877 yprim.BaseShape.SculptData = asset.Data;
878 // This will cause the prim to see that the filler shape is not the right
879 // one and try again to build the object.
880 // No race condition with the normal shape setting since the rebuild is at taint time.
881 yprim.ForceBodyShapeRebuild(false);
882
883 });
884 }
885 });
886 } 942 }
887 else 943 else
888 { 944 {
889 if (prim.LastAssetBuildFailed) 945 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
946 if (prim.BaseShape.SculptEntry
947 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
948 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
949 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
950 )
890 { 951 {
891 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", 952 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
892 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); 953 // Multiple requestors will know we're waiting for this asset
954 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
955
956 BSPhysObject xprim = prim;
957 Util.FireAndForget(delegate
958 {
959 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
960 if (assetProvider != null)
961 {
962 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
963 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
964 {
965 bool assetFound = false;
966 string mismatchIDs = String.Empty; // DEBUG DEBUG
967 if (asset != null && yprim.BaseShape.SculptEntry)
968 {
969 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
970 {
971 yprim.BaseShape.SculptData = asset.Data;
972 // This will cause the prim to see that the filler shape is not the right
973 // one and try again to build the object.
974 // No race condition with the normal shape setting since the rebuild is at taint time.
975 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
976 assetFound = true;
977 }
978 else
979 {
980 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
981 }
982 }
983 if (assetFound)
984 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
985 else
986 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
987 DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
988 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
989
990 });
991 }
992 else
993 {
994 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
995 PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
996 LogHeader, PhysicsScene.Name);
997 }
998 });
999 }
1000 else
1001 {
1002 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
1003 {
1004 PhysicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
1005 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
1006 }
893 } 1007 }
894 } 1008 }
895 1009
896 // While we figure out the real problem, stick a simple native shape on the object. 1010 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
897 BulletShape fillinShape = 1011 BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
898 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); 1012 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID);
899 1013
900 return fillinShape; 1014 return fillinShape;
901 } 1015 }
@@ -904,49 +1018,45 @@ public sealed class BSShapeCollection : IDisposable
904 // Updates prim.BSBody with the information about the new body if one is created. 1018 // Updates prim.BSBody with the information about the new body if one is created.
905 // Returns 'true' if an object was actually created. 1019 // Returns 'true' if an object was actually created.
906 // Called at taint-time. 1020 // Called at taint-time.
907 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, 1021 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BodyDestructionCallback bodyCallback)
908 BodyDestructionCallback bodyCallback)
909 { 1022 {
910 bool ret = false; 1023 bool ret = false;
911 1024
912 // the mesh, hull or native shape must have already been created in Bullet 1025 // the mesh, hull or native shape must have already been created in Bullet
913 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); 1026 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
914 1027
915 // If there is an existing body, verify it's of an acceptable type. 1028 // If there is an existing body, verify it's of an acceptable type.
916 // If not a solid object, body is a GhostObject. Otherwise a RigidBody. 1029 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
917 if (!mustRebuild) 1030 if (!mustRebuild)
918 { 1031 {
919 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); 1032 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody);
920 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 1033 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
921 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 1034 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
922 { 1035 {
923 // If the collisionObject is not the correct type for solidness, rebuild what's there 1036 // If the collisionObject is not the correct type for solidness, rebuild what's there
924 mustRebuild = true; 1037 mustRebuild = true;
1038 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType);
925 } 1039 }
926 } 1040 }
927 1041
928 if (mustRebuild || forceRebuild) 1042 if (mustRebuild || forceRebuild)
929 { 1043 {
930 // Free any old body 1044 // Free any old body
931 DereferenceBody(prim.PhysBody, true, bodyCallback); 1045 DereferenceBody(prim.PhysBody, bodyCallback);
932 1046
933 BulletBody aBody; 1047 BulletBody aBody;
934 IntPtr bodyPtr = IntPtr.Zero;
935 if (prim.IsSolid) 1048 if (prim.IsSolid)
936 { 1049 {
937 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 1050 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
938 prim.LocalID, prim.RawPosition, prim.RawOrientation); 1051 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody);
939 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
940 } 1052 }
941 else 1053 else
942 { 1054 {
943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 1055 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
944 prim.LocalID, prim.RawPosition, prim.RawOrientation); 1056 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
945 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
946 } 1057 }
947 aBody = new BulletBody(prim.LocalID, bodyPtr);
948 1058
949 ReferenceBody(aBody, true); 1059 ReferenceBody(aBody);
950 1060
951 prim.PhysBody = aBody; 1061 prim.PhysBody = aBody;
952 1062
@@ -956,13 +1066,13 @@ public sealed class BSShapeCollection : IDisposable
956 return ret; 1066 return ret;
957 } 1067 }
958 1068
959 private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc) 1069 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
960 { 1070 {
961 bool ret = false; 1071 bool ret = false;
962 MeshDesc foundDesc = new MeshDesc(); 1072 MeshDesc foundDesc = new MeshDesc();
963 foreach (MeshDesc md in Meshes.Values) 1073 foreach (MeshDesc md in Meshes.Values)
964 { 1074 {
965 if (md.ptr == addr) 1075 if (md.shape.ReferenceSame(shape))
966 { 1076 {
967 foundDesc = md; 1077 foundDesc = md;
968 ret = true; 1078 ret = true;
@@ -974,13 +1084,13 @@ public sealed class BSShapeCollection : IDisposable
974 return ret; 1084 return ret;
975 } 1085 }
976 1086
977 private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc) 1087 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
978 { 1088 {
979 bool ret = false; 1089 bool ret = false;
980 HullDesc foundDesc = new HullDesc(); 1090 HullDesc foundDesc = new HullDesc();
981 foreach (HullDesc hd in Hulls.Values) 1091 foreach (HullDesc hd in Hulls.Values)
982 { 1092 {
983 if (hd.ptr == addr) 1093 if (hd.shape.ReferenceSame(shape))
984 { 1094 {
985 foundDesc = hd; 1095 foundDesc = hd;
986 ret = true; 1096 ret = true;