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.cs716
1 files changed, 634 insertions, 82 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
index dd5ae1a..1008184 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,80 @@ 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
427 false,
428 false
264 ); 429 );
265 430
266 if (meshData != null) 431 if (meshData != null)
267 { 432 {
433 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
434 {
435 // Release the fetched asset data once it has been used.
436 pbs.SculptData = new byte[0];
437 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
438 }
268 439
269 int[] indices = meshData.getIndexListAsInt(); 440 int[] indices = meshData.getIndexListAsInt();
270 int realIndicesIndex = indices.Length; 441 int realIndicesIndex = indices.Length;
@@ -302,8 +473,8 @@ public class BSShapeMesh : BSShape
302 } 473 }
303 } 474 }
304 } 475 }
305 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}", 476 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
306 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); 477 BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
307 478
308 if (realIndicesIndex != 0) 479 if (realIndicesIndex != 0)
309 { 480 {
@@ -326,17 +497,239 @@ public class BSShapeMesh : BSShape
326public class BSShapeHull : BSShape 497public class BSShapeHull : BSShape
327{ 498{
328 private static string LogHeader = "[BULLETSIM SHAPE HULL]"; 499 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
329 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); 500 public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
330 501
331 public BSShapeHull(BulletShape pShape) : base(pShape) 502 public BSShapeHull(BulletShape pShape) : base(pShape)
332 { 503 {
333 } 504 }
334 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 505 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
335 { 506 {
336 return new BSShapeNull(); 507 float lod;
508 System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
509
510 BSShapeHull retHull = null;
511 lock (Hulls)
512 {
513 if (Hulls.TryGetValue(newHullKey, out retHull))
514 {
515 // The mesh has already been created. Return a new reference to same.
516 retHull.IncrementReference();
517 }
518 else
519 {
520 retHull = new BSShapeHull(new BulletShape());
521 // An instance of this mesh has not been created. Build and remember same.
522 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
523
524 // Check to see if hull was created (might require an asset).
525 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
526 if (!newShape.isNativeShape)
527 {
528 // If a mesh was what was created, remember the built shape for later sharing.
529 Hulls.Add(newHullKey, retHull);
530 }
531 retHull.physShapeInfo = newShape;
532 }
533 }
534 physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
535 return retHull;
536 }
537 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
538 {
539 // Another reference to this shape is just counted.
540 IncrementReference();
541 return this;
337 } 542 }
338 public override void Dereference(BSScene physicsScene) 543 public override void Dereference(BSScene physicsScene)
339 { 544 {
545 lock (Hulls)
546 {
547 this.DecrementReference();
548 physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
549 // TODO: schedule aging and destruction of unused meshes.
550 }
551 }
552 List<ConvexResult> m_hulls;
553 private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
554 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
555 {
556 BulletShape newShape = new BulletShape();
557 IntPtr hullPtr = IntPtr.Zero;
558
559 if (BSParam.ShouldUseBulletHACD)
560 {
561 // Build the hull shape from an existing mesh shape.
562 // The mesh should have already been created in Bullet.
563 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID);
564 BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
565
566 if (meshShape.physShapeInfo.HasPhysicalShape)
567 {
568 HACDParams parms;
569 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
570 parms.minClusters = BSParam.BHullMinClusters;
571 parms.compacityWeight = BSParam.BHullCompacityWeight;
572 parms.volumeWeight = BSParam.BHullVolumeWeight;
573 parms.concavity = BSParam.BHullConcavity;
574 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
575 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
576 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
577 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
578
579 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
580 newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
581 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
582
583 // Now done with the mesh shape.
584 meshShape.Dereference(physicsScene);
585 }
586 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
587 }
588 if (!newShape.HasPhysicalShape)
589 {
590 // Build a new hull in the physical world using the C# HACD algorigthm.
591 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
592 IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */, false, false);
593 if (meshData != null)
594 {
595 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
596 {
597 // Release the fetched asset data once it has been used.
598 pbs.SculptData = new byte[0];
599 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
600 }
601
602 int[] indices = meshData.getIndexListAsInt();
603 List<OMV.Vector3> vertices = meshData.getVertexList();
604
605 //format conversion from IMesh format to DecompDesc format
606 List<int> convIndices = new List<int>();
607 List<float3> convVertices = new List<float3>();
608 for (int ii = 0; ii < indices.GetLength(0); ii++)
609 {
610 convIndices.Add(indices[ii]);
611 }
612 foreach (OMV.Vector3 vv in vertices)
613 {
614 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
615 }
616
617 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
618 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
619 {
620 // Simple primitive shapes we know are convex so they are better implemented with
621 // fewer hulls.
622 // Check for simple shape (prim without cuts) and reduce split parameter if so.
623 if (BSShapeCollection.PrimHasNoCuts(pbs))
624 {
625 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
626 }
627 }
628
629 // setup and do convex hull conversion
630 m_hulls = new List<ConvexResult>();
631 DecompDesc dcomp = new DecompDesc();
632 dcomp.mIndices = convIndices;
633 dcomp.mVertices = convVertices;
634 dcomp.mDepth = maxDepthSplit;
635 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
636 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
637 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
638 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
639 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
640 // create the hull into the _hulls variable
641 convexBuilder.process(dcomp);
642
643 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
644 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
645
646 // Convert the vertices and indices for passing to unmanaged.
647 // The hull information is passed as a large floating point array.
648 // The format is:
649 // convHulls[0] = number of hulls
650 // convHulls[1] = number of vertices in first hull
651 // convHulls[2] = hull centroid X coordinate
652 // convHulls[3] = hull centroid Y coordinate
653 // convHulls[4] = hull centroid Z coordinate
654 // convHulls[5] = first hull vertex X
655 // convHulls[6] = first hull vertex Y
656 // convHulls[7] = first hull vertex Z
657 // convHulls[8] = second hull vertex X
658 // ...
659 // convHulls[n] = number of vertices in second hull
660 // convHulls[n+1] = second hull centroid X coordinate
661 // ...
662 //
663 // TODO: is is very inefficient. Someday change the convex hull generator to return
664 // data structures that do not need to be converted in order to pass to Bullet.
665 // And maybe put the values directly into pinned memory rather than marshaling.
666 int hullCount = m_hulls.Count;
667 int totalVertices = 1; // include one for the count of the hulls
668 foreach (ConvexResult cr in m_hulls)
669 {
670 totalVertices += 4; // add four for the vertex count and centroid
671 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
672 }
673 float[] convHulls = new float[totalVertices];
674
675 convHulls[0] = (float)hullCount;
676 int jj = 1;
677 foreach (ConvexResult cr in m_hulls)
678 {
679 // copy vertices for index access
680 float3[] verts = new float3[cr.HullVertices.Count];
681 int kk = 0;
682 foreach (float3 ff in cr.HullVertices)
683 {
684 verts[kk++] = ff;
685 }
686
687 // add to the array one hull's worth of data
688 convHulls[jj++] = cr.HullIndices.Count;
689 convHulls[jj++] = 0f; // centroid x,y,z
690 convHulls[jj++] = 0f;
691 convHulls[jj++] = 0f;
692 foreach (int ind in cr.HullIndices)
693 {
694 convHulls[jj++] = verts[ind].x;
695 convHulls[jj++] = verts[ind].y;
696 convHulls[jj++] = verts[ind].z;
697 }
698 }
699 // create the hull data structure in Bullet
700 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
701 }
702 newShape.shapeKey = newHullKey;
703 }
704 return newShape;
705 }
706 // Callback from convex hull creater with a newly created hull.
707 // Just add it to our collection of hulls for this shape.
708 private void HullReturn(ConvexResult result)
709 {
710 m_hulls.Add(result);
711 return;
712 }
713 // Loop through all the known hulls and return the description based on the physical address.
714 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
715 {
716 bool ret = false;
717 BSShapeHull foundDesc = null;
718 lock (Hulls)
719 {
720 foreach (BSShapeHull sh in Hulls.Values)
721 {
722 if (sh.physShapeInfo.ReferenceSame(pShape))
723 {
724 foundDesc = sh;
725 ret = true;
726 break;
727 }
728
729 }
730 }
731 outHull = foundDesc;
732 return ret;
340 } 733 }
341} 734}
342 735
@@ -344,14 +737,169 @@ public class BSShapeHull : BSShape
344public class BSShapeCompound : BSShape 737public class BSShapeCompound : BSShape
345{ 738{
346 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; 739 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
347 public BSShapeCompound() : base() 740 public BSShapeCompound(BulletShape pShape) : base(pShape)
348 { 741 {
349 } 742 }
350 public static BSShape GetReference(BSPhysObject prim) 743 public static BSShape GetReference(BSScene physicsScene)
351 { 744 {
352 return new BSShapeNull(); 745 // Base compound shapes are not shared so this returns a raw shape.
746 // A built compound shape can be reused in linksets.
747 return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
748 }
749 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
750 {
751 // Calling this reference means we want another handle to an existing compound shape
752 // (usually linksets) so return this copy.
753 IncrementReference();
754 return this;
755 }
756 // Dereferencing a compound shape releases the hold on all the child shapes.
757 public override void Dereference(BSScene physicsScene)
758 {
759 lock (physShapeInfo)
760 {
761 this.DecrementReference();
762 physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
763 if (referenceCount <= 0)
764 {
765 if (!physicsScene.PE.IsCompound(physShapeInfo))
766 {
767 // Failed the sanity check!!
768 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
769 LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
770 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
771 BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
772 return;
773 }
774
775 int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
776 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
777 BSScene.DetailLogZero, physShapeInfo, numChildren);
778
779 // Loop through all the children dereferencing each.
780 for (int ii = numChildren - 1; ii >= 0; ii--)
781 {
782 BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
783 DereferenceAnonCollisionShape(physicsScene, childShape);
784 }
785 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
786 }
787 }
788 }
789 private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
790 {
791 BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
792 return cShape;
793 }
794 // Sometimes we have a pointer to a collision shape but don't know what type it is.
795 // Figure out type and call the correct dereference routine.
796 // Called at taint-time.
797 private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
798 {
799 BSShapeMesh meshDesc;
800 if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
801 {
802 meshDesc.Dereference(physicsScene);
803 }
804 else
805 {
806 BSShapeHull hullDesc;
807 if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
808 {
809 hullDesc.Dereference(physicsScene);
810 }
811 else
812 {
813 if (physicsScene.PE.IsCompound(pShape))
814 {
815 BSShapeCompound recursiveCompound = new BSShapeCompound(pShape);
816 recursiveCompound.Dereference(physicsScene);
817 }
818 else
819 {
820 if (physicsScene.PE.IsNativeShape(pShape))
821 {
822 BSShapeNative nativeShape = new BSShapeNative(pShape);
823 nativeShape.Dereference(physicsScene);
824 }
825 }
826 }
827 }
828 }
829}
830
831// ============================================================================================================
832public class BSShapeConvexHull : BSShape
833{
834 private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
835 public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
836
837 public BSShapeConvexHull(BulletShape pShape) : base(pShape)
838 {
839 }
840 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
841 {
842 float lod;
843 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
844
845 physicsScene.DetailLog("{0},BSShapeMesh,getReference,newKey={1},size={2},lod={3}",
846 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
847
848 BSShapeConvexHull retConvexHull = null;
849 lock (ConvexHulls)
850 {
851 if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
852 {
853 // The mesh has already been created. Return a new reference to same.
854 retConvexHull.IncrementReference();
855 }
856 else
857 {
858 retConvexHull = new BSShapeConvexHull(new BulletShape());
859 BulletShape convexShape = null;
860
861 // Get a handle to a mesh to build the hull from
862 BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
863 if (baseMesh.physShapeInfo.isNativeShape)
864 {
865 // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
866 // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
867 // get back to this code with a buildable mesh.
868 // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
869 convexShape = baseMesh.physShapeInfo;
870 }
871 else
872 {
873 convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
874 convexShape.shapeKey = newMeshKey;
875 ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
876 }
877
878 // Done with the base mesh
879 baseMesh.Dereference(physicsScene);
880
881 retConvexHull.physShapeInfo = convexShape;
882 }
883 }
884 return retConvexHull;
885 }
886 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
887 {
888 // Calling this reference means we want another handle to an existing shape
889 // (usually linksets) so return this copy.
890 IncrementReference();
891 return this;
892 }
893 // Dereferencing a compound shape releases the hold on all the child shapes.
894 public override void Dereference(BSScene physicsScene)
895 {
896 lock (ConvexHulls)
897 {
898 this.DecrementReference();
899 physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
900 // TODO: schedule aging and destruction of unused meshes.
901 }
353 } 902 }
354 public override void Dereference(BSScene physicsScene) { }
355} 903}
356 904
357// ============================================================================================================ 905// ============================================================================================================
@@ -361,8 +909,12 @@ public class BSShapeAvatar : BSShape
361 public BSShapeAvatar() : base() 909 public BSShapeAvatar() : base()
362 { 910 {
363 } 911 }
364 public static BSShape GetReference(BSPhysObject prim) 912 public static BSShape GetReference(BSPhysObject prim)
365 { 913 {
914 return new BSShapeNull();
915 }
916 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
917 {
366 return new BSShapeNull(); 918 return new BSShapeNull();
367 } 919 }
368 public override void Dereference(BSScene physicsScene) { } 920 public override void Dereference(BSScene physicsScene) { }