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