From 7c140570db3b01eb83efc0d42a47715d3047e376 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 25 Aug 2012 23:18:46 -0700 Subject: BulletSim: Changes to terrain storage and management so mega-regions work. Moved all terrain code out of BSScene and into new BSTerrainManager. Added logic to manage multiple terrains for mega-regions. Added new functions to BulletSimAPI to match the library. Moved all of the terrain creation and setup logic from C++ code to C# code. The unused code has not yet been removed from either place. Soon. Moved checks for avatar above ground and in bounds into BSCharacter. --- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 37 ++- .../Region/Physics/BulletSPlugin/BSConstraint.cs | 3 +- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 9 +- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 118 ++++---- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 245 ++++++++-------- .../Physics/BulletSPlugin/BSTerrainManager.cs | 307 +++++++++++++++++++++ .../Region/Physics/BulletSPlugin/BulletSimAPI.cs | 61 +++- 8 files changed, 597 insertions(+), 185 deletions(-) create mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs (limited to 'OpenSim') diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 784076d..e76d8a4 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -226,16 +226,37 @@ public class BSCharacter : BSPhysObject bool ret = false; // If below the ground, move the avatar up - float terrainHeight = Scene.GetTerrainHeightAtXYZ(_position); - if (_position.Z < terrainHeight) + float terrainHeight = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); + if (Position.Z < terrainHeight) { - DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},orient={2}", LocalID, _position, _orientation); - _position.Z = terrainHeight + 2.0f; + DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); + Vector3 newPos = _position; + newPos.Z = terrainHeight + 2.0f; + _position = newPos; ret = true; } // TODO: check for out of bounds + return ret; + } + // A version of the sanity check that also makes sure a new position value is + // pushed back to the physics engine. This routine would be used by anyone + // who is not already pushing the value. + private bool PositionSanityCheck2() + { + bool ret = false; + if (PositionSanityCheck()) + { + // The new position value must be pushed into the physics engine but we can't + // just assign to "Position" because of potential call loops. + _scene.TaintedObject("BSCharacter.PositionSanityCheck", delegate() + { + DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); + BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); + }); + ret = true; + } return ret; } @@ -500,9 +521,13 @@ public class BSCharacter : BSPhysObject // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. // base.RequestPhysicsterseUpdate(); - DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", + // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. + PositionSanityCheck2(); + + float heightHere = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); // just for debug + DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}", LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, - entprop.Acceleration, entprop.RotationalVelocity); + entprop.Acceleration, entprop.RotationalVelocity, heightHere); } // Called by the scene when a collision with this object is reported diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs index 25084d8..d9270d1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs @@ -48,11 +48,10 @@ public abstract class BSConstraint : IDisposable { if (m_enabled) { - // BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID); + m_enabled = false; bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr); m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success); m_constraint.Ptr = System.IntPtr.Zero; - m_enabled = false; } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index d7213fc..8169e99 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -465,6 +465,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin } }//end SetDefaultsForType + // One step of the vehicle properties for the next 'pTimestep' seconds. internal void Step(float pTimestep) { if (m_type == Vehicle.TYPE_NONE) return; @@ -592,9 +593,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin } // If below the terrain, move us above the ground a little. - if (pos.Z < m_prim.Scene.GetTerrainHeightAtXYZ(pos)) + if (pos.Z < m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos)) { - pos.Z = m_prim.Scene.GetTerrainHeightAtXYZ(pos) + 2; + pos.Z = m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2; m_prim.Position = pos; VDetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos); } @@ -609,7 +610,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin } if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) { - m_VhoverTargetHeight = m_prim.Scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; + m_VhoverTargetHeight = m_prim.Scene.TerrainManager.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; } if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) { @@ -673,7 +674,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { grav.Z = (float)(grav.Z * 1.125); } - float terraintemp = m_prim.Scene.GetTerrainHeightAtXYZ(pos); + float terraintemp = m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos); float postemp = (pos.Z - terraintemp); if (postemp > 2.5f) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 6e205a9..ef463ca 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -1,58 +1,60 @@ -/* - * 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 copyrightD - * 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.Text; - -using OMV = OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -// Class to wrap all objects. -// The rest of BulletSim doesn't need to keep checking for avatars or prims -// unless the difference is significant. -public abstract class BSPhysObject : PhysicsActor -{ - public abstract BSLinkset Linkset { get; set; } - - public abstract void Collide(uint collidingWith, BSPhysObject collidee, ActorTypes type, - OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth); - public abstract void SendCollisions(); - - // Return the object mass without calculating it or side effects - public abstract float MassRaw { get; } - - public abstract BulletBody Body { get; set; } - public abstract void ZeroMotion(); - - public abstract void UpdateProperties(EntityProperties entprop); - - public abstract void Destroy(); -} -} +/* + * 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 copyrightD + * 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.Text; + +using OMV = OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Physics.Manager; + +namespace OpenSim.Region.Physics.BulletSPlugin +{ +// Class to wrap all objects. +// The rest of BulletSim doesn't need to keep checking for avatars or prims +// unless the difference is significant. +public abstract class BSPhysObject : PhysicsActor +{ + public abstract BSLinkset Linkset { get; set; } + + public abstract void Collide(uint collidingWith, BSPhysObject collidee, ActorTypes type, + OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth); + public abstract void SendCollisions(); + + // Return the object mass without calculating it or side effects + public abstract float MassRaw { get; } + + public abstract BulletBody Body { get; set; } + public abstract void ZeroMotion(); + + public virtual void StepVehicle(float timeStep) { } + + public abstract void UpdateProperties(EntityProperties entprop); + + public abstract void Destroy(); +} +} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 036fd4f..6bfce5c 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -377,7 +377,7 @@ public sealed class BSPrim : BSPhysObject // Called each simulation step to advance vehicle characteristics. // Called from Scene when doing simulation step so we're in taint processing time. - public void StepVehicle(float timeStep) + public override void StepVehicle(float timeStep) { if (IsPhysical) _vehicle.Step(timeStep); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index ce64b9b..f80304d 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -39,8 +39,6 @@ using log4net; using OpenMetaverse; // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) -// Debug linkset -// Test with multiple regions in one simulator // Adjust character capsule size when height is adjusted (ScenePresence.SetHeight) // Test sculpties // Compute physics FPS reasonably @@ -54,10 +52,8 @@ using OpenMetaverse; // Use collision masks for collision with terrain and phantom objects // Check out llVolumeDetect. Must do something for that. // Should prim.link() and prim.delink() membership checking happen at taint time? -// changing the position and orientation of a linked prim must rebuild the constraint with the root. // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect -// 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) // Does NeedsMeshing() really need to exclude all the different shapes? @@ -85,18 +81,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters // moved to a better place. private HashSet m_avatarsWithCollisions = new HashSet(); - private List m_vehicles = new List(); - - private float[] m_heightMap; - private float m_waterLevel; - private uint m_worldID; - public uint WorldID { get { return m_worldID; } } + // List of all the objects that have vehicle properties and should be called + // to update each physics step. + private List m_vehicles = new List(); // let my minuions use my logger public ILog Logger { get { return m_log; } } - private bool m_initialized = false; - + // If non-zero, the number of simulation steps between calls to the physics + // engine to output detailed physics stats. Debug logging level must be on also. private int m_detailedStatsStep = 0; public IMesher mesher; @@ -106,29 +99,31 @@ public class BSScene : PhysicsScene, IPhysicsParameters public float MeshMegaPrimThreshold { get; private set; } public float SculptLOD { get; private set; } - private BulletSim m_worldSim; - public BulletSim World - { - get { return m_worldSim; } - } - private BSConstraintCollection m_constraintCollection; - public BSConstraintCollection Constraints - { - get { return m_constraintCollection; } - } + public uint WorldID { get; private set; } + public BulletSim World { get; private set; } + + // All the constraints that have been allocated in this instance. + public BSConstraintCollection Constraints { get; private set; } + // Simulation parameters private int m_maxSubSteps; private float m_fixedTimeStep; private long m_simulationStep = 0; public long SimulationStep { get { return m_simulationStep; } } + // The length of the last timestep we were asked to simulate. + // This is used by the vehicle code. Since the vehicle code is called + // once per simulation step, its constants need to be scaled by this. public float LastSimulatedTimestep { get; private set; } // A value of the time now so all the collision and update routines do not have to get their own - // Set to 'now' just before all the prims and actors are called for collisions and updates - private int m_simulationNowTime; - public int SimulationNowTime { get { return m_simulationNowTime; } } + // Set to 'now' just before all the prims and actors are called for collisions and updates + public int SimulationNowTime { get; private set; } + + // True if initialized and ready to do simulation steps + private bool m_initialized = false; + // Pinned memory used to pass step information between managed and unmanaged private int m_maxCollisionsPerFrame; private CollisionDesc[] m_collisionArray; private GCHandle m_collisionArrayPinnedHandle; @@ -145,6 +140,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero public const uint GROUNDPLANE_ID = 1; + public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here + + private float m_waterLevel; + public BSTerrainManager TerrainManager { get; private set; } public ConfigurationParameters Params { @@ -155,12 +154,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters get { return new Vector3(0f, 0f, Params.gravity); } } - private float m_maximumObjectMass; - public float MaximumObjectMass - { - get { return m_maximumObjectMass; } - } + public float MaximumObjectMass { get; private set; } + // When functions in the unmanaged code must be called, it is only + // done at a known time just before the simulation step. The taint + // system saves all these function calls and executes them in + // order before the simulation. public delegate void TaintCallback(); private struct TaintCallbackEntry { @@ -176,6 +175,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters private Object _taintLock = new Object(); // A pointer to an instance if this structure is passed to the C++ code + // Used to pass basic configuration values to the unmanaged code. ConfigurationParameters[] m_params; GCHandle m_paramsHandle; @@ -189,11 +189,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters private bool m_physicsLoggingEnabled; private string m_physicsLoggingDir; private string m_physicsLoggingPrefix; - private int m_physicsLoggingFileMinutes; - - private bool m_vehicleLoggingEnabled; - public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } } + private int m_physicsLoggingFileMinutes; + // 'true' of the vehicle code is to log lots of details + public bool VehicleLoggingEnabled { get; private set; } + #region Construction and Initialization public BSScene(string identifier) { m_initialized = false; @@ -216,6 +216,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); + mesher = meshmerizer; + _taintedObjects = new List(); + // Enable very detailed logging. // By creating an empty logger when not logging, the log message invocation code // can be left in and every call doesn't have to check for null. @@ -228,11 +231,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters PhysicsLogging = new Logging.LogWriter(); } - // Get the version of the DLL - // TODO: this doesn't work yet. Something wrong with marshaling the returned string. - // BulletSimVersion = BulletSimAPI.GetVersion(); - // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); - // If Debug logging level, enable logging from the unmanaged code if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) { @@ -245,22 +243,32 @@ public class BSScene : PhysicsScene, IPhysicsParameters BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); } - _taintedObjects = new List(); - - mesher = meshmerizer; + // Get the version of the DLL + // TODO: this doesn't work yet. Something wrong with marshaling the returned string. + // BulletSimVersion = BulletSimAPI.GetVersion(); + // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); - // The bounding box for the simulated world + // The bounding box for the simulated world. The origin is 0,0,0 unless we're + // a child in a mega-region. + // Turns out that Bullet really doesn't care about the extents of the simulated + // area. It tracks active objects no matter where they are. Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); - m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), + WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); // Initialization to support the transition to a new API which puts most of the logic // into the C# code so it is easier to modify and add to. - m_worldSim = new BulletSim(m_worldID, this, BulletSimAPI.GetSimHandle2(m_worldID)); - m_constraintCollection = new BSConstraintCollection(World); + World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID)); + + Constraints = new BSConstraintCollection(World); + + // Note: choose one of the two following lines + // BulletSimAPI.CreateInitialGroundPlaneAndTerrain(WorldID); + TerrainManager = new BSTerrainManager(this); + TerrainManager.CreateInitialGroundPlaneAndTerrain(); m_initialized = true; } @@ -288,7 +296,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); // Very detailed logging for vehicle debugging - m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); + VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); // Do any replacements in the parameters m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); @@ -323,6 +331,38 @@ public class BSScene : PhysicsScene, IPhysicsParameters PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); } + public override void Dispose() + { + // m_log.DebugFormat("{0}: Dispose()", LogHeader); + + // make sure no stepping happens while we're deleting stuff + m_initialized = false; + + TerrainManager.ReleaseGroundPlaneAndTerrain(); + + foreach (KeyValuePair kvp in PhysObjects) + { + kvp.Value.Destroy(); + } + PhysObjects.Clear(); + + // Now that the prims are all cleaned up, there should be no constraints left + if (Constraints != null) + { + Constraints.Dispose(); + Constraints = null; + } + + // Anything left in the unmanaged code should be cleaned out + BulletSimAPI.Shutdown(WorldID); + + // Not logging any more + PhysicsLogging.Close(); + } + #endregion // Construction and Initialization + + #region Prim and Avatar addition and removal + public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) { m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); @@ -413,6 +453,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters // information call is not needed. public override void AddPhysicsActorTaint(PhysicsActor prim) { } + #endregion // Prim and Avatar addition and removal + + #region Simulation // Simulate one timestep public override float Simulate(float timeStep) { @@ -428,7 +471,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters int simulateStartTime = Util.EnvironmentTickCount(); - // update the prim states while we know the physics engine is not busy + // update the prim states while we know the physics engine is not busy + int numTaints = _taintedObjects.Count; ProcessTaints(); // Some of the prims operate with special vehicle properties @@ -440,14 +484,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters int numSubSteps = 0; try { - numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, + numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); - DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); + DetailLog("{0},Simulate,call, nTaints= {1}, substeps={2}, updates={3}, colliders={4}", + DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); } catch (Exception e) { - m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); - // DetailLog("{0},PhysicsStepException,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); + m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}", + LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e); + DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}", + DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); updatedEntityCount = 0; collidersCount = 0; } @@ -456,7 +503,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in // Get a value for 'now' so all the collision and update routines don't have to get their own - m_simulationNowTime = Util.EnvironmentTickCount(); + SimulationNowTime = Util.EnvironmentTickCount(); // If there were collisions, process them by sending the event to the prim. // Collisions must be processed before updates. @@ -527,7 +574,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters // Something has collided private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration) { - if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) + if (localID <= TerrainManager.HighestTerrainID) { return; // don't send collisions to the terrain } @@ -539,7 +586,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters BSPhysObject collidee = null; ActorTypes type = ActorTypes.Prim; - if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) + if (collidingWith <= TerrainManager.HighestTerrainID) { type = ActorTypes.Ground; } @@ -558,28 +605,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters return; } + #endregion // Simulation + public override void GetResults() { } - public override void SetTerrain(float[] heightMap) { - m_heightMap = heightMap; - this.TaintedObject("BSScene.SetTerrain", delegate() - { - BulletSimAPI.SetHeightmap(m_worldID, m_heightMap); - }); - } + #region Terrain - // Someday we will have complex terrain with caves and tunnels - // For the moment, it's flat and convex - public float GetTerrainHeightAtXYZ(Vector3 loc) - { - return GetTerrainHeightAtXY(loc.X, loc.Y); - } - - public float GetTerrainHeightAtXY(float tX, float tY) - { - if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize) - return 30; - return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)]; + public override void SetTerrain(float[] heightMap) { + TerrainManager.SetTerrain(heightMap); } public override void SetWaterLevel(float baseheight) @@ -595,35 +628,29 @@ public class BSScene : PhysicsScene, IPhysicsParameters public override void DeleteTerrain() { // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); + } + + // Although no one seems to check this, I do support combining. + public override bool SupportsCombining() + { + return TerrainManager.SupportsCombining(); } - - public override void Dispose() - { - // m_log.DebugFormat("{0}: Dispose()", LogHeader); - - // make sure no stepping happens while we're deleting stuff - m_initialized = false; - - foreach (KeyValuePair kvp in PhysObjects) - { - kvp.Value.Destroy(); - } - PhysObjects.Clear(); - - // Now that the prims are all cleaned up, there should be no constraints left - if (m_constraintCollection != null) - { - m_constraintCollection.Dispose(); - m_constraintCollection = null; - } - - // Anything left in the unmanaged code should be cleaned out - BulletSimAPI.Shutdown(WorldID); - - // Not logging any more - PhysicsLogging.Close(); + // This call says I am a child to region zero in a mega-region. 'pScene' is that + // of region zero, 'offset' is my offset from regions zero's origin, and + // 'extents' is the largest XY that is handled in my region. + public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) + { + TerrainManager.Combine(pScene, offset, extents); + } + + // Unhook all the combining that I know about. + public override void UnCombine(PhysicsScene pScene) + { + TerrainManager.UnCombine(pScene); } + #endregion // Terrain + public override Dictionary GetTopColliders() { return new Dictionary(); @@ -833,14 +860,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters // no locking because only called when physics engine is not busy private void ProcessVehicles(float timeStep) { - foreach (BSPrim prim in m_vehicles) + foreach (BSPhysObject pobj in m_vehicles) { - prim.StepVehicle(timeStep); + pobj.StepVehicle(timeStep); } } #endregion Vehicles - #region Parameters + #region INI and command line parameter processing delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); delegate float ParamGet(BSScene scene); @@ -943,9 +970,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", 10000.01f, - (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); }, - (s) => { return (float)s.m_maximumObjectMass; }, - (s,p,l,v) => { s.m_maximumObjectMass = v; } ), + (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, + (s) => { return (float)s.MaximumObjectMass; }, + (s,p,l,v) => { s.MaximumObjectMass = v; } ), new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 2200f, @@ -1207,6 +1234,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; + // This creates an array in the correct format for returning the list of + // parameters. This is used by the 'list' option of the 'physics' command. private void BuildParameterTable() { if (SettableParameters.Length < ParameterDefinitions.Length) @@ -1283,7 +1312,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters TaintedObject("BSScene.UpdateParameterSet", delegate() { foreach (uint lID in objectIDs) { - BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval); + BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval); } }); break; @@ -1301,7 +1330,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters string xparm = parm.ToLower(); float xval = val; TaintedObject("BSScene.TaintedUpdateParameter", delegate() { - BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); + BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval); }); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs new file mode 100755 index 0000000..28c1940 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs @@ -0,0 +1,307 @@ +/* + * 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 copyrightD + * 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.Text; + +using OpenSim.Framework; +using OpenSim.Region.Framework; +using OpenSim.Region.CoreModules; +using OpenSim.Region.Physics.Manager; + +using Nini.Config; +using log4net; + +using OpenMetaverse; + +namespace OpenSim.Region.Physics.BulletSPlugin +{ +public class BSTerrainManager +{ + static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; + + BSScene m_physicsScene; + + private BulletBody m_groundPlane; + + // If doing mega-regions, if we're region zero we will be managing multiple + // region terrains since region zero does the physics for the whole mega-region. + private Dictionary m_terrains; + private Dictionary m_heightMaps; + + // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. + // This is incremented before assigning to new region so it is the last ID allocated. + private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1; + public uint HighestTerrainID { get {return m_terrainCount; } } + + // If doing mega-regions, this holds our offset from region zero of + // the mega-regions. "parentScene" points to the PhysicsScene of region zero. + private Vector3 m_worldOffset = Vector3.Zero; + public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); + private PhysicsScene m_parentScene = null; + + public BSTerrainManager(BSScene physicsScene) + { + m_physicsScene = physicsScene; + m_terrains = new Dictionary(); + m_heightMaps = new Dictionary(); + } + + // Create the initial instance of terrain and the underlying ground plane. + // The objects are allocated in the unmanaged space and the pointers are tracked + // by the managed code. + // The terrains and the groundPlane are not added to the list of PhysObjects. + // This is called from the initialization routine so we presume it is + // safe to call Bullet in real time. We hope no one is moving around prim yet. + public void CreateInitialGroundPlaneAndTerrain() + { + // The ground plane is here to catch things that are trying to drop to negative infinity + m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, + BulletSimAPI.CreateGroundPlaneBody2(BSScene.GROUNDPLANE_ID, 1f, 0.4f)); + BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr); + + Vector3 minTerrainCoords = new Vector3(0f, 0f, 24f); + Vector3 maxTerrainCoords = new Vector3(Constants.RegionSize, Constants.RegionSize, 25f); + int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; + float[] initialMap = new float[totalHeights]; + for (int ii = 0; ii < totalHeights; ii++) + { + initialMap[ii] = 25f; + } + CreateNewTerrainSegment(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords); + } + + public void ReleaseGroundPlaneAndTerrain() + { + if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr)) + { + BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, m_groundPlane.Ptr); + } + m_groundPlane.Ptr = IntPtr.Zero; + + foreach (KeyValuePair kvp in m_terrains) + { + if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, kvp.Value.Ptr)) + { + BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, kvp.Value.Ptr); + BulletSimAPI.ReleaseHeightmapInfo2(m_heightMaps[kvp.Key].Ptr); + } + } + m_terrains.Clear(); + m_heightMaps.Clear(); + } + + // Create a new terrain description. This is used for mega-regions where + // the children of region zero give region zero all of the terrain + // segments since region zero does all the physics for the mega-region. + // Call at taint time!! + public void CreateNewTerrainSegment(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) + { + // The Z coordinates are recalculated to be the min and max height of the terrain + // itself. The caller may have passed us the real region extent. + float minZ = float.MaxValue; + float maxZ = float.MinValue; + int hSize = heightMap.Length; + for (int ii = 0; ii < hSize; ii++) + { + minZ = heightMap[ii] < minZ ? heightMap[ii] : minZ; + maxZ = heightMap[ii] > maxZ ? heightMap[ii] : maxZ; + } + minCoords.Z = minZ; + maxCoords.Z = maxZ; + // If the terrain is flat, make a difference so we get a good bounding box + if (minZ == maxZ) + minZ -= 0.2f; + Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y); + + // Create the heightmap data structure in the unmanaged space + BulletHeightMapInfo mapInfo = new BulletHeightMapInfo( + BulletSimAPI.CreateHeightmap2(minCoords, maxCoords, heightMap), heightMap); + mapInfo.terrainRegionBase = terrainRegionBase; + mapInfo.maxRegionExtent = maxCoords; + mapInfo.minZ = minZ; + mapInfo.maxZ = maxZ; + mapInfo.sizeX = maxCoords.X - minCoords.X; + mapInfo.sizeY = maxCoords.Y - minCoords.Y; + + DetailLog("{0},BSScene.CreateNewTerrainSegment,call,minZ={1},maxZ={2},hMapPtr={3},minC={4},maxC={5}", + BSScene.DetailLogZero, minZ, maxZ, mapInfo.Ptr, minCoords, maxCoords); + // Create the terrain body from that heightmap + BulletBody terrainBody = new BulletBody(id, BulletSimAPI.CreateTerrainBody2(id, mapInfo.Ptr, 0.01f)); + + BulletSimAPI.SetFriction2(terrainBody.Ptr, m_physicsScene.Params.terrainFriction); + BulletSimAPI.SetHitFraction2(terrainBody.Ptr, m_physicsScene.Params.terrainHitFraction); + BulletSimAPI.SetRestitution2(terrainBody.Ptr, m_physicsScene.Params.terrainRestitution); + BulletSimAPI.SetCollisionFlags2(terrainBody.Ptr, CollisionFlags.CF_STATIC_OBJECT); + BulletSimAPI.Activate2(terrainBody.Ptr, true); + + // Add the new terrain to the dynamics world + BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, terrainBody.Ptr); + BulletSimAPI.UpdateSingleAabb2(m_physicsScene.World.Ptr, terrainBody.Ptr); + + + // Add the created terrain to the management set. If we are doing mega-regions, + // the terrains of our children will be added. + m_terrains.Add(terrainRegionBase, terrainBody); + m_heightMaps.Add(terrainRegionBase, mapInfo); + } + + public void SetTerrain(float[] heightMap) { + if (m_worldOffset != Vector3.Zero && m_parentScene != null) + { + // If doing the mega-prim stuff and we are the child of the zero region, + // the terrain is really added to our parent + if (m_parentScene is BSScene) + { + ((BSScene)m_parentScene).TerrainManager.SetTerrain(heightMap, m_worldOffset); + } + } + else + { + // if not doing the mega-prim thing, just change the terrain + SetTerrain(heightMap, m_worldOffset); + } + } + + private void SetTerrain(float[] heightMap, Vector3 tOffset) + { + float minZ = float.MaxValue; + float maxZ = float.MinValue; + + // Copy heightMap local and compute some statistics. + // Not really sure if we need to do this deep copy but, given + // the magic that happens to make the closure for taint + // below, I don't want there to be any problem with sharing + // locations of there are multiple calls to this routine + // within one tick. + int heightMapSize = heightMap.Length; + float[] localHeightMap = new float[heightMapSize]; + for (int ii = 0; ii < heightMapSize; ii++) + { + float height = heightMap[ii]; + if (height < minZ) minZ = height; + if (height > maxZ) maxZ = height; + localHeightMap[ii] = height; + } + + Vector2 terrainRegionBase = new Vector2(tOffset.X, tOffset.Y); + BulletHeightMapInfo mapInfo; + if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo)) + { + // If this is terrain we know about, it's easy to update + mapInfo.heightMap = localHeightMap; + m_physicsScene.TaintedObject("BSScene.SetTerrain:UpdateExisting", delegate() + { + DetailLog("{0},SetTerrain:UpdateExisting,baseX={1},baseY={2},minZ={3},maxZ={4}", + BSScene.DetailLogZero, tOffset.X, tOffset.Y, minZ, maxZ); + BulletSimAPI.UpdateHeightMap2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.heightMap); + }); + } + else + { + // Our mega-prim child is giving us a new terrain to add to the phys world + uint newTerrainID = ++m_terrainCount; + + Vector3 minCoords = tOffset; + minCoords.Z = minZ; + Vector3 maxCoords = new Vector3(tOffset.X + Constants.RegionSize, + tOffset.Y + Constants.RegionSize, + maxZ); + m_physicsScene.TaintedObject("BSScene.SetTerrain:NewTerrain", delegate() + { + DetailLog("{0},SetTerrain:NewTerrain,baseX={1},baseY={2}", BSScene.DetailLogZero, tOffset.X, tOffset.Y); + CreateNewTerrainSegment(newTerrainID, heightMap, minCoords, maxCoords); + }); + } + } + + // Someday we will have complex terrain with caves and tunnels + // For the moment, it's flat and convex + public float GetTerrainHeightAtXYZ(Vector3 loc) + { + return GetTerrainHeightAtXY(loc.X, loc.Y); + } + + // Given an X and Y, find the height of the terrain. + // Since we could be handling multiple terrains for a mega-region, + // the base of the region is calcuated assuming all regions are + // the same size and that is the default. + // Once the heightMapInfo is found, we have all the information to + // compute the offset into the array. + public float GetTerrainHeightAtXY(float tX, float tY) + { + float ret = 30f; + + int offsetX = ((int)(tX / (int)Constants.RegionSize)) * (int)Constants.RegionSize; + int offsetY = ((int)(tY / (int)Constants.RegionSize)) * (int)Constants.RegionSize; + Vector2 terrainBaseXY = new Vector2(offsetX, offsetY); + + BulletHeightMapInfo mapInfo; + if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo)) + { + float regionX = tX - offsetX; + float regionY = tY - offsetY; + regionX = regionX > mapInfo.sizeX ? 0 : regionX; + regionY = regionY > mapInfo.sizeY ? 0 : regionY; + ret = mapInfo.heightMap[(int)(regionX * mapInfo.sizeX + regionY)]; + } + else + { + m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: x={1}, y={2}", + LogHeader, tX, tY); + } + return ret; + } + + // Although no one seems to check this, I do support combining. + public bool SupportsCombining() + { + return true; + } + // This call says I am a child to region zero in a mega-region. 'pScene' is that + // of region zero, 'offset' is my offset from regions zero's origin, and + // 'extents' is the largest XY that is handled in my region. + public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) + { + m_worldOffset = offset; + WorldExtents = new Vector2(extents.X, extents.Y); + m_parentScene = pScene; + } + + // Unhook all the combining that I know about. + public void UnCombine(PhysicsScene pScene) + { + // Just like ODE, for the moment a NOP + } + + + private void DetailLog(string msg, params Object[] args) + { + m_physicsScene.PhysicsLogging.Write(msg, args); + } +} +} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index dab2420..3b319fb 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs @@ -33,6 +33,9 @@ using OpenMetaverse; namespace OpenSim.Region.Physics.BulletSPlugin { // Classes to allow some type checking for the API +// These hold pointers to allocated objects in the unmanaged space. + +// The physics engine controller class created at initialization public struct BulletSim { public BulletSim(uint id, BSScene bss, IntPtr xx) { ID = id; scene = bss; Ptr = xx; } @@ -42,6 +45,7 @@ public struct BulletSim public IntPtr Ptr; } +// An allocated Bullet btRigidBody public struct BulletBody { public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; } @@ -49,12 +53,35 @@ public struct BulletBody public uint ID; } +// An allocated Bullet btConstraint public struct BulletConstraint { public BulletConstraint(IntPtr xx) { Ptr = xx; } public IntPtr Ptr; } +// An allocated HeightMapThing which hold various heightmap info +// Made a class rather than a struct so there would be only one +// instance of this and C# will pass around pointers rather +// than making copies. +public class BulletHeightMapInfo +{ + public BulletHeightMapInfo(IntPtr xx, float[] hm) { + Ptr = xx; + heightMap = hm; + terrainRegionBase = new Vector2(0f, 0f); + maxRegionExtent = new Vector3(100f, 100f, 25f); + minZ = maxZ = 0f; + sizeX = sizeY = 256f; + } + public IntPtr Ptr; + public float[] heightMap; + public Vector2 terrainRegionBase; + public Vector3 maxRegionExtent; + public float sizeX, sizeY; + public float minZ, maxZ; +} + // =============================================================================== [StructLayout(LayoutKind.Sequential)] public struct ConvexHull @@ -231,6 +258,9 @@ public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, int maxUpdates, IntPtr updateArray); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] @@ -414,12 +444,23 @@ public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); // ===================================================================================== [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateGroundPlaneBody2(uint id, Vector3 center, float collisionMargin); +public static extern IntPtr CreateGroundPlaneBody2(uint id, float height, float collisionMargin); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreateTerrainBody2(uint id, - Vector3 minCoords, Vector3 maxCoords, float collisionMargin, - [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); + IntPtr heightMapInfo, + float collisionMargin); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateHeightmap2(Vector3 minCoords, Vector3 maxCoords, + [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool ReleaseHeightmapInfo2(IntPtr heightMapInfo); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void UpdateHeightMap2(IntPtr world, IntPtr heightMapInfo, + [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); // ===================================================================================== [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] @@ -473,11 +514,16 @@ public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); +// ===================================================================================== [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 AddObjectToWorld2(IntPtr world, IntPtr obj); +public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 RemoveObjectFromWorld2(IntPtr world, IntPtr obj); +public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); + +// ===================================================================================== +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void Activate2(IntPtr obj, bool forceActivation); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern Vector3 GetPosition2(IntPtr obj); @@ -522,6 +568,9 @@ public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val); public static extern bool SetFriction2(IntPtr obj, float val); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetHitFraction2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern bool SetRestitution2(IntPtr obj, float val); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] @@ -564,7 +613,7 @@ public static extern bool SetMargin2(IntPtr obj, float val); public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool DestroyObject2(IntPtr world, uint id); +public static extern bool DestroyObject2(IntPtr world, IntPtr obj); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern void DumpPhysicsStatistics2(IntPtr sim); -- cgit v1.1