From 21708b832b1d6679d5f6de27eb3bd0b920ef0fa7 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 26 Aug 2011 15:51:21 -0700 Subject: BulletSim: add mesh representation. Use meshes for static objects and switch to hulls for physical objects. --- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 306 +++++++++++++-------- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 20 +- .../Region/Physics/BulletSPlugin/BulletSimAPI.cs | 31 ++- 3 files changed, 228 insertions(+), 129 deletions(-) (limited to 'OpenSim/Region/Physics') diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index cc414e9..d1fb576 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -45,6 +45,7 @@ public sealed class BSPrim : PhysicsActor private IMesh _mesh; private PrimitiveBaseShape _pbs; private ShapeData.PhysicsShapeType _shapeType; + private ulong _meshKey; private ulong _hullKey; private List _hulls; @@ -117,6 +118,7 @@ public sealed class BSPrim : PhysicsActor _rotationalVelocity = OMV.Vector3.Zero; _angularVelocity = OMV.Vector3.Zero; _hullKey = 0; + _meshKey = 0; _pbs = pbs; _isPhysical = pisPhysical; _isVolumeDetect = false; @@ -147,6 +149,7 @@ public sealed class BSPrim : PhysicsActor _scene.RemoveVehiclePrim(this); // just to make sure _scene.TaintedObject(delegate() { + // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. BulletSimAPI.DestroyObject(_scene.WorldID, _localID); }); } @@ -283,11 +286,6 @@ public sealed class BSPrim : PhysicsActor set { _parentPrim = value; } } - public ulong HullKey - { - get { return _hullKey; } - } - // return true if we are the root of a linkset (there are children to manage) public bool IsRootOfLinkset { @@ -463,7 +461,18 @@ public sealed class BSPrim : PhysicsActor private void SetObjectDynamic() { // non-physical things work best with a mass of zero - _mass = IsStatic ? 0f : CalculateMass(); + if (IsStatic) + { + _mass = 0f; + } + else + { + _mass = CalculateMass(); + // If it's dynamic, make sure the hull has been created for it + // This shouldn't do much work if the object had previously been built + RecreateGeomAndObject(); + + } BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass); // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}, mass={4}", LogHeader, _localID, IsStatic, IsSolid, _mass); } @@ -896,26 +905,19 @@ public sealed class BSPrim : PhysicsActor #endregion Mass Calculation // Create the geometry information in Bullet for later use + // The objects needs a hull if it's physical otherwise a mesh is enough // No locking here because this is done when we know physics is not simulating - private void CreateGeom() + // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used + private void CreateGeom(bool forceRebuild) { - // Since we're recreating new, get rid of any previously generated shape - if (_hullKey != 0) + // the mesher thought this was too simple to mesh. Use a native Bullet collision shape. + if (!_scene.NeedsMeshing(_pbs)) { - // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); - BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); - _hullKey = 0; - _hulls.Clear(); - } - - if (_mesh == null) - { - // the mesher thought this was too simple to mesh. Use a native Bullet collision shape. if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) { if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) { - // m_log.DebugFormat("{0}: CreateGeom: mesh null. Defaulting to sphere of size {1}", LogHeader, _size); + // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; // Bullet native objects are scaled by the Bullet engine so pass the size in _scale = _size; @@ -923,99 +925,190 @@ public sealed class BSPrim : PhysicsActor } else { - // m_log.DebugFormat("{0}: CreateGeom: mesh null. Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); + // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; _scale = _size; } } else { - int[] indices = _mesh.getIndexListAsInt(); - List vertices = _mesh.getVertexList(); - - //format conversion from IMesh format to DecompDesc format - List convIndices = new List(); - List convVertices = new List(); - for (int ii = 0; ii < indices.GetLength(0); ii++) + if (IsPhysical) { - convIndices.Add(indices[ii]); + if (forceRebuild || _hullKey == 0) + { + // physical objects require a hull for interaction. + // This will create the mesh if it doesn't already exist + CreateGeomHull(); + } } - foreach (OMV.Vector3 vv in vertices) + else { - convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); + if (forceRebuild || _meshKey == 0) + { + // Static (non-physical) objects only need a mesh for bumping into + CreateGeomMesh(); + } } + } + } + + // No locking here because this is done when we know physics is not simulating + private void CreateGeomMesh() + { + ulong newMeshKey = (ulong)_pbs.GetHashCode(); + + // if this new shape is the same as last time, don't recreate the mesh + if (_meshKey == newMeshKey) return; + + // Since we're recreating new, get rid of any previously generated shape + if (_meshKey != 0) + { + // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _meshKey); + BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); + _mesh = null; + _meshKey = 0; + } + + _meshKey = newMeshKey; + int lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD; + // always pass false for physicalness as this creates some sort of bounding box which we don't need + _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false); + + int[] indices = _mesh.getIndexListAsInt(); + List vertices = _mesh.getVertexList(); + + float[] verticesAsFloats = new float[vertices.Count * 3]; + int vi = 0; + foreach (OMV.Vector3 vv in vertices) + { + // m_log.DebugFormat("{0}: {1}: <{2:0.00}, {3:0.00}, {4:0.00}>", LogHeader, vi / 3, vv.X, vv.Y, vv.Z); + verticesAsFloats[vi++] = vv.X; + verticesAsFloats[vi++] = vv.Y; + verticesAsFloats[vi++] = vv.Z; + } - // setup and do convex hull conversion - _hulls = new List(); - DecompDesc dcomp = new DecompDesc(); - dcomp.mIndices = convIndices; - dcomp.mVertices = convVertices; - ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); - // create the hull into the _hulls variable - convexBuilder.process(dcomp); - - // Convert the vertices and indices for passing to unmanaged - // The hull information is passed as a large floating point array. - // The format is: - // convHulls[0] = number of hulls - // convHulls[1] = number of vertices in first hull - // convHulls[2] = hull centroid X coordinate - // convHulls[3] = hull centroid Y coordinate - // convHulls[4] = hull centroid Z coordinate - // convHulls[5] = first hull vertex X - // convHulls[6] = first hull vertex Y - // convHulls[7] = first hull vertex Z - // convHulls[8] = second hull vertex X - // ... - // convHulls[n] = number of vertices in second hull - // convHulls[n+1] = second hull centroid X coordinate - // ... - // - // TODO: is is very inefficient. Someday change the convex hull generator to return - // data structures that do not need to be converted in order to pass to Bullet. - // And maybe put the values directly into pinned memory rather than marshaling. - int hullCount = _hulls.Count; - int totalVertices = 1; // include one for the count of the hulls - foreach (ConvexResult cr in _hulls) + // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", + // LogHeader, _localID, _meshKey, indices.Length, vertices.Count); + BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices, + vertices.Count, verticesAsFloats); + + _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; + // meshes are already scaled by the meshmerizer + _scale = new OMV.Vector3(1f, 1f, 1f); + return; + } + + // No locking here because this is done when we know physics is not simulating + private void CreateGeomHull() + { + ulong newHullKey = (ulong)_pbs.GetHashCode(); + + // if the hull hasn't changed, don't rebuild it + if (newHullKey == _hullKey) return; + + // Since we're recreating new, get rid of any previously generated shape + if (_hullKey != 0) + { + // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); + BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); + _hullKey = 0; + _hulls.Clear(); + BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); + _mesh = null; // the mesh cannot match either + _meshKey = 0; + } + + _hullKey = newHullKey; + if (_meshKey != _hullKey) + { + // if the underlying mesh has changed, rebuild it + CreateGeomMesh(); + } + + int[] indices = _mesh.getIndexListAsInt(); + List vertices = _mesh.getVertexList(); + + //format conversion from IMesh format to DecompDesc format + List convIndices = new List(); + List convVertices = new List(); + for (int ii = 0; ii < indices.GetLength(0); ii++) + { + convIndices.Add(indices[ii]); + } + foreach (OMV.Vector3 vv in vertices) + { + convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); + } + + // setup and do convex hull conversion + _hulls = new List(); + DecompDesc dcomp = new DecompDesc(); + dcomp.mIndices = convIndices; + dcomp.mVertices = convVertices; + ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); + // create the hull into the _hulls variable + convexBuilder.process(dcomp); + + // Convert the vertices and indices for passing to unmanaged + // The hull information is passed as a large floating point array. + // The format is: + // convHulls[0] = number of hulls + // convHulls[1] = number of vertices in first hull + // convHulls[2] = hull centroid X coordinate + // convHulls[3] = hull centroid Y coordinate + // convHulls[4] = hull centroid Z coordinate + // convHulls[5] = first hull vertex X + // convHulls[6] = first hull vertex Y + // convHulls[7] = first hull vertex Z + // convHulls[8] = second hull vertex X + // ... + // convHulls[n] = number of vertices in second hull + // convHulls[n+1] = second hull centroid X coordinate + // ... + // + // TODO: is is very inefficient. Someday change the convex hull generator to return + // data structures that do not need to be converted in order to pass to Bullet. + // And maybe put the values directly into pinned memory rather than marshaling. + int hullCount = _hulls.Count; + int totalVertices = 1; // include one for the count of the hulls + foreach (ConvexResult cr in _hulls) + { + totalVertices += 4; // add four for the vertex count and centroid + totalVertices += cr.HullIndices.Count * 3; // we pass just triangles + } + float[] convHulls = new float[totalVertices]; + + convHulls[0] = (float)hullCount; + int jj = 1; + foreach (ConvexResult cr in _hulls) + { + // copy vertices for index access + float3[] verts = new float3[cr.HullVertices.Count]; + int kk = 0; + foreach (float3 ff in cr.HullVertices) { - totalVertices += 4; // add four for the vertex count and centroid - totalVertices += cr.HullIndices.Count * 3; // we pass just triangles + verts[kk++] = ff; } - float[] convHulls = new float[totalVertices]; - convHulls[0] = (float)hullCount; - int jj = 1; - foreach (ConvexResult cr in _hulls) + // add to the array one hull's worth of data + convHulls[jj++] = cr.HullIndices.Count; + convHulls[jj++] = 0f; // centroid x,y,z + convHulls[jj++] = 0f; + convHulls[jj++] = 0f; + foreach (int ind in cr.HullIndices) { - // copy vertices for index access - float3[] verts = new float3[cr.HullVertices.Count]; - int kk = 0; - foreach (float3 ff in cr.HullVertices) - { - verts[kk++] = ff; - } - - // add to the array one hull's worth of data - convHulls[jj++] = cr.HullIndices.Count; - convHulls[jj++] = 0f; // centroid x,y,z - convHulls[jj++] = 0f; - convHulls[jj++] = 0f; - foreach (int ind in cr.HullIndices) - { - convHulls[jj++] = verts[ind].x; - convHulls[jj++] = verts[ind].y; - convHulls[jj++] = verts[ind].z; - } + convHulls[jj++] = verts[ind].x; + convHulls[jj++] = verts[ind].y; + convHulls[jj++] = verts[ind].z; } - - // create the hull definition in Bullet - _hullKey = (ulong)_pbs.GetHashCode(); - // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount); - BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls); - _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; - // meshes are already scaled by the meshmerizer - _scale = new OMV.Vector3(1f, 1f, 1f); } + + // create the hull definition in Bullet + // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount); + BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls); + _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; + // meshes are already scaled by the meshmerizer + _scale = new OMV.Vector3(1f, 1f, 1f); return; } @@ -1040,6 +1133,7 @@ public sealed class BSPrim : PhysicsActor else { // simple object + // the mesh or hull must have already been created in Bullet ShapeData shape; FillShapeInfo(out shape); BulletSimAPI.CreateObject(_scene.WorldID, shape); @@ -1081,7 +1175,8 @@ public sealed class BSPrim : PhysicsActor shape.Scale = _scale; shape.Mass = _isPhysical ? _mass : 0f; shape.Buoyancy = _buoyancy; - shape.MeshKey = _hullKey; + shape.HullKey = _hullKey; + shape.MeshKey = _meshKey; shape.Friction = _friction; shape.Restitution = _restitution; shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; @@ -1098,13 +1193,13 @@ public sealed class BSPrim : PhysicsActor // remove any constraints that might be in place foreach (BSPrim prim in _childrenPrims) { - // m_log.DebugFormat("{0}: CreateObject: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); + // m_log.DebugFormat("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID); } // create constraints between the root prim and each of the children foreach (BSPrim prim in _childrenPrims) { - // m_log.DebugFormat("{0}: CreateObject: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); + // m_log.DebugFormat("{0}: CreateLinkset: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); // Zero motion for children so they don't interpolate prim.ZeroMotion(); @@ -1132,20 +1227,7 @@ public sealed class BSPrim : PhysicsActor // No locking here because this is done when the physics engine is not simulating private void RecreateGeomAndObject() { - // If this object is complex or we are the root of a linkset, build a mesh. - // The root of a linkset must be a mesh so we can create the linked compound object. - // if (_scene.NeedsMeshing(_pbs) || IsRootOfLinkset ) - if (_scene.NeedsMeshing(_pbs)) // linksets with constraints don't need a root mesh - { - // m_log.DebugFormat("{0}: RecreateGeomAndObject: creating mesh", LogHeader); - _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, _scene.MeshLOD, _isPhysical); - } - else - { - // implement the shape with a Bullet native shape. - _mesh = null; - } - CreateGeom(); + CreateGeom(true); CreateObject(); return; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 518be09..e91455a 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -37,7 +37,6 @@ using OpenMetaverse; using OpenSim.Region.Framework; // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) -// Parameterize BulletSim. Pass a structure of parameters to the C++ code. Capsule size, friction, ... // Adjust character capsule size when height is adjusted (ScenePresence.SetHeight) // Test sculpties // Compute physics FPS reasonably @@ -52,8 +51,6 @@ using OpenSim.Region.Framework; // Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions) // Implement LockAngularMotion // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) -// Built Galton board (lots of MoveTo's) and some slats were not positioned correctly (mistakes scattered) -// No mistakes with ODE. Shape creation race condition? // Does NeedsMeshing() really need to exclude all the different shapes? // namespace OpenSim.Region.Physics.BulletSPlugin @@ -81,6 +78,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters { get { return m_meshLOD; } } + private int m_sculptLOD; + public int SculptLOD + { + get { return m_sculptLOD; } + } private int m_maxSubSteps; private float m_fixedTimeStep; @@ -187,7 +189,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters _meshSculptedPrim = true; // mesh sculpted prims _forceSimplePrimMeshing = false; // use complex meshing if called for - m_meshLOD = 32; + m_meshLOD = 8; + m_sculptLOD = 32; m_maxSubSteps = 10; m_fixedTimeStep = 1f / 60f; @@ -229,6 +232,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing); m_meshLOD = pConfig.GetInt("MeshLevelOfDetail", m_meshLOD); + m_sculptLOD = pConfig.GetInt("SculptLevelOfDetail", m_sculptLOD); m_maxSubSteps = pConfig.GetInt("MaxSubSteps", m_maxSubSteps); m_fixedTimeStep = pConfig.GetFloat("FixedTimeStep", m_fixedTimeStep); @@ -489,10 +493,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters // can use an internal representation for the prim if (!_forceSimplePrimMeshing) { - // m_log.DebugFormat("{0}: NeedsMeshing: simple mesh: profshape={1}, curve={2}", LogHeader, pbs.ProfileShape, pbs.PathCurve); if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 - && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) + && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) { if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 @@ -663,7 +666,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters #region Runtime settable parameters public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[] { - new PhysParameterEntry("MeshLOD", "Level of detail to render meshes (Power of two. Default 32)"), + new PhysParameterEntry("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)"), + new PhysParameterEntry("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)"), new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"), new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"), new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"), @@ -712,6 +716,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters switch (lparm) { case "meshlod": m_meshLOD = (int)val; break; + case "sculptlod": m_sculptLOD = (int)val; break; case "maxsubstep": m_maxSubSteps = (int)val; break; case "fixedtimestep": m_fixedTimeStep = val; break; case "maxobjectmass": m_maximumObjectMass = val; break; @@ -812,6 +817,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters switch (parm.ToLower()) { case "meshlod": val = (float)m_meshLOD; break; + case "sculptlod": val = (float)m_sculptLOD; break; case "maxsubstep": val = (float)m_maxSubSteps; break; case "fixedtimestep": val = m_fixedTimeStep; break; case "maxobjectmass": val = m_maximumObjectMass; break; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index bf953df..a610c8d 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs @@ -49,7 +49,8 @@ public struct ShapeData SHAPE_CONE = 2, SHAPE_CYLINDER = 3, SHAPE_SPHERE = 4, - SHAPE_HULL = 5 + SHAPE_MESH = 5, + SHAPE_HULL = 6 }; public uint ID; public PhysicsShapeType Type; @@ -59,6 +60,7 @@ public struct ShapeData public Vector3 Scale; public float Mass; public float Buoyancy; + public System.UInt64 HullKey; public System.UInt64 MeshKey; public float Friction; public float Restitution; @@ -158,20 +160,29 @@ public static extern void Shutdown(uint worldID); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep, - out int updatedEntityCount, - out IntPtr updatedEntitiesPtr, - out int collidersCount, - out IntPtr collidersPtr); + out int updatedEntityCount, + out IntPtr updatedEntitiesPtr, + out int collidersCount, + out IntPtr collidersPtr); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, int hullCount, - [MarshalAs(UnmanagedType.LPArray)] float[] hulls +public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, + int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls + ); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey, + int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, + int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern bool CreateObject(uint worldID, ShapeData shapeData); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] @@ -179,9 +190,9 @@ public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern void AddConstraint(uint worldID, uint id1, uint id2, - Vector3 frame1, Quaternion frame1rot, - Vector3 frame2, Quaternion frame2rot, - Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular); + Vector3 frame1, Quaternion frame1rot, + Vector3 frame2, Quaternion frame2rot, + Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern bool RemoveConstraintByID(uint worldID, uint id1); -- cgit v1.1