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.cs497
1 files changed, 345 insertions, 152 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index d3ba273..892c34b 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -34,11 +34,11 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSShapeCollection : IDisposable 37public sealed class BSShapeCollection : IDisposable
38{ 38{
39 // private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; 39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40 40
41 protected BSScene PhysicsScene { get; set; } 41 private BSScene PhysicsScene { get; set; }
42 42
43 private Object m_collectionActivityLock = new Object(); 43 private Object m_collectionActivityLock = new Object();
44 44
@@ -48,6 +48,7 @@ public class BSShapeCollection : IDisposable
48 public IntPtr ptr; 48 public IntPtr ptr;
49 public int referenceCount; 49 public int referenceCount;
50 public DateTime lastReferenced; 50 public DateTime lastReferenced;
51 public UInt64 shapeKey;
51 } 52 }
52 53
53 // Description of a hull. 54 // Description of a hull.
@@ -57,6 +58,7 @@ public class BSShapeCollection : IDisposable
57 public IntPtr ptr; 58 public IntPtr ptr;
58 public int referenceCount; 59 public int referenceCount;
59 public DateTime lastReferenced; 60 public DateTime lastReferenced;
61 public UInt64 shapeKey;
60 } 62 }
61 63
62 // The sharable set of meshes and hulls. Indexed by their shape hash. 64 // The sharable set of meshes and hulls. Indexed by their shape hash.
@@ -89,10 +91,11 @@ public class BSShapeCollection : IDisposable
89 // higher level dependencies on the shape or body. Mostly used for LinkSets to 91 // higher level dependencies on the shape or body. Mostly used for LinkSets to
90 // remove the physical constraints before the body is destroyed. 92 // remove the physical constraints before the body is destroyed.
91 // Called at taint-time!! 93 // Called at taint-time!!
92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, 94 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
93 ShapeData shapeData, PrimitiveBaseShape pbs,
94 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 95 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
95 { 96 {
97 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
98
96 bool ret = false; 99 bool ret = false;
97 100
98 // This lock could probably be pushed down lower but building shouldn't take long 101 // This lock could probably be pushed down lower but building shouldn't take long
@@ -100,41 +103,38 @@ public class BSShapeCollection : IDisposable
100 { 103 {
101 // Do we have the correct geometry for this type of object? 104 // Do we have the correct geometry for this type of object?
102 // Updates prim.BSShape with information/pointers to shape. 105 // Updates prim.BSShape with information/pointers to shape.
103 // CreateGeom returns 'true' of BSShape as changed to a new shape. 106 // Returns 'true' of BSShape is changed to a new shape.
104 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback); 107 bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback);
105 // If we had to select a new shape geometry for the object, 108 // If we had to select a new shape geometry for the object,
106 // rebuild the body around it. 109 // rebuild the body around it.
107 // Updates prim.BSBody with information/pointers to requested body 110 // Updates prim.BSBody with information/pointers to requested body
108 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, 111 // Returns 'true' if BSBody was changed.
109 prim.BSShape, shapeData, bodyCallback); 112 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
113 prim.PhysShape, bodyCallback);
110 ret = newGeom || newBody; 114 ret = newGeom || newBody;
111 } 115 }
112 DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}", 116 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
113 prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape); 117 prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
114 118
115 return ret; 119 return ret;
116 } 120 }
117 121
118 // Track another user of a body 122 // Track another user of a body.
119 // We presume the caller has allocated the body. 123 // We presume the caller has allocated the body.
120 // Bodies only have one user so the body is just put into the world if not already there. 124 // Bodies only have one user so the body is just put into the world if not already there.
121 public void ReferenceBody(BulletBody body, bool inTaintTime) 125 public void ReferenceBody(BulletBody body, bool inTaintTime)
122 { 126 {
123 lock (m_collectionActivityLock) 127 lock (m_collectionActivityLock)
124 { 128 {
125 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body); 129 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
126 BSScene.TaintCallback createOperation = delegate() 130 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
127 { 131 {
128 if (!BulletSimAPI.IsInWorld2(body.ptr)) 132 if (!BulletSimAPI.IsInWorld2(body.ptr))
129 { 133 {
130 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 134 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
131 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); 135 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
132 } 136 }
133 }; 137 });
134 if (inTaintTime)
135 createOperation();
136 else
137 PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
138 } 138 }
139 } 139 }
140 140
@@ -147,25 +147,23 @@ public class BSShapeCollection : IDisposable
147 147
148 lock (m_collectionActivityLock) 148 lock (m_collectionActivityLock)
149 { 149 {
150 BSScene.TaintCallback removeOperation = delegate() 150 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
151 { 151 {
152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}", 152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
153 body.ID, body.ptr.ToString("X"), inTaintTime); 153 body.ID, body, inTaintTime);
154 // If the caller needs to know the old body is going away, pass the event up. 154 // If the caller needs to know the old body is going away, pass the event up.
155 if (bodyCallback != null) bodyCallback(body); 155 if (bodyCallback != null) bodyCallback(body);
156 156
157 // It may have already been removed from the world in which case the next is a NOOP. 157 if (BulletSimAPI.IsInWorld2(body.ptr))
158 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); 158 {
159 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
160 DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
161 }
159 162
160 // Zero any reference to the shape so it is not freed when the body is deleted. 163 // Zero any reference to the shape so it is not freed when the body is deleted.
161 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); 164 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
162 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); 165 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
163 }; 166 });
164 // If already in taint-time, do the operations now. Otherwise queue for later.
165 if (inTaintTime)
166 removeOperation();
167 else
168 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
169 } 167 }
170 } 168 }
171 169
@@ -175,12 +173,12 @@ public class BSShapeCollection : IDisposable
175 // Meshes and hulls for the same shape have the same hash key. 173 // Meshes and hulls for the same shape have the same hash key.
176 // NOTE that native shapes are not added to the mesh list or removed. 174 // NOTE that native shapes are not added to the mesh list or removed.
177 // Returns 'true' if this is the initial reference to the shape. Otherwise reused. 175 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
178 private bool ReferenceShape(BulletShape shape) 176 public bool ReferenceShape(BulletShape shape)
179 { 177 {
180 bool ret = false; 178 bool ret = false;
181 switch (shape.type) 179 switch (shape.type)
182 { 180 {
183 case ShapeData.PhysicsShapeType.SHAPE_MESH: 181 case BSPhysicsShapeType.SHAPE_MESH:
184 MeshDesc meshDesc; 182 MeshDesc meshDesc;
185 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) 183 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
186 { 184 {
@@ -193,6 +191,7 @@ public class BSShapeCollection : IDisposable
193 { 191 {
194 // This is a new reference to a mesh 192 // This is a new reference to a mesh
195 meshDesc.ptr = shape.ptr; 193 meshDesc.ptr = shape.ptr;
194 meshDesc.shapeKey = shape.shapeKey;
196 // We keep a reference to the underlying IMesh data so a hull can be built 195 // We keep a reference to the underlying IMesh data so a hull can be built
197 meshDesc.referenceCount = 1; 196 meshDesc.referenceCount = 1;
198 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", 197 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
@@ -202,7 +201,7 @@ public class BSShapeCollection : IDisposable
202 meshDesc.lastReferenced = System.DateTime.Now; 201 meshDesc.lastReferenced = System.DateTime.Now;
203 Meshes[shape.shapeKey] = meshDesc; 202 Meshes[shape.shapeKey] = meshDesc;
204 break; 203 break;
205 case ShapeData.PhysicsShapeType.SHAPE_HULL: 204 case BSPhysicsShapeType.SHAPE_HULL:
206 HullDesc hullDesc; 205 HullDesc hullDesc;
207 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) 206 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
208 { 207 {
@@ -215,6 +214,7 @@ public class BSShapeCollection : IDisposable
215 { 214 {
216 // This is a new reference to a hull 215 // This is a new reference to a hull
217 hullDesc.ptr = shape.ptr; 216 hullDesc.ptr = shape.ptr;
217 hullDesc.shapeKey = shape.shapeKey;
218 hullDesc.referenceCount = 1; 218 hullDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", 219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
@@ -224,7 +224,7 @@ public class BSShapeCollection : IDisposable
224 hullDesc.lastReferenced = System.DateTime.Now; 224 hullDesc.lastReferenced = System.DateTime.Now;
225 Hulls[shape.shapeKey] = hullDesc; 225 Hulls[shape.shapeKey] = hullDesc;
226 break; 226 break;
227 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: 227 case BSPhysicsShapeType.SHAPE_UNKNOWN:
228 break; 228 break;
229 default: 229 default:
230 // Native shapes are not tracked and they don't go into any list 230 // Native shapes are not tracked and they don't go into any list
@@ -239,7 +239,7 @@ public class BSShapeCollection : IDisposable
239 if (shape.ptr == IntPtr.Zero) 239 if (shape.ptr == IntPtr.Zero)
240 return; 240 return;
241 241
242 BSScene.TaintCallback dereferenceOperation = delegate() 242 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
243 { 243 {
244 if (shape.ptr != IntPtr.Zero) 244 if (shape.ptr != IntPtr.Zero)
245 { 245 {
@@ -255,31 +255,23 @@ public class BSShapeCollection : IDisposable
255 { 255 {
256 switch (shape.type) 256 switch (shape.type)
257 { 257 {
258 case ShapeData.PhysicsShapeType.SHAPE_HULL: 258 case BSPhysicsShapeType.SHAPE_HULL:
259 DereferenceHull(shape, shapeCallback); 259 DereferenceHull(shape, shapeCallback);
260 break; 260 break;
261 case ShapeData.PhysicsShapeType.SHAPE_MESH: 261 case BSPhysicsShapeType.SHAPE_MESH:
262 DereferenceMesh(shape, shapeCallback); 262 DereferenceMesh(shape, shapeCallback);
263 break; 263 break;
264 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: 264 case BSPhysicsShapeType.SHAPE_COMPOUND:
265 DereferenceCompound(shape, shapeCallback);
266 break;
267 case BSPhysicsShapeType.SHAPE_UNKNOWN:
265 break; 268 break;
266 default: 269 default:
267 break; 270 break;
268 } 271 }
269 } 272 }
270 } 273 }
271 }; 274 });
272 if (inTaintTime)
273 {
274 lock (m_collectionActivityLock)
275 {
276 dereferenceOperation();
277 }
278 }
279 else
280 {
281 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation);
282 }
283 } 275 }
284 276
285 // Count down the reference count for a mesh shape 277 // Count down the reference count for a mesh shape
@@ -294,8 +286,8 @@ public class BSShapeCollection : IDisposable
294 if (shapeCallback != null) shapeCallback(shape); 286 if (shapeCallback != null) shapeCallback(shape);
295 meshDesc.lastReferenced = System.DateTime.Now; 287 meshDesc.lastReferenced = System.DateTime.Now;
296 Meshes[shape.shapeKey] = meshDesc; 288 Meshes[shape.shapeKey] = meshDesc;
297 DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}", 289 DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
298 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 290 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
299 291
300 } 292 }
301 } 293 }
@@ -309,11 +301,94 @@ public class BSShapeCollection : IDisposable
309 { 301 {
310 hullDesc.referenceCount--; 302 hullDesc.referenceCount--;
311 // TODO: release the Bullet storage (aging old entries?) 303 // TODO: release the Bullet storage (aging old entries?)
304
305 // Tell upper layers that, if they have dependencies on this shape, this link is going away
312 if (shapeCallback != null) shapeCallback(shape); 306 if (shapeCallback != null) shapeCallback(shape);
307
313 hullDesc.lastReferenced = System.DateTime.Now; 308 hullDesc.lastReferenced = System.DateTime.Now;
314 Hulls[shape.shapeKey] = hullDesc; 309 Hulls[shape.shapeKey] = hullDesc;
315 DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}", 310 DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
316 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 311 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
312 }
313 }
314
315 // Remove a reference to a compound shape.
316 // Taking a compound shape apart is a little tricky because if you just delete the
317 // physical shape, it will free all the underlying children. We can't do that because
318 // they could be shared. So, this removes each of the children from the compound and
319 // dereferences them separately before destroying the compound collision object itself.
320 // Called at taint-time.
321 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
322 {
323 if (!BulletSimAPI.IsCompound2(shape.ptr))
324 {
325 // Failed the sanity check!!
326 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"));
328 DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
329 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
330 return;
331 }
332
333 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
334 DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
335
336 for (int ii = numChildren - 1; ii >= 0; ii--)
337 {
338 IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii);
339 DereferenceAnonCollisionShape(childShape);
340 }
341 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
342 }
343
344 // 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.
346 // Called at taint-time.
347 private void DereferenceAnonCollisionShape(IntPtr cShape)
348 {
349 MeshDesc meshDesc;
350 HullDesc hullDesc;
351
352 BulletShape shapeInfo = new BulletShape(cShape);
353 if (TryGetMeshByPtr(cShape, out meshDesc))
354 {
355 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
356 shapeInfo.shapeKey = meshDesc.shapeKey;
357 }
358 else
359 {
360 if (TryGetHullByPtr(cShape, out hullDesc))
361 {
362 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
363 shapeInfo.shapeKey = hullDesc.shapeKey;
364 }
365 else
366 {
367 if (BulletSimAPI.IsCompound2(cShape))
368 {
369 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
370 }
371 else
372 {
373 if (BulletSimAPI.IsNativeShape2(cShape))
374 {
375 shapeInfo.isNativeShape = true;
376 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
377 }
378 }
379 }
380 }
381
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383
384 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
385 {
386 DereferenceShape(shapeInfo, true, null);
387 }
388 else
389 {
390 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
391 LogHeader, PhysicsScene.RegionName, cShape.ToString("X"));
317 } 392 }
318 } 393 }
319 394
@@ -325,21 +400,46 @@ public class BSShapeCollection : IDisposable
325 // Info in prim.BSShape is updated to the new shape. 400 // Info in prim.BSShape is updated to the new shape.
326 // Returns 'true' if the geometry was rebuilt. 401 // Returns 'true' if the geometry was rebuilt.
327 // Called at taint-time! 402 // Called at taint-time!
328 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData, 403 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
329 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
330 { 404 {
331 bool ret = false; 405 bool ret = false;
332 bool haveShape = false; 406 bool haveShape = false;
333 bool nativeShapePossible = true;
334 407
335 if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 408 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
336 { 409 {
337 // an avatar capsule is close to a native shape (it is not shared) 410 // an avatar capsule is close to a native shape (it is not shared)
338 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR, 411 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
339 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback); 412 FixedShapeKey.KEY_CAPSULE, shapeCallback);
340 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape); 413 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
414 ret = true;
341 haveShape = true; 415 haveShape = true;
342 } 416 }
417
418 // 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.
420 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
421 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
424 haveShape = true;
425 }
426
427 if (!haveShape)
428 {
429 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
430 }
431
432 return ret;
433 }
434
435 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
436 private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
437 {
438 bool ret = false;
439 bool haveShape = false;
440 bool nativeShapePossible = true;
441 PrimitiveBaseShape pbs = prim.BaseShape;
442
343 // If the prim attributes are simple, this could be a simple Bullet native shape 443 // If the prim attributes are simple, this could be a simple Bullet native shape
344 if (!haveShape 444 if (!haveShape
345 && pbs != null 445 && pbs != null
@@ -353,97 +453,120 @@ public class BSShapeCollection : IDisposable
353 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 453 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
354 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 454 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
355 { 455 {
456 // It doesn't look like Bullet scales spheres so make sure the scales are all equal
356 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 457 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
357 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) 458 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
358 { 459 {
359 haveShape = true; 460 haveShape = true;
360 if (forceRebuild 461 if (forceRebuild
361 || prim.Scale != shapeData.Size 462 || prim.Scale != prim.Size
362 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE 463 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
363 ) 464 )
364 { 465 {
365 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE, 466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
366 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback); 467 FixedShapeKey.KEY_SPHERE, shapeCallback);
367 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", 468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
368 prim.LocalID, forceRebuild, prim.BSShape); 469 prim.LocalID, forceRebuild, prim.PhysShape);
369 } 470 }
370 } 471 }
371 if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 472 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
372 { 473 {
373 haveShape = true; 474 haveShape = true;
374 if (forceRebuild 475 if (forceRebuild
375 || prim.Scale != shapeData.Size 476 || prim.Scale != prim.Size
376 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX 477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
377 ) 478 )
378 { 479 {
379 ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX, 480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
380 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback); 481 FixedShapeKey.KEY_BOX, shapeCallback);
381 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", 482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
382 prim.LocalID, forceRebuild, prim.BSShape); 483 prim.LocalID, forceRebuild, prim.PhysShape);
383 } 484 }
384 } 485 }
385 } 486 }
487
386 // If a simple shape is not happening, create a mesh and possibly a hull. 488 // If a simple shape is not happening, create a mesh and possibly a hull.
387 // Note that if it's a native shape, the check for physical/non-physical is not
388 // made. Native shapes are best used in either case.
389 if (!haveShape && pbs != null) 489 if (!haveShape && pbs != null)
390 { 490 {
391 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 491 ret = CreateGeomMeshOrHull(prim, shapeCallback);
392 { 492 }
393 // Update prim.BSShape to reference a hull of this shape. 493
394 ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback); 494 return ret;
395 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 495 }
396 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X")); 496
397 } 497 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
398 else 498 {
399 { 499
400 ret = GetReferenceToMesh(prim, shapeData, pbs, shapeCallback); 500 bool ret = false;
401 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 501 // Note that if it's a native shape, the check for physical/non-physical is not
402 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X")); 502 // made. Native shapes work in either case.
403 } 503 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
504 {
505 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 }
510 else
511 {
512 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
404 } 515 }
405 return ret; 516 return ret;
406 } 517 }
407 518
408 // Creates a native shape and assignes it to prim.BSShape. 519 // Creates a native shape and assignes it to prim.BSShape.
409 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). 520 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
410 private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData, 521 private bool GetReferenceToNativeShape(BSPhysObject prim,
411 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, 522 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
412 ShapeDestructionCallback shapeCallback) 523 ShapeDestructionCallback shapeCallback)
413 { 524 {
414
415 shapeData.Type = shapeType;
416 // Bullet native objects are scaled by the Bullet engine so pass the size in
417 prim.Scale = shapeData.Size;
418 shapeData.Scale = shapeData.Size;
419
420 // release any previous shape 525 // release any previous shape
421 DereferenceShape(prim.BSShape, true, shapeCallback); 526 DereferenceShape(prim.PhysShape, true, shapeCallback);
422 527
423 BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey); 528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
424 529
425 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
426 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 531 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
427 shapeData.ID, newShape, shapeData.Scale); 532 prim.LocalID, newShape, prim.Scale);
428 533
429 prim.BSShape = newShape; 534 prim.PhysShape = newShape;
430 return true; 535 return true;
431 } 536 }
432 537
433 private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType, 538 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
434 ShapeData shapeData, ShapeData.FixedShapeKey shapeKey) 539 FixedShapeKey shapeKey)
435 { 540 {
436 BulletShape newShape; 541 BulletShape newShape;
437 542 // Need to make sure the passed shape information is for the native type.
438 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 543 ShapeData nativeShapeData = new ShapeData();
544 nativeShapeData.Type = shapeType;
545 nativeShapeData.ID = prim.LocalID;
546 nativeShapeData.Scale = prim.Scale;
547 nativeShapeData.Size = prim.Scale; // unneeded, I think.
548 nativeShapeData.MeshKey = (ulong)shapeKey;
549 nativeShapeData.HullKey = (ulong)shapeKey;
550
551 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
439 { 552 {
553 // The proper scale has been calculated in the prim.
440 newShape = new BulletShape( 554 newShape = new BulletShape(
441 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale), 555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
442 shapeType); 556 , shapeType);
557 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
443 } 558 }
444 else 559 else
445 { 560 {
446 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); 561 // Native shapes are scaled in Bullet so set the scaling to the size
562 prim.Scale = prim.Size;
563 nativeShapeData.Scale = prim.Scale;
564 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
565 }
566 if (newShape.ptr == IntPtr.Zero)
567 {
568 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
569 LogHeader, prim.LocalID, shapeType);
447 } 570 }
448 newShape.shapeKey = (System.UInt64)shapeKey; 571 newShape.shapeKey = (System.UInt64)shapeKey;
449 newShape.isNativeShape = true; 572 newShape.isNativeShape = true;
@@ -455,33 +578,32 @@ public class BSShapeCollection : IDisposable
455 // Dereferences previous shape in BSShape and adds a reference for this new shape. 578 // Dereferences previous shape in BSShape and adds a reference for this new shape.
456 // Returns 'true' of a mesh was actually built. Otherwise . 579 // Returns 'true' of a mesh was actually built. Otherwise .
457 // Called at taint-time! 580 // Called at taint-time!
458 private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs, 581 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
459 ShapeDestructionCallback shapeCallback)
460 { 582 {
461 BulletShape newShape = new BulletShape(IntPtr.Zero); 583 BulletShape newShape = new BulletShape(IntPtr.Zero);
462 584
463 float lod; 585 float lod;
464 System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, out lod); 586 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
465 587
466 // if this new shape is the same as last time, don't recreate the mesh 588 // if this new shape is the same as last time, don't recreate the mesh
467 if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) 589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
468 return false; 590 return false;
469 591
470 DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}", 592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
471 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); 593 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
472 594
473 // Since we're recreating new, get rid of the reference to the previous shape 595 // Since we're recreating new, get rid of the reference to the previous shape
474 DereferenceShape(prim.BSShape, true, shapeCallback); 596 DereferenceShape(prim.PhysShape, true, shapeCallback);
475 597
476 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); 598 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod);
477 // Take evasive action if the mesh was not constructed. 599 // Take evasive action if the mesh was not constructed.
478 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); 600 newShape = VerifyMeshCreated(newShape, prim);
479 601
480 ReferenceShape(newShape); 602 ReferenceShape(newShape);
481 603
482 // meshes are already scaled by the meshmerizer 604 // meshes are already scaled by the meshmerizer
483 prim.Scale = new OMV.Vector3(1f, 1f, 1f); 605 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
484 prim.BSShape = newShape; 606 prim.PhysShape = newShape;
485 607
486 return true; // 'true' means a new shape has been added to this prim 608 return true; // 'true' means a new shape has been added to this prim
487 } 609 }
@@ -515,14 +637,14 @@ public class BSShapeCollection : IDisposable
515 verticesAsFloats[vi++] = vv.Z; 637 verticesAsFloats[vi++] = vv.Z;
516 } 638 }
517 639
518 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 640 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
519 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 641 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
520 642
521 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 643 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
522 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 644 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
523 } 645 }
524 } 646 }
525 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); 647 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
526 newShape.shapeKey = newMeshKey; 648 newShape.shapeKey = newMeshKey;
527 649
528 return newShape; 650 return newShape;
@@ -530,32 +652,31 @@ public class BSShapeCollection : IDisposable
530 652
531 // See that hull shape exists in the physical world and update prim.BSShape. 653 // See that hull shape exists in the physical world and update prim.BSShape.
532 // We could be creating the hull because scale changed or whatever. 654 // We could be creating the hull because scale changed or whatever.
533 private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs, 655 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
534 ShapeDestructionCallback shapeCallback)
535 { 656 {
536 BulletShape newShape; 657 BulletShape newShape;
537 658
538 float lod; 659 float lod;
539 System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, out lod); 660 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
540 661
541 // if the hull hasn't changed, don't rebuild it 662 // if the hull hasn't changed, don't rebuild it
542 if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) 663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
543 return false; 664 return false;
544 665
545 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", 666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
546 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 667 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
547 668
548 // Remove usage of the previous shape. 669 // Remove usage of the previous shape.
549 DereferenceShape(prim.BSShape, true, shapeCallback); 670 DereferenceShape(prim.PhysShape, true, shapeCallback);
550 671
551 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); 672 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
552 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); 673 newShape = VerifyMeshCreated(newShape, prim);
553 674
554 ReferenceShape(newShape); 675 ReferenceShape(newShape);
555 676
556 // hulls are already scaled by the meshmerizer 677 // hulls are already scaled by the meshmerizer
557 prim.Scale = new OMV.Vector3(1f, 1f, 1f); 678 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
558 prim.BSShape = newShape; 679 prim.PhysShape = newShape;
559 return true; // 'true' means a new shape has been added to this prim 680 return true; // 'true' means a new shape has been added to this prim
560 } 681 }
561 682
@@ -660,7 +781,7 @@ public class BSShapeCollection : IDisposable
660 } 781 }
661 } 782 }
662 783
663 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); 784 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
664 newShape.shapeKey = newHullKey; 785 newShape.shapeKey = newHullKey;
665 786
666 return newShape; // 'true' means a new shape has been added to this prim 787 return newShape; // 'true' means a new shape has been added to this prim
@@ -674,9 +795,31 @@ public class BSShapeCollection : IDisposable
674 return; 795 return;
675 } 796 }
676 797
798 // Compound shapes are always built from scratch.
799 // This shouldn't be to bad since most of the parts will be meshes that had been built previously.
800 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
801 {
802 // Remove reference to the old shape
803 // 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);
805
806 BulletShape cShape = new BulletShape(
807 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND);
808
809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
810 CreateGeomMeshOrHull(prim, shapeCallback);
811 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
812 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
813 prim.LocalID, cShape, prim.PhysShape);
814
815 prim.PhysShape = cShape;
816
817 return true;
818 }
819
677 // Create a hash of all the shape parameters to be used as a key 820 // Create a hash of all the shape parameters to be used as a key
678 // for this particular shape. 821 // for this particular shape.
679 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod) 822 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
680 { 823 {
681 // level of detail based on size and type of the object 824 // level of detail based on size and type of the object
682 float lod = PhysicsScene.MeshLOD; 825 float lod = PhysicsScene.MeshLOD;
@@ -684,33 +827,40 @@ public class BSShapeCollection : IDisposable
684 lod = PhysicsScene.SculptLOD; 827 lod = PhysicsScene.SculptLOD;
685 828
686 // Mega prims usually get more detail because one can interact with shape approximations at this size. 829 // Mega prims usually get more detail because one can interact with shape approximations at this size.
687 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z)); 830 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
688 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) 831 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
689 lod = PhysicsScene.MeshMegaPrimLOD; 832 lod = PhysicsScene.MeshMegaPrimLOD;
690 833
691 retLod = lod; 834 retLod = lod;
692 return pbs.GetMeshKey(shapeData.Size, lod); 835 return pbs.GetMeshKey(size, lod);
693 } 836 }
694 // For those who don't want the LOD 837 // For those who don't want the LOD
695 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs) 838 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
696 { 839 {
697 float lod; 840 float lod;
698 return ComputeShapeKey(shapeData, pbs, out lod); 841 return ComputeShapeKey(size, pbs, out lod);
699 } 842 }
700 843
701 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs) 844 // The creation of a mesh or hull can fail if an underlying asset is not available.
845 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
846 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
847 // The first case causes the asset to be fetched. The second case requires
848 // us to not loop forever.
849 // Called after creating a physical mesh or hull. If the physical shape was created,
850 // just return.
851 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
702 { 852 {
703 // If the shape was successfully created, nothing more to do 853 // If the shape was successfully created, nothing more to do
704 if (newShape.ptr != IntPtr.Zero) 854 if (newShape.ptr != IntPtr.Zero)
705 return newShape; 855 return newShape;
706 856
707 // The most common reason for failure is that an underlying asset is not available
708
709 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 857 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
710 if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero) 858 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
711 { 859 {
712 prim.LastAssetBuildFailed = true; 860 prim.LastAssetBuildFailed = true;
713 BSPhysObject xprim = prim; 861 BSPhysObject xprim = prim;
862 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
863 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
714 Util.FireAndForget(delegate 864 Util.FireAndForget(delegate
715 { 865 {
716 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; 866 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
@@ -724,20 +874,28 @@ public class BSShapeCollection : IDisposable
724 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) 874 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
725 return; 875 return;
726 876
727 yprim.BaseShape.SculptData = new byte[asset.Data.Length]; 877 yprim.BaseShape.SculptData = asset.Data;
728 asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
729 // This will cause the prim to see that the filler shape is not the right 878 // This will cause the prim to see that the filler shape is not the right
730 // one and try again to build the object. 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.
731 yprim.ForceBodyShapeRebuild(false); 881 yprim.ForceBodyShapeRebuild(false);
732 882
733 }); 883 });
734 } 884 }
735 }); 885 });
736 } 886 }
887 else
888 {
889 if (prim.LastAssetBuildFailed)
890 {
891 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
892 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture);
893 }
894 }
737 895
738 // While we figure out the real problem, stick a simple native shape on the object. 896 // While we figure out the real problem, stick a simple native shape on the object.
739 BulletShape fillinShape = 897 BulletShape fillinShape =
740 BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE); 898 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
741 899
742 return fillinShape; 900 return fillinShape;
743 } 901 }
@@ -746,52 +904,51 @@ public class BSShapeCollection : IDisposable
746 // Updates prim.BSBody with the information about the new body if one is created. 904 // Updates prim.BSBody with the information about the new body if one is created.
747 // Returns 'true' if an object was actually created. 905 // Returns 'true' if an object was actually created.
748 // Called at taint-time. 906 // Called at taint-time.
749 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, 907 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
750 ShapeData shapeData, BodyDestructionCallback bodyCallback) 908 BodyDestructionCallback bodyCallback)
751 { 909 {
752 bool ret = false; 910 bool ret = false;
753 911
754 // the mesh, hull or native shape must have already been created in Bullet 912 // the mesh, hull or native shape must have already been created in Bullet
755 bool mustRebuild = (prim.BSBody.ptr == IntPtr.Zero); 913 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero);
756 914
757 // If there is an existing body, verify it's of an acceptable type. 915 // If there is an existing body, verify it's of an acceptable type.
758 // If not a solid object, body is a GhostObject. Otherwise a RigidBody. 916 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
759 if (!mustRebuild) 917 if (!mustRebuild)
760 { 918 {
761 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.BSBody.ptr); 919 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr);
762 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 920 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
763 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 921 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
764 { 922 {
765 // If the collisionObject is not the correct type for solidness, rebuild what's there 923 // If the collisionObject is not the correct type for solidness, rebuild what's there
766 mustRebuild = true; 924 mustRebuild = true;
767 } 925 }
768
769 } 926 }
770 927
771 if (mustRebuild || forceRebuild) 928 if (mustRebuild || forceRebuild)
772 { 929 {
773 // Free any old body 930 // Free any old body
774 DereferenceBody(prim.BSBody, true, bodyCallback); 931 DereferenceBody(prim.PhysBody, true, bodyCallback);
775 932
776 BulletBody aBody; 933 BulletBody aBody;
777 IntPtr bodyPtr = IntPtr.Zero; 934 IntPtr bodyPtr = IntPtr.Zero;
778 if (prim.IsSolid) 935 if (prim.IsSolid)
779 { 936 {
780 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 937 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
781 shapeData.ID, shapeData.Position, shapeData.Rotation); 938 prim.LocalID, prim.RawPosition, prim.RawOrientation);
782 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 939 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
783 } 940 }
784 else 941 else
785 { 942 {
786 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
787 shapeData.ID, shapeData.Position, shapeData.Rotation); 944 prim.LocalID, prim.RawPosition, prim.RawOrientation);
788 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 945 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
789 } 946 }
790 aBody = new BulletBody(shapeData.ID, bodyPtr); 947 aBody = new BulletBody(prim.LocalID, bodyPtr);
791 948
792 ReferenceBody(aBody, true); 949 ReferenceBody(aBody, true);
793 950
794 prim.BSBody = aBody; 951 prim.PhysBody = aBody;
795 952
796 ret = true; 953 ret = true;
797 } 954 }
@@ -799,6 +956,42 @@ public class BSShapeCollection : IDisposable
799 return ret; 956 return ret;
800 } 957 }
801 958
959 private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc)
960 {
961 bool ret = false;
962 MeshDesc foundDesc = new MeshDesc();
963 foreach (MeshDesc md in Meshes.Values)
964 {
965 if (md.ptr == addr)
966 {
967 foundDesc = md;
968 ret = true;
969 break;
970 }
971
972 }
973 outDesc = foundDesc;
974 return ret;
975 }
976
977 private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc)
978 {
979 bool ret = false;
980 HullDesc foundDesc = new HullDesc();
981 foreach (HullDesc hd in Hulls.Values)
982 {
983 if (hd.ptr == addr)
984 {
985 foundDesc = hd;
986 ret = true;
987 break;
988 }
989
990 }
991 outDesc = foundDesc;
992 return ret;
993 }
994
802 private void DetailLog(string msg, params Object[] args) 995 private void DetailLog(string msg, params Object[] args)
803 { 996 {
804 if (PhysicsScene.PhysicsLogging.Enabled) 997 if (PhysicsScene.PhysicsLogging.Enabled)