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.cs927
1 files changed, 152 insertions, 775 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index d361f18..64aaa15 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -38,38 +38,15 @@ public 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 private BSScene PhysicsScene { get; set; } 41 private BSScene m_physicsScene { get; set; }
42 42
43 private Object m_collectionActivityLock = new Object(); 43 private Object m_collectionActivityLock = new Object();
44 44
45 // Description of a Mesh
46 private struct MeshDesc
47 {
48 public BulletShape shape;
49 public int referenceCount;
50 public DateTime lastReferenced;
51 public UInt64 shapeKey;
52 }
53
54 // Description of a hull.
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc
57 {
58 public BulletShape shape;
59 public int referenceCount;
60 public DateTime lastReferenced;
61 public UInt64 shapeKey;
62 }
63
64 // The sharable set of meshes and hulls. Indexed by their shape hash.
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67
68 private bool DDetail = false; 45 private bool DDetail = false;
69 46
70 public BSShapeCollection(BSScene physScene) 47 public BSShapeCollection(BSScene physScene)
71 { 48 {
72 PhysicsScene = physScene; 49 m_physicsScene = physScene;
73 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) 50 // 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 51 // 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 52 // DetailLog statements. When debugging slows down, this and the protected logging
@@ -86,22 +63,18 @@ public sealed class BSShapeCollection : IDisposable
86 // Mostly used for changing bodies out from under Linksets. 63 // Mostly used for changing bodies out from under Linksets.
87 // Useful for other cases where parameters need saving. 64 // Useful for other cases where parameters need saving.
88 // Passing 'null' says no callback. 65 // Passing 'null' says no callback.
89 public delegate void ShapeDestructionCallback(BulletShape shape); 66 public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape);
90 public delegate void BodyDestructionCallback(BulletBody body);
91 67
92 // Called to update/change the body and shape for an object. 68 // Called to update/change the body and shape for an object.
93 // First checks the shape and updates that if necessary then makes 69 // The object has some shape and body on it. Here we decide if that is the correct shape
94 // sure the body is of the right type. 70 // for the current state of the object (static/dynamic/...).
71 // If bodyCallback is not null, it is called if either the body or the shape are changed
72 // so dependencies (like constraints) can be removed before the physical object is dereferenced.
95 // Return 'true' if either the body or the shape changed. 73 // Return 'true' if either the body or the shape changed.
96 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before 74 // Called at taint-time.
97 // the current shape or body is destroyed. This allows the caller to remove any 75 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback)
98 // higher level dependencies on the shape or body. Mostly used for LinkSets to
99 // remove the physical constraints before the body is destroyed.
100 // Called at taint-time!!
101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim,
102 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
103 { 76 {
104 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); 77 m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
105 78
106 bool ret = false; 79 bool ret = false;
107 80
@@ -111,13 +84,12 @@ public sealed class BSShapeCollection : IDisposable
111 // Do we have the correct geometry for this type of object? 84 // Do we have the correct geometry for this type of object?
112 // Updates prim.BSShape with information/pointers to shape. 85 // Updates prim.BSShape with information/pointers to shape.
113 // Returns 'true' of BSShape is changed to a new shape. 86 // Returns 'true' of BSShape is changed to a new shape.
114 bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback); 87 bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback);
115 // If we had to select a new shape geometry for the object, 88 // If we had to select a new shape geometry for the object,
116 // rebuild the body around it. 89 // rebuild the body around it.
117 // Updates prim.BSBody with information/pointers to requested body 90 // Updates prim.BSBody with information/pointers to requested body
118 // Returns 'true' if BSBody was changed. 91 // Returns 'true' if BSBody was changed.
119 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, 92 bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback);
120 prim.PhysShape, bodyCallback);
121 ret = newGeom || newBody; 93 ret = newGeom || newBody;
122 } 94 }
123 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", 95 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
@@ -128,279 +100,20 @@ public sealed class BSShapeCollection : IDisposable
128 100
129 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) 101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
130 { 102 {
131 return GetBodyAndShape(forceRebuild, sim, prim, null, null); 103 return GetBodyAndShape(forceRebuild, sim, prim, null);
132 }
133
134 // Track another user of a body.
135 // We presume the caller has allocated the body.
136 // Bodies only have one user so the body is just put into the world if not already there.
137 public void ReferenceBody(BulletBody body, bool inTaintTime)
138 {
139 lock (m_collectionActivityLock)
140 {
141 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
142 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
143 {
144 if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
145 {
146 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
147 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
148 }
149 });
150 }
151 }
152
153 // Release the usage of a body.
154 // Called when releasing use of a BSBody. BSShape is handled separately.
155 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
156 {
157 if (!body.HasPhysicalBody)
158 return;
159
160 lock (m_collectionActivityLock)
161 {
162 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
163 {
164 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
165 body.ID, body, inTaintTime);
166 // If the caller needs to know the old body is going away, pass the event up.
167 if (bodyCallback != null) bodyCallback(body);
168
169 if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
170 {
171 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
172 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
173 }
174
175 // Zero any reference to the shape so it is not freed when the body is deleted.
176 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
177 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
178 });
179 }
180 }
181
182 // Track the datastructures and use count for a shape.
183 // When creating a hull, this is called first to reference the mesh
184 // and then again to reference the hull.
185 // Meshes and hulls for the same shape have the same hash key.
186 // NOTE that native shapes are not added to the mesh list or removed.
187 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
188 public bool ReferenceShape(BulletShape shape)
189 {
190 bool ret = false;
191 switch (shape.type)
192 {
193 case BSPhysicsShapeType.SHAPE_MESH:
194 MeshDesc meshDesc;
195 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
196 {
197 // There is an existing instance of this mesh.
198 meshDesc.referenceCount++;
199 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
200 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
201 }
202 else
203 {
204 // This is a new reference to a mesh
205 meshDesc.shape = shape.Clone();
206 meshDesc.shapeKey = shape.shapeKey;
207 // We keep a reference to the underlying IMesh data so a hull can be built
208 meshDesc.referenceCount = 1;
209 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
210 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
211 ret = true;
212 }
213 meshDesc.lastReferenced = System.DateTime.Now;
214 Meshes[shape.shapeKey] = meshDesc;
215 break;
216 case BSPhysicsShapeType.SHAPE_HULL:
217 HullDesc hullDesc;
218 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
219 {
220 // There is an existing instance of this hull.
221 hullDesc.referenceCount++;
222 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
223 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
224 }
225 else
226 {
227 // This is a new reference to a hull
228 hullDesc.shape = shape.Clone();
229 hullDesc.shapeKey = shape.shapeKey;
230 hullDesc.referenceCount = 1;
231 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
232 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
233 ret = true;
234
235 }
236 hullDesc.lastReferenced = System.DateTime.Now;
237 Hulls[shape.shapeKey] = hullDesc;
238 break;
239 case BSPhysicsShapeType.SHAPE_UNKNOWN:
240 break;
241 default:
242 // Native shapes are not tracked and they don't go into any list
243 break;
244 }
245 return ret;
246 }
247
248 // Release the usage of a shape.
249 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
250 {
251 if (!shape.HasPhysicalShape)
252 return;
253
254 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
255 {
256 if (shape.HasPhysicalShape)
257 {
258 if (shape.isNativeShape)
259 {
260 // Native shapes are not tracked and are released immediately
261 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
262 BSScene.DetailLogZero, shape.AddrString, inTaintTime);
263 if (shapeCallback != null) shapeCallback(shape);
264 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
265 }
266 else
267 {
268 switch (shape.type)
269 {
270 case BSPhysicsShapeType.SHAPE_HULL:
271 DereferenceHull(shape, shapeCallback);
272 break;
273 case BSPhysicsShapeType.SHAPE_MESH:
274 DereferenceMesh(shape, shapeCallback);
275 break;
276 case BSPhysicsShapeType.SHAPE_COMPOUND:
277 DereferenceCompound(shape, shapeCallback);
278 break;
279 case BSPhysicsShapeType.SHAPE_UNKNOWN:
280 break;
281 default:
282 break;
283 }
284 }
285 }
286 });
287 }
288
289 // Count down the reference count for a mesh shape
290 // Called at taint-time.
291 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
292 {
293 MeshDesc meshDesc;
294 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
295 {
296 meshDesc.referenceCount--;
297 // TODO: release the Bullet storage
298 if (shapeCallback != null) shapeCallback(shape);
299 meshDesc.lastReferenced = System.DateTime.Now;
300 Meshes[shape.shapeKey] = meshDesc;
301 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
302 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
303
304 }
305 }
306
307 // Count down the reference count for a hull shape
308 // Called at taint-time.
309 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
310 {
311 HullDesc hullDesc;
312 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
313 {
314 hullDesc.referenceCount--;
315 // TODO: release the Bullet storage (aging old entries?)
316
317 // Tell upper layers that, if they have dependencies on this shape, this link is going away
318 if (shapeCallback != null) shapeCallback(shape);
319
320 hullDesc.lastReferenced = System.DateTime.Now;
321 Hulls[shape.shapeKey] = hullDesc;
322 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
323 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
324 }
325 }
326
327 // Remove a reference to a compound shape.
328 // Taking a compound shape apart is a little tricky because if you just delete the
329 // physical shape, it will free all the underlying children. We can't do that because
330 // they could be shared. So, this removes each of the children from the compound and
331 // dereferences them separately before destroying the compound collision object itself.
332 // Called at taint-time.
333 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
334 {
335 if (!PhysicsScene.PE.IsCompound(shape))
336 {
337 // Failed the sanity check!!
338 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
339 LogHeader, shape.type, shape.AddrString);
340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
341 BSScene.DetailLogZero, shape.type, shape.AddrString);
342 return;
343 }
344
345 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
346 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
347
348 for (int ii = numChildren - 1; ii >= 0; ii--)
349 {
350 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
351 DereferenceAnonCollisionShape(childShape);
352 }
353 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
354 } 104 }
355 105
356 // Sometimes we have a pointer to a collision shape but don't know what type it is. 106 // If the existing prim's shape is to be replaced, remove the tie to the existing shape
357 // Figure out type and call the correct dereference routine. 107 // before replacing it.
358 // Called at taint-time. 108 private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
359 private void DereferenceAnonCollisionShape(BulletShape shapeInfo)
360 { 109 {
361 MeshDesc meshDesc; 110 if (prim.PhysShape.HasPhysicalShape)
362 HullDesc hullDesc;
363
364 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
365 {
366 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
367 shapeInfo.shapeKey = meshDesc.shapeKey;
368 }
369 else
370 {
371 if (TryGetHullByPtr(shapeInfo, out hullDesc))
372 {
373 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
374 shapeInfo.shapeKey = hullDesc.shapeKey;
375 }
376 else
377 {
378 if (PhysicsScene.PE.IsCompound(shapeInfo))
379 {
380 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
381 }
382 else
383 {
384 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
385 {
386 shapeInfo.isNativeShape = true;
387 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
388 }
389 }
390 }
391 }
392
393 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
394
395 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
396 { 111 {
397 DereferenceShape(shapeInfo, true, null); 112 if (shapeCallback != null)
398 } 113 shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo);
399 else 114 prim.PhysShape.Dereference(m_physicsScene);
400 {
401 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
402 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString);
403 } 115 }
116 prim.PhysShape = new BSShapeNull();
404 } 117 }
405 118
406 // Create the geometry information in Bullet for later use. 119 // Create the geometry information in Bullet for later use.
@@ -411,95 +124,75 @@ public sealed class BSShapeCollection : IDisposable
411 // Info in prim.BSShape is updated to the new shape. 124 // Info in prim.BSShape is updated to the new shape.
412 // Returns 'true' if the geometry was rebuilt. 125 // Returns 'true' if the geometry was rebuilt.
413 // Called at taint-time! 126 // Called at taint-time!
414 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 127 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
415 { 128 {
416 bool ret = false; 129 bool ret = false;
417 bool haveShape = false; 130 bool haveShape = false;
131 bool nativeShapePossible = true;
132 PrimitiveBaseShape pbs = prim.BaseShape;
418 133
419 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 134 // Kludge to create the capsule for the avatar.
135 // TDOD: Remove/redo this when BSShapeAvatar is working!!
136 BSCharacter theChar = prim as BSCharacter;
137 if (theChar != null)
420 { 138 {
421 // an avatar capsule is close to a native shape (it is not shared) 139 DereferenceExistingShape(prim, shapeCallback);
422 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback); 140 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
423 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); 141 BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE);
424 ret = true; 142 ret = true;
425 haveShape = true; 143 haveShape = true;
426 } 144 }
427 145
428 // Compound shapes are handled special as they are rebuilt from scratch.
429 // This isn't too great a hardship since most of the child shapes will have already been created.
430 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
431 {
432 ret = GetReferenceToCompoundShape(prim, shapeCallback);
433 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
434 haveShape = true;
435 }
436
437 if (!haveShape)
438 {
439 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
440 }
441
442 return ret;
443 }
444
445 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
446 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
447 {
448 bool ret = false;
449 bool haveShape = false;
450 bool nativeShapePossible = true;
451 PrimitiveBaseShape pbs = prim.BaseShape;
452
453 // If the prim attributes are simple, this could be a simple Bullet native shape 146 // If the prim attributes are simple, this could be a simple Bullet native shape
147 // Native shapes work whether to object is static or physical.
454 if (!haveShape 148 if (!haveShape
455 && pbs != null
456 && nativeShapePossible 149 && nativeShapePossible
457 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) 150 && pbs != null
458 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 151 && PrimHasNoCuts(pbs)
459 && pbs.ProfileHollow == 0 152 && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) )
460 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 153 )
461 && pbs.PathBegin == 0 && pbs.PathEnd == 0
462 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
463 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
464 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
465 { 154 {
466 // Get the scale of any existing shape so we can see if the new shape is same native type and same size. 155 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
467 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; 156 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
468 if (prim.PhysShape.HasPhysicalShape) 157 if (prim.PhysShape.HasPhysicalShape)
469 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape); 158 scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo);
470 159
471 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", 160 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
472 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); 161 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType);
473 162
474 // It doesn't look like Bullet scales spheres so make sure the scales are all equal 163 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
475 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 164 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
476 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) 165 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
477 { 166 {
478 haveShape = true; 167 haveShape = true;
479 if (forceRebuild 168 if (forceRebuild
480 || prim.Scale != scaleOfExistingShape 169 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE
481 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 170 )
482 )
483 { 171 {
484 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 172 DereferenceExistingShape(prim, shapeCallback);
485 FixedShapeKey.KEY_SPHERE, shapeCallback); 173 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
486 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", 174 BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE);
487 prim.LocalID, forceRebuild, prim.PhysShape); 175 ret = true;
488 } 176 }
177 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
178 prim.LocalID, forceRebuild, ret, prim.PhysShape);
489 } 179 }
180 // If we didn't make a sphere, maybe a box will work.
490 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 181 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
491 { 182 {
492 haveShape = true; 183 haveShape = true;
493 if (forceRebuild 184 if (forceRebuild
494 || prim.Scale != scaleOfExistingShape 185 || prim.Scale != scaleOfExistingShape
495 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 186 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX
496 ) 187 )
497 { 188 {
498 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 189 DereferenceExistingShape(prim, shapeCallback);
499 FixedShapeKey.KEY_BOX, shapeCallback); 190 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
500 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", 191 BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
501 prim.LocalID, forceRebuild, prim.PhysShape); 192 ret = true;
502 } 193 }
194 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
195 prim.LocalID, forceRebuild, ret, prim.PhysShape);
503 } 196 }
504 } 197 }
505 198
@@ -512,7 +205,20 @@ public sealed class BSShapeCollection : IDisposable
512 return ret; 205 return ret;
513 } 206 }
514 207
515 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 208 // return 'true' if this shape description does not include any cutting or twisting.
209 public static bool PrimHasNoCuts(PrimitiveBaseShape pbs)
210 {
211 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
212 && pbs.ProfileHollow == 0
213 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
214 && pbs.PathBegin == 0 && pbs.PathEnd == 0
215 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
216 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
217 && pbs.PathShearX == 0 && pbs.PathShearY == 0;
218 }
219
220 // return 'true' if the prim's shape was changed.
221 private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
516 { 222 {
517 223
518 bool ret = false; 224 bool ret = false;
@@ -520,404 +226,110 @@ public sealed class BSShapeCollection : IDisposable
520 // made. Native shapes work in either case. 226 // made. Native shapes work in either case.
521 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) 227 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
522 { 228 {
523 // Update prim.BSShape to reference a hull of this shape. 229 // Use a simple, single mesh convex hull shape if the object is simple enough
524 ret = GetReferenceToHull(prim,shapeCallback); 230 BSShape potentialHull = null;
525 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
526 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
527 }
528 else
529 {
530 ret = GetReferenceToMesh(prim, shapeCallback);
531 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
532 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
533 }
534 return ret;
535 }
536
537 // Creates a native shape and assignes it to prim.BSShape.
538 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
539 private bool GetReferenceToNativeShape(BSPhysObject prim,
540 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
541 ShapeDestructionCallback shapeCallback)
542 {
543 // release any previous shape
544 DereferenceShape(prim.PhysShape, true, shapeCallback);
545
546 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
547
548 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
549 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
550 prim.LocalID, newShape, prim.Scale);
551
552 // native shapes are scaled by Bullet
553 prim.PhysShape = newShape;
554 return true;
555 }
556
557 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
558 FixedShapeKey shapeKey)
559 {
560 BulletShape newShape;
561 // Need to make sure the passed shape information is for the native type.
562 ShapeData nativeShapeData = new ShapeData();
563 nativeShapeData.Type = shapeType;
564 nativeShapeData.ID = prim.LocalID;
565 nativeShapeData.Scale = prim.Scale;
566 nativeShapeData.Size = prim.Scale; // unneeded, I think.
567 nativeShapeData.MeshKey = (ulong)shapeKey;
568 nativeShapeData.HullKey = (ulong)shapeKey;
569
570 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
571 {
572
573 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale);
574 if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
575 }
576 else
577 {
578 // Native shapes are scaled in Bullet so set the scaling to the size
579 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData);
580
581 }
582 if (!newShape.HasPhysicalShape)
583 {
584 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
585 LogHeader, prim.LocalID, shapeType);
586 }
587 newShape.shapeKey = (System.UInt64)shapeKey;
588 newShape.isNativeShape = true;
589
590 return newShape;
591 }
592
593 // Builds a mesh shape in the physical world and updates prim.BSShape.
594 // Dereferences previous shape in BSShape and adds a reference for this new shape.
595 // Returns 'true' of a mesh was actually built. Otherwise .
596 // Called at taint-time!
597 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
598 {
599 BulletShape newShape = new BulletShape();
600
601 float lod;
602 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
603
604 // if this new shape is the same as last time, don't recreate the mesh
605 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
606 return false;
607 231
608 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", 232 PrimitiveBaseShape pbs = prim.BaseShape;
609 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); 233 if (BSParam.ShouldUseSingleConvexHullForPrims
610 234 && pbs != null
611 // Since we're recreating new, get rid of the reference to the previous shape 235 && !pbs.SculptEntry
612 DereferenceShape(prim.PhysShape, true, shapeCallback); 236 && PrimHasNoCuts(pbs)
613 237 )
614 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); 238 {
615 // Take evasive action if the mesh was not constructed. 239 potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim);
616 newShape = VerifyMeshCreated(newShape, prim); 240 }
617 241 else
618 ReferenceShape(newShape); 242 {
619 243 potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
620 prim.PhysShape = newShape; 244 }
621
622 return true; // 'true' means a new shape has been added to this prim
623 }
624
625 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
626 {
627 BulletShape newShape = new BulletShape();
628 IMesh meshData = null;
629 245
630 MeshDesc meshDesc; 246 // If the current shape is not what is on the prim at the moment, time to change.
631 if (Meshes.TryGetValue(newMeshKey, out meshDesc)) 247 if (!prim.PhysShape.HasPhysicalShape
632 { 248 || potentialHull.ShapeType != prim.PhysShape.ShapeType
633 // If the mesh has already been built just use it. 249 || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
634 newShape = meshDesc.shape.Clone(); 250 {
251 DereferenceExistingShape(prim, shapeCallback);
252 prim.PhysShape = potentialHull;
253 ret = true;
254 }
255 else
256 {
257 // The current shape on the prim is the correct one. We don't need the potential reference.
258 potentialHull.Dereference(m_physicsScene);
259 }
260 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape);
635 } 261 }
636 else 262 else
637 { 263 {
638 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false); 264 // Update prim.BSShape to reference a mesh of this shape.
639 265 BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
640 if (meshData != null) 266 // If the current shape is not what is on the prim at the moment, time to change.
267 if (!prim.PhysShape.HasPhysicalShape
268 || potentialMesh.ShapeType != prim.PhysShape.ShapeType
269 || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
641 { 270 {
642 int[] indices = meshData.getIndexListAsInt(); 271 DereferenceExistingShape(prim, shapeCallback);
643 List<OMV.Vector3> vertices = meshData.getVertexList(); 272 prim.PhysShape = potentialMesh;
644 273 ret = true;
645 float[] verticesAsFloats = new float[vertices.Count * 3];
646 int vi = 0;
647 foreach (OMV.Vector3 vv in vertices)
648 {
649 verticesAsFloats[vi++] = vv.X;
650 verticesAsFloats[vi++] = vv.Y;
651 verticesAsFloats[vi++] = vv.Z;
652 }
653
654 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
655 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
656
657 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
658 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
659 } 274 }
275 else
276 {
277 // We don't need this reference to the mesh that is already being using.
278 potentialMesh.Dereference(m_physicsScene);
279 }
280 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape);
660 } 281 }
661 newShape.shapeKey = newMeshKey; 282 return ret;
662
663 return newShape;
664 }
665
666 // See that hull shape exists in the physical world and update prim.BSShape.
667 // We could be creating the hull because scale changed or whatever.
668 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
669 {
670 BulletShape newShape;
671
672 float lod;
673 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
674
675 // if the hull hasn't changed, don't rebuild it
676 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
677 return false;
678
679 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
680 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
681
682 // Remove usage of the previous shape.
683 DereferenceShape(prim.PhysShape, true, shapeCallback);
684
685 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
686 newShape = VerifyMeshCreated(newShape, prim);
687
688 ReferenceShape(newShape);
689
690 prim.PhysShape = newShape;
691 return true; // 'true' means a new shape has been added to this prim
692 } 283 }
693 284
694 List<ConvexResult> m_hulls; 285 // Track another user of a body.
695 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 286 // We presume the caller has allocated the body.
287 // Bodies only have one user so the body is just put into the world if not already there.
288 private void ReferenceBody(BulletBody body)
696 { 289 {
697 290 lock (m_collectionActivityLock)
698 BulletShape newShape = new BulletShape();
699 IntPtr hullPtr = IntPtr.Zero;
700
701 HullDesc hullDesc;
702 if (Hulls.TryGetValue(newHullKey, out hullDesc))
703 {
704 // If the hull shape already is created, just use it.
705 newShape = hullDesc.shape.Clone();
706 }
707 else
708 { 291 {
709 // Build a new hull in the physical world 292 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
710 // Pass true for physicalness as this creates some sort of bounding box which we don't need 293 if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body))
711 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false);
712 if (meshData != null)
713 { 294 {
714 295 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body);
715 int[] indices = meshData.getIndexListAsInt(); 296 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
716 List<OMV.Vector3> vertices = meshData.getVertexList();
717
718 //format conversion from IMesh format to DecompDesc format
719 List<int> convIndices = new List<int>();
720 List<float3> convVertices = new List<float3>();
721 for (int ii = 0; ii < indices.GetLength(0); ii++)
722 {
723 convIndices.Add(indices[ii]);
724 }
725 foreach (OMV.Vector3 vv in vertices)
726 {
727 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
728 }
729
730 // setup and do convex hull conversion
731 m_hulls = new List<ConvexResult>();
732 DecompDesc dcomp = new DecompDesc();
733 dcomp.mIndices = convIndices;
734 dcomp.mVertices = convVertices;
735 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
736 // create the hull into the _hulls variable
737 convexBuilder.process(dcomp);
738
739 // Convert the vertices and indices for passing to unmanaged.
740 // The hull information is passed as a large floating point array.
741 // The format is:
742 // convHulls[0] = number of hulls
743 // convHulls[1] = number of vertices in first hull
744 // convHulls[2] = hull centroid X coordinate
745 // convHulls[3] = hull centroid Y coordinate
746 // convHulls[4] = hull centroid Z coordinate
747 // convHulls[5] = first hull vertex X
748 // convHulls[6] = first hull vertex Y
749 // convHulls[7] = first hull vertex Z
750 // convHulls[8] = second hull vertex X
751 // ...
752 // convHulls[n] = number of vertices in second hull
753 // convHulls[n+1] = second hull centroid X coordinate
754 // ...
755 //
756 // TODO: is is very inefficient. Someday change the convex hull generator to return
757 // data structures that do not need to be converted in order to pass to Bullet.
758 // And maybe put the values directly into pinned memory rather than marshaling.
759 int hullCount = m_hulls.Count;
760 int totalVertices = 1; // include one for the count of the hulls
761 foreach (ConvexResult cr in m_hulls)
762 {
763 totalVertices += 4; // add four for the vertex count and centroid
764 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
765 }
766 float[] convHulls = new float[totalVertices];
767
768 convHulls[0] = (float)hullCount;
769 int jj = 1;
770 foreach (ConvexResult cr in m_hulls)
771 {
772 // copy vertices for index access
773 float3[] verts = new float3[cr.HullVertices.Count];
774 int kk = 0;
775 foreach (float3 ff in cr.HullVertices)
776 {
777 verts[kk++] = ff;
778 }
779
780 // add to the array one hull's worth of data
781 convHulls[jj++] = cr.HullIndices.Count;
782 convHulls[jj++] = 0f; // centroid x,y,z
783 convHulls[jj++] = 0f;
784 convHulls[jj++] = 0f;
785 foreach (int ind in cr.HullIndices)
786 {
787 convHulls[jj++] = verts[ind].x;
788 convHulls[jj++] = verts[ind].y;
789 convHulls[jj++] = verts[ind].z;
790 }
791 }
792 // create the hull data structure in Bullet
793 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
794 } 297 }
795 } 298 }
796
797 newShape.shapeKey = newHullKey;
798
799 return newShape;
800 } 299 }
801 300
802 // Callback from convex hull creater with a newly created hull. 301 // Release the usage of a body.
803 // Just add it to our collection of hulls for this shape. 302 // Called when releasing use of a BSBody. BSShape is handled separately.
804 private void HullReturn(ConvexResult result) 303 // Called in taint time.
805 { 304 public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback )
806 m_hulls.Add(result);
807 return;
808 }
809
810 // Compound shapes are always built from scratch.
811 // This shouldn't be to bad since most of the parts will be meshes that had been built previously.
812 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
813 { 305 {
814 // Remove reference to the old shape 306 if (!body.HasPhysicalBody)
815 // Don't need to do this as the shape is freed when the new root shape is created below. 307 return;
816 // DereferenceShape(prim.PhysShape, true, shapeCallback);
817 308
309 m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
818 310
819 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false); 311 lock (m_collectionActivityLock)
312 {
313 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
314 // If the caller needs to know the old body is going away, pass the event up.
315 if (bodyCallback != null)
316 bodyCallback(body, null);
820 317
821 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. 318 // Removing an object not in the world is a NOOP
822 CreateGeomMeshOrHull(prim, shapeCallback); 319 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body);
823 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
824 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
825 prim.LocalID, cShape, prim.PhysShape);
826 320
827 prim.PhysShape = cShape; 321 // Zero any reference to the shape so it is not freed when the body is deleted.
322 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null);
828 323
829 return true; 324 m_physicsScene.PE.DestroyObject(m_physicsScene.World, body);
830 }
831
832 // Create a hash of all the shape parameters to be used as a key
833 // for this particular shape.
834 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
835 {
836 // level of detail based on size and type of the object
837 float lod = BSParam.MeshLOD;
838 if (pbs.SculptEntry)
839 lod = BSParam.SculptLOD;
840
841 // Mega prims usually get more detail because one can interact with shape approximations at this size.
842 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
843 if (maxAxis > BSParam.MeshMegaPrimThreshold)
844 lod = BSParam.MeshMegaPrimLOD;
845
846 retLod = lod;
847 return pbs.GetMeshKey(size, lod);
848 }
849 // For those who don't want the LOD
850 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
851 {
852 float lod;
853 return ComputeShapeKey(size, pbs, out lod);
854 }
855
856 // The creation of a mesh or hull can fail if an underlying asset is not available.
857 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
858 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
859 // The first case causes the asset to be fetched. The second case requires
860 // us to not loop forever.
861 // Called after creating a physical mesh or hull. If the physical shape was created,
862 // just return.
863 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
864 {
865 // If the shape was successfully created, nothing more to do
866 if (newShape.HasPhysicalShape)
867 return newShape;
868
869 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
870 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
871 {
872 prim.LastAssetBuildFailed = true;
873 BSPhysObject xprim = prim;
874 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
875 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
876 Util.FireAndForget(delegate
877 {
878 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
879 if (assetProvider != null)
880 {
881 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
882 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
883 {
884 if (!yprim.BaseShape.SculptEntry)
885 return;
886 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
887 return;
888
889 yprim.BaseShape.SculptData = asset.Data;
890 // This will cause the prim to see that the filler shape is not the right
891 // one and try again to build the object.
892 // No race condition with the normal shape setting since the rebuild is at taint time.
893 yprim.ForceBodyShapeRebuild(false);
894
895 });
896 }
897 });
898 }
899 else
900 {
901 if (prim.LastAssetBuildFailed)
902 {
903 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
904 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture);
905 }
906 } 325 }
907
908 // While we figure out the real problem, stick a simple native shape on the object.
909 BulletShape fillinShape =
910 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
911
912 return fillinShape;
913 } 326 }
914 327
915 // Create a body object in Bullet. 328 // Create a body object in Bullet.
916 // Updates prim.BSBody with the information about the new body if one is created. 329 // Updates prim.BSBody with the information about the new body if one is created.
917 // Returns 'true' if an object was actually created. 330 // Returns 'true' if an object was actually created.
918 // Called at taint-time. 331 // Called at taint-time.
919 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape, 332 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback)
920 BodyDestructionCallback bodyCallback)
921 { 333 {
922 bool ret = false; 334 bool ret = false;
923 335
@@ -928,33 +340,34 @@ public sealed class BSShapeCollection : IDisposable
928 // If not a solid object, body is a GhostObject. Otherwise a RigidBody. 340 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
929 if (!mustRebuild) 341 if (!mustRebuild)
930 { 342 {
931 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody); 343 CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody);
932 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 344 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
933 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 345 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
934 { 346 {
935 // If the collisionObject is not the correct type for solidness, rebuild what's there 347 // If the collisionObject is not the correct type for solidness, rebuild what's there
936 mustRebuild = true; 348 mustRebuild = true;
349 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType);
937 } 350 }
938 } 351 }
939 352
940 if (mustRebuild || forceRebuild) 353 if (mustRebuild || forceRebuild)
941 { 354 {
942 // Free any old body 355 // Free any old body
943 DereferenceBody(prim.PhysBody, true, bodyCallback); 356 DereferenceBody(prim.PhysBody, bodyCallback);
944 357
945 BulletBody aBody; 358 BulletBody aBody;
946 if (prim.IsSolid) 359 if (prim.IsSolid)
947 { 360 {
948 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation); 361 aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
949 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); 362 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody);
950 } 363 }
951 else 364 else
952 { 365 {
953 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation); 366 aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
954 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); 367 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
955 } 368 }
956 369
957 ReferenceBody(aBody, true); 370 ReferenceBody(aBody);
958 371
959 prim.PhysBody = aBody; 372 prim.PhysBody = aBody;
960 373
@@ -964,46 +377,10 @@ public sealed class BSShapeCollection : IDisposable
964 return ret; 377 return ret;
965 } 378 }
966 379
967 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
968 {
969 bool ret = false;
970 MeshDesc foundDesc = new MeshDesc();
971 foreach (MeshDesc md in Meshes.Values)
972 {
973 if (md.shape.ReferenceSame(shape))
974 {
975 foundDesc = md;
976 ret = true;
977 break;
978 }
979
980 }
981 outDesc = foundDesc;
982 return ret;
983 }
984
985 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
986 {
987 bool ret = false;
988 HullDesc foundDesc = new HullDesc();
989 foreach (HullDesc hd in Hulls.Values)
990 {
991 if (hd.shape.ReferenceSame(shape))
992 {
993 foundDesc = hd;
994 ret = true;
995 break;
996 }
997
998 }
999 outDesc = foundDesc;
1000 return ret;
1001 }
1002
1003 private void DetailLog(string msg, params Object[] args) 380 private void DetailLog(string msg, params Object[] args)
1004 { 381 {
1005 if (PhysicsScene.PhysicsLogging.Enabled) 382 if (m_physicsScene.PhysicsLogging.Enabled)
1006 PhysicsScene.DetailLog(msg, args); 383 m_physicsScene.DetailLog(msg, args);
1007 } 384 }
1008} 385}
1009} 386}