OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
BSShapes.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyrightD
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Text;
31 
32 using OpenSim.Framework;
33 using OpenSim.Region.PhysicsModules.SharedBase;
34 using OpenSim.Region.PhysicsModule.Meshing;
35 using OpenSim.Region.PhysicsModules.ConvexDecompositionDotNet;
36 
37 using OMV = OpenMetaverse;
38 
39 namespace OpenSim.Region.PhysicsModule.BulletS
40 {
41 // Information class that holds stats for the shape. Which values mean
42 // something depends on the type of shape.
43 // This information is used for debugging and stats and is not used
44 // for operational things.
45 public class ShapeInfoInfo
46 {
47  public int Vertices { get; set; }
48  private int m_hullCount;
49  private int[] m_verticesPerHull;
50  public ShapeInfoInfo()
51  {
52  Vertices = 0;
53  m_hullCount = 0;
54  m_verticesPerHull = null;
55  }
56  public int HullCount
57  {
58  set
59  {
60  m_hullCount = value;
61  m_verticesPerHull = new int[m_hullCount];
62  Array.Clear(m_verticesPerHull, 0, m_hullCount);
63  }
64  get { return m_hullCount; }
65  }
66  public void SetVerticesPerHull(int hullNum, int vertices)
67  {
68  if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length)
69  {
70  m_verticesPerHull[hullNum] = vertices;
71  }
72  }
73  public int GetVerticesPerHull(int hullNum)
74  {
75  if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length)
76  {
77  return m_verticesPerHull[hullNum];
78  }
79  return 0;
80  }
81  public override string ToString()
82  {
83  StringBuilder buff = new StringBuilder();
84  // buff.Append("ShapeInfo=<");
85  buff.Append("<");
86  if (Vertices > 0)
87  {
88  buff.Append("verts=");
89  buff.Append(Vertices.ToString());
90  }
91 
92  if (Vertices > 0 && HullCount > 0) buff.Append(",");
93 
94  if (HullCount > 0)
95  {
96  buff.Append("nHulls=");
97  buff.Append(HullCount.ToString());
98  buff.Append(",");
99  buff.Append("hullVerts=");
100  for (int ii = 0; ii < HullCount; ii++)
101  {
102  if (ii != 0) buff.Append(",");
103  buff.Append(GetVerticesPerHull(ii).ToString());
104  }
105  }
106  buff.Append(">");
107  return buff.ToString();
108  }
109 }
110 
111 public abstract class BSShape
112 {
113  private static string LogHeader = "[BULLETSIM SHAPE]";
114 
115  public int referenceCount { get; set; }
116  public DateTime lastReferenced { get; set; }
117  public BulletShape physShapeInfo { get; set; }
118  public ShapeInfoInfo shapeInfo { get; private set; }
119 
120  public BSShape()
121  {
122  referenceCount = 1;
123  lastReferenced = DateTime.Now;
124  physShapeInfo = new BulletShape();
125  shapeInfo = new ShapeInfoInfo();
126  }
127  public BSShape(BulletShape pShape)
128  {
129  referenceCount = 1;
130  lastReferenced = DateTime.Now;
131  physShapeInfo = pShape;
132  shapeInfo = new ShapeInfoInfo();
133  }
134 
135  // Get another reference to this shape.
136  public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
137 
138  // Called when this shape is being used again.
139  // Used internally. External callers should call instance.GetReference() to properly copy/reference
140  // the shape.
141  protected virtual void IncrementReference()
142  {
143  referenceCount++;
144  lastReferenced = DateTime.Now;
145  }
146 
147  // Called when this shape is done being used.
148  protected virtual void DecrementReference()
149  {
150  referenceCount--;
151  lastReferenced = DateTime.Now;
152  }
153 
154  // Release the use of a physical shape.
155  public abstract void Dereference(BSScene physicsScene);
156 
157  // Return 'true' if there is an allocated physics physical shape under this class instance.
158  public virtual bool HasPhysicalShape
159  {
160  get
161  {
162  if (physShapeInfo != null)
163  return physShapeInfo.HasPhysicalShape;
164  return false;
165  }
166  }
167  public virtual BSPhysicsShapeType ShapeType
168  {
169  get
170  {
171  BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
172  if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
173  ret = physShapeInfo.shapeType;
174  return ret;
175  }
176  }
177 
178  // Returns a string for debugging that uniquily identifies the memory used by this instance
179  public virtual string AddrString
180  {
181  get
182  {
183  if (physShapeInfo != null)
184  return physShapeInfo.AddrString;
185  return "unknown";
186  }
187  }
188 
189  public override string ToString()
190  {
191  StringBuilder buff = new StringBuilder();
192  if (physShapeInfo == null)
193  {
194  buff.Append("<noPhys");
195  }
196  else
197  {
198  buff.Append("<phy=");
199  buff.Append(physShapeInfo.ToString());
200  }
201  buff.Append(",c=");
202  buff.Append(referenceCount.ToString());
203  buff.Append(">");
204  return buff.ToString();
205  }
206 
207  #region Common shape routines
208  // Create a hash of all the shape parameters to be used as a key for this particular shape.
209  public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
210  {
211  // level of detail based on size and type of the object
212  float lod = BSParam.MeshLOD;
213  if (pbs.SculptEntry)
214  lod = BSParam.SculptLOD;
215 
216  // Mega prims usually get more detail because one can interact with shape approximations at this size.
217  float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
218  if (maxAxis > BSParam.MeshMegaPrimThreshold)
219  lod = BSParam.MeshMegaPrimLOD;
220 
221  retLod = lod;
222  return pbs.GetMeshKey(size, lod);
223  }
224 
225  // The creation of a mesh or hull can fail if an underlying asset is not available.
226  // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
227  // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
228  // The first case causes the asset to be fetched. The second case requires
229  // us to not loop forever.
230  // Called after creating a physical mesh or hull. If the physical shape was created,
231  // just return.
232  public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
233  {
234  // If the shape was successfully created, nothing more to do
235  if (newShape.HasPhysicalShape)
236  return newShape;
237 
238  // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
239  // fetched but we end up here again, the meshing of the asset must have failed.
240  // Prevent trying to keep fetching the mesh by declaring failure.
241  if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
242  {
243  prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
244  physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}",
245  LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
246  physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}",
247  prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
248  }
249  else
250  {
251  // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
252  if (prim.BaseShape.SculptEntry
253  && !prim.AssetFailed()
254  && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
255  && prim.BaseShape.SculptTexture != OMV.UUID.Zero
256  )
257  {
258  physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
259  prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
260  // Multiple requestors will know we're waiting for this asset
261  prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
262 
263  BSPhysObject xprim = prim;
264  RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
265  if (assetProvider != null)
266  {
267  BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
268  assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
269  {
270  // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
271  bool assetFound = false;
272  string mismatchIDs = String.Empty; // DEBUG DEBUG
273  if (asset != null && yprim.BaseShape.SculptEntry)
274  {
275  if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
276  {
277  yprim.BaseShape.SculptData = asset.Data;
278  // This will cause the prim to see that the filler shape is not the right
279  // one and try again to build the object.
280  // No race condition with the normal shape setting since the rebuild is at taint time.
281  yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
282  yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
283  assetFound = true;
284  }
285  else
286  {
287  mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
288  }
289  }
290  if (!assetFound)
291  {
292  yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
293  }
294  physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
295  yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
296  });
297  }
298  else
299  {
300  xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
301  physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
302  LogHeader, physicsScene.PhysicsSceneName);
303  }
304  }
305  else
306  {
307  if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch)
308  {
309  physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}",
310  LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
311  physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}",
312  prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
313  }
314  if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing)
315  {
316  physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}",
317  LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
318  physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}",
319  prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
320  }
321  }
322  }
323 
324  // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
325  BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
326  physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
327 
328  return fillShape.physShapeInfo;
329  }
330 
331  public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim)
332  {
333  StringBuilder buff = new StringBuilder(prim.PhysObjectName);
334  buff.Append("/pos=");
335  buff.Append(prim.RawPosition.ToString());
336  if (pScene != null)
337  {
338  buff.Append("/rgn=");
339  buff.Append(pScene.PhysicsSceneName);
340  }
341  return buff.ToString();
342  }
343 
344  #endregion // Common shape routines
345 }
346 
347 // ============================================================================================================
348 public class BSShapeNull : BSShape
349 {
350  public BSShapeNull() : base()
351  {
352  }
353  public static BSShape GetReference() { return new BSShapeNull(); }
354  public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
355  public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
356 }
357 
358 // ============================================================================================================
359 // BSShapeNative is a wrapper for a Bullet 'native' shape -- cube and sphere.
360 // They are odd in that they don't allocate meshes but are computated/procedural.
361 // This means allocation and freeing is different than meshes.
362 public class BSShapeNative : BSShape
363 {
364  private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
365  public BSShapeNative(BulletShape pShape) : base(pShape)
366  {
367  }
368 
369  public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
370  BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
371  {
372  // Native shapes are not shared and are always built anew.
373  return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
374  }
375 
376  public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
377  {
378  // Native shapes are not shared so we return a new shape.
379  BSShape ret = null;
380  lock (physShapeInfo)
381  {
382  ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
383  physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey));
384  }
385  return ret;
386  }
387 
388  // Make this reference to the physical shape go away since native shapes are not shared.
389  public override void Dereference(BSScene physicsScene)
390  {
391  // Native shapes are not tracked and are released immediately
392  lock (physShapeInfo)
393  {
394  if (physShapeInfo.HasPhysicalShape)
395  {
396  physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
397  physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
398  }
399  physShapeInfo.Clear();
400  // Garbage collection will free up this instance.
401  }
402  }
403 
404  private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
405  BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
406  {
407  BulletShape newShape;
408 
409  ShapeData nativeShapeData = new ShapeData();
410  nativeShapeData.Type = shapeType;
411  nativeShapeData.ID = prim.LocalID;
412  nativeShapeData.Scale = prim.Scale;
413  nativeShapeData.Size = prim.Scale;
414  nativeShapeData.MeshKey = (ulong)shapeKey;
415  nativeShapeData.HullKey = (ulong)shapeKey;
416 
417  if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
418  {
419  newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
420  physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale);
421  }
422  else
423  {
424  newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
425  }
426  if (!newShape.HasPhysicalShape)
427  {
428  physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
429  LogHeader, prim.LocalID, shapeType);
430  }
431  newShape.shapeType = shapeType;
432  newShape.isNativeShape = true;
433  newShape.shapeKey = (UInt64)shapeKey;
434  return newShape;
435  }
436 
437 }
438 
439 // ============================================================================================================
440 // BSShapeMesh is a simple mesh.
441 public class BSShapeMesh : BSShape
442 {
443  private static string LogHeader = "[BULLETSIM SHAPE MESH]";
444  public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
445 
446  public BSShapeMesh(BulletShape pShape) : base(pShape)
447  {
448  }
449  public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
450  {
451  float lod;
452  System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
453 
454  BSShapeMesh retMesh = null;
455  lock (Meshes)
456  {
457  if (Meshes.TryGetValue(newMeshKey, out retMesh))
458  {
459  // The mesh has already been created. Return a new reference to same.
460  retMesh.IncrementReference();
461  }
462  else
463  {
464  retMesh = new BSShapeMesh(new BulletShape());
465  // An instance of this mesh has not been created. Build and remember same.
466  BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
467 
468  // Check to see if mesh was created (might require an asset).
469  newShape = VerifyMeshCreated(physicsScene, newShape, prim);
470  if (!newShape.isNativeShape || prim.AssetFailed() )
471  {
472  // If a mesh was what was created, remember the built shape for later sharing.
473  // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
474  Meshes.Add(newMeshKey, retMesh);
475  }
476 
477  retMesh.physShapeInfo = newShape;
478  }
479  }
480  physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
481  return retMesh;
482  }
483  public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
484  {
485  BSShape ret = null;
486  // If the underlying shape is native, the actual shape has not been build (waiting for asset)
487  // and we must create a copy of the native shape since they are never shared.
488  if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
489  {
490  // TODO: decide when the native shapes should be freed. Check in Dereference?
491  ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
492  }
493  else
494  {
495  // Another reference to this shape is just counted.
496  IncrementReference();
497  ret = this;
498  }
499  return ret;
500  }
501  public override void Dereference(BSScene physicsScene)
502  {
503  lock (Meshes)
504  {
505  this.DecrementReference();
506  physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
507  // TODO: schedule aging and destruction of unused meshes.
508  }
509  }
510  // Loop through all the known meshes and return the description based on the physical address.
511  public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
512  {
513  bool ret = false;
514  BSShapeMesh foundDesc = null;
515  lock (Meshes)
516  {
517  foreach (BSShapeMesh sm in Meshes.Values)
518  {
519  if (sm.physShapeInfo.ReferenceSame(pShape))
520  {
521  foundDesc = sm;
522  ret = true;
523  break;
524  }
525 
526  }
527  }
528  outMesh = foundDesc;
529  return ret;
530  }
531 
532  public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices );
533  private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
534  PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
535  {
536  return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
537  (w, iC, i, vC, v) =>
538  {
539  shapeInfo.Vertices = vC;
540  return physicsScene.PE.CreateMeshShape(w, iC, i, vC, v);
541  });
542  }
543 
544  // Code that uses the mesher to create the index/vertices info for a trimesh shape.
545  // This is used by the passed 'makeShape' call to create the Bullet mesh shape.
546  // The actual build call is passed so this logic can be used by several of the shapes that use a
547  // simple mesh as their base shape.
548  public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
549  PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape)
550  {
551  BulletShape newShape = new BulletShape();
552 
553  IMesh meshData = null;
554  lock (physicsScene.mesher)
555  {
556  meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
557  false, // say it is not physical so a bounding box is not built
558  false, // do not cache the mesh and do not use previously built versions
559  false,
560  false
561  );
562  }
563 
564  if (meshData != null)
565  {
566  if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
567  {
568  // Release the fetched asset data once it has been used.
569  pbs.SculptData = new byte[0];
570  prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
571  }
572 
573  int[] indices = meshData.getIndexListAsInt();
574  int realIndicesIndex = indices.Length;
575  float[] verticesAsFloats = meshData.getVertexListAsFloat();
576 
577  if (BSParam.ShouldRemoveZeroWidthTriangles)
578  {
579  // Remove degenerate triangles. These are triangles with two of the vertices
580  // are the same. This is complicated by the problem that vertices are not
581  // made unique in sculpties so we have to compare the values in the vertex.
582  realIndicesIndex = 0;
583  for (int tri = 0; tri < indices.Length; tri += 3)
584  {
585  // Compute displacements into vertex array for each vertex of the triangle
586  int v1 = indices[tri + 0] * 3;
587  int v2 = indices[tri + 1] * 3;
588  int v3 = indices[tri + 2] * 3;
589  // Check to see if any two of the vertices are the same
590  if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
591  && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
592  && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
593  || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
594  && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
595  && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
596  || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
597  && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
598  && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
599  )
600  {
601  // None of the vertices of the triangles are the same. This is a good triangle;
602  indices[realIndicesIndex + 0] = indices[tri + 0];
603  indices[realIndicesIndex + 1] = indices[tri + 1];
604  indices[realIndicesIndex + 2] = indices[tri + 2];
605  realIndicesIndex += 3;
606  }
607  }
608  }
609  physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
610  BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
611 
612  if (realIndicesIndex != 0)
613  {
614  newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
615  }
616  else
617  {
618  // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh.
619  prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
620  physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) );
621  physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey);
622  }
623  }
624  newShape.shapeKey = newMeshKey;
625 
626  return newShape;
627  }
628 }
629 
630 // ============================================================================================================
631 // BSShapeHull is a physical shape representation htat is made up of many convex hulls.
632 // The convex hulls are either supplied with the asset or are approximated by one of the
633 // convex hull creation routines (in OpenSim or in Bullet).
634 public class BSShapeHull : BSShape
635 {
636 #pragma warning disable 414
637  private static string LogHeader = "[BULLETSIM SHAPE HULL]";
638 #pragma warning restore 414
639 
640  public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
641 
642 
643  public BSShapeHull(BulletShape pShape) : base(pShape)
644  {
645  }
646  public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
647  {
648  float lod;
649  System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
650 
651  BSShapeHull retHull = null;
652  lock (Hulls)
653  {
654  if (Hulls.TryGetValue(newHullKey, out retHull))
655  {
656  // The mesh has already been created. Return a new reference to same.
657  retHull.IncrementReference();
658  }
659  else
660  {
661  retHull = new BSShapeHull(new BulletShape());
662  // An instance of this mesh has not been created. Build and remember same.
663  BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
664 
665  // Check to see if hull was created (might require an asset).
666  newShape = VerifyMeshCreated(physicsScene, newShape, prim);
667  if (!newShape.isNativeShape || prim.AssetFailed())
668  {
669  // If a mesh was what was created, remember the built shape for later sharing.
670  Hulls.Add(newHullKey, retHull);
671  }
672  retHull.physShapeInfo = newShape;
673  }
674  }
675  physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
676  return retHull;
677  }
678  public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
679  {
680  BSShape ret = null;
681  // If the underlying shape is native, the actual shape has not been build (waiting for asset)
682  // and we must create a copy of the native shape since they are never shared.
683  if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
684  {
685  // TODO: decide when the native shapes should be freed. Check in Dereference?
686  ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
687  }
688  else
689  {
690  // Another reference to this shape is just counted.
691  IncrementReference();
692  ret = this;
693  }
694  return ret;
695  }
696  public override void Dereference(BSScene physicsScene)
697  {
698  lock (Hulls)
699  {
700  this.DecrementReference();
701  physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
702  // TODO: schedule aging and destruction of unused meshes.
703  }
704  }
705 
706  List<ConvexResult> m_hulls;
707  private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
708  PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
709  {
710  BulletShape newShape = new BulletShape();
711 
712  IMesh meshData = null;
713  List<List<OMV.Vector3>> allHulls = null;
714  lock (physicsScene.mesher)
715  {
716  // Pass true for physicalness as this prevents the creation of bounding box which is not needed
717  meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */, false, false);
718 
719  // If we should use the asset's hull info, fetch it out of the locked mesher
720  if (meshData != null && BSParam.ShouldUseAssetHulls)
721  {
722  Meshmerizer realMesher = physicsScene.mesher as Meshmerizer;
723  if (realMesher != null)
724  {
725  allHulls = realMesher.GetConvexHulls(size);
726  }
727  if (allHulls == null)
728  {
729  physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID);
730  }
731  }
732  }
733 
734  // If there is hull data in the mesh asset, build the hull from that
735  if (allHulls != null && BSParam.ShouldUseAssetHulls)
736  {
737  int hullCount = allHulls.Count;
738  shapeInfo.HullCount = hullCount;
739  int totalVertices = 1; // include one for the count of the hulls
740  // Using the structure described for HACD hulls, create the memory sturcture
741  // to pass the hull data to the creater.
742  foreach (List<OMV.Vector3> hullVerts in allHulls)
743  {
744  totalVertices += 4; // add four for the vertex count and centroid
745  totalVertices += hullVerts.Count * 3; // one vertex is three dimensions
746  }
747  float[] convHulls = new float[totalVertices];
748 
749  convHulls[0] = (float)hullCount;
750  int jj = 1;
751  int hullIndex = 0;
752  foreach (List<OMV.Vector3> hullVerts in allHulls)
753  {
754  convHulls[jj + 0] = hullVerts.Count;
755  convHulls[jj + 1] = 0f; // centroid x,y,z
756  convHulls[jj + 2] = 0f;
757  convHulls[jj + 3] = 0f;
758  jj += 4;
759  foreach (OMV.Vector3 oneVert in hullVerts)
760  {
761  convHulls[jj + 0] = oneVert.X;
762  convHulls[jj + 1] = oneVert.Y;
763  convHulls[jj + 2] = oneVert.Z;
764  jj += 3;
765  }
766  shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count);
767  hullIndex++;
768  }
769 
770  // create the hull data structure in Bullet
771  newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
772 
773  physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}",
774  prim.LocalID, hullCount, totalVertices, newShape);
775  }
776 
777  // If no hull specified in the asset and we should use Bullet's HACD approximation...
778  if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD)
779  {
780  // Build the hull shape from an existing mesh shape.
781  // The mesh should have already been created in Bullet.
782  physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID);
783  BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
784 
785  if (meshShape.physShapeInfo.HasPhysicalShape)
786  {
787  HACDParams parms = new HACDParams();
788  parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
789  parms.minClusters = BSParam.BHullMinClusters;
790  parms.compacityWeight = BSParam.BHullCompacityWeight;
791  parms.volumeWeight = BSParam.BHullVolumeWeight;
792  parms.concavity = BSParam.BHullConcavity;
793  parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
794  parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
795  parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
796  parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
797  parms.whichHACD = 0; // Use the HACD routine that comes with Bullet
798 
799  physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
800  newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
801  physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape);
802 
803  // Now done with the mesh shape.
804  shapeInfo.HullCount = 1;
805  BSShapeMesh maybeMesh = meshShape as BSShapeMesh;
806  if (maybeMesh != null)
807  shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices);
808  meshShape.Dereference(physicsScene);
809  }
810  physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
811  }
812 
813  // If no other hull specifications, use our HACD hull approximation.
814  if (!newShape.HasPhysicalShape && meshData != null)
815  {
816  if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
817  {
818  // Release the fetched asset data once it has been used.
819  pbs.SculptData = new byte[0];
820  prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
821  }
822 
823  int[] indices = meshData.getIndexListAsInt();
824  List<OMV.Vector3> vertices = meshData.getVertexList();
825 
826  //format conversion from IMesh format to DecompDesc format
827  List<int> convIndices = new List<int>();
828  List<float3> convVertices = new List<float3>();
829  for (int ii = 0; ii < indices.GetLength(0); ii++)
830  {
831  convIndices.Add(indices[ii]);
832  }
833  foreach (OMV.Vector3 vv in vertices)
834  {
835  convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
836  }
837 
838  uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
839  if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
840  {
841  // Simple primitive shapes we know are convex so they are better implemented with
842  // fewer hulls.
843  // Check for simple shape (prim without cuts) and reduce split parameter if so.
844  if (BSShapeCollection.PrimHasNoCuts(pbs))
845  {
846  maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
847  }
848  }
849 
850  // setup and do convex hull conversion
851  m_hulls = new List<ConvexResult>();
852  DecompDesc dcomp = new DecompDesc();
853  dcomp.mIndices = convIndices;
854  dcomp.mVertices = convVertices;
855  dcomp.mDepth = maxDepthSplit;
856  dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
857  dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
858  dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
859  dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
860  ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
861  // create the hull into the _hulls variable
862  convexBuilder.process(dcomp);
863 
864  physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
865  BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
866 
867  // Convert the vertices and indices for passing to unmanaged.
868  // The hull information is passed as a large floating point array.
869  // The format is:
870  // convHulls[0] = number of hulls
871  // convHulls[1] = number of vertices in first hull
872  // convHulls[2] = hull centroid X coordinate
873  // convHulls[3] = hull centroid Y coordinate
874  // convHulls[4] = hull centroid Z coordinate
875  // convHulls[5] = first hull vertex X
876  // convHulls[6] = first hull vertex Y
877  // convHulls[7] = first hull vertex Z
878  // convHulls[8] = second hull vertex X
879  // ...
880  // convHulls[n] = number of vertices in second hull
881  // convHulls[n+1] = second hull centroid X coordinate
882  // ...
883  //
884  // TODO: is is very inefficient. Someday change the convex hull generator to return
885  // data structures that do not need to be converted in order to pass to Bullet.
886  // And maybe put the values directly into pinned memory rather than marshaling.
887  int hullCount = m_hulls.Count;
888  int totalVertices = 1; // include one for the count of the hulls
889  foreach (ConvexResult cr in m_hulls)
890  {
891  totalVertices += 4; // add four for the vertex count and centroid
892  totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
893  }
894  float[] convHulls = new float[totalVertices];
895 
896  convHulls[0] = (float)hullCount;
897  int jj = 1;
898  foreach (ConvexResult cr in m_hulls)
899  {
900  // copy vertices for index access
901  float3[] verts = new float3[cr.HullVertices.Count];
902  int kk = 0;
903  foreach (float3 ff in cr.HullVertices)
904  {
905  verts[kk++] = ff;
906  }
907 
908  // add to the array one hull's worth of data
909  convHulls[jj++] = cr.HullIndices.Count;
910  convHulls[jj++] = 0f; // centroid x,y,z
911  convHulls[jj++] = 0f;
912  convHulls[jj++] = 0f;
913  foreach (int ind in cr.HullIndices)
914  {
915  convHulls[jj++] = verts[ind].x;
916  convHulls[jj++] = verts[ind].y;
917  convHulls[jj++] = verts[ind].z;
918  }
919  }
920  // create the hull data structure in Bullet
921  newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
922  }
923  newShape.shapeKey = newHullKey;
924  return newShape;
925  }
926  // Callback from convex hull creater with a newly created hull.
927  // Just add it to our collection of hulls for this shape.
928  private void HullReturn(ConvexResult result)
929  {
930  m_hulls.Add(result);
931  return;
932  }
933  // Loop through all the known hulls and return the description based on the physical address.
934  public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
935  {
936  bool ret = false;
937  BSShapeHull foundDesc = null;
938  lock (Hulls)
939  {
940  foreach (BSShapeHull sh in Hulls.Values)
941  {
942  if (sh.physShapeInfo.ReferenceSame(pShape))
943  {
944  foundDesc = sh;
945  ret = true;
946  break;
947  }
948 
949  }
950  }
951  outHull = foundDesc;
952  return ret;
953  }
954 }
955 
956 // ============================================================================================================
957 // BSShapeCompound is a wrapper for the Bullet compound shape which is built from multiple, separate
958 // meshes. Used by BulletSim for complex shapes like linksets.
959 public class BSShapeCompound : BSShape
960 {
961  private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
962  public static Dictionary<string, BSShapeCompound> CompoundShapes = new Dictionary<string, BSShapeCompound>();
963 
964  public BSShapeCompound(BulletShape pShape) : base(pShape)
965  {
966  }
967  public static BSShape GetReference(BSScene physicsScene)
968  {
969  // Base compound shapes are not shared so this returns a raw shape.
970  // A built compound shape can be reused in linksets.
971  BSShapeCompound ret = new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
972  CompoundShapes.Add(ret.AddrString, ret);
973  return ret;
974  }
975  public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
976  {
977  // Calling this reference means we want another handle to an existing compound shape
978  // (usually linksets) so return this copy.
979  IncrementReference();
980  return this;
981  }
982  // Dereferencing a compound shape releases the hold on all the child shapes.
983  public override void Dereference(BSScene physicsScene)
984  {
985  lock (physShapeInfo)
986  {
987  this.DecrementReference();
988  physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
989  if (referenceCount <= 0)
990  {
991  if (!physicsScene.PE.IsCompound(physShapeInfo))
992  {
993  // Failed the sanity check!!
994  physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
995  LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
996  physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
997  BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
998  return;
999  }
1000 
1001  int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
1002  physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
1003  BSScene.DetailLogZero, physShapeInfo, numChildren);
1004 
1005  // Loop through all the children dereferencing each.
1006  for (int ii = numChildren - 1; ii >= 0; ii--)
1007  {
1008  BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
1009  DereferenceAnonCollisionShape(physicsScene, childShape);
1010  }
1011 
1012  lock (CompoundShapes)
1013  CompoundShapes.Remove(physShapeInfo.AddrString);
1014  physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
1015  }
1016  }
1017  }
1018  public static bool TryGetCompoundByPtr(BulletShape pShape, out BSShapeCompound outCompound)
1019  {
1020  lock (CompoundShapes)
1021  {
1022  string addr = pShape.AddrString;
1023  return CompoundShapes.TryGetValue(addr, out outCompound);
1024  }
1025  }
1026  private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
1027  {
1028  BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
1029  return cShape;
1030  }
1031  // Sometimes we have a pointer to a collision shape but don't know what type it is.
1032  // Figure out type and call the correct dereference routine.
1033  // Called at taint-time.
1034  private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
1035  {
1036  // TODO: figure a better way to go through all the shape types and find a possible instance.
1037  physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,shape={1}",
1038  BSScene.DetailLogZero, pShape);
1039  BSShapeMesh meshDesc;
1040  if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
1041  {
1042  meshDesc.Dereference(physicsScene);
1043  // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundMesh,shape={1}", BSScene.DetailLogZero, pShape);
1044  }
1045  else
1046  {
1047  BSShapeHull hullDesc;
1048  if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
1049  {
1050  hullDesc.Dereference(physicsScene);
1051  // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundHull,shape={1}", BSScene.DetailLogZero, pShape);
1052  }
1053  else
1054  {
1055  BSShapeConvexHull chullDesc;
1056  if (BSShapeConvexHull.TryGetConvexHullByPtr(pShape, out chullDesc))
1057  {
1058  chullDesc.Dereference(physicsScene);
1059  // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundConvexHull,shape={1}", BSScene.DetailLogZero, pShape);
1060  }
1061  else
1062  {
1063  BSShapeGImpact gImpactDesc;
1064  if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc))
1065  {
1066  gImpactDesc.Dereference(physicsScene);
1067  // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundgImpact,shape={1}", BSScene.DetailLogZero, pShape);
1068  }
1069  else
1070  {
1071  // Didn't find it in the lists of specific types. It could be compound.
1072  BSShapeCompound compoundDesc;
1073  if (BSShapeCompound.TryGetCompoundByPtr(pShape, out compoundDesc))
1074  {
1075  compoundDesc.Dereference(physicsScene);
1076  // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,recursiveCompoundShape,shape={1}", BSScene.DetailLogZero, pShape);
1077  }
1078  else
1079  {
1080  // If none of the above, maybe it is a simple native shape.
1081  if (physicsScene.PE.IsNativeShape(pShape))
1082  {
1083  // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,assumingNative,shape={1}", BSScene.DetailLogZero, pShape);
1084  BSShapeNative nativeShape = new BSShapeNative(pShape);
1085  nativeShape.Dereference(physicsScene);
1086  }
1087  else
1088  {
1089  physicsScene.Logger.WarnFormat("{0} DereferenceAnonCollisionShape. Did not find shape. {1}",
1090  LogHeader, pShape);
1091  }
1092  }
1093  }
1094  }
1095  }
1096  }
1097  }
1098 }
1099 
1100 // ============================================================================================================
1101 // BSShapeConvexHull is a wrapper for a Bullet single convex hull. A BSShapeHull contains multiple convex
1102 // hull shapes. This is used for simple prims that are convex and thus can be made into a simple
1103 // collision shape (a single hull). More complex physical shapes will be BSShapeHull's.
1105 {
1106 #pragma warning disable 414
1107  private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
1108 #pragma warning restore 414
1109 
1110  public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
1111 
1112  public BSShapeConvexHull(BulletShape pShape) : base(pShape)
1113  {
1114  }
1115  public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1116  {
1117  float lod;
1118  System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1119 
1120  physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}",
1121  prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1122 
1123  BSShapeConvexHull retConvexHull = null;
1124  lock (ConvexHulls)
1125  {
1126  if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
1127  {
1128  // The mesh has already been created. Return a new reference to same.
1129  retConvexHull.IncrementReference();
1130  }
1131  else
1132  {
1133  retConvexHull = new BSShapeConvexHull(new BulletShape());
1134  BulletShape convexShape = null;
1135 
1136  // Get a handle to a mesh to build the hull from
1137  BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
1138  if (baseMesh.physShapeInfo.isNativeShape)
1139  {
1140  // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
1141  // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
1142  // get back to this code with a buildable mesh.
1143  // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
1144  convexShape = baseMesh.physShapeInfo;
1145  }
1146  else
1147  {
1148  convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
1149  convexShape.shapeKey = newMeshKey;
1150  ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
1151  physicsScene.DetailLog("{0},BSShapeConvexHull.GetReference,addingNewlyCreatedShape,shape={1}",
1152  BSScene.DetailLogZero, convexShape);
1153  }
1154 
1155  // Done with the base mesh
1156  baseMesh.Dereference(physicsScene);
1157 
1158  retConvexHull.physShapeInfo = convexShape;
1159  }
1160  }
1161  return retConvexHull;
1162  }
1163  public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
1164  {
1165  // Calling this reference means we want another handle to an existing shape
1166  // (usually linksets) so return this copy.
1167  IncrementReference();
1168  return this;
1169  }
1170  // Dereferencing a compound shape releases the hold on all the child shapes.
1171  public override void Dereference(BSScene physicsScene)
1172  {
1173  lock (ConvexHulls)
1174  {
1175  this.DecrementReference();
1176  physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
1177  // TODO: schedule aging and destruction of unused meshes.
1178  }
1179  }
1180  // Loop through all the known hulls and return the description based on the physical address.
1181  public static bool TryGetConvexHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull)
1182  {
1183  bool ret = false;
1184  BSShapeConvexHull foundDesc = null;
1185  lock (ConvexHulls)
1186  {
1187  foreach (BSShapeConvexHull sh in ConvexHulls.Values)
1188  {
1189  if (sh.physShapeInfo.ReferenceSame(pShape))
1190  {
1191  foundDesc = sh;
1192  ret = true;
1193  break;
1194  }
1195 
1196  }
1197  }
1198  outHull = foundDesc;
1199  return ret;
1200  }
1201 }
1202 // ============================================================================================================
1203 // BSShapeGImpact is a wrapper for the Bullet GImpact shape which is a collision mesh shape that
1204 // can handle concave as well as convex shapes. Much slower computationally but creates smoother
1205 // shapes than multiple convex hull approximations.
1206 public class BSShapeGImpact : BSShape
1207 {
1208 #pragma warning disable 414
1209  private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]";
1210 #pragma warning restore 414
1211 
1212  public static Dictionary<System.UInt64, BSShapeGImpact> GImpacts = new Dictionary<System.UInt64, BSShapeGImpact>();
1213 
1214  public BSShapeGImpact(BulletShape pShape) : base(pShape)
1215  {
1216  }
1217  public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1218  {
1219  float lod;
1220  System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1221 
1222  physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}",
1223  prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1224 
1225  BSShapeGImpact retGImpact = null;
1226  lock (GImpacts)
1227  {
1228  if (GImpacts.TryGetValue(newMeshKey, out retGImpact))
1229  {
1230  // The mesh has already been created. Return a new reference to same.
1231  retGImpact.IncrementReference();
1232  }
1233  else
1234  {
1235  retGImpact = new BSShapeGImpact(new BulletShape());
1236  BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
1237 
1238  // Check to see if mesh was created (might require an asset).
1239  newShape = VerifyMeshCreated(physicsScene, newShape, prim);
1240  newShape.shapeKey = newMeshKey;
1241  if (!newShape.isNativeShape || prim.AssetFailed())
1242  {
1243  // If a mesh was what was created, remember the built shape for later sharing.
1244  // Also note that if meshing failed we put it in the mesh list as there is nothing
1245  // else to do about the mesh.
1246  GImpacts.Add(newMeshKey, retGImpact);
1247  }
1248 
1249  retGImpact.physShapeInfo = newShape;
1250  }
1251  }
1252  return retGImpact;
1253  }
1254 
1255  private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
1256  PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
1257  {
1258  return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
1259  (w, iC, i, vC, v) =>
1260  {
1261  shapeInfo.Vertices = vC;
1262  return physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v);
1263  });
1264  }
1265 
1266  public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1267  {
1268  BSShape ret = null;
1269  // If the underlying shape is native, the actual shape has not been build (waiting for asset)
1270  // and we must create a copy of the native shape since they are never shared.
1271  if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
1272  {
1273  // TODO: decide when the native shapes should be freed. Check in Dereference?
1274  ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
1275  }
1276  else
1277  {
1278  // Another reference to this shape is just counted.
1279  IncrementReference();
1280  ret = this;
1281  }
1282  return ret;
1283  }
1284  // Dereferencing a compound shape releases the hold on all the child shapes.
1285  public override void Dereference(BSScene physicsScene)
1286  {
1287  lock (GImpacts)
1288  {
1289  this.DecrementReference();
1290  physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this);
1291  // TODO: schedule aging and destruction of unused meshes.
1292  }
1293  }
1294  // Loop through all the known hulls and return the description based on the physical address.
1295  public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull)
1296  {
1297  bool ret = false;
1298  BSShapeGImpact foundDesc = null;
1299  lock (GImpacts)
1300  {
1301  foreach (BSShapeGImpact sh in GImpacts.Values)
1302  {
1303  if (sh.physShapeInfo.ReferenceSame(pShape))
1304  {
1305  foundDesc = sh;
1306  ret = true;
1307  break;
1308  }
1309 
1310  }
1311  }
1312  outHull = foundDesc;
1313  return ret;
1314  }
1315 }
1316 
1317 // ============================================================================================================
1318 // BSShapeAvatar is a specialized mesh shape for avatars.
1319 public class BSShapeAvatar : BSShape
1320 {
1321 #pragma warning disable 414
1322  private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
1323 #pragma warning restore 414
1324 
1325  public BSShapeAvatar()
1326  : base()
1327  {
1328  }
1329  public static BSShape GetReference(BSPhysObject prim)
1330  {
1331  return new BSShapeNull();
1332  }
1333  public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1334  {
1335  return new BSShapeNull();
1336  }
1337  public override void Dereference(BSScene physicsScene) { }
1338 
1339  // From the front:
1340  // A---A
1341  // / \
1342  // B-------B
1343  // / \ +Z
1344  // C-----------C |
1345  // \ / -Y --+-- +Y
1346  // \ / |
1347  // \ / -Z
1348  // D-----D
1349  // \ /
1350  // E-E
1351 
1352  // From the top A and E are just lines.
1353  // B, C and D are hexagons:
1354  //
1355  // C1--C2 +X
1356  // / \ |
1357  // C0 C3 -Y --+-- +Y
1358  // \ / |
1359  // C5--C4 -X
1360 
1361  // Zero goes directly through the middle so the offsets are from that middle axis
1362  // and up and down from a middle horizon (A and E are the same distance from the zero).
1363  // The height, width and depth is one. All scaling is done by the simulator.
1364 
1365  // Z component -- how far the level is from the middle zero
1366  private const float Aup = 0.5f;
1367  private const float Bup = 0.4f;
1368  private const float Cup = 0.3f;
1369  private const float Dup = -0.4f;
1370  private const float Eup = -0.5f;
1371 
1372  // Y component -- distance from center to x0 and x3
1373  private const float Awid = 0.25f;
1374  private const float Bwid = 0.3f;
1375  private const float Cwid = 0.5f;
1376  private const float Dwid = 0.3f;
1377  private const float Ewid = 0.2f;
1378 
1379  // Y component -- distance from center to x1, x2, x4 and x5
1380  private const float Afwid = 0.0f;
1381  private const float Bfwid = 0.2f;
1382  private const float Cfwid = 0.4f;
1383  private const float Dfwid = 0.2f;
1384  private const float Efwid = 0.0f;
1385 
1386  // X component -- distance from zero to the front or back of a level
1387  private const float Adep = 0f;
1388  private const float Bdep = 0.3f;
1389  private const float Cdep = 0.5f;
1390  private const float Ddep = 0.2f;
1391  private const float Edep = 0f;
1392 
1393  private OMV.Vector3[] avatarVertices = {
1394  new OMV.Vector3( 0.0f, -Awid, Aup), // A0
1395  new OMV.Vector3( 0.0f, +Awid, Aup), // A3
1396 
1397  new OMV.Vector3( 0.0f, -Bwid, Bup), // B0
1398  new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1
1399  new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2
1400  new OMV.Vector3( 0.0f, +Bwid, Bup), // B3
1401  new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4
1402  new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5
1403 
1404  new OMV.Vector3( 0.0f, -Cwid, Cup), // C0
1405  new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1
1406  new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2
1407  new OMV.Vector3( 0.0f, +Cwid, Cup), // C3
1408  new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4
1409  new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5
1410 
1411  new OMV.Vector3( 0.0f, -Dwid, Dup), // D0
1412  new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1
1413  new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2
1414  new OMV.Vector3( 0.0f, +Dwid, Dup), // D3
1415  new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4
1416  new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5
1417 
1418  new OMV.Vector3( 0.0f, -Ewid, Eup), // E0
1419  new OMV.Vector3( 0.0f, +Ewid, Eup), // E3
1420  };
1421 
1422  // Offsets of the vertices in the vertices array
1423  private enum Ind : int
1424  {
1425  A0, A3,
1426  B0, B1, B2, B3, B4, B5,
1427  C0, C1, C2, C3, C4, C5,
1428  D0, D1, D2, D3, D4, D5,
1429  E0, E3
1430  }
1431 
1432  // Comments specify trianges and quads in clockwise direction
1433  private Ind[] avatarIndices = {
1434  Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1
1435  Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3
1436  Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3
1437  Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4
1438  Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0
1439  Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0
1440 
1441  Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1
1442  Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2
1443  Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3
1444  Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4
1445  Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5
1446  Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0
1447 
1448  Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1
1449  Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2
1450  Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3
1451  Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4
1452  Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5
1453  Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0
1454 
1455  Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1
1456  Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3
1457  Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3
1458  Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4
1459  Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0
1460  Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0
1461 
1462  };
1463 
1464 }
1465 }
OpenMetaverse OMV
static BSShape GetReference(BSScene physicsScene)
Definition: BSShapes.cs:967
static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
Definition: BSShapes.cs:1217
override void Dereference(BSScene physicsScene)
Definition: BSShapes.cs:983
static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim)
Definition: BSShapes.cs:331
override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
Definition: BSShapes.cs:1266
static bool TryGetConvexHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull)
Definition: BSShapes.cs:1181
override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
Definition: BSShapes.cs:376
override void Dereference(BSScene physicsScene)
Definition: BSShapes.cs:501
static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
Definition: BSShapes.cs:934
void SetVerticesPerHull(int hullNum, int vertices)
Definition: BSShapes.cs:66
override void Dereference(BSScene physicsScene)
Definition: BSShapes.cs:389
static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
Definition: BSShapes.cs:449
static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
Definition: BSShapes.cs:369
Asset class. All Assets are reference by this class or a class derived from this class ...
Definition: AssetBase.cs:49
abstract bool IsCompound(BulletShape shape)
static BSShape GetReference(BSPhysObject prim)
Definition: BSShapes.cs:1329
override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
Definition: BSShapes.cs:354
delegate void RequestAssetDelegate(UUID assetID, AssetReceivedDelegate callback)
override void Dereference(BSScene physicsScene)
Definition: BSShapes.cs:1337
override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
Definition: BSShapes.cs:975
static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape)
Definition: BSShapes.cs:548
override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
Definition: BSShapes.cs:1333
static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
Definition: BSShapes.cs:1115
static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
Definition: BSShapes.cs:646
override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
Definition: BSShapes.cs:678
static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
Definition: BSShapes.cs:511
static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
Definition: BSShapes.cs:209
static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull)
Definition: BSShapes.cs:1295
override void Dereference(BSScene physicsScene)
Definition: BSShapes.cs:355
override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
Definition: BSShapes.cs:483
override void Dereference(BSScene physicsScene)
Definition: BSShapes.cs:696
string ID
Asset MetaData ID (transferring from UUID to string ID)
Definition: AssetBase.cs:177
static bool TryGetCompoundByPtr(BulletShape pShape, out BSShapeCompound outCompound)
Definition: BSShapes.cs:1018
static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
Definition: BSShapes.cs:232
override void Dereference(BSScene physicsScene)
Definition: BSShapes.cs:1171
override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
Definition: BSShapes.cs:1163
override void Dereference(BSScene physicsScene)
Definition: BSShapes.cs:1285