diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | 448 |
1 files changed, 255 insertions, 193 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 892c34b..2e54a93 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -45,7 +45,7 @@ public sealed class BSShapeCollection : IDisposable | |||
45 | // Description of a Mesh | 45 | // Description of a Mesh |
46 | private struct MeshDesc | 46 | private struct MeshDesc |
47 | { | 47 | { |
48 | public IntPtr ptr; | 48 | public BulletShape shape; |
49 | public int referenceCount; | 49 | public int referenceCount; |
50 | public DateTime lastReferenced; | 50 | public DateTime lastReferenced; |
51 | public UInt64 shapeKey; | 51 | public UInt64 shapeKey; |
@@ -55,7 +55,7 @@ public sealed class BSShapeCollection : IDisposable | |||
55 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. | 55 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. |
56 | private struct HullDesc | 56 | private struct HullDesc |
57 | { | 57 | { |
58 | public IntPtr ptr; | 58 | public BulletShape shape; |
59 | public int referenceCount; | 59 | public int referenceCount; |
60 | public DateTime lastReferenced; | 60 | public DateTime lastReferenced; |
61 | public UInt64 shapeKey; | 61 | public UInt64 shapeKey; |
@@ -65,9 +65,16 @@ public sealed class BSShapeCollection : IDisposable | |||
65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); | 65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); |
66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); | 66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); |
67 | 67 | ||
68 | private bool DDetail = false; | ||
69 | |||
68 | public BSShapeCollection(BSScene physScene) | 70 | public BSShapeCollection(BSScene physScene) |
69 | { | 71 | { |
70 | PhysicsScene = physScene; | 72 | PhysicsScene = physScene; |
73 | // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) | ||
74 | // While detailed debugging is still active, this is better than commenting out all the | ||
75 | // DetailLog statements. When debugging slows down, this and the protected logging | ||
76 | // statements can be commented/removed. | ||
77 | DDetail = true; | ||
71 | } | 78 | } |
72 | 79 | ||
73 | public void Dispose() | 80 | public void Dispose() |
@@ -91,7 +98,7 @@ public sealed class BSShapeCollection : IDisposable | |||
91 | // higher level dependencies on the shape or body. Mostly used for LinkSets to | 98 | // higher level dependencies on the shape or body. Mostly used for LinkSets to |
92 | // remove the physical constraints before the body is destroyed. | 99 | // remove the physical constraints before the body is destroyed. |
93 | // Called at taint-time!! | 100 | // Called at taint-time!! |
94 | public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, | 101 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, |
95 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) | 102 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) |
96 | { | 103 | { |
97 | PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); | 104 | PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); |
@@ -109,8 +116,7 @@ public sealed class BSShapeCollection : IDisposable | |||
109 | // rebuild the body around it. | 116 | // rebuild the body around it. |
110 | // Updates prim.BSBody with information/pointers to requested body | 117 | // Updates prim.BSBody with information/pointers to requested body |
111 | // Returns 'true' if BSBody was changed. | 118 | // Returns 'true' if BSBody was changed. |
112 | bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, | 119 | bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, bodyCallback); |
113 | prim.PhysShape, bodyCallback); | ||
114 | ret = newGeom || newBody; | 120 | ret = newGeom || newBody; |
115 | } | 121 | } |
116 | DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", | 122 | DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", |
@@ -119,51 +125,52 @@ public sealed class BSShapeCollection : IDisposable | |||
119 | return ret; | 125 | return ret; |
120 | } | 126 | } |
121 | 127 | ||
128 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) | ||
129 | { | ||
130 | return GetBodyAndShape(forceRebuild, sim, prim, null, null); | ||
131 | } | ||
132 | |||
122 | // Track another user of a body. | 133 | // Track another user of a body. |
123 | // We presume the caller has allocated the body. | 134 | // We presume the caller has allocated the body. |
124 | // Bodies only have one user so the body is just put into the world if not already there. | 135 | // Bodies only have one user so the body is just put into the world if not already there. |
125 | public void ReferenceBody(BulletBody body, bool inTaintTime) | 136 | private void ReferenceBody(BulletBody body) |
126 | { | 137 | { |
127 | lock (m_collectionActivityLock) | 138 | lock (m_collectionActivityLock) |
128 | { | 139 | { |
129 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); | 140 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); |
130 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() | 141 | if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) |
131 | { | 142 | { |
132 | if (!BulletSimAPI.IsInWorld2(body.ptr)) | 143 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body); |
133 | { | 144 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); |
134 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); | 145 | } |
135 | DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | ||
136 | } | ||
137 | }); | ||
138 | } | 146 | } |
139 | } | 147 | } |
140 | 148 | ||
141 | // Release the usage of a body. | 149 | // Release the usage of a body. |
142 | // Called when releasing use of a BSBody. BSShape is handled separately. | 150 | // Called when releasing use of a BSBody. BSShape is handled separately. |
143 | public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) | 151 | // Called in taint time. |
152 | public void DereferenceBody(BulletBody body, BodyDestructionCallback bodyCallback ) | ||
144 | { | 153 | { |
145 | if (body.ptr == IntPtr.Zero) | 154 | if (!body.HasPhysicalBody) |
146 | return; | 155 | return; |
147 | 156 | ||
157 | PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody"); | ||
158 | |||
148 | lock (m_collectionActivityLock) | 159 | lock (m_collectionActivityLock) |
149 | { | 160 | { |
150 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() | 161 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); |
151 | { | 162 | // If the caller needs to know the old body is going away, pass the event up. |
152 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", | 163 | if (bodyCallback != null) bodyCallback(body); |
153 | body.ID, body, inTaintTime); | ||
154 | // If the caller needs to know the old body is going away, pass the event up. | ||
155 | if (bodyCallback != null) bodyCallback(body); | ||
156 | 164 | ||
157 | if (BulletSimAPI.IsInWorld2(body.ptr)) | 165 | if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) |
158 | { | 166 | { |
159 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); | 167 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body); |
160 | DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); | 168 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); |
161 | } | 169 | } |
162 | 170 | ||
163 | // Zero any reference to the shape so it is not freed when the body is deleted. | 171 | // Zero any reference to the shape so it is not freed when the body is deleted. |
164 | BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); | 172 | PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null); |
165 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); | 173 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, body); |
166 | }); | ||
167 | } | 174 | } |
168 | } | 175 | } |
169 | 176 | ||
@@ -184,17 +191,17 @@ public sealed class BSShapeCollection : IDisposable | |||
184 | { | 191 | { |
185 | // There is an existing instance of this mesh. | 192 | // There is an existing instance of this mesh. |
186 | meshDesc.referenceCount++; | 193 | meshDesc.referenceCount++; |
187 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", | 194 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", |
188 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 195 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
189 | } | 196 | } |
190 | else | 197 | else |
191 | { | 198 | { |
192 | // This is a new reference to a mesh | 199 | // This is a new reference to a mesh |
193 | meshDesc.ptr = shape.ptr; | 200 | meshDesc.shape = shape.Clone(); |
194 | meshDesc.shapeKey = shape.shapeKey; | 201 | meshDesc.shapeKey = shape.shapeKey; |
195 | // We keep a reference to the underlying IMesh data so a hull can be built | 202 | // We keep a reference to the underlying IMesh data so a hull can be built |
196 | meshDesc.referenceCount = 1; | 203 | meshDesc.referenceCount = 1; |
197 | DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", | 204 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", |
198 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 205 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
199 | ret = true; | 206 | ret = true; |
200 | } | 207 | } |
@@ -207,16 +214,16 @@ public sealed class BSShapeCollection : IDisposable | |||
207 | { | 214 | { |
208 | // There is an existing instance of this hull. | 215 | // There is an existing instance of this hull. |
209 | hullDesc.referenceCount++; | 216 | hullDesc.referenceCount++; |
210 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", | 217 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", |
211 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 218 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
212 | } | 219 | } |
213 | else | 220 | else |
214 | { | 221 | { |
215 | // This is a new reference to a hull | 222 | // This is a new reference to a hull |
216 | hullDesc.ptr = shape.ptr; | 223 | hullDesc.shape = shape.Clone(); |
217 | hullDesc.shapeKey = shape.shapeKey; | 224 | hullDesc.shapeKey = shape.shapeKey; |
218 | hullDesc.referenceCount = 1; | 225 | hullDesc.referenceCount = 1; |
219 | DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", | 226 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", |
220 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 227 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
221 | ret = true; | 228 | ret = true; |
222 | 229 | ||
@@ -234,44 +241,43 @@ public sealed class BSShapeCollection : IDisposable | |||
234 | } | 241 | } |
235 | 242 | ||
236 | // Release the usage of a shape. | 243 | // Release the usage of a shape. |
237 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) | 244 | public void DereferenceShape(BulletShape shape, ShapeDestructionCallback shapeCallback) |
238 | { | 245 | { |
239 | if (shape.ptr == IntPtr.Zero) | 246 | if (!shape.HasPhysicalShape) |
240 | return; | 247 | return; |
241 | 248 | ||
242 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() | 249 | PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceShape"); |
250 | |||
251 | if (shape.HasPhysicalShape) | ||
243 | { | 252 | { |
244 | if (shape.ptr != IntPtr.Zero) | 253 | if (shape.isNativeShape) |
245 | { | 254 | { |
246 | if (shape.isNativeShape) | 255 | // Native shapes are not tracked and are released immediately |
247 | { | 256 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1}", |
248 | // Native shapes are not tracked and are released immediately | 257 | BSScene.DetailLogZero, shape.AddrString); |
249 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", | 258 | if (shapeCallback != null) shapeCallback(shape); |
250 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); | 259 | PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); |
251 | if (shapeCallback != null) shapeCallback(shape); | 260 | } |
252 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | 261 | else |
253 | } | 262 | { |
254 | else | 263 | switch (shape.type) |
255 | { | 264 | { |
256 | switch (shape.type) | 265 | case BSPhysicsShapeType.SHAPE_HULL: |
257 | { | 266 | DereferenceHull(shape, shapeCallback); |
258 | case BSPhysicsShapeType.SHAPE_HULL: | 267 | break; |
259 | DereferenceHull(shape, shapeCallback); | 268 | case BSPhysicsShapeType.SHAPE_MESH: |
260 | break; | 269 | DereferenceMesh(shape, shapeCallback); |
261 | case BSPhysicsShapeType.SHAPE_MESH: | 270 | break; |
262 | DereferenceMesh(shape, shapeCallback); | 271 | case BSPhysicsShapeType.SHAPE_COMPOUND: |
263 | break; | 272 | DereferenceCompound(shape, shapeCallback); |
264 | case BSPhysicsShapeType.SHAPE_COMPOUND: | 273 | break; |
265 | DereferenceCompound(shape, shapeCallback); | 274 | case BSPhysicsShapeType.SHAPE_UNKNOWN: |
266 | break; | 275 | break; |
267 | case BSPhysicsShapeType.SHAPE_UNKNOWN: | 276 | default: |
268 | break; | 277 | break; |
269 | default: | ||
270 | break; | ||
271 | } | ||
272 | } | 278 | } |
273 | } | 279 | } |
274 | }); | 280 | } |
275 | } | 281 | } |
276 | 282 | ||
277 | // Count down the reference count for a mesh shape | 283 | // Count down the reference count for a mesh shape |
@@ -286,7 +292,7 @@ public sealed class BSShapeCollection : IDisposable | |||
286 | if (shapeCallback != null) shapeCallback(shape); | 292 | if (shapeCallback != null) shapeCallback(shape); |
287 | meshDesc.lastReferenced = System.DateTime.Now; | 293 | meshDesc.lastReferenced = System.DateTime.Now; |
288 | Meshes[shape.shapeKey] = meshDesc; | 294 | Meshes[shape.shapeKey] = meshDesc; |
289 | DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", | 295 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", |
290 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); | 296 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); |
291 | 297 | ||
292 | } | 298 | } |
@@ -307,7 +313,7 @@ public sealed class BSShapeCollection : IDisposable | |||
307 | 313 | ||
308 | hullDesc.lastReferenced = System.DateTime.Now; | 314 | hullDesc.lastReferenced = System.DateTime.Now; |
309 | Hulls[shape.shapeKey] = hullDesc; | 315 | Hulls[shape.shapeKey] = hullDesc; |
310 | DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", | 316 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", |
311 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); | 317 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); |
312 | } | 318 | } |
313 | } | 319 | } |
@@ -320,57 +326,56 @@ public sealed class BSShapeCollection : IDisposable | |||
320 | // Called at taint-time. | 326 | // Called at taint-time. |
321 | private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) | 327 | private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) |
322 | { | 328 | { |
323 | if (!BulletSimAPI.IsCompound2(shape.ptr)) | 329 | if (!PhysicsScene.PE.IsCompound(shape)) |
324 | { | 330 | { |
325 | // Failed the sanity check!! | 331 | // Failed the sanity check!! |
326 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | 332 | 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")); | 333 | LogHeader, shape.type, shape.AddrString); |
328 | DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | 334 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", |
329 | BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); | 335 | BSScene.DetailLogZero, shape.type, shape.AddrString); |
330 | return; | 336 | return; |
331 | } | 337 | } |
332 | 338 | ||
333 | int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); | 339 | int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape); |
334 | DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); | 340 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); |
335 | 341 | ||
336 | for (int ii = numChildren - 1; ii >= 0; ii--) | 342 | for (int ii = numChildren - 1; ii >= 0; ii--) |
337 | { | 343 | { |
338 | IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); | 344 | BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii); |
339 | DereferenceAnonCollisionShape(childShape); | 345 | DereferenceAnonCollisionShape(childShape); |
340 | } | 346 | } |
341 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | 347 | PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); |
342 | } | 348 | } |
343 | 349 | ||
344 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | 350 | // 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. | 351 | // Figure out type and call the correct dereference routine. |
346 | // Called at taint-time. | 352 | // Called at taint-time. |
347 | private void DereferenceAnonCollisionShape(IntPtr cShape) | 353 | private void DereferenceAnonCollisionShape(BulletShape shapeInfo) |
348 | { | 354 | { |
349 | MeshDesc meshDesc; | 355 | MeshDesc meshDesc; |
350 | HullDesc hullDesc; | 356 | HullDesc hullDesc; |
351 | 357 | ||
352 | BulletShape shapeInfo = new BulletShape(cShape); | 358 | if (TryGetMeshByPtr(shapeInfo, out meshDesc)) |
353 | if (TryGetMeshByPtr(cShape, out meshDesc)) | ||
354 | { | 359 | { |
355 | shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; | 360 | shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; |
356 | shapeInfo.shapeKey = meshDesc.shapeKey; | 361 | shapeInfo.shapeKey = meshDesc.shapeKey; |
357 | } | 362 | } |
358 | else | 363 | else |
359 | { | 364 | { |
360 | if (TryGetHullByPtr(cShape, out hullDesc)) | 365 | if (TryGetHullByPtr(shapeInfo, out hullDesc)) |
361 | { | 366 | { |
362 | shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; | 367 | shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; |
363 | shapeInfo.shapeKey = hullDesc.shapeKey; | 368 | shapeInfo.shapeKey = hullDesc.shapeKey; |
364 | } | 369 | } |
365 | else | 370 | else |
366 | { | 371 | { |
367 | if (BulletSimAPI.IsCompound2(cShape)) | 372 | if (PhysicsScene.PE.IsCompound(shapeInfo)) |
368 | { | 373 | { |
369 | shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; | 374 | shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; |
370 | } | 375 | } |
371 | else | 376 | else |
372 | { | 377 | { |
373 | if (BulletSimAPI.IsNativeShape2(cShape)) | 378 | if (PhysicsScene.PE.IsNativeShape(shapeInfo)) |
374 | { | 379 | { |
375 | shapeInfo.isNativeShape = true; | 380 | shapeInfo.isNativeShape = true; |
376 | shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) | 381 | shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) |
@@ -379,16 +384,16 @@ public sealed class BSShapeCollection : IDisposable | |||
379 | } | 384 | } |
380 | } | 385 | } |
381 | 386 | ||
382 | DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); | 387 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); |
383 | 388 | ||
384 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) | 389 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) |
385 | { | 390 | { |
386 | DereferenceShape(shapeInfo, true, null); | 391 | DereferenceShape(shapeInfo, null); |
387 | } | 392 | } |
388 | else | 393 | else |
389 | { | 394 | { |
390 | PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", | 395 | PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", |
391 | LogHeader, PhysicsScene.RegionName, cShape.ToString("X")); | 396 | LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString); |
392 | } | 397 | } |
393 | } | 398 | } |
394 | 399 | ||
@@ -408,19 +413,18 @@ public sealed class BSShapeCollection : IDisposable | |||
408 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) | 413 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) |
409 | { | 414 | { |
410 | // an avatar capsule is close to a native shape (it is not shared) | 415 | // an avatar capsule is close to a native shape (it is not shared) |
411 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, | 416 | GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback); |
412 | FixedShapeKey.KEY_CAPSULE, shapeCallback); | 417 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); |
413 | DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); | ||
414 | ret = true; | 418 | ret = true; |
415 | haveShape = true; | 419 | haveShape = true; |
416 | } | 420 | } |
417 | 421 | ||
418 | // Compound shapes are handled special as they are rebuilt from scratch. | 422 | // 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. | 423 | // This isn't too great a hardship since most of the child shapes will have already been created. |
420 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | 424 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) |
421 | { | 425 | { |
422 | ret = GetReferenceToCompoundShape(prim, shapeCallback); | 426 | ret = GetReferenceToCompoundShape(prim, shapeCallback); |
423 | DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); | 427 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); |
424 | haveShape = true; | 428 | haveShape = true; |
425 | } | 429 | } |
426 | 430 | ||
@@ -432,8 +436,9 @@ public sealed class BSShapeCollection : IDisposable | |||
432 | return ret; | 436 | return ret; |
433 | } | 437 | } |
434 | 438 | ||
435 | // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. | 439 | // Create a mesh, hull or native shape. |
436 | private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 440 | // Return 'true' if the prim's shape was changed. |
441 | public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
437 | { | 442 | { |
438 | bool ret = false; | 443 | bool ret = false; |
439 | bool haveShape = false; | 444 | bool haveShape = false; |
@@ -443,8 +448,9 @@ public sealed class BSShapeCollection : IDisposable | |||
443 | // If the prim attributes are simple, this could be a simple Bullet native shape | 448 | // If the prim attributes are simple, this could be a simple Bullet native shape |
444 | if (!haveShape | 449 | if (!haveShape |
445 | && pbs != null | 450 | && pbs != null |
451 | && !pbs.SculptEntry | ||
446 | && nativeShapePossible | 452 | && nativeShapePossible |
447 | && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) | 453 | && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) |
448 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | 454 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 |
449 | && pbs.ProfileHollow == 0 | 455 | && pbs.ProfileHollow == 0 |
450 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | 456 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 |
@@ -453,35 +459,43 @@ public sealed class BSShapeCollection : IDisposable | |||
453 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | 459 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 |
454 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | 460 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) |
455 | { | 461 | { |
456 | // It doesn't look like Bullet scales spheres so make sure the scales are all equal | 462 | // Get the scale of any existing shape so we can see if the new shape is same native type and same size. |
463 | OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; | ||
464 | if (prim.PhysShape.HasPhysicalShape) | ||
465 | scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape); | ||
466 | |||
467 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", | ||
468 | prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); | ||
469 | |||
470 | // It doesn't look like Bullet scales native spheres so make sure the scales are all equal | ||
457 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | 471 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) |
458 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) | 472 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) |
459 | { | 473 | { |
460 | haveShape = true; | 474 | haveShape = true; |
461 | if (forceRebuild | 475 | if (forceRebuild |
462 | || prim.Scale != prim.Size | 476 | || prim.Scale != scaleOfExistingShape |
463 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE | 477 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE |
464 | ) | 478 | ) |
465 | { | 479 | { |
466 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, | 480 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, |
467 | FixedShapeKey.KEY_SPHERE, shapeCallback); | 481 | FixedShapeKey.KEY_SPHERE, shapeCallback); |
468 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", | ||
469 | prim.LocalID, forceRebuild, prim.PhysShape); | ||
470 | } | 482 | } |
483 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", | ||
484 | prim.LocalID, forceRebuild, ret, prim.PhysShape); | ||
471 | } | 485 | } |
472 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | 486 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) |
473 | { | 487 | { |
474 | haveShape = true; | 488 | haveShape = true; |
475 | if (forceRebuild | 489 | if (forceRebuild |
476 | || prim.Scale != prim.Size | 490 | || prim.Scale != scaleOfExistingShape |
477 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX | 491 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX |
478 | ) | 492 | ) |
479 | { | 493 | { |
480 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, | 494 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, |
481 | FixedShapeKey.KEY_BOX, shapeCallback); | 495 | FixedShapeKey.KEY_BOX, shapeCallback); |
482 | DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", | ||
483 | prim.LocalID, forceRebuild, prim.PhysShape); | ||
484 | } | 496 | } |
497 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", | ||
498 | prim.LocalID, forceRebuild, ret, prim.PhysShape); | ||
485 | } | 499 | } |
486 | } | 500 | } |
487 | 501 | ||
@@ -494,23 +508,24 @@ public sealed class BSShapeCollection : IDisposable | |||
494 | return ret; | 508 | return ret; |
495 | } | 509 | } |
496 | 510 | ||
511 | // return 'true' if the prim's shape was changed. | ||
497 | public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 512 | public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
498 | { | 513 | { |
499 | 514 | ||
500 | bool ret = false; | 515 | bool ret = false; |
501 | // Note that if it's a native shape, the check for physical/non-physical is not | 516 | // Note that if it's a native shape, the check for physical/non-physical is not |
502 | // made. Native shapes work in either case. | 517 | // made. Native shapes work in either case. |
503 | if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) | 518 | if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) |
504 | { | 519 | { |
505 | // Update prim.BSShape to reference a hull of this shape. | 520 | // Update prim.BSShape to reference a hull of this shape. |
506 | ret = GetReferenceToHull(prim,shapeCallback); | 521 | ret = GetReferenceToHull(prim,shapeCallback); |
507 | DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", | 522 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", |
508 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | 523 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); |
509 | } | 524 | } |
510 | else | 525 | else |
511 | { | 526 | { |
512 | ret = GetReferenceToMesh(prim, shapeCallback); | 527 | ret = GetReferenceToMesh(prim, shapeCallback); |
513 | DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", | 528 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", |
514 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | 529 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); |
515 | } | 530 | } |
516 | return ret; | 531 | return ret; |
@@ -523,14 +538,15 @@ public sealed class BSShapeCollection : IDisposable | |||
523 | ShapeDestructionCallback shapeCallback) | 538 | ShapeDestructionCallback shapeCallback) |
524 | { | 539 | { |
525 | // release any previous shape | 540 | // release any previous shape |
526 | DereferenceShape(prim.PhysShape, true, shapeCallback); | 541 | DereferenceShape(prim.PhysShape, shapeCallback); |
527 | 542 | ||
528 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); | 543 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); |
529 | 544 | ||
530 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | 545 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. |
531 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | 546 | if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", |
532 | prim.LocalID, newShape, prim.Scale); | 547 | prim.LocalID, newShape, prim.Scale); |
533 | 548 | ||
549 | // native shapes are scaled by Bullet | ||
534 | prim.PhysShape = newShape; | 550 | prim.PhysShape = newShape; |
535 | return true; | 551 | return true; |
536 | } | 552 | } |
@@ -550,20 +566,17 @@ public sealed class BSShapeCollection : IDisposable | |||
550 | 566 | ||
551 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) | 567 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) |
552 | { | 568 | { |
553 | // The proper scale has been calculated in the prim. | 569 | |
554 | newShape = new BulletShape( | 570 | newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale); |
555 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) | 571 | if (DDetail) DetailLog("{0},BSShapeCollection.BuildPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); |
556 | , shapeType); | ||
557 | DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | ||
558 | } | 572 | } |
559 | else | 573 | else |
560 | { | 574 | { |
561 | // Native shapes are scaled in Bullet so set the scaling to the size | 575 | // Native shapes are scaled in Bullet so set the scaling to the size |
562 | prim.Scale = prim.Size; | 576 | newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData); |
563 | nativeShapeData.Scale = prim.Scale; | 577 | |
564 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); | ||
565 | } | 578 | } |
566 | if (newShape.ptr == IntPtr.Zero) | 579 | if (!newShape.HasPhysicalShape) |
567 | { | 580 | { |
568 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | 581 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", |
569 | LogHeader, prim.LocalID, shapeType); | 582 | LogHeader, prim.LocalID, shapeType); |
@@ -580,7 +593,7 @@ public sealed class BSShapeCollection : IDisposable | |||
580 | // Called at taint-time! | 593 | // Called at taint-time! |
581 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 594 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
582 | { | 595 | { |
583 | BulletShape newShape = new BulletShape(IntPtr.Zero); | 596 | BulletShape newShape = new BulletShape(); |
584 | 597 | ||
585 | float lod; | 598 | float lod; |
586 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | 599 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); |
@@ -589,62 +602,96 @@ public sealed class BSShapeCollection : IDisposable | |||
589 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) | 602 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) |
590 | return false; | 603 | return false; |
591 | 604 | ||
592 | DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", | 605 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2},size={3},lod={4}", |
593 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); | 606 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod); |
594 | 607 | ||
595 | // Since we're recreating new, get rid of the reference to the previous shape | 608 | // Since we're recreating new, get rid of the reference to the previous shape |
596 | DereferenceShape(prim.PhysShape, true, shapeCallback); | 609 | DereferenceShape(prim.PhysShape, shapeCallback); |
597 | 610 | ||
598 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); | 611 | newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod); |
599 | // Take evasive action if the mesh was not constructed. | 612 | // Take evasive action if the mesh was not constructed. |
600 | newShape = VerifyMeshCreated(newShape, prim); | 613 | newShape = VerifyMeshCreated(newShape, prim); |
601 | 614 | ||
602 | ReferenceShape(newShape); | 615 | ReferenceShape(newShape); |
603 | 616 | ||
604 | // meshes are already scaled by the meshmerizer | ||
605 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
606 | prim.PhysShape = newShape; | 617 | prim.PhysShape = newShape; |
607 | 618 | ||
608 | return true; // 'true' means a new shape has been added to this prim | 619 | return true; // 'true' means a new shape has been added to this prim |
609 | } | 620 | } |
610 | 621 | ||
611 | private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 622 | private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
612 | { | 623 | { |
613 | IMesh meshData = null; | 624 | BulletShape newShape = new BulletShape(); |
614 | IntPtr meshPtr = IntPtr.Zero; | 625 | |
615 | MeshDesc meshDesc; | 626 | MeshDesc meshDesc; |
616 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) | 627 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) |
617 | { | 628 | { |
618 | // If the mesh has already been built just use it. | 629 | // If the mesh has already been built just use it. |
619 | meshPtr = meshDesc.ptr; | 630 | newShape = meshDesc.shape.Clone(); |
620 | } | 631 | } |
621 | else | 632 | else |
622 | { | 633 | { |
623 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 634 | IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, |
624 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 635 | true, |
636 | false, // say it is not physical so a bounding box is not built | ||
637 | false, // do not cache the mesh and do not use previously built versions | ||
638 | false // It's NOT for ODE | ||
639 | ); | ||
625 | 640 | ||
626 | if (meshData != null) | 641 | if (meshData != null) |
627 | { | 642 | { |
643 | |||
628 | int[] indices = meshData.getIndexListAsInt(); | 644 | int[] indices = meshData.getIndexListAsInt(); |
629 | List<OMV.Vector3> vertices = meshData.getVertexList(); | 645 | int realIndicesIndex = indices.Length; |
646 | float[] verticesAsFloats = meshData.getVertexListAsFloat(); | ||
630 | 647 | ||
631 | float[] verticesAsFloats = new float[vertices.Count * 3]; | 648 | if (BSParam.ShouldRemoveZeroWidthTriangles) |
632 | int vi = 0; | ||
633 | foreach (OMV.Vector3 vv in vertices) | ||
634 | { | 649 | { |
635 | verticesAsFloats[vi++] = vv.X; | 650 | // Remove degenerate triangles. These are triangles with two of the vertices |
636 | verticesAsFloats[vi++] = vv.Y; | 651 | // are the same. This is complicated by the problem that vertices are not |
637 | verticesAsFloats[vi++] = vv.Z; | 652 | // made unique in sculpties so we have to compare the values in the vertex. |
653 | realIndicesIndex = 0; | ||
654 | for (int tri = 0; tri < indices.Length; tri += 3) | ||
655 | { | ||
656 | // Compute displacements into vertex array for each vertex of the triangle | ||
657 | int v1 = indices[tri + 0] * 3; | ||
658 | int v2 = indices[tri + 1] * 3; | ||
659 | int v3 = indices[tri + 2] * 3; | ||
660 | // Check to see if any two of the vertices are the same | ||
661 | if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] | ||
662 | && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] | ||
663 | && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) | ||
664 | || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] | ||
665 | && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] | ||
666 | && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) | ||
667 | || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] | ||
668 | && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] | ||
669 | && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) | ||
670 | ) | ||
671 | { | ||
672 | // None of the vertices of the triangles are the same. This is a good triangle; | ||
673 | indices[realIndicesIndex + 0] = indices[tri + 0]; | ||
674 | indices[realIndicesIndex + 1] = indices[tri + 1]; | ||
675 | indices[realIndicesIndex + 2] = indices[tri + 2]; | ||
676 | realIndicesIndex += 3; | ||
677 | } | ||
678 | } | ||
638 | } | 679 | } |
680 | DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}", | ||
681 | BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); | ||
639 | 682 | ||
640 | // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | 683 | if (realIndicesIndex != 0) |
641 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | 684 | { |
642 | 685 | newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, | |
643 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 686 | realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); |
644 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); | 687 | } |
688 | else | ||
689 | { | ||
690 | PhysicsScene.Logger.ErrorFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", | ||
691 | LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name); | ||
692 | } | ||
645 | } | 693 | } |
646 | } | 694 | } |
647 | BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH); | ||
648 | newShape.shapeKey = newMeshKey; | 695 | newShape.shapeKey = newMeshKey; |
649 | 696 | ||
650 | return newShape; | 697 | return newShape; |
@@ -663,19 +710,17 @@ public sealed class BSShapeCollection : IDisposable | |||
663 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) | 710 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) |
664 | return false; | 711 | return false; |
665 | 712 | ||
666 | DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", | 713 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", |
667 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | 714 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); |
668 | 715 | ||
669 | // Remove usage of the previous shape. | 716 | // Remove usage of the previous shape. |
670 | DereferenceShape(prim.PhysShape, true, shapeCallback); | 717 | DereferenceShape(prim.PhysShape, shapeCallback); |
671 | 718 | ||
672 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); | 719 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); |
673 | newShape = VerifyMeshCreated(newShape, prim); | 720 | newShape = VerifyMeshCreated(newShape, prim); |
674 | 721 | ||
675 | ReferenceShape(newShape); | 722 | ReferenceShape(newShape); |
676 | 723 | ||
677 | // hulls are already scaled by the meshmerizer | ||
678 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
679 | prim.PhysShape = newShape; | 724 | prim.PhysShape = newShape; |
680 | return true; // 'true' means a new shape has been added to this prim | 725 | return true; // 'true' means a new shape has been added to this prim |
681 | } | 726 | } |
@@ -684,18 +729,20 @@ public sealed class BSShapeCollection : IDisposable | |||
684 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 729 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
685 | { | 730 | { |
686 | 731 | ||
732 | BulletShape newShape = new BulletShape(); | ||
687 | IntPtr hullPtr = IntPtr.Zero; | 733 | IntPtr hullPtr = IntPtr.Zero; |
734 | |||
688 | HullDesc hullDesc; | 735 | HullDesc hullDesc; |
689 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) | 736 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) |
690 | { | 737 | { |
691 | // If the hull shape already is created, just use it. | 738 | // If the hull shape already is created, just use it. |
692 | hullPtr = hullDesc.ptr; | 739 | newShape = hullDesc.shape.Clone(); |
693 | } | 740 | } |
694 | else | 741 | else |
695 | { | 742 | { |
696 | // Build a new hull in the physical world | 743 | // Build a new hull in the physical world |
697 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 744 | // Pass true for physicalness as this creates some sort of bounding box which we don't need |
698 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 745 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); |
699 | if (meshData != null) | 746 | if (meshData != null) |
700 | { | 747 | { |
701 | 748 | ||
@@ -777,14 +824,13 @@ public sealed class BSShapeCollection : IDisposable | |||
777 | } | 824 | } |
778 | } | 825 | } |
779 | // create the hull data structure in Bullet | 826 | // create the hull data structure in Bullet |
780 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); | 827 | newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls); |
781 | } | 828 | } |
782 | } | 829 | } |
783 | 830 | ||
784 | BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL); | ||
785 | newShape.shapeKey = newHullKey; | 831 | newShape.shapeKey = newHullKey; |
786 | 832 | ||
787 | return newShape; // 'true' means a new shape has been added to this prim | 833 | return newShape; |
788 | } | 834 | } |
789 | 835 | ||
790 | // Callback from convex hull creater with a newly created hull. | 836 | // Callback from convex hull creater with a newly created hull. |
@@ -803,13 +849,12 @@ public sealed class BSShapeCollection : IDisposable | |||
803 | // Don't need to do this as the shape is freed when the new root shape is created below. | 849 | // 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); | 850 | // DereferenceShape(prim.PhysShape, true, shapeCallback); |
805 | 851 | ||
806 | BulletShape cShape = new BulletShape( | 852 | BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false); |
807 | BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND); | ||
808 | 853 | ||
809 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. | 854 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. |
810 | CreateGeomMeshOrHull(prim, shapeCallback); | 855 | CreateGeomMeshOrHull(prim, shapeCallback); |
811 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); | 856 | PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity); |
812 | DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", | 857 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", |
813 | prim.LocalID, cShape, prim.PhysShape); | 858 | prim.LocalID, cShape, prim.PhysShape); |
814 | 859 | ||
815 | prim.PhysShape = cShape; | 860 | prim.PhysShape = cShape; |
@@ -822,14 +867,19 @@ public sealed class BSShapeCollection : IDisposable | |||
822 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) | 867 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) |
823 | { | 868 | { |
824 | // level of detail based on size and type of the object | 869 | // level of detail based on size and type of the object |
825 | float lod = PhysicsScene.MeshLOD; | 870 | float lod = BSParam.MeshLOD; |
871 | |||
872 | // prims with curvy internal cuts need higher lod | ||
873 | if (pbs.HollowShape == HollowShape.Circle) | ||
874 | lod = BSParam.MeshCircularLOD; | ||
875 | |||
826 | if (pbs.SculptEntry) | 876 | if (pbs.SculptEntry) |
827 | lod = PhysicsScene.SculptLOD; | 877 | lod = BSParam.SculptLOD; |
828 | 878 | ||
829 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | 879 | // Mega prims usually get more detail because one can interact with shape approximations at this size. |
830 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); | 880 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); |
831 | if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) | 881 | if (maxAxis > BSParam.MeshMegaPrimThreshold) |
832 | lod = PhysicsScene.MeshMegaPrimLOD; | 882 | lod = BSParam.MeshMegaPrimLOD; |
833 | 883 | ||
834 | retLod = lod; | 884 | retLod = lod; |
835 | return pbs.GetMeshKey(size, lod); | 885 | return pbs.GetMeshKey(size, lod); |
@@ -851,16 +901,17 @@ public sealed class BSShapeCollection : IDisposable | |||
851 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) | 901 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) |
852 | { | 902 | { |
853 | // If the shape was successfully created, nothing more to do | 903 | // If the shape was successfully created, nothing more to do |
854 | if (newShape.ptr != IntPtr.Zero) | 904 | if (newShape.HasPhysicalShape) |
855 | return newShape; | 905 | return newShape; |
856 | 906 | ||
857 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | 907 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset |
858 | if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) | 908 | if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) |
859 | { | 909 | { |
910 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lastFailed={1}", prim.LocalID, prim.LastAssetBuildFailed); | ||
911 | // This will prevent looping through this code as we keep trying to get the failed shape | ||
860 | prim.LastAssetBuildFailed = true; | 912 | prim.LastAssetBuildFailed = true; |
913 | |||
861 | BSPhysObject xprim = prim; | 914 | BSPhysObject xprim = prim; |
862 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", | ||
863 | LogHeader, prim.LocalID, prim.LastAssetBuildFailed); | ||
864 | Util.FireAndForget(delegate | 915 | Util.FireAndForget(delegate |
865 | { | 916 | { |
866 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; | 917 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; |
@@ -869,19 +920,34 @@ public sealed class BSShapeCollection : IDisposable | |||
869 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | 920 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. |
870 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | 921 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) |
871 | { | 922 | { |
872 | if (!yprim.BaseShape.SculptEntry) | 923 | bool assetFound = false; // DEBUG DEBUG |
873 | return; | 924 | string mismatchIDs = String.Empty; // DEBUG DEBUG |
874 | if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) | 925 | if (asset != null && yprim.BaseShape.SculptEntry) |
875 | return; | 926 | { |
876 | 927 | if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) | |
877 | yprim.BaseShape.SculptData = asset.Data; | 928 | { |
878 | // This will cause the prim to see that the filler shape is not the right | 929 | yprim.BaseShape.SculptData = asset.Data; |
879 | // one and try again to build the object. | 930 | // This will cause the prim to see that the filler shape is not the right |
880 | // No race condition with the normal shape setting since the rebuild is at taint time. | 931 | // one and try again to build the object. |
881 | yprim.ForceBodyShapeRebuild(false); | 932 | // No race condition with the normal shape setting since the rebuild is at taint time. |
933 | yprim.ForceBodyShapeRebuild(false /* inTaintTime */); | ||
934 | assetFound = true; | ||
935 | } | ||
936 | else | ||
937 | { | ||
938 | mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; | ||
939 | } | ||
940 | } | ||
941 | DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}", | ||
942 | yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); | ||
882 | 943 | ||
883 | }); | 944 | }); |
884 | } | 945 | } |
946 | else | ||
947 | { | ||
948 | PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", | ||
949 | LogHeader, PhysicsScene.Name); | ||
950 | } | ||
885 | }); | 951 | }); |
886 | } | 952 | } |
887 | else | 953 | else |
@@ -893,9 +959,9 @@ public sealed class BSShapeCollection : IDisposable | |||
893 | } | 959 | } |
894 | } | 960 | } |
895 | 961 | ||
896 | // While we figure out the real problem, stick a simple native shape on the object. | 962 | // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. |
897 | BulletShape fillinShape = | 963 | BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); |
898 | BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | 964 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID); |
899 | 965 | ||
900 | return fillinShape; | 966 | return fillinShape; |
901 | } | 967 | } |
@@ -904,49 +970,45 @@ public sealed class BSShapeCollection : IDisposable | |||
904 | // Updates prim.BSBody with the information about the new body if one is created. | 970 | // Updates prim.BSBody with the information about the new body if one is created. |
905 | // Returns 'true' if an object was actually created. | 971 | // Returns 'true' if an object was actually created. |
906 | // Called at taint-time. | 972 | // Called at taint-time. |
907 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, | 973 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BodyDestructionCallback bodyCallback) |
908 | BodyDestructionCallback bodyCallback) | ||
909 | { | 974 | { |
910 | bool ret = false; | 975 | bool ret = false; |
911 | 976 | ||
912 | // the mesh, hull or native shape must have already been created in Bullet | 977 | // the mesh, hull or native shape must have already been created in Bullet |
913 | bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); | 978 | bool mustRebuild = !prim.PhysBody.HasPhysicalBody; |
914 | 979 | ||
915 | // If there is an existing body, verify it's of an acceptable type. | 980 | // If there is an existing body, verify it's of an acceptable type. |
916 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. | 981 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. |
917 | if (!mustRebuild) | 982 | if (!mustRebuild) |
918 | { | 983 | { |
919 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); | 984 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody); |
920 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY | 985 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY |
921 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) | 986 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) |
922 | { | 987 | { |
923 | // If the collisionObject is not the correct type for solidness, rebuild what's there | 988 | // If the collisionObject is not the correct type for solidness, rebuild what's there |
924 | mustRebuild = true; | 989 | mustRebuild = true; |
990 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType); | ||
925 | } | 991 | } |
926 | } | 992 | } |
927 | 993 | ||
928 | if (mustRebuild || forceRebuild) | 994 | if (mustRebuild || forceRebuild) |
929 | { | 995 | { |
930 | // Free any old body | 996 | // Free any old body |
931 | DereferenceBody(prim.PhysBody, true, bodyCallback); | 997 | DereferenceBody(prim.PhysBody, bodyCallback); |
932 | 998 | ||
933 | BulletBody aBody; | 999 | BulletBody aBody; |
934 | IntPtr bodyPtr = IntPtr.Zero; | ||
935 | if (prim.IsSolid) | 1000 | if (prim.IsSolid) |
936 | { | 1001 | { |
937 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, | 1002 | aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
938 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | 1003 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); |
939 | DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | ||
940 | } | 1004 | } |
941 | else | 1005 | else |
942 | { | 1006 | { |
943 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, | 1007 | aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
944 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | 1008 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); |
945 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | ||
946 | } | 1009 | } |
947 | aBody = new BulletBody(prim.LocalID, bodyPtr); | ||
948 | 1010 | ||
949 | ReferenceBody(aBody, true); | 1011 | ReferenceBody(aBody); |
950 | 1012 | ||
951 | prim.PhysBody = aBody; | 1013 | prim.PhysBody = aBody; |
952 | 1014 | ||
@@ -956,13 +1018,13 @@ public sealed class BSShapeCollection : IDisposable | |||
956 | return ret; | 1018 | return ret; |
957 | } | 1019 | } |
958 | 1020 | ||
959 | private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc) | 1021 | private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc) |
960 | { | 1022 | { |
961 | bool ret = false; | 1023 | bool ret = false; |
962 | MeshDesc foundDesc = new MeshDesc(); | 1024 | MeshDesc foundDesc = new MeshDesc(); |
963 | foreach (MeshDesc md in Meshes.Values) | 1025 | foreach (MeshDesc md in Meshes.Values) |
964 | { | 1026 | { |
965 | if (md.ptr == addr) | 1027 | if (md.shape.ReferenceSame(shape)) |
966 | { | 1028 | { |
967 | foundDesc = md; | 1029 | foundDesc = md; |
968 | ret = true; | 1030 | ret = true; |
@@ -974,13 +1036,13 @@ public sealed class BSShapeCollection : IDisposable | |||
974 | return ret; | 1036 | return ret; |
975 | } | 1037 | } |
976 | 1038 | ||
977 | private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc) | 1039 | private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc) |
978 | { | 1040 | { |
979 | bool ret = false; | 1041 | bool ret = false; |
980 | HullDesc foundDesc = new HullDesc(); | 1042 | HullDesc foundDesc = new HullDesc(); |
981 | foreach (HullDesc hd in Hulls.Values) | 1043 | foreach (HullDesc hd in Hulls.Values) |
982 | { | 1044 | { |
983 | if (hd.ptr == addr) | 1045 | if (hd.shape.ReferenceSame(shape)) |
984 | { | 1046 | { |
985 | foundDesc = hd; | 1047 | foundDesc = hd; |
986 | ret = true; | 1048 | ret = true; |