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.cs448
1 files changed, 255 insertions, 193 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 892c34b..096b300 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;
@@ -443,8 +448,9 @@ public sealed class BSShapeCollection : IDisposable
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 450 && pbs != null
451 && !pbs.SculptEntry
446 && nativeShapePossible 452 && nativeShapePossible
447 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) 453 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
448 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 454 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
449 && pbs.ProfileHollow == 0 455 && pbs.ProfileHollow == 0
450 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 456 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
@@ -453,35 +459,43 @@ public sealed class BSShapeCollection : IDisposable
453 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 459 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
454 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 460 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
455 { 461 {
456 // It doesn't look like Bullet scales spheres so make sure the scales are all equal 462 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
463 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
464 if (prim.PhysShape.HasPhysicalShape)
465 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape);
466
467 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
468 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
469
470 // 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) 471 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
458 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) 472 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
459 { 473 {
460 haveShape = true; 474 haveShape = true;
461 if (forceRebuild 475 if (forceRebuild
462 || prim.Scale != prim.Size 476 || prim.Scale != scaleOfExistingShape
463 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
464 ) 478 )
465 { 479 {
466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 480 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
467 FixedShapeKey.KEY_SPHERE, shapeCallback); 481 FixedShapeKey.KEY_SPHERE, shapeCallback);
468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
469 prim.LocalID, forceRebuild, prim.PhysShape);
470 } 482 }
483 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
484 prim.LocalID, forceRebuild, ret, prim.PhysShape);
471 } 485 }
472 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 486 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
473 { 487 {
474 haveShape = true; 488 haveShape = true;
475 if (forceRebuild 489 if (forceRebuild
476 || prim.Scale != prim.Size 490 || prim.Scale != scaleOfExistingShape
477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 491 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
478 ) 492 )
479 { 493 {
480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 494 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
481 FixedShapeKey.KEY_BOX, shapeCallback); 495 FixedShapeKey.KEY_BOX, shapeCallback);
482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
483 prim.LocalID, forceRebuild, prim.PhysShape);
484 } 496 }
497 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
498 prim.LocalID, forceRebuild, ret, prim.PhysShape);
485 } 499 }
486 } 500 }
487 501
@@ -494,23 +508,24 @@ public sealed class BSShapeCollection : IDisposable
494 return ret; 508 return ret;
495 } 509 }
496 510
511 // return 'true' if the prim's shape was changed.
497 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 512 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
498 { 513 {
499 514
500 bool ret = false; 515 bool ret = false;
501 // Note that if it's a native shape, the check for physical/non-physical is not 516 // Note that if it's a native shape, the check for physical/non-physical is not
502 // made. Native shapes work in either case. 517 // made. Native shapes work in either case.
503 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 518 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
504 { 519 {
505 // Update prim.BSShape to reference a hull of this shape. 520 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback); 521 ret = GetReferenceToHull(prim,shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 522 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 523 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 } 524 }
510 else 525 else
511 { 526 {
512 ret = GetReferenceToMesh(prim, shapeCallback); 527 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 528 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 529 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
515 } 530 }
516 return ret; 531 return ret;
@@ -523,14 +538,15 @@ public sealed class BSShapeCollection : IDisposable
523 ShapeDestructionCallback shapeCallback) 538 ShapeDestructionCallback shapeCallback)
524 { 539 {
525 // release any previous shape 540 // release any previous shape
526 DereferenceShape(prim.PhysShape, true, shapeCallback); 541 DereferenceShape(prim.PhysShape, shapeCallback);
527 542
528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); 543 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
529 544
530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 545 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
531 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 546 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
532 prim.LocalID, newShape, prim.Scale); 547 prim.LocalID, newShape, prim.Scale);
533 548
549 // native shapes are scaled by Bullet
534 prim.PhysShape = newShape; 550 prim.PhysShape = newShape;
535 return true; 551 return true;
536 } 552 }
@@ -550,20 +566,17 @@ public sealed class BSShapeCollection : IDisposable
550 566
551 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 567 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
552 { 568 {
553 // The proper scale has been calculated in the prim. 569
554 newShape = new BulletShape( 570 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale);
555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) 571 if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
556 , shapeType);
557 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
558 } 572 }
559 else 573 else
560 { 574 {
561 // Native shapes are scaled in Bullet so set the scaling to the size 575 // Native shapes are scaled in Bullet so set the scaling to the size
562 prim.Scale = prim.Size; 576 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData);
563 nativeShapeData.Scale = prim.Scale; 577
564 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
565 } 578 }
566 if (newShape.ptr == IntPtr.Zero) 579 if (!newShape.HasPhysicalShape)
567 { 580 {
568 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 581 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
569 LogHeader, prim.LocalID, shapeType); 582 LogHeader, prim.LocalID, shapeType);
@@ -580,7 +593,7 @@ public sealed class BSShapeCollection : IDisposable
580 // Called at taint-time! 593 // Called at taint-time!
581 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 594 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
582 { 595 {
583 BulletShape newShape = new BulletShape(IntPtr.Zero); 596 BulletShape newShape = new BulletShape();
584 597
585 float lod; 598 float lod;
586 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 599 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
@@ -589,62 +602,96 @@ public sealed class BSShapeCollection : IDisposable
589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) 602 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
590 return false; 603 return false;
591 604
592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", 605 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")); 606 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod);
594 607
595 // Since we're recreating new, get rid of the reference to the previous shape 608 // Since we're recreating new, get rid of the reference to the previous shape
596 DereferenceShape(prim.PhysShape, true, shapeCallback); 609 DereferenceShape(prim.PhysShape, shapeCallback);
597 610
598 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); 611 newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod);
599 // Take evasive action if the mesh was not constructed. 612 // Take evasive action if the mesh was not constructed.
600 newShape = VerifyMeshCreated(newShape, prim); 613 newShape = VerifyMeshCreated(newShape, prim);
601 614
602 ReferenceShape(newShape); 615 ReferenceShape(newShape);
603 616
604 // meshes are already scaled by the meshmerizer
605 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
606 prim.PhysShape = newShape; 617 prim.PhysShape = newShape;
607 618
608 return true; // 'true' means a new shape has been added to this prim 619 return true; // 'true' means a new shape has been added to this prim
609 } 620 }
610 621
611 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 622 private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
612 { 623 {
613 IMesh meshData = null; 624 BulletShape newShape = new BulletShape();
614 IntPtr meshPtr = IntPtr.Zero; 625
615 MeshDesc meshDesc; 626 MeshDesc meshDesc;
616 if (Meshes.TryGetValue(newMeshKey, out meshDesc)) 627 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
617 { 628 {
618 // If the mesh has already been built just use it. 629 // If the mesh has already been built just use it.
619 meshPtr = meshDesc.ptr; 630 newShape = meshDesc.shape.Clone();
620 } 631 }
621 else 632 else
622 { 633 {
623 // Pass false for physicalness as this creates some sort of bounding box which we don't need 634 IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
624 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 635 true,
636 false, // say it is not physical so a bounding box is not built
637 false, // do not cache the mesh and do not use previously built versions
638 false // It's NOT for ODE
639 );
625 640
626 if (meshData != null) 641 if (meshData != null)
627 { 642 {
643
628 int[] indices = meshData.getIndexListAsInt(); 644 int[] indices = meshData.getIndexListAsInt();
629 List<OMV.Vector3> vertices = meshData.getVertexList(); 645 int realIndicesIndex = indices.Length;
646 float[] verticesAsFloats = meshData.getVertexListAsFloat();
630 647
631 float[] verticesAsFloats = new float[vertices.Count * 3]; 648 if (BSParam.ShouldRemoveZeroWidthTriangles)
632 int vi = 0;
633 foreach (OMV.Vector3 vv in vertices)
634 { 649 {
635 verticesAsFloats[vi++] = vv.X; 650 // Remove degenerate triangles. These are triangles with two of the vertices
636 verticesAsFloats[vi++] = vv.Y; 651 // are the same. This is complicated by the problem that vertices are not
637 verticesAsFloats[vi++] = vv.Z; 652 // made unique in sculpties so we have to compare the values in the vertex.
653 realIndicesIndex = 0;
654 for (int tri = 0; tri < indices.Length; tri += 3)
655 {
656 // Compute displacements into vertex array for each vertex of the triangle
657 int v1 = indices[tri + 0] * 3;
658 int v2 = indices[tri + 1] * 3;
659 int v3 = indices[tri + 2] * 3;
660 // Check to see if any two of the vertices are the same
661 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
662 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
663 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
664 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
665 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
666 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
667 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
668 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
669 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
670 )
671 {
672 // None of the vertices of the triangles are the same. This is a good triangle;
673 indices[realIndicesIndex + 0] = indices[tri + 0];
674 indices[realIndicesIndex + 1] = indices[tri + 1];
675 indices[realIndicesIndex + 2] = indices[tri + 2];
676 realIndicesIndex += 3;
677 }
678 }
638 } 679 }
680 DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}",
681 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
639 682
640 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 683 if (realIndicesIndex != 0)
641 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 684 {
642 685 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
643 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 686 realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
644 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 687 }
688 else
689 {
690 PhysicsScene.Logger.ErrorFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
691 LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name);
692 }
645 } 693 }
646 } 694 }
647 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
648 newShape.shapeKey = newMeshKey; 695 newShape.shapeKey = newMeshKey;
649 696
650 return newShape; 697 return newShape;
@@ -663,19 +710,17 @@ public sealed class BSShapeCollection : IDisposable
663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) 710 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
664 return false; 711 return false;
665 712
666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", 713 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
667 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 714 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
668 715
669 // Remove usage of the previous shape. 716 // Remove usage of the previous shape.
670 DereferenceShape(prim.PhysShape, true, shapeCallback); 717 DereferenceShape(prim.PhysShape, shapeCallback);
671 718
672 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); 719 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
673 newShape = VerifyMeshCreated(newShape, prim); 720 newShape = VerifyMeshCreated(newShape, prim);
674 721
675 ReferenceShape(newShape); 722 ReferenceShape(newShape);
676 723
677 // hulls are already scaled by the meshmerizer
678 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
679 prim.PhysShape = newShape; 724 prim.PhysShape = newShape;
680 return true; // 'true' means a new shape has been added to this prim 725 return true; // 'true' means a new shape has been added to this prim
681 } 726 }
@@ -684,18 +729,20 @@ public sealed class BSShapeCollection : IDisposable
684 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 729 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
685 { 730 {
686 731
732 BulletShape newShape = new BulletShape();
687 IntPtr hullPtr = IntPtr.Zero; 733 IntPtr hullPtr = IntPtr.Zero;
734
688 HullDesc hullDesc; 735 HullDesc hullDesc;
689 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 736 if (Hulls.TryGetValue(newHullKey, out hullDesc))
690 { 737 {
691 // If the hull shape already is created, just use it. 738 // If the hull shape already is created, just use it.
692 hullPtr = hullDesc.ptr; 739 newShape = hullDesc.shape.Clone();
693 } 740 }
694 else 741 else
695 { 742 {
696 // Build a new hull in the physical world 743 // 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 744 // Pass true for physicalness as this creates some sort of bounding box which we don't need
698 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 745 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
699 if (meshData != null) 746 if (meshData != null)
700 { 747 {
701 748
@@ -777,14 +824,13 @@ public sealed class BSShapeCollection : IDisposable
777 } 824 }
778 } 825 }
779 // create the hull data structure in Bullet 826 // create the hull data structure in Bullet
780 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); 827 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
781 } 828 }
782 } 829 }
783 830
784 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
785 newShape.shapeKey = newHullKey; 831 newShape.shapeKey = newHullKey;
786 832
787 return newShape; // 'true' means a new shape has been added to this prim 833 return newShape;
788 } 834 }
789 835
790 // Callback from convex hull creater with a newly created hull. 836 // Callback from convex hull creater with a newly created hull.
@@ -803,13 +849,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. 849 // 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); 850 // DereferenceShape(prim.PhysShape, true, shapeCallback);
805 851
806 BulletShape cShape = new BulletShape( 852 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false);
807 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND);
808 853
809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. 854 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
810 CreateGeomMeshOrHull(prim, shapeCallback); 855 CreateGeomMeshOrHull(prim, shapeCallback);
811 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); 856 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
812 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", 857 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
813 prim.LocalID, cShape, prim.PhysShape); 858 prim.LocalID, cShape, prim.PhysShape);
814 859
815 prim.PhysShape = cShape; 860 prim.PhysShape = cShape;
@@ -822,14 +867,19 @@ public sealed class BSShapeCollection : IDisposable
822 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) 867 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
823 { 868 {
824 // level of detail based on size and type of the object 869 // level of detail based on size and type of the object
825 float lod = PhysicsScene.MeshLOD; 870 float lod = BSParam.MeshLOD;
871
872 // prims with curvy internal cuts need higher lod
873 if (pbs.HollowShape == HollowShape.Circle)
874 lod = BSParam.MeshCircularLOD;
875
826 if (pbs.SculptEntry) 876 if (pbs.SculptEntry)
827 lod = PhysicsScene.SculptLOD; 877 lod = BSParam.SculptLOD;
828 878
829 // Mega prims usually get more detail because one can interact with shape approximations at this size. 879 // 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)); 880 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
831 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) 881 if (maxAxis > BSParam.MeshMegaPrimThreshold)
832 lod = PhysicsScene.MeshMegaPrimLOD; 882 lod = BSParam.MeshMegaPrimLOD;
833 883
834 retLod = lod; 884 retLod = lod;
835 return pbs.GetMeshKey(size, lod); 885 return pbs.GetMeshKey(size, lod);
@@ -851,16 +901,17 @@ public sealed class BSShapeCollection : IDisposable
851 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) 901 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
852 { 902 {
853 // If the shape was successfully created, nothing more to do 903 // If the shape was successfully created, nothing more to do
854 if (newShape.ptr != IntPtr.Zero) 904 if (newShape.HasPhysicalShape)
855 return newShape; 905 return newShape;
856 906
857 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 907 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
858 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) 908 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
859 { 909 {
910 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lastFailed={1}", prim.LocalID, prim.LastAssetBuildFailed);
911 // This will prevent looping through this code as we keep trying to get the failed shape
860 prim.LastAssetBuildFailed = true; 912 prim.LastAssetBuildFailed = true;
913
861 BSPhysObject xprim = prim; 914 BSPhysObject xprim = prim;
862 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
863 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
864 Util.FireAndForget(delegate 915 Util.FireAndForget(delegate
865 { 916 {
866 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; 917 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
@@ -869,19 +920,34 @@ public sealed class BSShapeCollection : IDisposable
869 BSPhysObject yprim = xprim; // probably not necessary, but, just in case. 920 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
870 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) 921 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
871 { 922 {
872 if (!yprim.BaseShape.SculptEntry) 923 bool assetFound = false; // DEBUG DEBUG
873 return; 924 string mismatchIDs = String.Empty; // DEBUG DEBUG
874 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) 925 if (asset != null && yprim.BaseShape.SculptEntry)
875 return; 926 {
876 927 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
877 yprim.BaseShape.SculptData = asset.Data; 928 {
878 // This will cause the prim to see that the filler shape is not the right 929 yprim.BaseShape.SculptData = asset.Data;
879 // one and try again to build the object. 930 // This will cause the prim to see that the filler shape is not the right
880 // No race condition with the normal shape setting since the rebuild is at taint time. 931 // one and try again to build the object.
881 yprim.ForceBodyShapeRebuild(false); 932 // No race condition with the normal shape setting since the rebuild is at taint time.
933 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
934 assetFound = true;
935 }
936 else
937 {
938 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
939 }
940 }
941 DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
942 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
882 943
883 }); 944 });
884 } 945 }
946 else
947 {
948 PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
949 LogHeader, PhysicsScene.Name);
950 }
885 }); 951 });
886 } 952 }
887 else 953 else
@@ -893,9 +959,9 @@ public sealed class BSShapeCollection : IDisposable
893 } 959 }
894 } 960 }
895 961
896 // While we figure out the real problem, stick a simple native shape on the object. 962 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
897 BulletShape fillinShape = 963 BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
898 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); 964 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID);
899 965
900 return fillinShape; 966 return fillinShape;
901 } 967 }
@@ -904,49 +970,45 @@ public sealed class BSShapeCollection : IDisposable
904 // Updates prim.BSBody with the information about the new body if one is created. 970 // Updates prim.BSBody with the information about the new body if one is created.
905 // Returns 'true' if an object was actually created. 971 // Returns 'true' if an object was actually created.
906 // Called at taint-time. 972 // Called at taint-time.
907 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, 973 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BodyDestructionCallback bodyCallback)
908 BodyDestructionCallback bodyCallback)
909 { 974 {
910 bool ret = false; 975 bool ret = false;
911 976
912 // the mesh, hull or native shape must have already been created in Bullet 977 // the mesh, hull or native shape must have already been created in Bullet
913 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); 978 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
914 979
915 // If there is an existing body, verify it's of an acceptable type. 980 // 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. 981 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
917 if (!mustRebuild) 982 if (!mustRebuild)
918 { 983 {
919 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); 984 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody);
920 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 985 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
921 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 986 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
922 { 987 {
923 // If the collisionObject is not the correct type for solidness, rebuild what's there 988 // If the collisionObject is not the correct type for solidness, rebuild what's there
924 mustRebuild = true; 989 mustRebuild = true;
990 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType);
925 } 991 }
926 } 992 }
927 993
928 if (mustRebuild || forceRebuild) 994 if (mustRebuild || forceRebuild)
929 { 995 {
930 // Free any old body 996 // Free any old body
931 DereferenceBody(prim.PhysBody, true, bodyCallback); 997 DereferenceBody(prim.PhysBody, bodyCallback);
932 998
933 BulletBody aBody; 999 BulletBody aBody;
934 IntPtr bodyPtr = IntPtr.Zero;
935 if (prim.IsSolid) 1000 if (prim.IsSolid)
936 { 1001 {
937 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 1002 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
938 prim.LocalID, prim.RawPosition, prim.RawOrientation); 1003 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 } 1004 }
941 else 1005 else
942 { 1006 {
943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 1007 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
944 prim.LocalID, prim.RawPosition, prim.RawOrientation); 1008 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 } 1009 }
947 aBody = new BulletBody(prim.LocalID, bodyPtr);
948 1010
949 ReferenceBody(aBody, true); 1011 ReferenceBody(aBody);
950 1012
951 prim.PhysBody = aBody; 1013 prim.PhysBody = aBody;
952 1014
@@ -956,13 +1018,13 @@ public sealed class BSShapeCollection : IDisposable
956 return ret; 1018 return ret;
957 } 1019 }
958 1020
959 private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc) 1021 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
960 { 1022 {
961 bool ret = false; 1023 bool ret = false;
962 MeshDesc foundDesc = new MeshDesc(); 1024 MeshDesc foundDesc = new MeshDesc();
963 foreach (MeshDesc md in Meshes.Values) 1025 foreach (MeshDesc md in Meshes.Values)
964 { 1026 {
965 if (md.ptr == addr) 1027 if (md.shape.ReferenceSame(shape))
966 { 1028 {
967 foundDesc = md; 1029 foundDesc = md;
968 ret = true; 1030 ret = true;
@@ -974,13 +1036,13 @@ public sealed class BSShapeCollection : IDisposable
974 return ret; 1036 return ret;
975 } 1037 }
976 1038
977 private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc) 1039 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
978 { 1040 {
979 bool ret = false; 1041 bool ret = false;
980 HullDesc foundDesc = new HullDesc(); 1042 HullDesc foundDesc = new HullDesc();
981 foreach (HullDesc hd in Hulls.Values) 1043 foreach (HullDesc hd in Hulls.Values)
982 { 1044 {
983 if (hd.ptr == addr) 1045 if (hd.shape.ReferenceSame(shape))
984 { 1046 {
985 foundDesc = hd; 1047 foundDesc = hd;
986 ret = true; 1048 ret = true;