aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs1111
1 files changed, 1026 insertions, 85 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
index ee18379..326fc9e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -29,115 +29,291 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31 31
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.Meshing;
35using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36
32using OMV = OpenMetaverse; 37using OMV = OpenMetaverse;
33 38
34namespace OpenSim.Region.Physics.BulletSPlugin 39namespace OpenSim.Region.Physics.BulletSPlugin
35{ 40{
36public abstract class BSShape 41public abstract class BSShape
37{ 42{
43 private static string LogHeader = "[BULLETSIM SHAPE]";
44
38 public int referenceCount { get; set; } 45 public int referenceCount { get; set; }
39 public DateTime lastReferenced { get; set; } 46 public DateTime lastReferenced { get; set; }
47 public BulletShape physShapeInfo { get; set; }
40 48
41 public BSShape() 49 public BSShape()
42 { 50 {
43 referenceCount = 0; 51 referenceCount = 1;
44 lastReferenced = DateTime.Now; 52 lastReferenced = DateTime.Now;
53 physShapeInfo = new BulletShape();
45 } 54 }
46 55 public BSShape(BulletShape pShape)
47 // Get a reference to a physical shape. Create if it doesn't exist
48 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
49 { 56 {
50 BSShape ret = null; 57 referenceCount = 1;
51 58 lastReferenced = DateTime.Now;
52 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 59 physShapeInfo = pShape;
53 { 60 }
54 // an avatar capsule is close to a native shape (it is not shared)
55 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
56 FixedShapeKey.KEY_CAPSULE);
57 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
58 }
59
60 // Compound shapes are handled special as they are rebuilt from scratch.
61 // This isn't too great a hardship since most of the child shapes will have already been created.
62 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
63 {
64 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
65 ret = BSShapeCompound.GetReference(prim);
66 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
67 }
68
69 // Avatars have their own unique shape
70 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR)
71 {
72 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
73 ret = BSShapeAvatar.GetReference(prim);
74 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret);
75 }
76 61
77 if (ret == null) 62 // Get another reference to this shape.
78 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); 63 public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
79 64
80 return ret; 65 // Called when this shape is being used again.
81 } 66 // Used internally. External callers should call instance.GetReference() to properly copy/reference
82 public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 67 // the shape.
68 protected virtual void IncrementReference()
83 { 69 {
84 return null; 70 referenceCount++;
71 lastReferenced = DateTime.Now;
85 } 72 }
86 public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 73
74 // Called when this shape is being used again.
75 protected virtual void DecrementReference()
87 { 76 {
88 return null; 77 referenceCount--;
78 lastReferenced = DateTime.Now;
89 } 79 }
90 80
91 // Release the use of a physical shape. 81 // Release the use of a physical shape.
92 public abstract void Dereference(BSScene physicsScene); 82 public abstract void Dereference(BSScene physicsScene);
93 83
94 // All shapes have a static call to get a reference to the physical shape 84 // Return 'true' if there is an allocated physics physical shape under this class instance.
95 // protected abstract static BSShape GetReference(); 85 public virtual bool HasPhysicalShape
86 {
87 get
88 {
89 if (physShapeInfo != null)
90 return physShapeInfo.HasPhysicalShape;
91 return false;
92 }
93 }
94 public virtual BSPhysicsShapeType ShapeType
95 {
96 get
97 {
98 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
99 if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
100 ret = physShapeInfo.shapeType;
101 return ret;
102 }
103 }
96 104
97 // Returns a string for debugging that uniquily identifies the memory used by this instance 105 // Returns a string for debugging that uniquily identifies the memory used by this instance
98 public virtual string AddrString 106 public virtual string AddrString
99 { 107 {
100 get { return "unknown"; } 108 get
109 {
110 if (physShapeInfo != null)
111 return physShapeInfo.AddrString;
112 return "unknown";
113 }
101 } 114 }
102 115
103 public override string ToString() 116 public override string ToString()
104 { 117 {
105 StringBuilder buff = new StringBuilder(); 118 StringBuilder buff = new StringBuilder();
106 buff.Append("<p="); 119 if (physShapeInfo == null)
107 buff.Append(AddrString); 120 {
121 buff.Append("<noPhys");
122 }
123 else
124 {
125 buff.Append("<phy=");
126 buff.Append(physShapeInfo.ToString());
127 }
108 buff.Append(",c="); 128 buff.Append(",c=");
109 buff.Append(referenceCount.ToString()); 129 buff.Append(referenceCount.ToString());
110 buff.Append(">"); 130 buff.Append(">");
111 return buff.ToString(); 131 return buff.ToString();
112 } 132 }
133
134 #region Common shape routines
135 // Create a hash of all the shape parameters to be used as a key for this particular shape.
136 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
137 {
138 // level of detail based on size and type of the object
139 float lod = BSParam.MeshLOD;
140 if (pbs.SculptEntry)
141 lod = BSParam.SculptLOD;
142
143 // Mega prims usually get more detail because one can interact with shape approximations at this size.
144 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
145 if (maxAxis > BSParam.MeshMegaPrimThreshold)
146 lod = BSParam.MeshMegaPrimLOD;
147
148 retLod = lod;
149 return pbs.GetMeshKey(size, lod);
150 }
151
152 // The creation of a mesh or hull can fail if an underlying asset is not available.
153 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
154 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
155 // The first case causes the asset to be fetched. The second case requires
156 // us to not loop forever.
157 // Called after creating a physical mesh or hull. If the physical shape was created,
158 // just return.
159 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
160 {
161 // If the shape was successfully created, nothing more to do
162 if (newShape.HasPhysicalShape)
163 return newShape;
164
165 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
166 // fetched but we end up here again, the meshing of the asset must have failed.
167 // Prevent trying to keep fetching the mesh by declaring failure.
168 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
169 {
170 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
171 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
172 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
173 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,objNam={1},tex={2}",
174 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
175 }
176 else
177 {
178 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
179 if (prim.BaseShape.SculptEntry
180 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
181 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
182 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
183 )
184 {
185 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
186 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
187 // Multiple requestors will know we're waiting for this asset
188 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
189
190 BSPhysObject xprim = prim;
191 Util.FireAndForget(delegate
192 {
193 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID);
194 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
195 if (assetProvider != null)
196 {
197 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
198 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
199 {
200 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
201 bool assetFound = false;
202 string mismatchIDs = String.Empty; // DEBUG DEBUG
203 if (asset != null && yprim.BaseShape.SculptEntry)
204 {
205 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
206 {
207 yprim.BaseShape.SculptData = asset.Data;
208 // This will cause the prim to see that the filler shape is not the right
209 // one and try again to build the object.
210 // No race condition with the normal shape setting since the rebuild is at taint time.
211 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
212 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
213 assetFound = true;
214 }
215 else
216 {
217 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
218 }
219 }
220 if (!assetFound)
221 {
222 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
223 }
224 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
225 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
226 });
227 }
228 else
229 {
230 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
231 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
232 LogHeader, physicsScene.Name);
233 }
234 });
235 }
236 else
237 {
238 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
239 {
240 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
241 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
242 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,objNam={1},tex={2}",
243 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
244 }
245 }
246 }
247
248 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
249 BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
250 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
251
252 return fillShape.physShapeInfo;
253 }
254
255 #endregion // Common shape routines
113} 256}
114 257
258// ============================================================================================================
115public class BSShapeNull : BSShape 259public class BSShapeNull : BSShape
116{ 260{
117 public BSShapeNull() : base() 261 public BSShapeNull() : base()
118 { 262 {
119 } 263 }
120 public static BSShape GetReference() { return new BSShapeNull(); } 264 public static BSShape GetReference() { return new BSShapeNull(); }
265 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
121 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } 266 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
122} 267}
123 268
269// ============================================================================================================
124public class BSShapeNative : BSShape 270public class BSShapeNative : BSShape
125{ 271{
126 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; 272 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
127 public BSShapeNative() : base() 273 public BSShapeNative(BulletShape pShape) : base(pShape)
128 { 274 {
129 } 275 }
130 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, 276
131 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) 277 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
278 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
132 { 279 {
133 // Native shapes are not shared and are always built anew. 280 // Native shapes are not shared and are always built anew.
134 //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); 281 return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
135 return null; 282 }
283
284 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
285 {
286 // Native shapes are not shared so we return a new shape.
287 BSShape ret = null;
288 lock (physShapeInfo)
289 {
290 ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
291 physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey));
292 }
293 return ret;
294 }
295
296 // Make this reference to the physical shape go away since native shapes are not shared.
297 public override void Dereference(BSScene physicsScene)
298 {
299 // Native shapes are not tracked and are released immediately
300 lock (physShapeInfo)
301 {
302 if (physShapeInfo.HasPhysicalShape)
303 {
304 physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
305 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
306 }
307 physShapeInfo.Clear();
308 // Garbage collection will free up this instance.
309 }
136 } 310 }
137 311
138 private BSShapeNative(BSScene physicsScene, BSPhysObject prim, 312 private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
139 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) 313 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
140 { 314 {
315 BulletShape newShape;
316
141 ShapeData nativeShapeData = new ShapeData(); 317 ShapeData nativeShapeData = new ShapeData();
142 nativeShapeData.Type = shapeType; 318 nativeShapeData.Type = shapeType;
143 nativeShapeData.ID = prim.LocalID; 319 nativeShapeData.ID = prim.LocalID;
@@ -146,84 +322,849 @@ public class BSShapeNative : BSShape
146 nativeShapeData.MeshKey = (ulong)shapeKey; 322 nativeShapeData.MeshKey = (ulong)shapeKey;
147 nativeShapeData.HullKey = (ulong)shapeKey; 323 nativeShapeData.HullKey = (ulong)shapeKey;
148 324
149
150 /*
151 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 325 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
152 { 326 {
153 ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); 327 newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
154 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 328 physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale);
155 } 329 }
156 else 330 else
157 { 331 {
158 ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); 332 newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
159 } 333 }
160 if (ptr == IntPtr.Zero) 334 if (!newShape.HasPhysicalShape)
161 { 335 {
162 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 336 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
163 LogHeader, prim.LocalID, shapeType); 337 LogHeader, prim.LocalID, shapeType);
164 } 338 }
165 type = shapeType; 339 newShape.shapeType = shapeType;
166 key = (UInt64)shapeKey; 340 newShape.isNativeShape = true;
167 */ 341 newShape.shapeKey = (UInt64)shapeKey;
168 } 342 return newShape;
169 // Make this reference to the physical shape go away since native shapes are not shared.
170 public override void Dereference(BSScene physicsScene)
171 {
172 /*
173 // Native shapes are not tracked and are released immediately
174 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
175 PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this);
176 ptr = IntPtr.Zero;
177 // Garbage collection will free up this instance.
178 */
179 } 343 }
344
180} 345}
181 346
347// ============================================================================================================
182public class BSShapeMesh : BSShape 348public class BSShapeMesh : BSShape
183{ 349{
184 private static string LogHeader = "[BULLETSIM SHAPE MESH]"; 350 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
185 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); 351 public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
186 352
187 public BSShapeMesh() : base() 353 public BSShapeMesh(BulletShape pShape) : base(pShape)
188 { 354 {
189 } 355 }
190 public static BSShape GetReference() { return new BSShapeNull(); } 356 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
191 public override void Dereference(BSScene physicsScene) { } 357 {
358 float lod;
359 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
360
361 BSShapeMesh retMesh = null;
362 lock (Meshes)
363 {
364 if (Meshes.TryGetValue(newMeshKey, out retMesh))
365 {
366 // The mesh has already been created. Return a new reference to same.
367 retMesh.IncrementReference();
368 }
369 else
370 {
371 retMesh = new BSShapeMesh(new BulletShape());
372 // An instance of this mesh has not been created. Build and remember same.
373 BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
374
375 // Check to see if mesh was created (might require an asset).
376 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
377 if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
378 {
379 // If a mesh was what was created, remember the built shape for later sharing.
380 // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
381 Meshes.Add(newMeshKey, retMesh);
382 }
383
384 retMesh.physShapeInfo = newShape;
385 }
386 }
387 physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
388 return retMesh;
389 }
390 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
391 {
392 BSShape ret = null;
393 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
394 // and we must create a copy of the native shape since they are never shared.
395 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
396 {
397 // TODO: decide when the native shapes should be freed. Check in Dereference?
398 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
399 }
400 else
401 {
402 // Another reference to this shape is just counted.
403 IncrementReference();
404 ret = this;
405 }
406 return ret;
407 }
408 public override void Dereference(BSScene physicsScene)
409 {
410 lock (Meshes)
411 {
412 this.DecrementReference();
413 physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
414 // TODO: schedule aging and destruction of unused meshes.
415 }
416 }
417 // Loop through all the known meshes and return the description based on the physical address.
418 public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
419 {
420 bool ret = false;
421 BSShapeMesh foundDesc = null;
422 lock (Meshes)
423 {
424 foreach (BSShapeMesh sm in Meshes.Values)
425 {
426 if (sm.physShapeInfo.ReferenceSame(pShape))
427 {
428 foundDesc = sm;
429 ret = true;
430 break;
431 }
432
433 }
434 }
435 outMesh = foundDesc;
436 return ret;
437 }
438
439 public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices );
440 private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
441 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
442 {
443 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
444 (w, iC, i, vC, v) => physicsScene.PE.CreateMeshShape(w, iC, i, vC, v) );
445 }
446
447 // Code that uses the mesher to create the index/vertices info for a trimesh shape.
448 // This is used by the passed 'makeShape' call to create the Bullet mesh shape.
449 // The actual build call is passed so this logic can be used by several of the shapes that use a
450 // simple mesh as their base shape.
451 public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
452 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape)
453 {
454 BulletShape newShape = new BulletShape();
455
456 IMesh meshData = null;
457 lock (physicsScene.mesher)
458 {
459 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
460 false, // say it is not physical so a bounding box is not built
461 false, // do not cache the mesh and do not use previously built versions
462 false,
463 false
464 );
465 }
466
467 if (meshData != null)
468 {
469 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
470 {
471 // Release the fetched asset data once it has been used.
472 pbs.SculptData = new byte[0];
473 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
474 }
475
476 int[] indices = meshData.getIndexListAsInt();
477 int realIndicesIndex = indices.Length;
478 float[] verticesAsFloats = meshData.getVertexListAsFloat();
479
480 if (BSParam.ShouldRemoveZeroWidthTriangles)
481 {
482 // Remove degenerate triangles. These are triangles with two of the vertices
483 // are the same. This is complicated by the problem that vertices are not
484 // made unique in sculpties so we have to compare the values in the vertex.
485 realIndicesIndex = 0;
486 for (int tri = 0; tri < indices.Length; tri += 3)
487 {
488 // Compute displacements into vertex array for each vertex of the triangle
489 int v1 = indices[tri + 0] * 3;
490 int v2 = indices[tri + 1] * 3;
491 int v3 = indices[tri + 2] * 3;
492 // Check to see if any two of the vertices are the same
493 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
494 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
495 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
496 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
497 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
498 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
499 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
500 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
501 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
502 )
503 {
504 // None of the vertices of the triangles are the same. This is a good triangle;
505 indices[realIndicesIndex + 0] = indices[tri + 0];
506 indices[realIndicesIndex + 1] = indices[tri + 1];
507 indices[realIndicesIndex + 2] = indices[tri + 2];
508 realIndicesIndex += 3;
509 }
510 }
511 }
512 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
513 BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
514
515 if (realIndicesIndex != 0)
516 {
517 newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
518 }
519 else
520 {
521 // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh.
522 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
523 physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
524 LogHeader, prim.PhysObjectName, prim.RawPosition, physicsScene.Name);
525 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey);
526 }
527 }
528 newShape.shapeKey = newMeshKey;
529
530 return newShape;
531 }
192} 532}
193 533
534// ============================================================================================================
194public class BSShapeHull : BSShape 535public class BSShapeHull : BSShape
195{ 536{
196 private static string LogHeader = "[BULLETSIM SHAPE HULL]"; 537 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
197 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); 538 public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
198 539
199 public BSShapeHull() : base() 540 public BSShapeHull(BulletShape pShape) : base(pShape)
200 { 541 {
201 } 542 }
202 public static BSShape GetReference() { return new BSShapeNull(); } 543 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
203 public override void Dereference(BSScene physicsScene) { } 544 {
545 float lod;
546 System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
547
548 BSShapeHull retHull = null;
549 lock (Hulls)
550 {
551 if (Hulls.TryGetValue(newHullKey, out retHull))
552 {
553 // The mesh has already been created. Return a new reference to same.
554 retHull.IncrementReference();
555 }
556 else
557 {
558 retHull = new BSShapeHull(new BulletShape());
559 // An instance of this mesh has not been created. Build and remember same.
560 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
561
562 // Check to see if hull was created (might require an asset).
563 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
564 if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
565 {
566 // If a mesh was what was created, remember the built shape for later sharing.
567 Hulls.Add(newHullKey, retHull);
568 }
569 retHull.physShapeInfo = newShape;
570 }
571 }
572 physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
573 return retHull;
574 }
575 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
576 {
577 BSShape ret = null;
578 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
579 // and we must create a copy of the native shape since they are never shared.
580 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
581 {
582 // TODO: decide when the native shapes should be freed. Check in Dereference?
583 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
584 }
585 else
586 {
587 // Another reference to this shape is just counted.
588 IncrementReference();
589 ret = this;
590 }
591 return ret;
592 }
593 public override void Dereference(BSScene physicsScene)
594 {
595 lock (Hulls)
596 {
597 this.DecrementReference();
598 physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
599 // TODO: schedule aging and destruction of unused meshes.
600 }
601 }
602 List<ConvexResult> m_hulls;
603 private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
604 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
605 {
606 BulletShape newShape = new BulletShape();
607
608 IMesh meshData = null;
609 List<List<OMV.Vector3>> allHulls = null;
610 lock (physicsScene.mesher)
611 {
612 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
613 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */, false, false);
614
615 // If we should use the asset's hull info, fetch it out of the locked mesher
616 if (meshData != null && BSParam.ShouldUseAssetHulls)
617 {
618 Meshmerizer realMesher = physicsScene.mesher as Meshmerizer;
619 if (realMesher != null)
620 {
621 allHulls = realMesher.GetConvexHulls(size);
622 }
623 if (allHulls == null)
624 {
625 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID);
626 }
627 }
628 }
629
630 // If there is hull data in the mesh asset, build the hull from that
631 if (allHulls != null && BSParam.ShouldUseAssetHulls)
632 {
633 int hullCount = allHulls.Count;
634 int totalVertices = 1; // include one for the count of the hulls
635 // Using the structure described for HACD hulls, create the memory sturcture
636 // to pass the hull data to the creater.
637 foreach (List<OMV.Vector3> hullVerts in allHulls)
638 {
639 totalVertices += 4; // add four for the vertex count and centroid
640 totalVertices += hullVerts.Count * 3; // one vertex is three dimensions
641 }
642 float[] convHulls = new float[totalVertices];
643
644 convHulls[0] = (float)hullCount;
645 int jj = 1;
646 foreach (List<OMV.Vector3> hullVerts in allHulls)
647 {
648 convHulls[jj + 0] = hullVerts.Count;
649 convHulls[jj + 1] = 0f; // centroid x,y,z
650 convHulls[jj + 2] = 0f;
651 convHulls[jj + 3] = 0f;
652 jj += 4;
653 foreach (OMV.Vector3 oneVert in hullVerts)
654 {
655 convHulls[jj + 0] = oneVert.X;
656 convHulls[jj + 1] = oneVert.Y;
657 convHulls[jj + 2] = oneVert.Z;
658 jj += 3;
659 }
660 }
661
662 // create the hull data structure in Bullet
663 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
664
665 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}",
666 prim.LocalID, hullCount, totalVertices, newShape);
667 }
668
669 // If no hull specified in the asset and we should use Bullet's HACD approximation...
670 if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD)
671 {
672 // Build the hull shape from an existing mesh shape.
673 // The mesh should have already been created in Bullet.
674 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID);
675 BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
676
677 if (meshShape.physShapeInfo.HasPhysicalShape)
678 {
679 HACDParams parms;
680 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
681 parms.minClusters = BSParam.BHullMinClusters;
682 parms.compacityWeight = BSParam.BHullCompacityWeight;
683 parms.volumeWeight = BSParam.BHullVolumeWeight;
684 parms.concavity = BSParam.BHullConcavity;
685 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
686 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
687 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
688 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
689
690 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
691 newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
692 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape);
693
694 // Now done with the mesh shape.
695 meshShape.Dereference(physicsScene);
696 }
697 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
698 }
699
700 // If no other hull specifications, use our HACD hull approximation.
701 if (!newShape.HasPhysicalShape && meshData != null)
702 {
703 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
704 {
705 // Release the fetched asset data once it has been used.
706 pbs.SculptData = new byte[0];
707 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
708 }
709
710 int[] indices = meshData.getIndexListAsInt();
711 List<OMV.Vector3> vertices = meshData.getVertexList();
712
713 //format conversion from IMesh format to DecompDesc format
714 List<int> convIndices = new List<int>();
715 List<float3> convVertices = new List<float3>();
716 for (int ii = 0; ii < indices.GetLength(0); ii++)
717 {
718 convIndices.Add(indices[ii]);
719 }
720 foreach (OMV.Vector3 vv in vertices)
721 {
722 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
723 }
724
725 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
726 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
727 {
728 // Simple primitive shapes we know are convex so they are better implemented with
729 // fewer hulls.
730 // Check for simple shape (prim without cuts) and reduce split parameter if so.
731 if (BSShapeCollection.PrimHasNoCuts(pbs))
732 {
733 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
734 }
735 }
736
737 // setup and do convex hull conversion
738 m_hulls = new List<ConvexResult>();
739 DecompDesc dcomp = new DecompDesc();
740 dcomp.mIndices = convIndices;
741 dcomp.mVertices = convVertices;
742 dcomp.mDepth = maxDepthSplit;
743 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
744 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
745 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
746 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
747 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
748 // create the hull into the _hulls variable
749 convexBuilder.process(dcomp);
750
751 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
752 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
753
754 // Convert the vertices and indices for passing to unmanaged.
755 // The hull information is passed as a large floating point array.
756 // The format is:
757 // convHulls[0] = number of hulls
758 // convHulls[1] = number of vertices in first hull
759 // convHulls[2] = hull centroid X coordinate
760 // convHulls[3] = hull centroid Y coordinate
761 // convHulls[4] = hull centroid Z coordinate
762 // convHulls[5] = first hull vertex X
763 // convHulls[6] = first hull vertex Y
764 // convHulls[7] = first hull vertex Z
765 // convHulls[8] = second hull vertex X
766 // ...
767 // convHulls[n] = number of vertices in second hull
768 // convHulls[n+1] = second hull centroid X coordinate
769 // ...
770 //
771 // TODO: is is very inefficient. Someday change the convex hull generator to return
772 // data structures that do not need to be converted in order to pass to Bullet.
773 // And maybe put the values directly into pinned memory rather than marshaling.
774 int hullCount = m_hulls.Count;
775 int totalVertices = 1; // include one for the count of the hulls
776 foreach (ConvexResult cr in m_hulls)
777 {
778 totalVertices += 4; // add four for the vertex count and centroid
779 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
780 }
781 float[] convHulls = new float[totalVertices];
782
783 convHulls[0] = (float)hullCount;
784 int jj = 1;
785 foreach (ConvexResult cr in m_hulls)
786 {
787 // copy vertices for index access
788 float3[] verts = new float3[cr.HullVertices.Count];
789 int kk = 0;
790 foreach (float3 ff in cr.HullVertices)
791 {
792 verts[kk++] = ff;
793 }
794
795 // add to the array one hull's worth of data
796 convHulls[jj++] = cr.HullIndices.Count;
797 convHulls[jj++] = 0f; // centroid x,y,z
798 convHulls[jj++] = 0f;
799 convHulls[jj++] = 0f;
800 foreach (int ind in cr.HullIndices)
801 {
802 convHulls[jj++] = verts[ind].x;
803 convHulls[jj++] = verts[ind].y;
804 convHulls[jj++] = verts[ind].z;
805 }
806 }
807 // create the hull data structure in Bullet
808 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
809 }
810 newShape.shapeKey = newHullKey;
811 return newShape;
812 }
813 // Callback from convex hull creater with a newly created hull.
814 // Just add it to our collection of hulls for this shape.
815 private void HullReturn(ConvexResult result)
816 {
817 m_hulls.Add(result);
818 return;
819 }
820 // Loop through all the known hulls and return the description based on the physical address.
821 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
822 {
823 bool ret = false;
824 BSShapeHull foundDesc = null;
825 lock (Hulls)
826 {
827 foreach (BSShapeHull sh in Hulls.Values)
828 {
829 if (sh.physShapeInfo.ReferenceSame(pShape))
830 {
831 foundDesc = sh;
832 ret = true;
833 break;
834 }
835
836 }
837 }
838 outHull = foundDesc;
839 return ret;
840 }
204} 841}
205 842
843// ============================================================================================================
206public class BSShapeCompound : BSShape 844public class BSShapeCompound : BSShape
207{ 845{
208 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; 846 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
209 public BSShapeCompound() : base() 847 public BSShapeCompound(BulletShape pShape) : base(pShape)
210 { 848 {
211 } 849 }
212 public static BSShape GetReference(BSPhysObject prim) 850 public static BSShape GetReference(BSScene physicsScene)
213 { 851 {
214 return new BSShapeNull(); 852 // Base compound shapes are not shared so this returns a raw shape.
853 // A built compound shape can be reused in linksets.
854 return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
855 }
856 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
857 {
858 // Calling this reference means we want another handle to an existing compound shape
859 // (usually linksets) so return this copy.
860 IncrementReference();
861 return this;
862 }
863 // Dereferencing a compound shape releases the hold on all the child shapes.
864 public override void Dereference(BSScene physicsScene)
865 {
866 lock (physShapeInfo)
867 {
868 this.DecrementReference();
869 physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
870 if (referenceCount <= 0)
871 {
872 if (!physicsScene.PE.IsCompound(physShapeInfo))
873 {
874 // Failed the sanity check!!
875 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
876 LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
877 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
878 BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
879 return;
880 }
881
882 int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
883 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
884 BSScene.DetailLogZero, physShapeInfo, numChildren);
885
886 // Loop through all the children dereferencing each.
887 for (int ii = numChildren - 1; ii >= 0; ii--)
888 {
889 BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
890 DereferenceAnonCollisionShape(physicsScene, childShape);
891 }
892 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
893 }
894 }
895 }
896 private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
897 {
898 BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
899 return cShape;
900 }
901 // Sometimes we have a pointer to a collision shape but don't know what type it is.
902 // Figure out type and call the correct dereference routine.
903 // Called at taint-time.
904 private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
905 {
906 // TODO: figure a better way to go through all the shape types and find a possible instance.
907 BSShapeMesh meshDesc;
908 if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
909 {
910 meshDesc.Dereference(physicsScene);
911 }
912 else
913 {
914 BSShapeHull hullDesc;
915 if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
916 {
917 hullDesc.Dereference(physicsScene);
918 }
919 else
920 {
921 BSShapeConvexHull chullDesc;
922 if (BSShapeConvexHull.TryGetHullByPtr(pShape, out chullDesc))
923 {
924 chullDesc.Dereference(physicsScene);
925 }
926 else
927 {
928 BSShapeGImpact gImpactDesc;
929 if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc))
930 {
931 gImpactDesc.Dereference(physicsScene);
932 }
933 else
934 {
935 // Didn't find it in the lists of specific types. It could be compound.
936 if (physicsScene.PE.IsCompound(pShape))
937 {
938 BSShapeCompound recursiveCompound = new BSShapeCompound(pShape);
939 recursiveCompound.Dereference(physicsScene);
940 }
941 else
942 {
943 // If none of the above, maybe it is a simple native shape.
944 if (physicsScene.PE.IsNativeShape(pShape))
945 {
946 BSShapeNative nativeShape = new BSShapeNative(pShape);
947 nativeShape.Dereference(physicsScene);
948 }
949 }
950 }
951 }
952 }
953 }
954 }
955}
956
957// ============================================================================================================
958public class BSShapeConvexHull : BSShape
959{
960 private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
961 public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
962
963 public BSShapeConvexHull(BulletShape pShape) : base(pShape)
964 {
965 }
966 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
967 {
968 float lod;
969 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
970
971 physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}",
972 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
973
974 BSShapeConvexHull retConvexHull = null;
975 lock (ConvexHulls)
976 {
977 if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
978 {
979 // The mesh has already been created. Return a new reference to same.
980 retConvexHull.IncrementReference();
981 }
982 else
983 {
984 retConvexHull = new BSShapeConvexHull(new BulletShape());
985 BulletShape convexShape = null;
986
987 // Get a handle to a mesh to build the hull from
988 BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
989 if (baseMesh.physShapeInfo.isNativeShape)
990 {
991 // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
992 // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
993 // get back to this code with a buildable mesh.
994 // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
995 convexShape = baseMesh.physShapeInfo;
996 }
997 else
998 {
999 convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
1000 convexShape.shapeKey = newMeshKey;
1001 ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
1002 }
1003
1004 // Done with the base mesh
1005 baseMesh.Dereference(physicsScene);
1006
1007 retConvexHull.physShapeInfo = convexShape;
1008 }
1009 }
1010 return retConvexHull;
1011 }
1012 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
1013 {
1014 // Calling this reference means we want another handle to an existing shape
1015 // (usually linksets) so return this copy.
1016 IncrementReference();
1017 return this;
1018 }
1019 // Dereferencing a compound shape releases the hold on all the child shapes.
1020 public override void Dereference(BSScene physicsScene)
1021 {
1022 lock (ConvexHulls)
1023 {
1024 this.DecrementReference();
1025 physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
1026 // TODO: schedule aging and destruction of unused meshes.
1027 }
1028 }
1029 // Loop through all the known hulls and return the description based on the physical address.
1030 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull)
1031 {
1032 bool ret = false;
1033 BSShapeConvexHull foundDesc = null;
1034 lock (ConvexHulls)
1035 {
1036 foreach (BSShapeConvexHull sh in ConvexHulls.Values)
1037 {
1038 if (sh.physShapeInfo.ReferenceSame(pShape))
1039 {
1040 foundDesc = sh;
1041 ret = true;
1042 break;
1043 }
1044
1045 }
1046 }
1047 outHull = foundDesc;
1048 return ret;
215 } 1049 }
216 public override void Dereference(BSScene physicsScene) { }
217} 1050}
1051// ============================================================================================================
1052public class BSShapeGImpact : BSShape
1053{
1054 private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]";
1055 public static Dictionary<System.UInt64, BSShapeGImpact> GImpacts = new Dictionary<System.UInt64, BSShapeGImpact>();
1056
1057 public BSShapeGImpact(BulletShape pShape) : base(pShape)
1058 {
1059 }
1060 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1061 {
1062 float lod;
1063 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1064
1065 physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}",
1066 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1067
1068 BSShapeGImpact retGImpact = null;
1069 lock (GImpacts)
1070 {
1071 if (GImpacts.TryGetValue(newMeshKey, out retGImpact))
1072 {
1073 // The mesh has already been created. Return a new reference to same.
1074 retGImpact.IncrementReference();
1075 }
1076 else
1077 {
1078 retGImpact = new BSShapeGImpact(new BulletShape());
1079 BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
218 1080
1081 // Check to see if mesh was created (might require an asset).
1082 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
1083 newShape.shapeKey = newMeshKey;
1084 if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
1085 {
1086 // If a mesh was what was created, remember the built shape for later sharing.
1087 // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
1088 GImpacts.Add(newMeshKey, retGImpact);
1089 }
1090
1091 retGImpact.physShapeInfo = newShape;
1092 }
1093 }
1094 return retGImpact;
1095 }
1096
1097 private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
1098 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
1099 {
1100 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
1101 (w, iC, i, vC, v) => physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v) );
1102 }
1103
1104 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1105 {
1106 BSShape ret = null;
1107 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
1108 // and we must create a copy of the native shape since they are never shared.
1109 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
1110 {
1111 // TODO: decide when the native shapes should be freed. Check in Dereference?
1112 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
1113 }
1114 else
1115 {
1116 // Another reference to this shape is just counted.
1117 IncrementReference();
1118 ret = this;
1119 }
1120 return ret;
1121 }
1122 // Dereferencing a compound shape releases the hold on all the child shapes.
1123 public override void Dereference(BSScene physicsScene)
1124 {
1125 lock (GImpacts)
1126 {
1127 this.DecrementReference();
1128 physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this);
1129 // TODO: schedule aging and destruction of unused meshes.
1130 }
1131 }
1132 // Loop through all the known hulls and return the description based on the physical address.
1133 public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull)
1134 {
1135 bool ret = false;
1136 BSShapeGImpact foundDesc = null;
1137 lock (GImpacts)
1138 {
1139 foreach (BSShapeGImpact sh in GImpacts.Values)
1140 {
1141 if (sh.physShapeInfo.ReferenceSame(pShape))
1142 {
1143 foundDesc = sh;
1144 ret = true;
1145 break;
1146 }
1147
1148 }
1149 }
1150 outHull = foundDesc;
1151 return ret;
1152 }
1153}
1154
1155// ============================================================================================================
219public class BSShapeAvatar : BSShape 1156public class BSShapeAvatar : BSShape
220{ 1157{
221 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; 1158 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
222 public BSShapeAvatar() : base() 1159 public BSShapeAvatar() : base()
223 { 1160 {
224 } 1161 }
225 public static BSShape GetReference(BSPhysObject prim) 1162 public static BSShape GetReference(BSPhysObject prim)
226 { 1163 {
1164 return new BSShapeNull();
1165 }
1166 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1167 {
227 return new BSShapeNull(); 1168 return new BSShapeNull();
228 } 1169 }
229 public override void Dereference(BSScene physicsScene) { } 1170 public override void Dereference(BSScene physicsScene) { }