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