diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | 479 |
1 files changed, 275 insertions, 204 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 399a133..d3ba273 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -51,7 +51,7 @@ public class BSShapeCollection : IDisposable | |||
51 | } | 51 | } |
52 | 52 | ||
53 | // Description of a hull. | 53 | // Description of a hull. |
54 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient physical objects | 54 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. |
55 | private struct HullDesc | 55 | private struct HullDesc |
56 | { | 56 | { |
57 | public IntPtr ptr; | 57 | public IntPtr ptr; |
@@ -59,17 +59,9 @@ public class BSShapeCollection : IDisposable | |||
59 | public DateTime lastReferenced; | 59 | public DateTime lastReferenced; |
60 | } | 60 | } |
61 | 61 | ||
62 | private struct BodyDesc | 62 | // The sharable set of meshes and hulls. Indexed by their shape hash. |
63 | { | 63 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); |
64 | public IntPtr ptr; | 64 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); |
65 | // Bodies are only used once so reference count is always either one or zero | ||
66 | public int referenceCount; | ||
67 | public DateTime lastReferenced; | ||
68 | } | ||
69 | |||
70 | private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>(); | ||
71 | private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>(); | ||
72 | private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>(); | ||
73 | 65 | ||
74 | public BSShapeCollection(BSScene physScene) | 66 | public BSShapeCollection(BSScene physScene) |
75 | { | 67 | { |
@@ -92,8 +84,12 @@ public class BSShapeCollection : IDisposable | |||
92 | // First checks the shape and updates that if necessary then makes | 84 | // First checks the shape and updates that if necessary then makes |
93 | // sure the body is of the right type. | 85 | // sure the body is of the right type. |
94 | // Return 'true' if either the body or the shape changed. | 86 | // Return 'true' if either the body or the shape changed. |
87 | // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before | ||
88 | // the current shape or body is destroyed. This allows the caller to remove any | ||
89 | // higher level dependencies on the shape or body. Mostly used for LinkSets to | ||
90 | // remove the physical constraints before the body is destroyed. | ||
95 | // Called at taint-time!! | 91 | // Called at taint-time!! |
96 | public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim, | 92 | public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, |
97 | ShapeData shapeData, PrimitiveBaseShape pbs, | 93 | ShapeData shapeData, PrimitiveBaseShape pbs, |
98 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) | 94 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) |
99 | { | 95 | { |
@@ -103,7 +99,8 @@ public class BSShapeCollection : IDisposable | |||
103 | lock (m_collectionActivityLock) | 99 | lock (m_collectionActivityLock) |
104 | { | 100 | { |
105 | // Do we have the correct geometry for this type of object? | 101 | // Do we have the correct geometry for this type of object? |
106 | // Updates prim.BSShape with information/pointers to requested shape | 102 | // Updates prim.BSShape with information/pointers to shape. |
103 | // CreateGeom returns 'true' of BSShape as changed to a new shape. | ||
107 | bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback); | 104 | bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback); |
108 | // If we had to select a new shape geometry for the object, | 105 | // If we had to select a new shape geometry for the object, |
109 | // rebuild the body around it. | 106 | // rebuild the body around it. |
@@ -120,26 +117,24 @@ public class BSShapeCollection : IDisposable | |||
120 | 117 | ||
121 | // Track another user of a body | 118 | // Track another user of a body |
122 | // We presume the caller has allocated the body. | 119 | // We presume the caller has allocated the body. |
123 | // Bodies only have one user so the reference count is either 1 or 0. | 120 | // Bodies only have one user so the body is just put into the world if not already there. |
124 | public void ReferenceBody(BulletBody body, bool atTaintTime) | 121 | public void ReferenceBody(BulletBody body, bool inTaintTime) |
125 | { | 122 | { |
126 | lock (m_collectionActivityLock) | 123 | lock (m_collectionActivityLock) |
127 | { | 124 | { |
128 | BodyDesc bodyDesc; | 125 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body); |
129 | if (Bodies.TryGetValue(body.ID, out bodyDesc)) | 126 | BSScene.TaintCallback createOperation = delegate() |
130 | { | 127 | { |
131 | bodyDesc.referenceCount++; | 128 | if (!BulletSimAPI.IsInWorld2(body.ptr)) |
132 | DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,body={1},ref={2}", body.ID, body, bodyDesc.referenceCount); | 129 | { |
133 | } | 130 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); |
131 | DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | ||
132 | } | ||
133 | }; | ||
134 | if (inTaintTime) | ||
135 | createOperation(); | ||
134 | else | 136 | else |
135 | { | 137 | PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation); |
136 | // New entry | ||
137 | bodyDesc.ptr = body.ptr; | ||
138 | bodyDesc.referenceCount = 1; | ||
139 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", body.ID, body, bodyDesc.referenceCount); | ||
140 | } | ||
141 | bodyDesc.lastReferenced = System.DateTime.Now; | ||
142 | Bodies[body.ID] = bodyDesc; | ||
143 | } | 138 | } |
144 | } | 139 | } |
145 | 140 | ||
@@ -152,42 +147,25 @@ public class BSShapeCollection : IDisposable | |||
152 | 147 | ||
153 | lock (m_collectionActivityLock) | 148 | lock (m_collectionActivityLock) |
154 | { | 149 | { |
155 | BodyDesc bodyDesc; | 150 | BSScene.TaintCallback removeOperation = delegate() |
156 | if (Bodies.TryGetValue(body.ID, out bodyDesc)) | ||
157 | { | 151 | { |
158 | bodyDesc.referenceCount--; | 152 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}", |
159 | bodyDesc.lastReferenced = System.DateTime.Now; | 153 | body.ID, body.ptr.ToString("X"), inTaintTime); |
160 | Bodies[body.ID] = bodyDesc; | 154 | // If the caller needs to know the old body is going away, pass the event up. |
161 | DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount); | 155 | if (bodyCallback != null) bodyCallback(body); |
162 | 156 | ||
163 | // If body is no longer being used, free it -- bodies are never shared. | 157 | // It may have already been removed from the world in which case the next is a NOOP. |
164 | if (bodyDesc.referenceCount == 0) | 158 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); |
165 | { | 159 | |
166 | Bodies.Remove(body.ID); | 160 | // Zero any reference to the shape so it is not freed when the body is deleted. |
167 | BSScene.TaintCallback removeOperation = delegate() | 161 | BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); |
168 | { | 162 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); |
169 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}", | 163 | }; |
170 | body.ID, body.ptr.ToString("X")); | 164 | // If already in taint-time, do the operations now. Otherwise queue for later. |
171 | // If the caller needs to know the old body is going away, pass the event up. | 165 | if (inTaintTime) |
172 | if (bodyCallback != null) bodyCallback(body); | 166 | removeOperation(); |
173 | |||
174 | // Zero any reference to the shape so it is not freed when the body is deleted. | ||
175 | BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); | ||
176 | // It may have already been removed from the world in which case the next is a NOOP. | ||
177 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); | ||
178 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); | ||
179 | }; | ||
180 | // If already in taint-time, do the operations now. Otherwise queue for later. | ||
181 | if (inTaintTime) | ||
182 | removeOperation(); | ||
183 | else | ||
184 | PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation); | ||
185 | } | ||
186 | } | ||
187 | else | 167 | else |
188 | { | 168 | PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation); |
189 | DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount); | ||
190 | } | ||
191 | } | 169 | } |
192 | } | 170 | } |
193 | 171 | ||
@@ -208,7 +186,7 @@ public class BSShapeCollection : IDisposable | |||
208 | { | 186 | { |
209 | // There is an existing instance of this mesh. | 187 | // There is an existing instance of this mesh. |
210 | meshDesc.referenceCount++; | 188 | meshDesc.referenceCount++; |
211 | DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}", | 189 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", |
212 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 190 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
213 | } | 191 | } |
214 | else | 192 | else |
@@ -217,7 +195,7 @@ public class BSShapeCollection : IDisposable | |||
217 | meshDesc.ptr = shape.ptr; | 195 | meshDesc.ptr = shape.ptr; |
218 | // We keep a reference to the underlying IMesh data so a hull can be built | 196 | // We keep a reference to the underlying IMesh data so a hull can be built |
219 | meshDesc.referenceCount = 1; | 197 | meshDesc.referenceCount = 1; |
220 | DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}", | 198 | DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", |
221 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 199 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
222 | ret = true; | 200 | ret = true; |
223 | } | 201 | } |
@@ -230,7 +208,7 @@ public class BSShapeCollection : IDisposable | |||
230 | { | 208 | { |
231 | // There is an existing instance of this hull. | 209 | // There is an existing instance of this hull. |
232 | hullDesc.referenceCount++; | 210 | hullDesc.referenceCount++; |
233 | DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}", | 211 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", |
234 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 212 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
235 | } | 213 | } |
236 | else | 214 | else |
@@ -238,7 +216,7 @@ public class BSShapeCollection : IDisposable | |||
238 | // This is a new reference to a hull | 216 | // This is a new reference to a hull |
239 | hullDesc.ptr = shape.ptr; | 217 | hullDesc.ptr = shape.ptr; |
240 | hullDesc.referenceCount = 1; | 218 | hullDesc.referenceCount = 1; |
241 | DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}", | 219 | DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", |
242 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 220 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
243 | ret = true; | 221 | ret = true; |
244 | 222 | ||
@@ -256,37 +234,42 @@ public class BSShapeCollection : IDisposable | |||
256 | } | 234 | } |
257 | 235 | ||
258 | // Release the usage of a shape. | 236 | // Release the usage of a shape. |
259 | // The collisionObject is released since it is a copy of the real collision shape. | 237 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) |
260 | public void DereferenceShape(BulletShape shape, bool atTaintTime, ShapeDestructionCallback shapeCallback) | ||
261 | { | 238 | { |
262 | if (shape.ptr == IntPtr.Zero) | 239 | if (shape.ptr == IntPtr.Zero) |
263 | return; | 240 | return; |
264 | 241 | ||
265 | BSScene.TaintCallback dereferenceOperation = delegate() | 242 | BSScene.TaintCallback dereferenceOperation = delegate() |
266 | { | 243 | { |
267 | switch (shape.type) | 244 | if (shape.ptr != IntPtr.Zero) |
268 | { | 245 | { |
269 | case ShapeData.PhysicsShapeType.SHAPE_HULL: | 246 | if (shape.isNativeShape) |
270 | DereferenceHull(shape, shapeCallback); | 247 | { |
271 | break; | ||
272 | case ShapeData.PhysicsShapeType.SHAPE_MESH: | ||
273 | DereferenceMesh(shape, shapeCallback); | ||
274 | break; | ||
275 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: | ||
276 | break; | ||
277 | default: | ||
278 | // Native shapes are not tracked and are released immediately | 248 | // Native shapes are not tracked and are released immediately |
279 | if (shape.ptr != IntPtr.Zero & shape.isNativeShape) | 249 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", |
250 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); | ||
251 | if (shapeCallback != null) shapeCallback(shape); | ||
252 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | ||
253 | } | ||
254 | else | ||
255 | { | ||
256 | switch (shape.type) | ||
280 | { | 257 | { |
281 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", | 258 | case ShapeData.PhysicsShapeType.SHAPE_HULL: |
282 | BSScene.DetailLogZero, shape.ptr.ToString("X"), atTaintTime); | 259 | DereferenceHull(shape, shapeCallback); |
283 | if (shapeCallback != null) shapeCallback(shape); | 260 | break; |
284 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | 261 | case ShapeData.PhysicsShapeType.SHAPE_MESH: |
262 | DereferenceMesh(shape, shapeCallback); | ||
263 | break; | ||
264 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: | ||
265 | break; | ||
266 | default: | ||
267 | break; | ||
285 | } | 268 | } |
286 | break; | 269 | } |
287 | } | 270 | } |
288 | }; | 271 | }; |
289 | if (atTaintTime) | 272 | if (inTaintTime) |
290 | { | 273 | { |
291 | lock (m_collectionActivityLock) | 274 | lock (m_collectionActivityLock) |
292 | { | 275 | { |
@@ -336,19 +319,31 @@ public class BSShapeCollection : IDisposable | |||
336 | 319 | ||
337 | // Create the geometry information in Bullet for later use. | 320 | // Create the geometry information in Bullet for later use. |
338 | // The objects needs a hull if it's physical otherwise a mesh is enough. | 321 | // The objects needs a hull if it's physical otherwise a mesh is enough. |
339 | // No locking here because this is done when we know physics is not simulating. | 322 | // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls, |
340 | // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used. | 323 | // shared geometries will be used. If the parameters of the existing shape are the same |
324 | // as this request, the shape is not rebuilt. | ||
325 | // Info in prim.BSShape is updated to the new shape. | ||
341 | // Returns 'true' if the geometry was rebuilt. | 326 | // Returns 'true' if the geometry was rebuilt. |
342 | // Called at taint-time! | 327 | // Called at taint-time! |
343 | private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData, | 328 | private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData, |
344 | PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback) | 329 | PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback) |
345 | { | 330 | { |
346 | bool ret = false; | 331 | bool ret = false; |
347 | bool haveShape = false; | 332 | bool haveShape = false; |
348 | bool nativeShapePossible = true; | 333 | bool nativeShapePossible = true; |
349 | 334 | ||
335 | if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | ||
336 | { | ||
337 | // an avatar capsule is close to a native shape (it is not shared) | ||
338 | ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR, | ||
339 | ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback); | ||
340 | DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape); | ||
341 | haveShape = true; | ||
342 | } | ||
350 | // If the prim attributes are simple, this could be a simple Bullet native shape | 343 | // If the prim attributes are simple, this could be a simple Bullet native shape |
351 | if (nativeShapePossible | 344 | if (!haveShape |
345 | && pbs != null | ||
346 | && nativeShapePossible | ||
352 | && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) | 347 | && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) |
353 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | 348 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 |
354 | && pbs.ProfileHollow == 0 | 349 | && pbs.ProfileHollow == 0 |
@@ -358,7 +353,8 @@ public class BSShapeCollection : IDisposable | |||
358 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | 353 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 |
359 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | 354 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) |
360 | { | 355 | { |
361 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | 356 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) |
357 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) | ||
362 | { | 358 | { |
363 | haveShape = true; | 359 | haveShape = true; |
364 | if (forceRebuild | 360 | if (forceRebuild |
@@ -372,7 +368,7 @@ public class BSShapeCollection : IDisposable | |||
372 | prim.LocalID, forceRebuild, prim.BSShape); | 368 | prim.LocalID, forceRebuild, prim.BSShape); |
373 | } | 369 | } |
374 | } | 370 | } |
375 | else | 371 | if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) |
376 | { | 372 | { |
377 | haveShape = true; | 373 | haveShape = true; |
378 | if (forceRebuild | 374 | if (forceRebuild |
@@ -390,9 +386,9 @@ public class BSShapeCollection : IDisposable | |||
390 | // If a simple shape is not happening, create a mesh and possibly a hull. | 386 | // If a simple shape is not happening, create a mesh and possibly a hull. |
391 | // Note that if it's a native shape, the check for physical/non-physical is not | 387 | // Note that if it's a native shape, the check for physical/non-physical is not |
392 | // made. Native shapes are best used in either case. | 388 | // made. Native shapes are best used in either case. |
393 | if (!haveShape) | 389 | if (!haveShape && pbs != null) |
394 | { | 390 | { |
395 | if (prim.IsPhysical) | 391 | if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) |
396 | { | 392 | { |
397 | // Update prim.BSShape to reference a hull of this shape. | 393 | // Update prim.BSShape to reference a hull of this shape. |
398 | ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback); | 394 | ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback); |
@@ -409,12 +405,12 @@ public class BSShapeCollection : IDisposable | |||
409 | return ret; | 405 | return ret; |
410 | } | 406 | } |
411 | 407 | ||
412 | // Creates a native shape and assignes it to prim.BSShape | 408 | // Creates a native shape and assignes it to prim.BSShape. |
413 | private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData, | 409 | // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). |
410 | private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData, | ||
414 | ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, | 411 | ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, |
415 | ShapeDestructionCallback shapeCallback) | 412 | ShapeDestructionCallback shapeCallback) |
416 | { | 413 | { |
417 | BulletShape newShape; | ||
418 | 414 | ||
419 | shapeData.Type = shapeType; | 415 | shapeData.Type = shapeType; |
420 | // Bullet native objects are scaled by the Bullet engine so pass the size in | 416 | // Bullet native objects are scaled by the Bullet engine so pass the size in |
@@ -424,29 +420,48 @@ public class BSShapeCollection : IDisposable | |||
424 | // release any previous shape | 420 | // release any previous shape |
425 | DereferenceShape(prim.BSShape, true, shapeCallback); | 421 | DereferenceShape(prim.BSShape, true, shapeCallback); |
426 | 422 | ||
427 | // Native shapes are always built independently. | 423 | BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey); |
428 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); | ||
429 | newShape.shapeKey = (ulong)shapeKey; | ||
430 | newShape.isNativeShape = true; | ||
431 | 424 | ||
432 | // Don't need to do a 'ReferenceShape()' here because native shapes are not tracked. | 425 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. |
433 | // DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape); | 426 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", |
427 | shapeData.ID, newShape, shapeData.Scale); | ||
434 | 428 | ||
435 | prim.BSShape = newShape; | 429 | prim.BSShape = newShape; |
436 | return true; | 430 | return true; |
437 | } | 431 | } |
438 | 432 | ||
433 | private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType, | ||
434 | ShapeData shapeData, ShapeData.FixedShapeKey shapeKey) | ||
435 | { | ||
436 | BulletShape newShape; | ||
437 | |||
438 | if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | ||
439 | { | ||
440 | newShape = new BulletShape( | ||
441 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale), | ||
442 | shapeType); | ||
443 | } | ||
444 | else | ||
445 | { | ||
446 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); | ||
447 | } | ||
448 | newShape.shapeKey = (System.UInt64)shapeKey; | ||
449 | newShape.isNativeShape = true; | ||
450 | |||
451 | return newShape; | ||
452 | } | ||
453 | |||
439 | // Builds a mesh shape in the physical world and updates prim.BSShape. | 454 | // Builds a mesh shape in the physical world and updates prim.BSShape. |
440 | // Dereferences previous shape in BSShape and adds a reference for this new shape. | 455 | // Dereferences previous shape in BSShape and adds a reference for this new shape. |
441 | // Returns 'true' of a mesh was actually built. Otherwise . | 456 | // Returns 'true' of a mesh was actually built. Otherwise . |
442 | // Called at taint-time! | 457 | // Called at taint-time! |
443 | private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs, | 458 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs, |
444 | ShapeDestructionCallback shapeCallback) | 459 | ShapeDestructionCallback shapeCallback) |
445 | { | 460 | { |
446 | BulletShape newShape = new BulletShape(IntPtr.Zero); | 461 | BulletShape newShape = new BulletShape(IntPtr.Zero); |
447 | 462 | ||
448 | float lod; | 463 | float lod; |
449 | ulong newMeshKey = ComputeShapeKey(shapeData, pbs, out lod); | 464 | System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, out lod); |
450 | 465 | ||
451 | // if this new shape is the same as last time, don't recreate the mesh | 466 | // if this new shape is the same as last time, don't recreate the mesh |
452 | if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) | 467 | if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) |
@@ -459,6 +474,8 @@ public class BSShapeCollection : IDisposable | |||
459 | DereferenceShape(prim.BSShape, true, shapeCallback); | 474 | DereferenceShape(prim.BSShape, true, shapeCallback); |
460 | 475 | ||
461 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); | 476 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); |
477 | // Take evasive action if the mesh was not constructed. | ||
478 | newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); | ||
462 | 479 | ||
463 | ReferenceShape(newShape); | 480 | ReferenceShape(newShape); |
464 | 481 | ||
@@ -469,10 +486,10 @@ public class BSShapeCollection : IDisposable | |||
469 | return true; // 'true' means a new shape has been added to this prim | 486 | return true; // 'true' means a new shape has been added to this prim |
470 | } | 487 | } |
471 | 488 | ||
472 | private BulletShape CreatePhysicalMesh(string objName, ulong newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 489 | private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
473 | { | 490 | { |
474 | IMesh meshData = null; | 491 | IMesh meshData = null; |
475 | IntPtr meshPtr; | 492 | IntPtr meshPtr = IntPtr.Zero; |
476 | MeshDesc meshDesc; | 493 | MeshDesc meshDesc; |
477 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) | 494 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) |
478 | { | 495 | { |
@@ -484,23 +501,26 @@ public class BSShapeCollection : IDisposable | |||
484 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 501 | // Pass false for physicalness as this creates some sort of bounding box which we don't need |
485 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 502 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); |
486 | 503 | ||
487 | int[] indices = meshData.getIndexListAsInt(); | 504 | if (meshData != null) |
488 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
489 | |||
490 | float[] verticesAsFloats = new float[vertices.Count * 3]; | ||
491 | int vi = 0; | ||
492 | foreach (OMV.Vector3 vv in vertices) | ||
493 | { | 505 | { |
494 | verticesAsFloats[vi++] = vv.X; | 506 | int[] indices = meshData.getIndexListAsInt(); |
495 | verticesAsFloats[vi++] = vv.Y; | 507 | List<OMV.Vector3> vertices = meshData.getVertexList(); |
496 | verticesAsFloats[vi++] = vv.Z; | 508 | |
497 | } | 509 | float[] verticesAsFloats = new float[vertices.Count * 3]; |
510 | int vi = 0; | ||
511 | foreach (OMV.Vector3 vv in vertices) | ||
512 | { | ||
513 | verticesAsFloats[vi++] = vv.X; | ||
514 | verticesAsFloats[vi++] = vv.Y; | ||
515 | verticesAsFloats[vi++] = vv.Z; | ||
516 | } | ||
498 | 517 | ||
499 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | 518 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", |
500 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | 519 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); |
501 | 520 | ||
502 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 521 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, |
503 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); | 522 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); |
523 | } | ||
504 | } | 524 | } |
505 | BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); | 525 | BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); |
506 | newShape.shapeKey = newMeshKey; | 526 | newShape.shapeKey = newMeshKey; |
@@ -510,13 +530,13 @@ public class BSShapeCollection : IDisposable | |||
510 | 530 | ||
511 | // See that hull shape exists in the physical world and update prim.BSShape. | 531 | // See that hull shape exists in the physical world and update prim.BSShape. |
512 | // We could be creating the hull because scale changed or whatever. | 532 | // We could be creating the hull because scale changed or whatever. |
513 | private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs, | 533 | private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs, |
514 | ShapeDestructionCallback shapeCallback) | 534 | ShapeDestructionCallback shapeCallback) |
515 | { | 535 | { |
516 | BulletShape newShape; | 536 | BulletShape newShape; |
517 | 537 | ||
518 | float lod; | 538 | float lod; |
519 | ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod); | 539 | System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, out lod); |
520 | 540 | ||
521 | // if the hull hasn't changed, don't rebuild it | 541 | // if the hull hasn't changed, don't rebuild it |
522 | if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) | 542 | if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) |
@@ -525,10 +545,11 @@ public class BSShapeCollection : IDisposable | |||
525 | DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", | 545 | DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", |
526 | prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | 546 | prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X")); |
527 | 547 | ||
528 | // Remove usage of the previous shape. Also removes reference to underlying mesh if it is a hull. | 548 | // Remove usage of the previous shape. |
529 | DereferenceShape(prim.BSShape, true, shapeCallback); | 549 | DereferenceShape(prim.BSShape, true, shapeCallback); |
530 | 550 | ||
531 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); | 551 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); |
552 | newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); | ||
532 | 553 | ||
533 | ReferenceShape(newShape); | 554 | ReferenceShape(newShape); |
534 | 555 | ||
@@ -539,10 +560,10 @@ public class BSShapeCollection : IDisposable | |||
539 | } | 560 | } |
540 | 561 | ||
541 | List<ConvexResult> m_hulls; | 562 | List<ConvexResult> m_hulls; |
542 | private BulletShape CreatePhysicalHull(string objName, ulong newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 563 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
543 | { | 564 | { |
544 | 565 | ||
545 | IntPtr hullPtr; | 566 | IntPtr hullPtr = IntPtr.Zero; |
546 | HullDesc hullDesc; | 567 | HullDesc hullDesc; |
547 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) | 568 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) |
548 | { | 569 | { |
@@ -554,86 +575,89 @@ public class BSShapeCollection : IDisposable | |||
554 | // Build a new hull in the physical world | 575 | // Build a new hull in the physical world |
555 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 576 | // Pass false for physicalness as this creates some sort of bounding box which we don't need |
556 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 577 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); |
557 | 578 | if (meshData != null) | |
558 | int[] indices = meshData.getIndexListAsInt(); | ||
559 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
560 | |||
561 | //format conversion from IMesh format to DecompDesc format | ||
562 | List<int> convIndices = new List<int>(); | ||
563 | List<float3> convVertices = new List<float3>(); | ||
564 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
565 | { | 579 | { |
566 | convIndices.Add(indices[ii]); | ||
567 | } | ||
568 | foreach (OMV.Vector3 vv in vertices) | ||
569 | { | ||
570 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
571 | } | ||
572 | 580 | ||
573 | // setup and do convex hull conversion | 581 | int[] indices = meshData.getIndexListAsInt(); |
574 | m_hulls = new List<ConvexResult>(); | 582 | List<OMV.Vector3> vertices = meshData.getVertexList(); |
575 | DecompDesc dcomp = new DecompDesc(); | ||
576 | dcomp.mIndices = convIndices; | ||
577 | dcomp.mVertices = convVertices; | ||
578 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
579 | // create the hull into the _hulls variable | ||
580 | convexBuilder.process(dcomp); | ||
581 | |||
582 | // Convert the vertices and indices for passing to unmanaged. | ||
583 | // The hull information is passed as a large floating point array. | ||
584 | // The format is: | ||
585 | // convHulls[0] = number of hulls | ||
586 | // convHulls[1] = number of vertices in first hull | ||
587 | // convHulls[2] = hull centroid X coordinate | ||
588 | // convHulls[3] = hull centroid Y coordinate | ||
589 | // convHulls[4] = hull centroid Z coordinate | ||
590 | // convHulls[5] = first hull vertex X | ||
591 | // convHulls[6] = first hull vertex Y | ||
592 | // convHulls[7] = first hull vertex Z | ||
593 | // convHulls[8] = second hull vertex X | ||
594 | // ... | ||
595 | // convHulls[n] = number of vertices in second hull | ||
596 | // convHulls[n+1] = second hull centroid X coordinate | ||
597 | // ... | ||
598 | // | ||
599 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
600 | // data structures that do not need to be converted in order to pass to Bullet. | ||
601 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
602 | int hullCount = m_hulls.Count; | ||
603 | int totalVertices = 1; // include one for the count of the hulls | ||
604 | foreach (ConvexResult cr in m_hulls) | ||
605 | { | ||
606 | totalVertices += 4; // add four for the vertex count and centroid | ||
607 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
608 | } | ||
609 | float[] convHulls = new float[totalVertices]; | ||
610 | 583 | ||
611 | convHulls[0] = (float)hullCount; | 584 | //format conversion from IMesh format to DecompDesc format |
612 | int jj = 1; | 585 | List<int> convIndices = new List<int>(); |
613 | foreach (ConvexResult cr in m_hulls) | 586 | List<float3> convVertices = new List<float3>(); |
614 | { | 587 | for (int ii = 0; ii < indices.GetLength(0); ii++) |
615 | // copy vertices for index access | 588 | { |
616 | float3[] verts = new float3[cr.HullVertices.Count]; | 589 | convIndices.Add(indices[ii]); |
617 | int kk = 0; | 590 | } |
618 | foreach (float3 ff in cr.HullVertices) | 591 | foreach (OMV.Vector3 vv in vertices) |
592 | { | ||
593 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
594 | } | ||
595 | |||
596 | // setup and do convex hull conversion | ||
597 | m_hulls = new List<ConvexResult>(); | ||
598 | DecompDesc dcomp = new DecompDesc(); | ||
599 | dcomp.mIndices = convIndices; | ||
600 | dcomp.mVertices = convVertices; | ||
601 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
602 | // create the hull into the _hulls variable | ||
603 | convexBuilder.process(dcomp); | ||
604 | |||
605 | // Convert the vertices and indices for passing to unmanaged. | ||
606 | // The hull information is passed as a large floating point array. | ||
607 | // The format is: | ||
608 | // convHulls[0] = number of hulls | ||
609 | // convHulls[1] = number of vertices in first hull | ||
610 | // convHulls[2] = hull centroid X coordinate | ||
611 | // convHulls[3] = hull centroid Y coordinate | ||
612 | // convHulls[4] = hull centroid Z coordinate | ||
613 | // convHulls[5] = first hull vertex X | ||
614 | // convHulls[6] = first hull vertex Y | ||
615 | // convHulls[7] = first hull vertex Z | ||
616 | // convHulls[8] = second hull vertex X | ||
617 | // ... | ||
618 | // convHulls[n] = number of vertices in second hull | ||
619 | // convHulls[n+1] = second hull centroid X coordinate | ||
620 | // ... | ||
621 | // | ||
622 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
623 | // data structures that do not need to be converted in order to pass to Bullet. | ||
624 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
625 | int hullCount = m_hulls.Count; | ||
626 | int totalVertices = 1; // include one for the count of the hulls | ||
627 | foreach (ConvexResult cr in m_hulls) | ||
619 | { | 628 | { |
620 | verts[kk++] = ff; | 629 | totalVertices += 4; // add four for the vertex count and centroid |
630 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
621 | } | 631 | } |
632 | float[] convHulls = new float[totalVertices]; | ||
622 | 633 | ||
623 | // add to the array one hull's worth of data | 634 | convHulls[0] = (float)hullCount; |
624 | convHulls[jj++] = cr.HullIndices.Count; | 635 | int jj = 1; |
625 | convHulls[jj++] = 0f; // centroid x,y,z | 636 | foreach (ConvexResult cr in m_hulls) |
626 | convHulls[jj++] = 0f; | ||
627 | convHulls[jj++] = 0f; | ||
628 | foreach (int ind in cr.HullIndices) | ||
629 | { | 637 | { |
630 | convHulls[jj++] = verts[ind].x; | 638 | // copy vertices for index access |
631 | convHulls[jj++] = verts[ind].y; | 639 | float3[] verts = new float3[cr.HullVertices.Count]; |
632 | convHulls[jj++] = verts[ind].z; | 640 | int kk = 0; |
641 | foreach (float3 ff in cr.HullVertices) | ||
642 | { | ||
643 | verts[kk++] = ff; | ||
644 | } | ||
645 | |||
646 | // add to the array one hull's worth of data | ||
647 | convHulls[jj++] = cr.HullIndices.Count; | ||
648 | convHulls[jj++] = 0f; // centroid x,y,z | ||
649 | convHulls[jj++] = 0f; | ||
650 | convHulls[jj++] = 0f; | ||
651 | foreach (int ind in cr.HullIndices) | ||
652 | { | ||
653 | convHulls[jj++] = verts[ind].x; | ||
654 | convHulls[jj++] = verts[ind].y; | ||
655 | convHulls[jj++] = verts[ind].z; | ||
656 | } | ||
633 | } | 657 | } |
658 | // create the hull data structure in Bullet | ||
659 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); | ||
634 | } | 660 | } |
635 | // create the hull data structure in Bullet | ||
636 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); | ||
637 | } | 661 | } |
638 | 662 | ||
639 | BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); | 663 | BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); |
@@ -652,32 +676,77 @@ public class BSShapeCollection : IDisposable | |||
652 | 676 | ||
653 | // Create a hash of all the shape parameters to be used as a key | 677 | // Create a hash of all the shape parameters to be used as a key |
654 | // for this particular shape. | 678 | // for this particular shape. |
655 | private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod) | 679 | private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod) |
656 | { | 680 | { |
657 | // level of detail based on size and type of the object | 681 | // level of detail based on size and type of the object |
658 | float lod = PhysicsScene.MeshLOD; | 682 | float lod = PhysicsScene.MeshLOD; |
659 | if (pbs.SculptEntry) | 683 | if (pbs.SculptEntry) |
660 | lod = PhysicsScene.SculptLOD; | 684 | lod = PhysicsScene.SculptLOD; |
661 | 685 | ||
686 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | ||
662 | float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z)); | 687 | float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z)); |
663 | if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) | 688 | if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) |
664 | lod = PhysicsScene.MeshMegaPrimLOD; | 689 | lod = PhysicsScene.MeshMegaPrimLOD; |
665 | 690 | ||
666 | retLod = lod; | 691 | retLod = lod; |
667 | return (ulong)pbs.GetMeshKey(shapeData.Size, lod); | 692 | return pbs.GetMeshKey(shapeData.Size, lod); |
668 | } | 693 | } |
669 | // For those who don't want the LOD | 694 | // For those who don't want the LOD |
670 | private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs) | 695 | private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs) |
671 | { | 696 | { |
672 | float lod; | 697 | float lod; |
673 | return ComputeShapeKey(shapeData, pbs, out lod); | 698 | return ComputeShapeKey(shapeData, pbs, out lod); |
674 | } | 699 | } |
675 | 700 | ||
701 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs) | ||
702 | { | ||
703 | // If the shape was successfully created, nothing more to do | ||
704 | if (newShape.ptr != IntPtr.Zero) | ||
705 | return newShape; | ||
706 | |||
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 | ||
710 | if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero) | ||
711 | { | ||
712 | prim.LastAssetBuildFailed = true; | ||
713 | BSPhysObject xprim = prim; | ||
714 | Util.FireAndForget(delegate | ||
715 | { | ||
716 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; | ||
717 | if (assetProvider != null) | ||
718 | { | ||
719 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | ||
720 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | ||
721 | { | ||
722 | if (!yprim.BaseShape.SculptEntry) | ||
723 | return; | ||
724 | if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) | ||
725 | return; | ||
726 | |||
727 | yprim.BaseShape.SculptData = new byte[asset.Data.Length]; | ||
728 | asset.Data.CopyTo(yprim.BaseShape.SculptData, 0); | ||
729 | // This will cause the prim to see that the filler shape is not the right | ||
730 | // one and try again to build the object. | ||
731 | yprim.ForceBodyShapeRebuild(false); | ||
732 | |||
733 | }); | ||
734 | } | ||
735 | }); | ||
736 | } | ||
737 | |||
738 | // While we figure out the real problem, stick a simple native shape on the object. | ||
739 | BulletShape fillinShape = | ||
740 | BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE); | ||
741 | |||
742 | return fillinShape; | ||
743 | } | ||
744 | |||
676 | // Create a body object in Bullet. | 745 | // Create a body object in Bullet. |
677 | // Updates prim.BSBody with the information about the new body if one is created. | 746 | // Updates prim.BSBody with the information about the new body if one is created. |
678 | // Returns 'true' if an object was actually created. | 747 | // Returns 'true' if an object was actually created. |
679 | // Called at taint-time. | 748 | // Called at taint-time. |
680 | private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape, | 749 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, |
681 | ShapeData shapeData, BodyDestructionCallback bodyCallback) | 750 | ShapeData shapeData, BodyDestructionCallback bodyCallback) |
682 | { | 751 | { |
683 | bool ret = false; | 752 | bool ret = false; |
@@ -701,6 +770,7 @@ public class BSShapeCollection : IDisposable | |||
701 | 770 | ||
702 | if (mustRebuild || forceRebuild) | 771 | if (mustRebuild || forceRebuild) |
703 | { | 772 | { |
773 | // Free any old body | ||
704 | DereferenceBody(prim.BSBody, true, bodyCallback); | 774 | DereferenceBody(prim.BSBody, true, bodyCallback); |
705 | 775 | ||
706 | BulletBody aBody; | 776 | BulletBody aBody; |
@@ -709,13 +779,13 @@ public class BSShapeCollection : IDisposable | |||
709 | { | 779 | { |
710 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, | 780 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, |
711 | shapeData.ID, shapeData.Position, shapeData.Rotation); | 781 | shapeData.ID, shapeData.Position, shapeData.Rotation); |
712 | // DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 782 | DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
713 | } | 783 | } |
714 | else | 784 | else |
715 | { | 785 | { |
716 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, | 786 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, |
717 | shapeData.ID, shapeData.Position, shapeData.Rotation); | 787 | shapeData.ID, shapeData.Position, shapeData.Rotation); |
718 | // DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 788 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
719 | } | 789 | } |
720 | aBody = new BulletBody(shapeData.ID, bodyPtr); | 790 | aBody = new BulletBody(shapeData.ID, bodyPtr); |
721 | 791 | ||
@@ -731,7 +801,8 @@ public class BSShapeCollection : IDisposable | |||
731 | 801 | ||
732 | private void DetailLog(string msg, params Object[] args) | 802 | private void DetailLog(string msg, params Object[] args) |
733 | { | 803 | { |
734 | PhysicsScene.PhysicsLogging.Write(msg, args); | 804 | if (PhysicsScene.PhysicsLogging.Enabled) |
805 | PhysicsScene.DetailLog(msg, args); | ||
735 | } | 806 | } |
736 | } | 807 | } |
737 | } | 808 | } |