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.cs712
1 files changed, 631 insertions, 81 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
index dd5ae1a..3e4ee5a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -31,6 +31,7 @@ using System.Text;
31 31
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34 35
35using OMV = OpenMetaverse; 36using OMV = OpenMetaverse;
36 37
@@ -38,74 +39,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin
38{ 39{
39public abstract class BSShape 40public abstract class BSShape
40{ 41{
42 private static string LogHeader = "[BULLETSIM SHAPE]";
43
41 public int referenceCount { get; set; } 44 public int referenceCount { get; set; }
42 public DateTime lastReferenced { get; set; } 45 public DateTime lastReferenced { get; set; }
43 public BulletShape physShapeInfo { get; set; } 46 public BulletShape physShapeInfo { get; set; }
44 47
45 public BSShape() 48 public BSShape()
46 { 49 {
47 referenceCount = 0; 50 referenceCount = 1;
48 lastReferenced = DateTime.Now; 51 lastReferenced = DateTime.Now;
49 physShapeInfo = new BulletShape(); 52 physShapeInfo = new BulletShape();
50 } 53 }
51 public BSShape(BulletShape pShape) 54 public BSShape(BulletShape pShape)
52 { 55 {
53 referenceCount = 0; 56 referenceCount = 1;
54 lastReferenced = DateTime.Now; 57 lastReferenced = DateTime.Now;
55 physShapeInfo = pShape; 58 physShapeInfo = pShape;
56 } 59 }
57 60
58 // Get a reference to a physical shape. Create if it doesn't exist 61 // Get another reference to this shape.
59 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 62 public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
60 {
61 BSShape ret = null;
62
63 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
64 {
65 // an avatar capsule is close to a native shape (it is not shared)
66 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
67 FixedShapeKey.KEY_CAPSULE);
68 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
69 }
70
71 // Compound shapes are handled special as they are rebuilt from scratch.
72 // This isn't too great a hardship since most of the child shapes will have already been created.
73 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
74 {
75 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
76 ret = BSShapeCompound.GetReference(prim);
77 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
78 }
79
80 // Avatars have their own unique shape
81 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR)
82 {
83 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
84 ret = BSShapeAvatar.GetReference(prim);
85 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret);
86 }
87
88 if (ret == null)
89 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
90
91 return ret;
92 }
93 private static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
94 {
95 BSShapeMesh.GetReference(physicsScene, forceRebuild, prim);
96 BSShapeHull.GetReference(physicsScene, forceRebuild, prim);
97 return null;
98 }
99 63
100 // Called when this shape is being used again. 64 // Called when this shape is being used again.
101 public virtual void IncrementReference() 65 // Used internally. External callers should call instance.GetReference() to properly copy/reference
66 // the shape.
67 protected virtual void IncrementReference()
102 { 68 {
103 referenceCount++; 69 referenceCount++;
104 lastReferenced = DateTime.Now; 70 lastReferenced = DateTime.Now;
105 } 71 }
106 72
107 // Called when this shape is being used again. 73 // Called when this shape is being used again.
108 public virtual void DecrementReference() 74 protected virtual void DecrementReference()
109 { 75 {
110 referenceCount--; 76 referenceCount--;
111 lastReferenced = DateTime.Now; 77 lastReferenced = DateTime.Now;
@@ -114,22 +80,178 @@ public abstract class BSShape
114 // Release the use of a physical shape. 80 // Release the use of a physical shape.
115 public abstract void Dereference(BSScene physicsScene); 81 public abstract void Dereference(BSScene physicsScene);
116 82
83 // Return 'true' if there is an allocated physics physical shape under this class instance.
84 public virtual bool HasPhysicalShape
85 {
86 get
87 {
88 if (physShapeInfo != null)
89 return physShapeInfo.HasPhysicalShape;
90 return false;
91 }
92 }
93 public virtual BSPhysicsShapeType ShapeType
94 {
95 get
96 {
97 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
98 if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
99 ret = physShapeInfo.shapeType;
100 return ret;
101 }
102 }
103
117 // Returns a string for debugging that uniquily identifies the memory used by this instance 104 // Returns a string for debugging that uniquily identifies the memory used by this instance
118 public virtual string AddrString 105 public virtual string AddrString
119 { 106 {
120 get { return "unknown"; } 107 get
108 {
109 if (physShapeInfo != null)
110 return physShapeInfo.AddrString;
111 return "unknown";
112 }
121 } 113 }
122 114
123 public override string ToString() 115 public override string ToString()
124 { 116 {
125 StringBuilder buff = new StringBuilder(); 117 StringBuilder buff = new StringBuilder();
126 buff.Append("<p="); 118 if (physShapeInfo == null)
127 buff.Append(AddrString); 119 {
120 buff.Append(",noPhys");
121 }
122 else
123 {
124 buff.Append(",phy=");
125 buff.Append(physShapeInfo.ToString());
126 }
128 buff.Append(",c="); 127 buff.Append(",c=");
129 buff.Append(referenceCount.ToString()); 128 buff.Append(referenceCount.ToString());
130 buff.Append(">"); 129 buff.Append(">");
131 return buff.ToString(); 130 return buff.ToString();
132 } 131 }
132
133 #region Common shape routines
134 // Create a hash of all the shape parameters to be used as a key for this particular shape.
135 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
136 {
137 // level of detail based on size and type of the object
138 float lod = BSParam.MeshLOD;
139 if (pbs.SculptEntry)
140 lod = BSParam.SculptLOD;
141
142 // Mega prims usually get more detail because one can interact with shape approximations at this size.
143 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
144 if (maxAxis > BSParam.MeshMegaPrimThreshold)
145 lod = BSParam.MeshMegaPrimLOD;
146
147 retLod = lod;
148 return pbs.GetMeshKey(size, lod);
149 }
150
151 // The creation of a mesh or hull can fail if an underlying asset is not available.
152 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
153 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
154 // The first case causes the asset to be fetched. The second case requires
155 // us to not loop forever.
156 // Called after creating a physical mesh or hull. If the physical shape was created,
157 // just return.
158 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
159 {
160 // If the shape was successfully created, nothing more to do
161 if (newShape.HasPhysicalShape)
162 return newShape;
163
164 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
165 // fetched but we end up here again, the meshing of the asset must have failed.
166 // Prevent trying to keep fetching the mesh by declaring failure.
167 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
168 {
169 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
170 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
171 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
172 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,objNam={1},tex={2}",
173 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
174 }
175 else
176 {
177 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
178 if (prim.BaseShape.SculptEntry
179 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
180 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
181 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
182 )
183 {
184 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
185 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
186 // Multiple requestors will know we're waiting for this asset
187 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
188
189 BSPhysObject xprim = prim;
190 Util.FireAndForget(delegate
191 {
192 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID);
193 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
194 if (assetProvider != null)
195 {
196 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
197 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
198 {
199 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
200 bool assetFound = false;
201 string mismatchIDs = String.Empty; // DEBUG DEBUG
202 if (asset != null && yprim.BaseShape.SculptEntry)
203 {
204 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
205 {
206 yprim.BaseShape.SculptData = asset.Data;
207 // This will cause the prim to see that the filler shape is not the right
208 // one and try again to build the object.
209 // No race condition with the normal shape setting since the rebuild is at taint time.
210 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
211 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
212 assetFound = true;
213 }
214 else
215 {
216 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
217 }
218 }
219 if (!assetFound)
220 {
221 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
222 }
223 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
224 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
225 });
226 }
227 else
228 {
229 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
230 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
231 LogHeader, physicsScene.Name);
232 }
233 });
234 }
235 else
236 {
237 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
238 {
239 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
240 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
241 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,objNam={1},tex={2}",
242 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
243 }
244 }
245 }
246
247 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
248 BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
249 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
250
251 return fillShape.physShapeInfo;
252 }
253
254 #endregion // Common shape routines
133} 255}
134 256
135// ============================================================================================================ 257// ============================================================================================================
@@ -139,6 +261,7 @@ public class BSShapeNull : BSShape
139 { 261 {
140 } 262 }
141 public static BSShape GetReference() { return new BSShapeNull(); } 263 public static BSShape GetReference() { return new BSShapeNull(); }
264 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
142 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } 265 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
143} 266}
144 267
@@ -150,24 +273,34 @@ public class BSShapeNative : BSShape
150 { 273 {
151 } 274 }
152 275
153 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, 276 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
154 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) 277 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
155 { 278 {
156 // Native shapes are not shared and are always built anew. 279 // Native shapes are not shared and are always built anew.
157 return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); 280 return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
158 } 281 }
159 282
283 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
284 {
285 // Native shapes are not shared so we return a new shape.
286 return new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
287 physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey) );
288 }
289
160 // Make this reference to the physical shape go away since native shapes are not shared. 290 // Make this reference to the physical shape go away since native shapes are not shared.
161 public override void Dereference(BSScene physicsScene) 291 public override void Dereference(BSScene physicsScene)
162 { 292 {
163 // Native shapes are not tracked and are released immediately 293 // Native shapes are not tracked and are released immediately
164 if (physShapeInfo.HasPhysicalShape) 294 lock (physShapeInfo)
165 { 295 {
166 physicsScene.DetailLog("{0},BSShapeNative.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); 296 if (physShapeInfo.HasPhysicalShape)
167 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); 297 {
298 physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
299 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
300 }
301 physShapeInfo.Clear();
302 // Garbage collection will free up this instance.
168 } 303 }
169 physShapeInfo.Clear();
170 // Garbage collection will free up this instance.
171 } 304 }
172 305
173 private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, 306 private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
@@ -197,7 +330,7 @@ public class BSShapeNative : BSShape
197 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 330 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
198 LogHeader, prim.LocalID, shapeType); 331 LogHeader, prim.LocalID, shapeType);
199 } 332 }
200 newShape.type = shapeType; 333 newShape.shapeType = shapeType;
201 newShape.isNativeShape = true; 334 newShape.isNativeShape = true;
202 newShape.shapeKey = (UInt64)shapeKey; 335 newShape.shapeKey = (UInt64)shapeKey;
203 return newShape; 336 return newShape;
@@ -209,7 +342,7 @@ public class BSShapeNative : BSShape
209public class BSShapeMesh : BSShape 342public class BSShapeMesh : BSShape
210{ 343{
211 private static string LogHeader = "[BULLETSIM SHAPE MESH]"; 344 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
212 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); 345 public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
213 346
214 public BSShapeMesh(BulletShape pShape) : base(pShape) 347 public BSShapeMesh(BulletShape pShape) : base(pShape)
215 { 348 {
@@ -217,12 +350,9 @@ public class BSShapeMesh : BSShape
217 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 350 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
218 { 351 {
219 float lod; 352 float lod;
220 System.UInt64 newMeshKey = BSShapeCollection.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 353 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
221 354
222 physicsScene.DetailLog("{0},BSShapeMesh,create,oldKey={1},newKey={2},size={3},lod={4}", 355 BSShapeMesh retMesh = null;
223 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod);
224
225 BSShapeMesh retMesh;
226 lock (Meshes) 356 lock (Meshes)
227 { 357 {
228 if (Meshes.TryGetValue(newMeshKey, out retMesh)) 358 if (Meshes.TryGetValue(newMeshKey, out retMesh))
@@ -232,39 +362,78 @@ public class BSShapeMesh : BSShape
232 } 362 }
233 else 363 else
234 { 364 {
365 retMesh = new BSShapeMesh(new BulletShape());
235 // An instance of this mesh has not been created. Build and remember same. 366 // An instance of this mesh has not been created. Build and remember same.
236 BulletShape newShape = CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); 367 BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
237 // Take evasive action if the mesh was not constructed.
238 newShape = BSShapeCollection.VerifyMeshCreated(physicsScene, newShape, prim);
239 368
240 retMesh = new BSShapeMesh(newShape); 369 // Check to see if mesh was created (might require an asset).
370 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
371 if (!newShape.isNativeShape)
372 {
373 // If a mesh was what was created, remember the built shape for later sharing.
374 Meshes.Add(newMeshKey, retMesh);
375 }
241 376
242 Meshes.Add(newMeshKey, retMesh); 377 retMesh.physShapeInfo = newShape;
243 } 378 }
244 } 379 }
380 physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
245 return retMesh; 381 return retMesh;
246 } 382 }
383 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
384 {
385 // Another reference to this shape is just counted.
386 IncrementReference();
387 return this;
388 }
247 public override void Dereference(BSScene physicsScene) 389 public override void Dereference(BSScene physicsScene)
248 { 390 {
249 lock (Meshes) 391 lock (Meshes)
250 { 392 {
251 this.DecrementReference(); 393 this.DecrementReference();
394 physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
252 // TODO: schedule aging and destruction of unused meshes. 395 // TODO: schedule aging and destruction of unused meshes.
253 } 396 }
254 } 397 }
398 // Loop through all the known meshes and return the description based on the physical address.
399 public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
400 {
401 bool ret = false;
402 BSShapeMesh foundDesc = null;
403 lock (Meshes)
404 {
405 foreach (BSShapeMesh sm in Meshes.Values)
406 {
407 if (sm.physShapeInfo.ReferenceSame(pShape))
408 {
409 foundDesc = sm;
410 ret = true;
411 break;
412 }
255 413
256 private static BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, 414 }
415 }
416 outMesh = foundDesc;
417 return ret;
418 }
419 private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
257 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 420 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
258 { 421 {
259 BulletShape newShape = null; 422 BulletShape newShape = new BulletShape();
260 423
261 IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, 424 IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
262 false, // say it is not physical so a bounding box is not built 425 false, // say it is not physical so a bounding box is not built
263 false // do not cache the mesh and do not use previously built versions 426 false // do not cache the mesh and do not use previously built versions
264 ); 427 );
265 428
266 if (meshData != null) 429 if (meshData != null)
267 { 430 {
431 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
432 {
433 // Release the fetched asset data once it has been used.
434 pbs.SculptData = new byte[0];
435 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
436 }
268 437
269 int[] indices = meshData.getIndexListAsInt(); 438 int[] indices = meshData.getIndexListAsInt();
270 int realIndicesIndex = indices.Length; 439 int realIndicesIndex = indices.Length;
@@ -302,8 +471,8 @@ public class BSShapeMesh : BSShape
302 } 471 }
303 } 472 }
304 } 473 }
305 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}", 474 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
306 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); 475 BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
307 476
308 if (realIndicesIndex != 0) 477 if (realIndicesIndex != 0)
309 { 478 {
@@ -326,17 +495,239 @@ public class BSShapeMesh : BSShape
326public class BSShapeHull : BSShape 495public class BSShapeHull : BSShape
327{ 496{
328 private static string LogHeader = "[BULLETSIM SHAPE HULL]"; 497 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
329 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); 498 public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
330 499
331 public BSShapeHull(BulletShape pShape) : base(pShape) 500 public BSShapeHull(BulletShape pShape) : base(pShape)
332 { 501 {
333 } 502 }
334 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 503 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
335 { 504 {
336 return new BSShapeNull(); 505 float lod;
506 System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
507
508 BSShapeHull retHull = null;
509 lock (Hulls)
510 {
511 if (Hulls.TryGetValue(newHullKey, out retHull))
512 {
513 // The mesh has already been created. Return a new reference to same.
514 retHull.IncrementReference();
515 }
516 else
517 {
518 retHull = new BSShapeHull(new BulletShape());
519 // An instance of this mesh has not been created. Build and remember same.
520 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
521
522 // Check to see if hull was created (might require an asset).
523 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
524 if (!newShape.isNativeShape)
525 {
526 // If a mesh was what was created, remember the built shape for later sharing.
527 Hulls.Add(newHullKey, retHull);
528 }
529 retHull.physShapeInfo = newShape;
530 }
531 }
532 physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
533 return retHull;
534 }
535 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
536 {
537 // Another reference to this shape is just counted.
538 IncrementReference();
539 return this;
337 } 540 }
338 public override void Dereference(BSScene physicsScene) 541 public override void Dereference(BSScene physicsScene)
339 { 542 {
543 lock (Hulls)
544 {
545 this.DecrementReference();
546 physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
547 // TODO: schedule aging and destruction of unused meshes.
548 }
549 }
550 List<ConvexResult> m_hulls;
551 private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
552 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
553 {
554 BulletShape newShape = new BulletShape();
555 IntPtr hullPtr = IntPtr.Zero;
556
557 if (BSParam.ShouldUseBulletHACD)
558 {
559 // Build the hull shape from an existing mesh shape.
560 // The mesh should have already been created in Bullet.
561 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID);
562 BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
563
564 if (meshShape.physShapeInfo.HasPhysicalShape)
565 {
566 HACDParams parms;
567 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
568 parms.minClusters = BSParam.BHullMinClusters;
569 parms.compacityWeight = BSParam.BHullCompacityWeight;
570 parms.volumeWeight = BSParam.BHullVolumeWeight;
571 parms.concavity = BSParam.BHullConcavity;
572 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
573 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
574 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
575 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
576
577 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
578 newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
579 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
580
581 // Now done with the mesh shape.
582 meshShape.Dereference(physicsScene);
583 }
584 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
585 }
586 if (!newShape.HasPhysicalShape)
587 {
588 // Build a new hull in the physical world using the C# HACD algorigthm.
589 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
590 IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
591 if (meshData != null)
592 {
593 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
594 {
595 // Release the fetched asset data once it has been used.
596 pbs.SculptData = new byte[0];
597 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
598 }
599
600 int[] indices = meshData.getIndexListAsInt();
601 List<OMV.Vector3> vertices = meshData.getVertexList();
602
603 //format conversion from IMesh format to DecompDesc format
604 List<int> convIndices = new List<int>();
605 List<float3> convVertices = new List<float3>();
606 for (int ii = 0; ii < indices.GetLength(0); ii++)
607 {
608 convIndices.Add(indices[ii]);
609 }
610 foreach (OMV.Vector3 vv in vertices)
611 {
612 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
613 }
614
615 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
616 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
617 {
618 // Simple primitive shapes we know are convex so they are better implemented with
619 // fewer hulls.
620 // Check for simple shape (prim without cuts) and reduce split parameter if so.
621 if (BSShapeCollection.PrimHasNoCuts(pbs))
622 {
623 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
624 }
625 }
626
627 // setup and do convex hull conversion
628 m_hulls = new List<ConvexResult>();
629 DecompDesc dcomp = new DecompDesc();
630 dcomp.mIndices = convIndices;
631 dcomp.mVertices = convVertices;
632 dcomp.mDepth = maxDepthSplit;
633 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
634 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
635 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
636 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
637 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
638 // create the hull into the _hulls variable
639 convexBuilder.process(dcomp);
640
641 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
642 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
643
644 // Convert the vertices and indices for passing to unmanaged.
645 // The hull information is passed as a large floating point array.
646 // The format is:
647 // convHulls[0] = number of hulls
648 // convHulls[1] = number of vertices in first hull
649 // convHulls[2] = hull centroid X coordinate
650 // convHulls[3] = hull centroid Y coordinate
651 // convHulls[4] = hull centroid Z coordinate
652 // convHulls[5] = first hull vertex X
653 // convHulls[6] = first hull vertex Y
654 // convHulls[7] = first hull vertex Z
655 // convHulls[8] = second hull vertex X
656 // ...
657 // convHulls[n] = number of vertices in second hull
658 // convHulls[n+1] = second hull centroid X coordinate
659 // ...
660 //
661 // TODO: is is very inefficient. Someday change the convex hull generator to return
662 // data structures that do not need to be converted in order to pass to Bullet.
663 // And maybe put the values directly into pinned memory rather than marshaling.
664 int hullCount = m_hulls.Count;
665 int totalVertices = 1; // include one for the count of the hulls
666 foreach (ConvexResult cr in m_hulls)
667 {
668 totalVertices += 4; // add four for the vertex count and centroid
669 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
670 }
671 float[] convHulls = new float[totalVertices];
672
673 convHulls[0] = (float)hullCount;
674 int jj = 1;
675 foreach (ConvexResult cr in m_hulls)
676 {
677 // copy vertices for index access
678 float3[] verts = new float3[cr.HullVertices.Count];
679 int kk = 0;
680 foreach (float3 ff in cr.HullVertices)
681 {
682 verts[kk++] = ff;
683 }
684
685 // add to the array one hull's worth of data
686 convHulls[jj++] = cr.HullIndices.Count;
687 convHulls[jj++] = 0f; // centroid x,y,z
688 convHulls[jj++] = 0f;
689 convHulls[jj++] = 0f;
690 foreach (int ind in cr.HullIndices)
691 {
692 convHulls[jj++] = verts[ind].x;
693 convHulls[jj++] = verts[ind].y;
694 convHulls[jj++] = verts[ind].z;
695 }
696 }
697 // create the hull data structure in Bullet
698 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
699 }
700 newShape.shapeKey = newHullKey;
701 }
702 return newShape;
703 }
704 // Callback from convex hull creater with a newly created hull.
705 // Just add it to our collection of hulls for this shape.
706 private void HullReturn(ConvexResult result)
707 {
708 m_hulls.Add(result);
709 return;
710 }
711 // Loop through all the known hulls and return the description based on the physical address.
712 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
713 {
714 bool ret = false;
715 BSShapeHull foundDesc = null;
716 lock (Hulls)
717 {
718 foreach (BSShapeHull sh in Hulls.Values)
719 {
720 if (sh.physShapeInfo.ReferenceSame(pShape))
721 {
722 foundDesc = sh;
723 ret = true;
724 break;
725 }
726
727 }
728 }
729 outHull = foundDesc;
730 return ret;
340 } 731 }
341} 732}
342 733
@@ -344,14 +735,169 @@ public class BSShapeHull : BSShape
344public class BSShapeCompound : BSShape 735public class BSShapeCompound : BSShape
345{ 736{
346 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; 737 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
347 public BSShapeCompound() : base() 738 public BSShapeCompound(BulletShape pShape) : base(pShape)
348 { 739 {
349 } 740 }
350 public static BSShape GetReference(BSPhysObject prim) 741 public static BSShape GetReference(BSScene physicsScene)
351 { 742 {
352 return new BSShapeNull(); 743 // Base compound shapes are not shared so this returns a raw shape.
744 // A built compound shape can be reused in linksets.
745 return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
746 }
747 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
748 {
749 // Calling this reference means we want another handle to an existing compound shape
750 // (usually linksets) so return this copy.
751 IncrementReference();
752 return this;
753 }
754 // Dereferencing a compound shape releases the hold on all the child shapes.
755 public override void Dereference(BSScene physicsScene)
756 {
757 lock (physShapeInfo)
758 {
759 this.DecrementReference();
760 physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
761 if (referenceCount <= 0)
762 {
763 if (!physicsScene.PE.IsCompound(physShapeInfo))
764 {
765 // Failed the sanity check!!
766 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
767 LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
768 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
769 BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
770 return;
771 }
772
773 int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
774 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
775 BSScene.DetailLogZero, physShapeInfo, numChildren);
776
777 // Loop through all the children dereferencing each.
778 for (int ii = numChildren - 1; ii >= 0; ii--)
779 {
780 BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
781 DereferenceAnonCollisionShape(physicsScene, childShape);
782 }
783 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
784 }
785 }
786 }
787 private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
788 {
789 BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
790 return cShape;
791 }
792 // Sometimes we have a pointer to a collision shape but don't know what type it is.
793 // Figure out type and call the correct dereference routine.
794 // Called at taint-time.
795 private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
796 {
797 BSShapeMesh meshDesc;
798 if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
799 {
800 meshDesc.Dereference(physicsScene);
801 }
802 else
803 {
804 BSShapeHull hullDesc;
805 if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
806 {
807 hullDesc.Dereference(physicsScene);
808 }
809 else
810 {
811 if (physicsScene.PE.IsCompound(pShape))
812 {
813 BSShapeCompound recursiveCompound = new BSShapeCompound(pShape);
814 recursiveCompound.Dereference(physicsScene);
815 }
816 else
817 {
818 if (physicsScene.PE.IsNativeShape(pShape))
819 {
820 BSShapeNative nativeShape = new BSShapeNative(pShape);
821 nativeShape.Dereference(physicsScene);
822 }
823 }
824 }
825 }
826 }
827}
828
829// ============================================================================================================
830public class BSShapeConvexHull : BSShape
831{
832 private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
833 public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
834
835 public BSShapeConvexHull(BulletShape pShape) : base(pShape)
836 {
837 }
838 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
839 {
840 float lod;
841 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
842
843 physicsScene.DetailLog("{0},BSShapeMesh,getReference,newKey={1},size={2},lod={3}",
844 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
845
846 BSShapeConvexHull retConvexHull = null;
847 lock (ConvexHulls)
848 {
849 if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
850 {
851 // The mesh has already been created. Return a new reference to same.
852 retConvexHull.IncrementReference();
853 }
854 else
855 {
856 retConvexHull = new BSShapeConvexHull(new BulletShape());
857 BulletShape convexShape = null;
858
859 // Get a handle to a mesh to build the hull from
860 BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
861 if (baseMesh.physShapeInfo.isNativeShape)
862 {
863 // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
864 // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
865 // get back to this code with a buildable mesh.
866 // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
867 convexShape = baseMesh.physShapeInfo;
868 }
869 else
870 {
871 convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
872 convexShape.shapeKey = newMeshKey;
873 ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
874 }
875
876 // Done with the base mesh
877 baseMesh.Dereference(physicsScene);
878
879 retConvexHull.physShapeInfo = convexShape;
880 }
881 }
882 return retConvexHull;
883 }
884 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
885 {
886 // Calling this reference means we want another handle to an existing shape
887 // (usually linksets) so return this copy.
888 IncrementReference();
889 return this;
890 }
891 // Dereferencing a compound shape releases the hold on all the child shapes.
892 public override void Dereference(BSScene physicsScene)
893 {
894 lock (ConvexHulls)
895 {
896 this.DecrementReference();
897 physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
898 // TODO: schedule aging and destruction of unused meshes.
899 }
353 } 900 }
354 public override void Dereference(BSScene physicsScene) { }
355} 901}
356 902
357// ============================================================================================================ 903// ============================================================================================================
@@ -361,8 +907,12 @@ public class BSShapeAvatar : BSShape
361 public BSShapeAvatar() : base() 907 public BSShapeAvatar() : base()
362 { 908 {
363 } 909 }
364 public static BSShape GetReference(BSPhysObject prim) 910 public static BSShape GetReference(BSPhysObject prim)
365 { 911 {
912 return new BSShapeNull();
913 }
914 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
915 {
366 return new BSShapeNull(); 916 return new BSShapeNull();
367 } 917 }
368 public override void Dereference(BSScene physicsScene) { } 918 public override void Dereference(BSScene physicsScene) { }