From c89d0e26b2c098cd2c5679fb73987a742a66ce38 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 31 Dec 2014 12:48:26 -0800 Subject: [PATCH] BulletSim: add the beginnings of hull creation unit testing. Change how physics engine is created in unit tests to resolve a lib reference problem. Add ShapeInfoInfo class to collect info about the created physical shape for debugging and unit test testing. --- .../Region/Physics/BulletSPlugin/BSPrim.cs | 5 +- .../Region/Physics/BulletSPlugin/BSScene.cs | 67 ++++++ .../Region/Physics/BulletSPlugin/BSShapes.cs | 111 +++++++++- .../BulletSPlugin/Tests/BulletSimTestsUtil.cs | 19 +- .../BulletSPlugin/Tests/HullCreation.cs | 204 ++++++++++++++++++ 5 files changed, 394 insertions(+), 12 deletions(-) create mode 100644 OpenSim/Region/Physics/BulletSPlugin/Tests/HullCreation.cs diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 9695fcff69..5d359e8ffc 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -96,11 +96,9 @@ public class BSPrim : BSPhysObject _isPhysical = pisPhysical; _isVolumeDetect = false; - // Add a dynamic vehicle to our set of actors that can move this prim. - // PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName)); - _mass = CalculateMass(); + DetailLog("{0},BSPrim.constructor,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(pbs)); // DetailLog("{0},BSPrim.constructor,call", LocalID); // do the actual object creation at taint time PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate() @@ -168,6 +166,7 @@ public class BSPrim : BSPhysObject public override PrimitiveBaseShape Shape { set { BaseShape = value; + DetailLog("{0},BSPrim.changeShape,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(BaseShape)); PrimAssetState = PrimAssetCondition.Unknown; ForceBodyShapeRebuild(false); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 414bc92a0b..238fcc2adf 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -947,6 +947,73 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters } #endregion // Extensions + public static string PrimitiveBaseShapeToString(PrimitiveBaseShape pbs) + { + float pathShearX = pbs.PathShearX < 128 ? (float)pbs.PathShearX * 0.01f : (float)(pbs.PathShearX - 256) * 0.01f; + float pathShearY = pbs.PathShearY < 128 ? (float)pbs.PathShearY * 0.01f : (float)(pbs.PathShearY - 256) * 0.01f; + float pathBegin = (float)pbs.PathBegin * 2.0e-5f; + float pathEnd = 1.0f - (float)pbs.PathEnd * 2.0e-5f; + float pathScaleX = (float)(pbs.PathScaleX - 100) * 0.01f; + float pathScaleY = (float)(pbs.PathScaleY - 100) * 0.01f; + + float profileBegin = (float)pbs.ProfileBegin * 2.0e-5f; + float profileEnd = 1.0f - (float)pbs.ProfileEnd * 2.0e-5f; + float profileHollow = (float)pbs.ProfileHollow * 2.0e-5f; + if (profileHollow > 0.95f) + profileHollow = 0.95f; + + StringBuilder buff = new StringBuilder(); + buff.Append("shape="); + buff.Append(((ProfileShape)pbs.ProfileShape).ToString()); + buff.Append(","); + buff.Append("hollow="); + buff.Append(((HollowShape)pbs.HollowShape).ToString()); + buff.Append(","); + buff.Append("pathCurve="); + buff.Append(((Extrusion)pbs.PathCurve).ToString()); + buff.Append(","); + buff.Append("profCurve="); + buff.Append(((Extrusion)pbs.ProfileCurve).ToString()); + buff.Append(","); + buff.Append("profHollow="); + buff.Append(profileHollow.ToString()); + buff.Append(","); + buff.Append("pathBegEnd="); + buff.Append(pathBegin.ToString()); + buff.Append("/"); + buff.Append(pathEnd.ToString()); + buff.Append(","); + buff.Append("profileBegEnd="); + buff.Append(profileBegin.ToString()); + buff.Append("/"); + buff.Append(profileEnd.ToString()); + buff.Append(","); + buff.Append("scaleXY="); + buff.Append(pathScaleX.ToString()); + buff.Append("/"); + buff.Append(pathScaleY.ToString()); + buff.Append(","); + buff.Append("shearXY="); + buff.Append(pathShearX.ToString()); + buff.Append("/"); + buff.Append(pathShearY.ToString()); + buff.Append(","); + buff.Append("taperXY="); + buff.Append(pbs.PathTaperX.ToString()); + buff.Append("/"); + buff.Append(pbs.PathTaperY.ToString()); + buff.Append(","); + buff.Append("skew="); + buff.Append(pbs.PathSkew.ToString()); + buff.Append(","); + buff.Append("twist/Beg="); + buff.Append(pbs.PathTwist.ToString()); + buff.Append("/"); + buff.Append(pbs.PathTwistBegin.ToString()); + + return buff.ToString(); + } + #region Taints // The simulation execution order is: // Simulate() diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 09f5bc44ba..aa04726109 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -38,6 +38,76 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.Physics.BulletSPlugin { +// Information class that holds stats for the shape. Which values mean +// something depends on the type of shape. +// This information is used for debugging and stats and is not used +// for operational things. +public class ShapeInfoInfo +{ + public int Vertices { get; set; } + private int m_hullCount; + private int[] m_verticesPerHull; + public ShapeInfoInfo() + { + Vertices = 0; + m_hullCount = 0; + m_verticesPerHull = null; + } + public int HullCount + { + set + { + m_hullCount = value; + m_verticesPerHull = new int[m_hullCount]; + Array.Clear(m_verticesPerHull, 0, m_hullCount); + } + get { return m_hullCount; } + } + public void SetVerticesPerHull(int hullNum, int vertices) + { + if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length) + { + m_verticesPerHull[hullNum] = vertices; + } + } + public int GetVerticesPerHull(int hullNum) + { + if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length) + { + return m_verticesPerHull[hullNum]; + } + return 0; + } + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + // buff.Append("ShapeInfo=<"); + buff.Append("<"); + if (Vertices > 0) + { + buff.Append("verts="); + buff.Append(Vertices.ToString()); + } + + if (Vertices > 0 && HullCount > 0) buff.Append(","); + + if (HullCount > 0) + { + buff.Append("nHulls="); + buff.Append(HullCount.ToString()); + buff.Append(","); + buff.Append("hullVerts="); + for (int ii = 0; ii < HullCount; ii++) + { + if (ii != 0) buff.Append(","); + buff.Append(GetVerticesPerHull(ii).ToString()); + } + } + buff.Append(">"); + return buff.ToString(); + } +} + public abstract class BSShape { private static string LogHeader = "[BULLETSIM SHAPE]"; @@ -45,18 +115,21 @@ public abstract class BSShape public int referenceCount { get; set; } public DateTime lastReferenced { get; set; } public BulletShape physShapeInfo { get; set; } + public ShapeInfoInfo shapeInfo { get; private set; } public BSShape() { referenceCount = 1; lastReferenced = DateTime.Now; physShapeInfo = new BulletShape(); + shapeInfo = new ShapeInfoInfo(); } public BSShape(BulletShape pShape) { referenceCount = 1; lastReferenced = DateTime.Now; physShapeInfo = pShape; + shapeInfo = new ShapeInfoInfo(); } // Get another reference to this shape. @@ -283,6 +356,9 @@ public class BSShapeNull : BSShape } // ============================================================================================================ +// BSShapeNative is a wrapper for a Bullet 'native' shape -- cube and sphere. +// They are odd in that they don't allocate meshes but are computated/procedural. +// This means allocation and freeing is different than meshes. public class BSShapeNative : BSShape { private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; @@ -361,6 +437,7 @@ public class BSShapeNative : BSShape } // ============================================================================================================ +// BSShapeMesh is a simple mesh. public class BSShapeMesh : BSShape { private static string LogHeader = "[BULLETSIM SHAPE MESH]"; @@ -457,7 +534,11 @@ public class BSShapeMesh : BSShape PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, - (w, iC, i, vC, v) => physicsScene.PE.CreateMeshShape(w, iC, i, vC, v) ); + (w, iC, i, vC, v) => + { + shapeInfo.Vertices = vC; + return physicsScene.PE.CreateMeshShape(w, iC, i, vC, v); + }); } // Code that uses the mesher to create the index/vertices info for a trimesh shape. @@ -545,6 +626,9 @@ public class BSShapeMesh : BSShape } // ============================================================================================================ +// BSShapeHull is a physical shape representation htat is made up of many convex hulls. +// The convex hulls are either supplied with the asset or are approximated by one of the +// convex hull creation routines (in OpenSim or in Bullet). public class BSShapeHull : BSShape { #pragma warning disable 414 @@ -553,6 +637,7 @@ public class BSShapeHull : BSShape public static Dictionary Hulls = new Dictionary(); + public BSShapeHull(BulletShape pShape) : base(pShape) { } @@ -615,6 +700,7 @@ public class BSShapeHull : BSShape // TODO: schedule aging and destruction of unused meshes. } } + List m_hulls; private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) @@ -647,6 +733,7 @@ public class BSShapeHull : BSShape if (allHulls != null && BSParam.ShouldUseAssetHulls) { int hullCount = allHulls.Count; + shapeInfo.HullCount = hullCount; int totalVertices = 1; // include one for the count of the hulls // Using the structure described for HACD hulls, create the memory sturcture // to pass the hull data to the creater. @@ -659,6 +746,7 @@ public class BSShapeHull : BSShape convHulls[0] = (float)hullCount; int jj = 1; + int hullIndex = 0; foreach (List hullVerts in allHulls) { convHulls[jj + 0] = hullVerts.Count; @@ -673,6 +761,8 @@ public class BSShapeHull : BSShape convHulls[jj + 2] = oneVert.Z; jj += 3; } + shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count); + hullIndex++; } // create the hull data structure in Bullet @@ -708,6 +798,10 @@ public class BSShapeHull : BSShape physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape); // Now done with the mesh shape. + shapeInfo.HullCount = 1; + BSShapeMesh maybeMesh = meshShape as BSShapeMesh; + if (maybeMesh != null) + shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices); meshShape.Dereference(physicsScene); } physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); @@ -857,6 +951,8 @@ public class BSShapeHull : BSShape } // ============================================================================================================ +// BSShapeCompound is a wrapper for the Bullet compound shape which is built from multiple, separate +// meshes. Used by BulletSim for complex shapes like linksets. public class BSShapeCompound : BSShape { private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; @@ -999,6 +1095,9 @@ public class BSShapeCompound : BSShape } // ============================================================================================================ +// BSShapeConvexHull is a wrapper for a Bullet single convex hull. A BSShapeHull contains multiple convex +// hull shapes. This is used for simple prims that are convex and thus can be made into a simple +// collision shape (a single hull). More complex physical shapes will be BSShapeHull's. public class BSShapeConvexHull : BSShape { #pragma warning disable 414 @@ -1098,6 +1197,9 @@ public class BSShapeConvexHull : BSShape } } // ============================================================================================================ +// BSShapeGImpact is a wrapper for the Bullet GImpact shape which is a collision mesh shape that +// can handle concave as well as convex shapes. Much slower computationally but creates smoother +// shapes than multiple convex hull approximations. public class BSShapeGImpact : BSShape { #pragma warning disable 414 @@ -1151,7 +1253,11 @@ public class BSShapeGImpact : BSShape PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, - (w, iC, i, vC, v) => physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v) ); + (w, iC, i, vC, v) => + { + shapeInfo.Vertices = vC; + return physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v); + }); } public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) @@ -1206,6 +1312,7 @@ public class BSShapeGImpact : BSShape } // ============================================================================================================ +// BSShapeAvatar is a specialized mesh shape for avatars. public class BSShapeAvatar : BSShape { #pragma warning disable 414 diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs index 28207a43ab..775bca213c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BulletSimTestsUtil.cs @@ -28,15 +28,16 @@ using System; using System.IO; using System.Collections.Generic; -using System.Linq; using System.Text; using Nini.Config; using OpenSim.Framework; -using OpenSim.Region.Physics.BulletSPlugin; +using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.Meshing; +using OpenMetaverse; + namespace OpenSim.Region.Physics.BulletSPlugin.Tests { // Utility functions for building up and tearing down the sample physics environments @@ -77,17 +78,21 @@ public static class BulletSimTestsUtil bulletSimConfig.Set("VehicleLoggingEnabled","True"); } - BSPlugin bsPlugin = new BSPlugin(); + PhysicsPluginManager physicsPluginManager; + physicsPluginManager = new PhysicsPluginManager(); + physicsPluginManager.LoadPluginsFromAssemblies("Physics"); - BSScene bsScene = (BSScene)bsPlugin.GetScene("BSTestRegion"); + Vector3 regionExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); + + PhysicsScene pScene = physicsPluginManager.GetPhysicsScene( + "BulletSim", "Meshmerizer", openSimINI, "BSTestRegion", regionExtent); + + BSScene bsScene = pScene as BSScene; // Since the asset requestor is not initialized, any mesh or sculptie will be a cube. // In the future, add a fake asset fetcher to get meshes and sculpts. // bsScene.RequestAssetMethod = ???; - Meshing.Meshmerizer mesher = new Meshmerizer(openSimINI); - bsScene.Initialise(mesher, openSimINI); - return bsScene; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/HullCreation.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/HullCreation.cs new file mode 100644 index 0000000000..da532e0e38 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/HullCreation.cs @@ -0,0 +1,204 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using log4net; + +using OpenSim.Framework; +using OpenSim.Region.Physics.BulletSPlugin; +using OpenSim.Region.Physics.Manager; +using OpenSim.Tests.Common; + +using OpenMetaverse; + +namespace OpenSim.Region.Physics.BulletSPlugin.Tests +{ +[TestFixture] +public class HullCreation : OpenSimTestCase +{ + // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 + // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 + + BSScene PhysicsScene { get; set; } + Vector3 ObjectInitPosition; + float simulationTimeStep = 0.089f; + + [TestFixtureSetUp] + public void Init() + { + + } + + [TestFixtureTearDown] + public void TearDown() + { + if (PhysicsScene != null) + { + // The Dispose() will also free any physical objects in the scene + PhysicsScene.Dispose(); + PhysicsScene = null; + } + } + + [TestCase(7, 2, 5f, 5f, 32, 0f)] /* default hull parameters */ + public void GeomHullConvexDecomp( int maxDepthSplit, + int maxDepthSplitForSimpleShapes, + float concavityThresholdPercent, + float volumeConservationThresholdPercent, + int maxVertices, + float maxSkinWidth) + { + // Setup the physics engine to use the C# version of convex decomp + Dictionary engineParams = new Dictionary(); + engineParams.Add("MeshSculptedPrim", "true"); // ShouldMeshSculptedPrim + engineParams.Add("ForceSimplePrimMeshing", "false"); // ShouldForceSimplePrimMeshing + engineParams.Add("UseHullsForPhysicalObjects", "true"); // ShouldUseHullsForPhysicalObjects + engineParams.Add("ShouldRemoveZeroWidthTriangles", "true"); + engineParams.Add("ShouldUseBulletHACD", "false"); + engineParams.Add("ShouldUseSingleConvexHullForPrims", "true"); + engineParams.Add("ShouldUseGImpactShapeForPrims", "false"); + engineParams.Add("ShouldUseAssetHulls", "true"); + + engineParams.Add("CSHullMaxDepthSplit", maxDepthSplit.ToString()); + engineParams.Add("CSHullMaxDepthSplitForSimpleShapes", maxDepthSplitForSimpleShapes.ToString()); + engineParams.Add("CSHullConcavityThresholdPercent", concavityThresholdPercent.ToString()); + engineParams.Add("CSHullVolumeConservationThresholdPercent", volumeConservationThresholdPercent.ToString()); + engineParams.Add("CSHullMaxVertices", maxVertices.ToString()); + engineParams.Add("CSHullMaxSkinWidth", maxSkinWidth.ToString()); + + PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams); + + PrimitiveBaseShape pbs; + Vector3 pos; + Vector3 size; + Quaternion rot; + bool isPhys; + + // Cylinder + pbs = PrimitiveBaseShape.CreateCylinder(); + pos = new Vector3(100.0f, 100.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; + ObjectInitPosition = pos; + size = new Vector3(2f, 2f, 2f); + pbs.Scale = size; + rot = Quaternion.Identity; + isPhys = true; + uint cylinderLocalID = 123; + PhysicsScene.AddPrimShape("testCylinder", pbs, pos, size, rot, isPhys, cylinderLocalID); + BSPrim primTypeCylinder = (BSPrim)PhysicsScene.PhysObjects[cylinderLocalID]; + + // Hollow Cylinder + pbs = PrimitiveBaseShape.CreateCylinder(); + pbs.ProfileHollow = (ushort)(0.70f * 50000); + pos = new Vector3(110.0f, 110.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; + ObjectInitPosition = pos; + size = new Vector3(2f, 2f, 2f); + pbs.Scale = size; + rot = Quaternion.Identity; + isPhys = true; + uint hollowCylinderLocalID = 124; + PhysicsScene.AddPrimShape("testHollowCylinder", pbs, pos, size, rot, isPhys, hollowCylinderLocalID); + BSPrim primTypeHollowCylinder = (BSPrim)PhysicsScene.PhysObjects[hollowCylinderLocalID]; + + // Torus + // ProfileCurve = Circle, PathCurve = Curve1 + pbs = PrimitiveBaseShape.CreateSphere(); + pbs.ProfileShape = (byte)ProfileShape.Circle; + pbs.PathCurve = (byte)Extrusion.Curve1; + pos = new Vector3(120.0f, 120.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; + ObjectInitPosition = pos; + size = new Vector3(2f, 4f, 4f); + pbs.Scale = size; + rot = Quaternion.Identity; + isPhys = true; + uint torusLocalID = 125; + PhysicsScene.AddPrimShape("testTorus", pbs, pos, size, rot, isPhys, torusLocalID); + BSPrim primTypeTorus = (BSPrim)PhysicsScene.PhysObjects[torusLocalID]; + + // The actual prim shape creation happens at taint time + PhysicsScene.ProcessTaints(); + + // Check out the created hull shapes and report their characteristics + ReportShapeGeom(primTypeCylinder); + ReportShapeGeom(primTypeHollowCylinder); + ReportShapeGeom(primTypeTorus); + } + + [TestCase] + public void GeomHullBulletHACD() + { + // Cylinder + // Hollow Cylinder + // Torus + } + + private void ReportShapeGeom(BSPrim prim) + { + if (prim != null) + { + if (prim.PhysShape.HasPhysicalShape) + { + BSShape physShape = prim.PhysShape; + string shapeType = physShape.GetType().ToString(); + switch (shapeType) + { + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeNative": + BSShapeNative nShape = physShape as BSShapeNative; + prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeMesh": + BSShapeMesh mShape = physShape as BSShapeMesh; + prim.PhysScene.DetailLog("{0}, mesh, shapeInfo={1}", prim.Name, mShape.shapeInfo); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeHull": + BSShapeHull hShape = physShape as BSShapeHull; + prim.PhysScene.DetailLog("{0}, hull, shapeInfo={1}", prim.Name, hShape.shapeInfo); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeConvexHull": + BSShapeConvexHull chShape = physShape as BSShapeConvexHull; + prim.PhysScene.DetailLog("{0}, convexHull, shapeInfo={1}", prim.Name, chShape.shapeInfo); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeCompound": + BSShapeCompound cShape = physShape as BSShapeCompound; + prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); + break; + default: + prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); + break; + } + } + } + } +} +} \ No newline at end of file