diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | 344 |
1 files changed, 249 insertions, 95 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 7470d23..6b90661 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -38,8 +38,9 @@ public class BSShapeCollection : IDisposable | |||
38 | { | 38 | { |
39 | protected BSScene PhysicsScene { get; set; } | 39 | protected BSScene PhysicsScene { get; set; } |
40 | 40 | ||
41 | private Object m_shapeActivityLock = new Object(); | 41 | private Object m_collectionActivityLock = new Object(); |
42 | 42 | ||
43 | // Description of a Mesh | ||
43 | private struct MeshDesc | 44 | private struct MeshDesc |
44 | { | 45 | { |
45 | public IntPtr Ptr; | 46 | public IntPtr Ptr; |
@@ -48,6 +49,8 @@ public class BSShapeCollection : IDisposable | |||
48 | public IMesh meshData; | 49 | public IMesh meshData; |
49 | } | 50 | } |
50 | 51 | ||
52 | // Description of a hull. | ||
53 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient physical objects | ||
51 | private struct HullDesc | 54 | private struct HullDesc |
52 | { | 55 | { |
53 | public IntPtr Ptr; | 56 | public IntPtr Ptr; |
@@ -55,8 +58,17 @@ public class BSShapeCollection : IDisposable | |||
55 | public DateTime lastReferenced; | 58 | public DateTime lastReferenced; |
56 | } | 59 | } |
57 | 60 | ||
61 | private struct BodyDesc | ||
62 | { | ||
63 | public IntPtr Ptr; | ||
64 | // Bodies are only used once so reference count is always either one or zero | ||
65 | public int referenceCount; | ||
66 | public DateTime lastReferenced; | ||
67 | } | ||
68 | |||
58 | private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>(); | 69 | private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>(); |
59 | private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>(); | 70 | private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>(); |
71 | private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>(); | ||
60 | 72 | ||
61 | public BSShapeCollection(BSScene physScene) | 73 | public BSShapeCollection(BSScene physScene) |
62 | { | 74 | { |
@@ -65,6 +77,7 @@ public class BSShapeCollection : IDisposable | |||
65 | 77 | ||
66 | public void Dispose() | 78 | public void Dispose() |
67 | { | 79 | { |
80 | // TODO!!!!!!!!! | ||
68 | } | 81 | } |
69 | 82 | ||
70 | // Called to update/change the body and shape for an object. | 83 | // Called to update/change the body and shape for an object. |
@@ -76,40 +89,104 @@ public class BSShapeCollection : IDisposable | |||
76 | { | 89 | { |
77 | bool ret = false; | 90 | bool ret = false; |
78 | 91 | ||
79 | // Do we have the correct geometry for this type of object? | 92 | // This lock could probably be pushed down lower but building shouldn't take long |
80 | if (CreateGeom(forceRebuild, prim, shapeData, pbs)) | 93 | lock (m_collectionActivityLock) |
81 | { | 94 | { |
95 | // Do we have the correct geometry for this type of object? | ||
96 | bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs); | ||
82 | // If we had to select a new shape geometry for the object, | 97 | // If we had to select a new shape geometry for the object, |
83 | // rebuild the body around it. | 98 | // rebuild the body around it. |
84 | CreateObject(true, prim, PhysicsScene.World, prim.BSShape, shapeData); | 99 | bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, prim.BSShape, shapeData); |
85 | ret = true; | 100 | ret = newGeom || newBody; |
86 | } | 101 | } |
102 | DetailLog("{0},BSShapeCollection.GetBodyAndShape,force-{1},ret={2},body={3},shape={4}", | ||
103 | prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape); | ||
87 | 104 | ||
88 | return ret; | 105 | return ret; |
89 | } | 106 | } |
90 | 107 | ||
91 | // Track another user of a body | 108 | // Track another user of a body |
92 | public void ReferenceBody(BulletBody shape) | 109 | // We presume the caller has allocated the body. |
110 | // Bodies only have one user so the reference count is either 1 or 0. | ||
111 | public void ReferenceBody(BulletBody shape, bool atTaintTime) | ||
93 | { | 112 | { |
94 | } | 113 | lock (m_collectionActivityLock) |
114 | { | ||
115 | BodyDesc bodyDesc; | ||
116 | if (Bodies.TryGetValue(shape.ID, out bodyDesc)) | ||
117 | { | ||
118 | bodyDesc.referenceCount++; | ||
119 | DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,ref={1}", shape.ID, bodyDesc.referenceCount); | ||
120 | } | ||
121 | else | ||
122 | { | ||
123 | bodyDesc.Ptr = shape.ptr; | ||
124 | bodyDesc.referenceCount = 1; | ||
125 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", shape.ID, bodyDesc.referenceCount); | ||
126 | } | ||
127 | bodyDesc.lastReferenced = System.DateTime.Now; | ||
128 | Bodies[shape.ID] = bodyDesc; | ||
129 | } | ||
130 | } | ||
95 | 131 | ||
96 | // Release the usage of a body | 132 | // Release the usage of a body. |
97 | public void DereferenceBody(BulletBody shape) | 133 | // Not that this will also delete the body in BUllet if the body is now unused (reference count = 0). |
134 | public void DereferenceBody(BulletBody shape, bool inTaintTime) | ||
98 | { | 135 | { |
136 | if (shape.ptr == IntPtr.Zero) | ||
137 | return; | ||
138 | |||
139 | lock (m_collectionActivityLock) | ||
140 | { | ||
141 | BodyDesc bodyDesc; | ||
142 | if (Bodies.TryGetValue(shape.ID, out bodyDesc)) | ||
143 | { | ||
144 | bodyDesc.referenceCount--; | ||
145 | bodyDesc.lastReferenced = System.DateTime.Now; | ||
146 | Bodies[shape.ID] = bodyDesc; | ||
147 | DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", shape.ID, bodyDesc.referenceCount); | ||
148 | |||
149 | if (bodyDesc.referenceCount == 0) | ||
150 | { | ||
151 | Bodies.Remove(shape.ID); | ||
152 | BSScene.TaintCallback removeOperation = delegate() | ||
153 | { | ||
154 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. Ptr={1:X}", shape.ID, shape.ptr); | ||
155 | // zero any reference to the shape so it is not freed when the body is deleted | ||
156 | BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, shape.ptr, IntPtr.Zero); | ||
157 | // It may have already been removed from the world in which case the next is a NOOP | ||
158 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, shape.ptr); | ||
159 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, shape.ptr); | ||
160 | }; | ||
161 | // If already in taint-time, do the operations now. Otherwise queue for later. | ||
162 | if (inTaintTime) | ||
163 | removeOperation(); | ||
164 | else | ||
165 | PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation); | ||
166 | } | ||
167 | } | ||
168 | else | ||
169 | { | ||
170 | DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", shape.ID, bodyDesc.referenceCount); | ||
171 | } | ||
172 | } | ||
99 | } | 173 | } |
100 | 174 | ||
101 | // Track another user of the shape | 175 | // Track another user of the shape |
102 | public void ReferenceShape(BulletShape shape) | 176 | private bool ReferenceShape(BulletShape shape) |
103 | { | 177 | { |
104 | ReferenceShape(shape, null); | 178 | return ReferenceShape(shape, null); |
105 | } | 179 | } |
106 | 180 | ||
107 | // Track the datastructures and use count for a shape. | 181 | // Track the datastructures and use count for a shape. |
108 | // When creating a hull, this is called first to reference the mesh | 182 | // When creating a hull, this is called first to reference the mesh |
109 | // and then again to reference the hull. | 183 | // and then again to reference the hull. |
110 | // Meshes and hulls for the same shape have the same hash key. | 184 | // Meshes and hulls for the same shape have the same hash key. |
111 | private void ReferenceShape(BulletShape shape, IMesh meshData) | 185 | // NOTE that native shapes are not added to the mesh list or removed. |
186 | // Returns 'true' if this is the initial reference to the shape. Otherwise reused. | ||
187 | private bool ReferenceShape(BulletShape shape, IMesh meshData) | ||
112 | { | 188 | { |
189 | bool ret = false; | ||
113 | switch (shape.type) | 190 | switch (shape.type) |
114 | { | 191 | { |
115 | case ShapeData.PhysicsShapeType.SHAPE_MESH: | 192 | case ShapeData.PhysicsShapeType.SHAPE_MESH: |
@@ -118,14 +195,18 @@ public class BSShapeCollection : IDisposable | |||
118 | { | 195 | { |
119 | // There is an existing instance of this mesh. | 196 | // There is an existing instance of this mesh. |
120 | meshDesc.referenceCount++; | 197 | meshDesc.referenceCount++; |
198 | DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}", | ||
199 | BSScene.DetailLogZero, shape.shapeKey, meshDesc.referenceCount); | ||
121 | } | 200 | } |
122 | else | 201 | else |
123 | { | 202 | { |
124 | // This is a new reference to a mesh | 203 | // This is a new reference to a mesh |
125 | meshDesc.Ptr = shape.Ptr; | 204 | meshDesc.Ptr = shape.ptr; |
126 | meshDesc.meshData = meshData; | 205 | meshDesc.meshData = meshData; |
127 | meshDesc.referenceCount = 1; | 206 | meshDesc.referenceCount = 1; |
128 | 207 | DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}", | |
208 | BSScene.DetailLogZero, shape.shapeKey, meshDesc.referenceCount); | ||
209 | ret = true; | ||
129 | } | 210 | } |
130 | meshDesc.lastReferenced = System.DateTime.Now; | 211 | meshDesc.lastReferenced = System.DateTime.Now; |
131 | Meshes[shape.shapeKey] = meshDesc; | 212 | Meshes[shape.shapeKey] = meshDesc; |
@@ -136,41 +217,68 @@ public class BSShapeCollection : IDisposable | |||
136 | { | 217 | { |
137 | // There is an existing instance of this mesh. | 218 | // There is an existing instance of this mesh. |
138 | hullDesc.referenceCount++; | 219 | hullDesc.referenceCount++; |
220 | DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}", | ||
221 | BSScene.DetailLogZero, shape.shapeKey, hullDesc.referenceCount); | ||
139 | } | 222 | } |
140 | else | 223 | else |
141 | { | 224 | { |
142 | // This is a new reference to a mesh | 225 | // This is a new reference to a hull |
143 | hullDesc.Ptr = shape.Ptr; | 226 | hullDesc.Ptr = shape.ptr; |
144 | hullDesc.referenceCount = 1; | 227 | hullDesc.referenceCount = 1; |
228 | DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}", | ||
229 | BSScene.DetailLogZero, shape.shapeKey, hullDesc.referenceCount); | ||
230 | ret = true; | ||
145 | 231 | ||
146 | } | 232 | } |
147 | hullDesc.lastReferenced = System.DateTime.Now; | 233 | hullDesc.lastReferenced = System.DateTime.Now; |
148 | Hulls[shape.shapeKey] = hullDesc; | 234 | Hulls[shape.shapeKey] = hullDesc; |
149 | break; | 235 | break; |
236 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: | ||
237 | break; | ||
150 | default: | 238 | default: |
239 | // Native shapes are not tracked and they don't go into any list | ||
151 | break; | 240 | break; |
152 | } | 241 | } |
242 | return ret; | ||
153 | } | 243 | } |
154 | 244 | ||
155 | // Release the usage of a shape | 245 | // Release the usage of a shape |
156 | public void DereferenceShape(BulletShape shape) | 246 | private void DereferenceShape(BulletShape shape, bool atTaintTime) |
157 | { | 247 | { |
158 | switch (shape.type) | 248 | if (shape.ptr == IntPtr.Zero) |
249 | return; | ||
250 | |||
251 | BSScene.TaintCallback dereferenceOperation = delegate() | ||
159 | { | 252 | { |
160 | case ShapeData.PhysicsShapeType.SHAPE_HULL: | 253 | switch (shape.type) |
161 | DereferenceHull(shape); | 254 | { |
162 | // Hulls also include a mesh | 255 | case ShapeData.PhysicsShapeType.SHAPE_HULL: |
163 | DereferenceMesh(shape); | 256 | DereferenceHull(shape); |
164 | break; | 257 | // Hulls also include a mesh |
165 | case ShapeData.PhysicsShapeType.SHAPE_MESH: | 258 | DereferenceMesh(shape); |
166 | DereferenceMesh(shape); | 259 | break; |
167 | break; | 260 | case ShapeData.PhysicsShapeType.SHAPE_MESH: |
168 | default: | 261 | DereferenceMesh(shape); |
169 | break; | 262 | break; |
170 | } | 263 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: |
264 | break; | ||
265 | default: | ||
266 | // Native shapes are not tracked and are released immediately | ||
267 | if (shape.ptr != IntPtr.Zero & shape.isNativeShape) | ||
268 | { | ||
269 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | ||
270 | } | ||
271 | break; | ||
272 | } | ||
273 | }; | ||
274 | if (atTaintTime) | ||
275 | dereferenceOperation(); | ||
276 | else | ||
277 | PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation); | ||
171 | } | 278 | } |
172 | 279 | ||
173 | // Count down the reference count for a mesh shape | 280 | // Count down the reference count for a mesh shape |
281 | // Called at taint-time. | ||
174 | private void DereferenceMesh(BulletShape shape) | 282 | private void DereferenceMesh(BulletShape shape) |
175 | { | 283 | { |
176 | MeshDesc meshDesc; | 284 | MeshDesc meshDesc; |
@@ -180,10 +288,14 @@ public class BSShapeCollection : IDisposable | |||
180 | // TODO: release the Bullet storage | 288 | // TODO: release the Bullet storage |
181 | meshDesc.lastReferenced = System.DateTime.Now; | 289 | meshDesc.lastReferenced = System.DateTime.Now; |
182 | Meshes[shape.shapeKey] = meshDesc; | 290 | Meshes[shape.shapeKey] = meshDesc; |
291 | DetailLog("{0},BSShapeColliction.DereferenceMesh,key={1},cnt={2}", | ||
292 | BSScene.DetailLogZero, shape.shapeKey, meshDesc.referenceCount); | ||
293 | |||
183 | } | 294 | } |
184 | } | 295 | } |
185 | 296 | ||
186 | // Count down the reference count for a hull shape | 297 | // Count down the reference count for a hull shape |
298 | // Called at taint-time. | ||
187 | private void DereferenceHull(BulletShape shape) | 299 | private void DereferenceHull(BulletShape shape) |
188 | { | 300 | { |
189 | HullDesc hullDesc; | 301 | HullDesc hullDesc; |
@@ -193,6 +305,8 @@ public class BSShapeCollection : IDisposable | |||
193 | // TODO: release the Bullet storage (aging old entries?) | 305 | // TODO: release the Bullet storage (aging old entries?) |
194 | hullDesc.lastReferenced = System.DateTime.Now; | 306 | hullDesc.lastReferenced = System.DateTime.Now; |
195 | Hulls[shape.shapeKey] = hullDesc; | 307 | Hulls[shape.shapeKey] = hullDesc; |
308 | DetailLog("{0},BSShapeColliction.DereferenceHull,key={1},cnt={2}", | ||
309 | BSScene.DetailLogZero, shape.shapeKey, hullDesc.referenceCount); | ||
196 | } | 310 | } |
197 | } | 311 | } |
198 | 312 | ||
@@ -210,10 +324,6 @@ public class BSShapeCollection : IDisposable | |||
210 | 324 | ||
211 | BulletShape newShape = new BulletShape(IntPtr.Zero); | 325 | BulletShape newShape = new BulletShape(IntPtr.Zero); |
212 | 326 | ||
213 | // If the object is dynamic, it must have a hull shape | ||
214 | if (prim.IsPhysical) | ||
215 | nativeShapePossible = false; | ||
216 | |||
217 | // If the prim attributes are simple, this could be a simple Bullet native shape | 327 | // If the prim attributes are simple, this could be a simple Bullet native shape |
218 | if (nativeShapePossible | 328 | if (nativeShapePossible |
219 | && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) | 329 | && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) |
@@ -230,8 +340,10 @@ public class BSShapeCollection : IDisposable | |||
230 | haveShape = true; | 340 | haveShape = true; |
231 | if (forceRebuild || (prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE)) | 341 | if (forceRebuild || (prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE)) |
232 | { | 342 | { |
233 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere (force={1}", prim.LocalID, forceRebuild); | 343 | newShape = AddNativeShapeToPrim( |
234 | newShape = AddNativeShapeToPrim(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE); | 344 | prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE, ShapeData.FixedShapeKey.KEY_SPHERE); |
345 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", | ||
346 | prim.LocalID, forceRebuild,prim.BSShape); | ||
235 | 347 | ||
236 | ret = true; | 348 | ret = true; |
237 | } | 349 | } |
@@ -242,71 +354,87 @@ public class BSShapeCollection : IDisposable | |||
242 | haveShape = true; | 354 | haveShape = true; |
243 | if (forceRebuild || (prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX)) | 355 | if (forceRebuild || (prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX)) |
244 | { | 356 | { |
245 | DetailLog("{0},BSShapeCollection.CreateGeom,box (force={1})", prim.LocalID, forceRebuild); | 357 | newShape = AddNativeShapeToPrim( |
246 | newShape = AddNativeShapeToPrim(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX); | 358 | prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX, ShapeData.FixedShapeKey.KEY_BOX); |
359 | DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", | ||
360 | prim.LocalID, forceRebuild,prim.BSShape); | ||
247 | 361 | ||
248 | ret = true; | 362 | ret = true; |
249 | } | 363 | } |
250 | } | 364 | } |
251 | } | 365 | } |
252 | // If a simple shape isn't happening, create a mesh and possibly a hull | 366 | // If a simple shape is not happening, create a mesh and possibly a hull |
367 | // Note that if it's a native shape, the check for physical/non-physical is not | ||
368 | // made. Native shapes are best used in either case. | ||
253 | if (!haveShape) | 369 | if (!haveShape) |
254 | { | 370 | { |
255 | if (prim.IsPhysical) | 371 | if (prim.IsPhysical) |
256 | { | 372 | { |
257 | if (forceRebuild || !Hulls.ContainsKey(prim.BSShape.shapeKey)) | 373 | if (forceRebuild || !Hulls.ContainsKey(shapeData.HullKey)) |
258 | { | 374 | { |
259 | // physical objects require a hull for interaction. | 375 | // physical objects require a hull for interaction. |
260 | // This also creates the mesh if it doesn't already exist | 376 | // This also creates the mesh if it doesn't already exist. |
261 | ret = CreateGeomHull(prim, shapeData, pbs); | 377 | ret = CreateGeomHull(prim, shapeData, pbs); |
262 | } | 378 | } |
379 | else | ||
380 | { | ||
381 | prim.BSShape = new BulletShape(Hulls[shapeData.HullKey].Ptr, | ||
382 | ShapeData.PhysicsShapeType.SHAPE_HULL); | ||
383 | prim.BSShape.shapeKey = shapeData.HullKey; | ||
384 | // Another user of this shape. | ||
385 | ReferenceShape(prim.BSShape); | ||
386 | ret = true; | ||
387 | } | ||
263 | } | 388 | } |
264 | else | 389 | else |
265 | { | 390 | { |
266 | if (forceRebuild || !Meshes.ContainsKey(prim.BSShape.shapeKey)) | 391 | if (forceRebuild || !Meshes.ContainsKey(prim.BSShape.shapeKey)) |
267 | { | 392 | { |
268 | // Static (non-physical) objects only need a mesh for bumping into | 393 | // Static (non-physical) objects only need a mesh for bumping into |
394 | // Returning 'true' means prim.BShape was changed. | ||
269 | ret = CreateGeomMesh(prim, shapeData, pbs); | 395 | ret = CreateGeomMesh(prim, shapeData, pbs); |
270 | } | 396 | } |
397 | else | ||
398 | { | ||
399 | prim.BSShape = new BulletShape(Hulls[shapeData.MeshKey].Ptr, | ||
400 | ShapeData.PhysicsShapeType.SHAPE_MESH); | ||
401 | prim.BSShape.shapeKey = shapeData.MeshKey; | ||
402 | ReferenceShape(prim.BSShape); | ||
403 | ret = true; | ||
404 | } | ||
271 | } | 405 | } |
272 | } | 406 | } |
273 | return ret; | 407 | return ret; |
274 | } | 408 | } |
275 | 409 | ||
276 | private BulletShape AddNativeShapeToPrim(BSPrim prim, ShapeData shapeData, ShapeData.PhysicsShapeType shapeType) | 410 | // Creates a native shape and assignes it to prim.BSShape |
411 | private BulletShape AddNativeShapeToPrim( | ||
412 | BSPrim prim, ShapeData shapeData, ShapeData.PhysicsShapeType shapeType, | ||
413 | ShapeData.FixedShapeKey shapeKey) | ||
277 | { | 414 | { |
278 | BulletShape newShape; | 415 | BulletShape newShape; |
279 | 416 | ||
280 | // Bullet native objects are scaled by the Bullet engine so pass the size in | 417 | // Bullet native objects are scaled by the Bullet engine so pass the size in |
281 | prim.Scale = shapeData.Size; | 418 | prim.Scale = shapeData.Size; |
419 | shapeData.Type = shapeType; | ||
420 | shapeData.Scale = prim.Scale; | ||
282 | 421 | ||
283 | // release any previous shape | 422 | // release any previous shape |
284 | DereferenceShape(prim.BSShape); | 423 | DereferenceShape(prim.BSShape, true); |
424 | |||
425 | // Shape of this discriptioin is not allocated. Create new. | ||
426 | newShape = new BulletShape( | ||
427 | BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); | ||
428 | newShape.shapeKey = (ulong)shapeKey; | ||
429 | newShape.isNativeShape = true; | ||
430 | |||
431 | // Don't to a 'ReferenceShape()' here because native shapes are not tracked. | ||
285 | 432 | ||
286 | MeshDesc existingShapeDesc; | ||
287 | if (Meshes.TryGetValue(shapeData.MeshKey, out existingShapeDesc)) | ||
288 | { | ||
289 | // If there is an existing allocated shape, use it | ||
290 | newShape = new BulletShape(existingShapeDesc.Ptr, shapeType); | ||
291 | } | ||
292 | else | ||
293 | { | ||
294 | // Shape of this discriptioin is not allocated. Create new. | ||
295 | newShape = new BulletShape( | ||
296 | BulletSimAPI.BuildNativeShape2(PhysicsScene.World.Ptr, | ||
297 | (float)shapeType, | ||
298 | PhysicsScene.Params.collisionMargin, | ||
299 | prim.Scale), | ||
300 | shapeType); | ||
301 | } | ||
302 | newShape.shapeKey = shapeData.MeshKey; | ||
303 | ReferenceShape(newShape); | ||
304 | prim.BSShape = newShape; | 433 | prim.BSShape = newShape; |
305 | return newShape; | 434 | return newShape; |
306 | } | 435 | } |
307 | 436 | ||
308 | // No locking here because this is done when we know physics is not simulating | 437 | // Returns 'true' of a mesh was actually rebuild. |
309 | // Returns 'true' of a mesh was actually rebuild (we could also have one of these specs). | ||
310 | // Called at taint-time! | 438 | // Called at taint-time! |
311 | private bool CreateGeomMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs) | 439 | private bool CreateGeomMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs) |
312 | { | 440 | { |
@@ -322,7 +450,6 @@ public class BSShapeCollection : IDisposable | |||
322 | lod = PhysicsScene.MeshMegaPrimLOD; | 450 | lod = PhysicsScene.MeshMegaPrimLOD; |
323 | 451 | ||
324 | ulong newMeshKey = (ulong)pbs.GetMeshKey(shapeData.Size, lod); | 452 | ulong newMeshKey = (ulong)pbs.GetMeshKey(shapeData.Size, lod); |
325 | // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, LocalID, _meshKey, newMeshKey); | ||
326 | 453 | ||
327 | // if this new shape is the same as last time, don't recreate the mesh | 454 | // if this new shape is the same as last time, don't recreate the mesh |
328 | if (prim.BSShape.shapeKey == newMeshKey) return false; | 455 | if (prim.BSShape.shapeKey == newMeshKey) return false; |
@@ -330,7 +457,7 @@ public class BSShapeCollection : IDisposable | |||
330 | DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,key={1}", prim.LocalID, newMeshKey); | 457 | DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,key={1}", prim.LocalID, newMeshKey); |
331 | 458 | ||
332 | // Since we're recreating new, get rid of the reference to the previous shape | 459 | // Since we're recreating new, get rid of the reference to the previous shape |
333 | DereferenceShape(prim.BSShape); | 460 | DereferenceShape(prim.BSShape, true); |
334 | 461 | ||
335 | IMesh meshData = null; | 462 | IMesh meshData = null; |
336 | IntPtr meshPtr; | 463 | IntPtr meshPtr; |
@@ -360,7 +487,7 @@ public class BSShapeCollection : IDisposable | |||
360 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | 487 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", |
361 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | 488 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); |
362 | 489 | ||
363 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.Ptr, | 490 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, |
364 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); | 491 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); |
365 | } | 492 | } |
366 | newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); | 493 | newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); |
@@ -374,26 +501,29 @@ public class BSShapeCollection : IDisposable | |||
374 | return true; // 'true' means a new shape has been added to this prim | 501 | return true; // 'true' means a new shape has been added to this prim |
375 | } | 502 | } |
376 | 503 | ||
377 | // No locking here because this is done when we know physics is not simulating | ||
378 | // Returns 'true' of a mesh was actually rebuild (we could also have one of these specs). | 504 | // Returns 'true' of a mesh was actually rebuild (we could also have one of these specs). |
379 | List<ConvexResult> m_hulls; | 505 | List<ConvexResult> m_hulls; |
380 | private bool CreateGeomHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs) | 506 | private bool CreateGeomHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs) |
381 | { | 507 | { |
382 | BulletShape newShape; | 508 | BulletShape newShape; |
383 | 509 | ||
510 | // Level of detail for the mesh can be different for sculpties and regular meshes. | ||
384 | float lod = pbs.SculptEntry ? PhysicsScene.SculptLOD : PhysicsScene.MeshLOD; | 511 | float lod = pbs.SculptEntry ? PhysicsScene.SculptLOD : PhysicsScene.MeshLOD; |
512 | |||
385 | ulong newHullKey = (ulong)pbs.GetMeshKey(shapeData.Size, lod); | 513 | ulong newHullKey = (ulong)pbs.GetMeshKey(shapeData.Size, lod); |
386 | // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, LocalID, _hullKey, newHullKey); | ||
387 | 514 | ||
388 | // if the hull hasn't changed, don't rebuild it | 515 | // if the hull hasn't changed, don't rebuild it |
389 | if (newHullKey == prim.BSShape.shapeKey) return false; | 516 | if (newHullKey == prim.BSShape.shapeKey) return false; |
390 | 517 | ||
391 | DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", prim.LocalID, newHullKey, newHullKey); | 518 | DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", prim.LocalID, newHullKey, newHullKey); |
392 | 519 | ||
393 | // remove references to any previous shape | 520 | // Remove references to the previous shape. Also removes reference to underlying mesh. |
394 | DereferenceShape(prim.BSShape); | 521 | DereferenceShape(prim.BSShape, true); |
395 | 522 | ||
396 | // Make sure the underlying mesh exists and is correct | 523 | // Do not let the mesh dereference itself again. Was done in the above DerefereceShape(). |
524 | prim.BSShape.type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | ||
525 | |||
526 | // Make sure the underlying mesh exists and is correct. | ||
397 | // Since we're in the hull code, we know CreateGeomMesh() will not create a native shape. | 527 | // Since we're in the hull code, we know CreateGeomMesh() will not create a native shape. |
398 | CreateGeomMesh(prim, shapeData, pbs); | 528 | CreateGeomMesh(prim, shapeData, pbs); |
399 | MeshDesc meshDesc = Meshes[newHullKey]; | 529 | MeshDesc meshDesc = Meshes[newHullKey]; |
@@ -402,10 +532,12 @@ public class BSShapeCollection : IDisposable | |||
402 | HullDesc hullDesc; | 532 | HullDesc hullDesc; |
403 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) | 533 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) |
404 | { | 534 | { |
535 | // If the hull shape already is created, just use it. | ||
405 | hullPtr = hullDesc.Ptr; | 536 | hullPtr = hullDesc.Ptr; |
406 | } | 537 | } |
407 | else | 538 | else |
408 | { | 539 | { |
540 | // Build a new hull in the physical world | ||
409 | int[] indices = meshDesc.meshData.getIndexListAsInt(); | 541 | int[] indices = meshDesc.meshData.getIndexListAsInt(); |
410 | List<OMV.Vector3> vertices = meshDesc.meshData.getVertexList(); | 542 | List<OMV.Vector3> vertices = meshDesc.meshData.getVertexList(); |
411 | 543 | ||
@@ -485,63 +617,85 @@ public class BSShapeCollection : IDisposable | |||
485 | } | 617 | } |
486 | // create the hull data structure in Bullet | 618 | // create the hull data structure in Bullet |
487 | // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, LocalID, _hullKey, hullCount); | 619 | // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, LocalID, _hullKey, hullCount); |
488 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.Ptr, hullCount, convHulls); | 620 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); |
489 | } | 621 | } |
622 | |||
490 | newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); | 623 | newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); |
491 | newShape.shapeKey = newHullKey; | 624 | newShape.shapeKey = newHullKey; |
625 | newShape.meshPtr = meshDesc.Ptr; | ||
492 | 626 | ||
493 | ReferenceShape(newShape); | 627 | ReferenceShape(newShape); |
494 | 628 | ||
495 | // meshes are already scaled by the meshmerizer | 629 | // meshes and hulls are already scaled by the meshmerizer |
496 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | 630 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); |
497 | prim.BSShape = newShape; | 631 | prim.BSShape = newShape; |
498 | return true; // 'true' means a new shape has been added to this prim | 632 | return true; // 'true' means a new shape has been added to this prim |
499 | } | 633 | } |
500 | 634 | ||
501 | // Callback from convex hull creater with a newly created hull. | 635 | // Callback from convex hull creater with a newly created hull. |
502 | // Just add it to the collection of hulls for this shape. | 636 | // Just add it to our collection of hulls for this shape. |
503 | private void HullReturn(ConvexResult result) | 637 | private void HullReturn(ConvexResult result) |
504 | { | 638 | { |
505 | m_hulls.Add(result); | 639 | m_hulls.Add(result); |
506 | return; | 640 | return; |
507 | } | 641 | } |
508 | 642 | ||
509 | // Create an object in Bullet if it has not already been created | 643 | // Create an object in Bullet if it has not already been created. |
510 | // No locking here because this is done when the physics engine is not simulating | 644 | // Updates prim.BSBody with the information about the new body if one is created. |
511 | // Returns 'true' if an object was actually created. | 645 | // Returns 'true' if an object was actually created. |
512 | private bool CreateObject(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape, ShapeData shapeData) | 646 | // Called at taint-time. |
647 | private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape, ShapeData shapeData) | ||
513 | { | 648 | { |
514 | // the mesh or hull must have already been created in Bullet | 649 | bool ret = false; |
515 | // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, LocalID, shape.Type); | ||
516 | 650 | ||
517 | DereferenceBody(prim.BSBody); | 651 | // the mesh, hull or native shape must have already been created in Bullet |
652 | bool mustRebuild = (prim.BSBody.ptr == IntPtr.Zero); | ||
518 | 653 | ||
519 | BulletBody aBody; | 654 | // If there is an existing body, verify it's of an acceptable type. |
520 | IntPtr bodyPtr = IntPtr.Zero; | 655 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. |
521 | if (prim.IsSolid) | 656 | if (!mustRebuild) |
522 | { | 657 | { |
523 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.Ptr, shape.Ptr, shapeData.Position, shapeData.Rotation); | 658 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.BSBody.ptr); |
659 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY | ||
660 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) | ||
661 | { | ||
662 | // If the collisionObject is not the correct type for solidness, rebuild what's there | ||
663 | mustRebuild = true; | ||
664 | } | ||
665 | |||
524 | } | 666 | } |
525 | else | 667 | |
668 | if (mustRebuild) | ||
526 | { | 669 | { |
527 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.Ptr, shape.Ptr, shapeData.Position, shapeData.Rotation); | 670 | DereferenceBody(prim.BSBody, true); |
528 | } | 671 | |
529 | aBody = new BulletBody(shapeData.ID, bodyPtr); | 672 | BulletBody aBody; |
673 | IntPtr bodyPtr = IntPtr.Zero; | ||
674 | if (prim.IsSolid) | ||
675 | { | ||
676 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, shapeData.Position, shapeData.Rotation); | ||
677 | DetailLog("{0},BSShapeCollection.CreateObject,mesh,ptr={1:X}", prim.LocalID, bodyPtr); | ||
678 | } | ||
679 | else | ||
680 | { | ||
681 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, shapeData.Position, shapeData.Rotation); | ||
682 | DetailLog("{0},BSShapeCollection.CreateObject,ghost,ptr={1:X}", prim.LocalID, bodyPtr); | ||
683 | } | ||
684 | aBody = new BulletBody(shapeData.ID, bodyPtr); | ||
685 | |||
686 | ReferenceBody(aBody, true); | ||
687 | |||
688 | prim.BSBody = aBody; | ||
530 | 689 | ||
531 | ReferenceBody(aBody); | 690 | ret = true; |
691 | } | ||
532 | 692 | ||
533 | prim.BSBody = aBody; | 693 | return ret; |
534 | return true; | ||
535 | } | 694 | } |
536 | 695 | ||
537 | private void DetailLog(string msg, params Object[] args) | 696 | private void DetailLog(string msg, params Object[] args) |
538 | { | 697 | { |
539 | PhysicsScene.PhysicsLogging.Write(msg, args); | 698 | PhysicsScene.PhysicsLogging.Write(msg, args); |
540 | } | 699 | } |
541 | |||
542 | |||
543 | |||
544 | |||
545 | |||
546 | } | 700 | } |
547 | } | 701 | } |