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.
integration
Robert Adams 2012-08-25 23:18:46 -07:00
parent 7b6987ce83
commit 7c140570db
8 changed files with 597 additions and 185 deletions

View File

@ -226,16 +226,37 @@ public class BSCharacter : BSPhysObject
bool ret = false; bool ret = false;
// If below the ground, move the avatar up // If below the ground, move the avatar up
float terrainHeight = Scene.GetTerrainHeightAtXYZ(_position); float terrainHeight = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position);
if (_position.Z < terrainHeight) if (Position.Z < terrainHeight)
{ {
DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},orient={2}", LocalID, _position, _orientation); DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
_position.Z = terrainHeight + 2.0f; Vector3 newPos = _position;
newPos.Z = terrainHeight + 2.0f;
_position = newPos;
ret = true; ret = true;
} }
// TODO: check for out of bounds // 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; 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. // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
// base.RequestPhysicsterseUpdate(); // 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, 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 // Called by the scene when a collision with this object is reported

View File

@ -48,11 +48,10 @@ public abstract class BSConstraint : IDisposable
{ {
if (m_enabled) 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); 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_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_constraint.Ptr = System.IntPtr.Zero;
m_enabled = false;
} }
} }

View File

@ -465,6 +465,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
} }
}//end SetDefaultsForType }//end SetDefaultsForType
// One step of the vehicle properties for the next 'pTimestep' seconds.
internal void Step(float pTimestep) internal void Step(float pTimestep)
{ {
if (m_type == Vehicle.TYPE_NONE) return; 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 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; m_prim.Position = pos;
VDetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, 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) 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) if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
{ {
@ -673,7 +674,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
grav.Z = (float)(grav.Z * 1.125); 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); float postemp = (pos.Z - terraintemp);
if (postemp > 2.5f) if (postemp > 2.5f)
{ {

View File

@ -51,6 +51,8 @@ public abstract class BSPhysObject : PhysicsActor
public abstract BulletBody Body { get; set; } public abstract BulletBody Body { get; set; }
public abstract void ZeroMotion(); public abstract void ZeroMotion();
public virtual void StepVehicle(float timeStep) { }
public abstract void UpdateProperties(EntityProperties entprop); public abstract void UpdateProperties(EntityProperties entprop);
public abstract void Destroy(); public abstract void Destroy();

View File

@ -377,7 +377,7 @@ public sealed class BSPrim : BSPhysObject
// Called each simulation step to advance vehicle characteristics. // Called each simulation step to advance vehicle characteristics.
// Called from Scene when doing simulation step so we're in taint processing time. // 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) if (IsPhysical)
_vehicle.Step(timeStep); _vehicle.Step(timeStep);

View File

@ -39,8 +39,6 @@ using log4net;
using OpenMetaverse; using OpenMetaverse;
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) // 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) // Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
// Test sculpties // Test sculpties
// Compute physics FPS reasonably // Compute physics FPS reasonably
@ -54,10 +52,8 @@ using OpenMetaverse;
// Use collision masks for collision with terrain and phantom objects // Use collision masks for collision with terrain and phantom objects
// Check out llVolumeDetect. Must do something for that. // Check out llVolumeDetect. Must do something for that.
// Should prim.link() and prim.delink() membership checking happen at taint time? // 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 // 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 // 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 // Implement LockAngularMotion
// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) // 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? // Does NeedsMeshing() really need to exclude all the different shapes?
@ -85,18 +81,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// moved to a better place. // moved to a better place.
private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>(); private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>();
private List<BSPrim> m_vehicles = new List<BSPrim>(); // List of all the objects that have vehicle properties and should be called
// to update each physics step.
private float[] m_heightMap; private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
private float m_waterLevel;
private uint m_worldID;
public uint WorldID { get { return m_worldID; } }
// let my minuions use my logger // let my minuions use my logger
public ILog Logger { get { return m_log; } } 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; private int m_detailedStatsStep = 0;
public IMesher mesher; public IMesher mesher;
@ -106,29 +99,31 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public float MeshMegaPrimThreshold { get; private set; } public float MeshMegaPrimThreshold { get; private set; }
public float SculptLOD { get; private set; } public float SculptLOD { get; private set; }
private BulletSim m_worldSim; public uint WorldID { get; private set; }
public BulletSim World public BulletSim World { get; private set; }
{
get { return m_worldSim; }
}
private BSConstraintCollection m_constraintCollection;
public BSConstraintCollection Constraints
{
get { return m_constraintCollection; }
}
// All the constraints that have been allocated in this instance.
public BSConstraintCollection Constraints { get; private set; }
// Simulation parameters
private int m_maxSubSteps; private int m_maxSubSteps;
private float m_fixedTimeStep; private float m_fixedTimeStep;
private long m_simulationStep = 0; private long m_simulationStep = 0;
public long SimulationStep { get { return m_simulationStep; } } 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; } 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 // 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 // Set to 'now' just before all the prims and actors are called for collisions and updates
private int m_simulationNowTime; public int SimulationNowTime { get; private set; }
public int SimulationNowTime { get { return m_simulationNowTime; } }
// 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 int m_maxCollisionsPerFrame;
private CollisionDesc[] m_collisionArray; private CollisionDesc[] m_collisionArray;
private GCHandle m_collisionArrayPinnedHandle; 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 TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
public const uint GROUNDPLANE_ID = 1; 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 public ConfigurationParameters Params
{ {
@ -155,12 +154,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
get { return new Vector3(0f, 0f, Params.gravity); } get { return new Vector3(0f, 0f, Params.gravity); }
} }
private float m_maximumObjectMass; public float MaximumObjectMass { get; private set; }
public float MaximumObjectMass
{
get { return m_maximumObjectMass; }
}
// 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(); public delegate void TaintCallback();
private struct TaintCallbackEntry private struct TaintCallbackEntry
{ {
@ -176,6 +175,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private Object _taintLock = new Object(); private Object _taintLock = new Object();
// A pointer to an instance if this structure is passed to the C++ code // 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; ConfigurationParameters[] m_params;
GCHandle m_paramsHandle; GCHandle m_paramsHandle;
@ -190,10 +190,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private string m_physicsLoggingDir; private string m_physicsLoggingDir;
private string m_physicsLoggingPrefix; private string m_physicsLoggingPrefix;
private int m_physicsLoggingFileMinutes; private int m_physicsLoggingFileMinutes;
// 'true' of the vehicle code is to log lots of details
public bool VehicleLoggingEnabled { get; private set; }
private bool m_vehicleLoggingEnabled; #region Construction and Initialization
public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
public BSScene(string identifier) public BSScene(string identifier)
{ {
m_initialized = false; m_initialized = false;
@ -216,6 +216,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
mesher = meshmerizer;
_taintedObjects = new List<TaintCallbackEntry>();
// Enable very detailed logging. // Enable very detailed logging.
// By creating an empty logger when not logging, the log message invocation code // 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. // 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(); 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 Debug logging level, enable logging from the unmanaged code
if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
{ {
@ -245,22 +243,32 @@ public class BSScene : PhysicsScene, IPhysicsParameters
BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
} }
_taintedObjects = new List<TaintCallbackEntry>(); // 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);
mesher = meshmerizer; // The bounding box for the simulated world. The origin is 0,0,0 unless we're
// a child in a mega-region.
// The bounding box for the simulated world // 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); Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f);
// m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); // 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_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject());
// Initialization to support the transition to a new API which puts most of the logic // 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. // into the C# code so it is easier to modify and add to.
m_worldSim = new BulletSim(m_worldID, this, BulletSimAPI.GetSimHandle2(m_worldID)); World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID));
m_constraintCollection = new BSConstraintCollection(World);
Constraints = new BSConstraintCollection(World);
// Note: choose one of the two following lines
// BulletSimAPI.CreateInitialGroundPlaneAndTerrain(WorldID);
TerrainManager = new BSTerrainManager(this);
TerrainManager.CreateInitialGroundPlaneAndTerrain();
m_initialized = true; m_initialized = true;
} }
@ -288,7 +296,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
// Very detailed logging for vehicle debugging // Very detailed logging for vehicle debugging
m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
// Do any replacements in the parameters // Do any replacements in the parameters
m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
@ -323,6 +331,38 @@ public class BSScene : PhysicsScene, IPhysicsParameters
PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); 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<uint, BSPhysObject> 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) public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
{ {
m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); 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. // information call is not needed.
public override void AddPhysicsActorTaint(PhysicsActor prim) { } public override void AddPhysicsActorTaint(PhysicsActor prim) { }
#endregion // Prim and Avatar addition and removal
#region Simulation
// Simulate one timestep // Simulate one timestep
public override float Simulate(float timeStep) public override float Simulate(float timeStep)
{ {
@ -429,6 +472,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
int simulateStartTime = Util.EnvironmentTickCount(); 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(); ProcessTaints();
// Some of the prims operate with special vehicle properties // Some of the prims operate with special vehicle properties
@ -440,14 +484,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
int numSubSteps = 0; int numSubSteps = 0;
try 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); 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) catch (Exception e)
{ {
m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
// DetailLog("{0},PhysicsStepException,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 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; updatedEntityCount = 0;
collidersCount = 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 // 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 // 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. // If there were collisions, process them by sending the event to the prim.
// Collisions must be processed before updates. // Collisions must be processed before updates.
@ -527,7 +574,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// Something has collided // Something has collided
private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration) 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 return; // don't send collisions to the terrain
} }
@ -539,7 +586,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
BSPhysObject collidee = null; BSPhysObject collidee = null;
ActorTypes type = ActorTypes.Prim; ActorTypes type = ActorTypes.Prim;
if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) if (collidingWith <= TerrainManager.HighestTerrainID)
{ {
type = ActorTypes.Ground; type = ActorTypes.Ground;
} }
@ -558,28 +605,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
return; return;
} }
#endregion // Simulation
public override void GetResults() { } public override void GetResults() { }
#region Terrain
public override void SetTerrain(float[] heightMap) { public override void SetTerrain(float[] heightMap) {
m_heightMap = heightMap; TerrainManager.SetTerrain(heightMap);
this.TaintedObject("BSScene.SetTerrain", delegate()
{
BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
});
}
// 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 SetWaterLevel(float baseheight) public override void SetWaterLevel(float baseheight)
@ -597,33 +630,27 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
} }
public override void Dispose() // Although no one seems to check this, I do support combining.
public override bool SupportsCombining()
{ {
// m_log.DebugFormat("{0}: Dispose()", LogHeader); return TerrainManager.SupportsCombining();
// make sure no stepping happens while we're deleting stuff
m_initialized = false;
foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
{
kvp.Value.Destroy();
} }
PhysObjects.Clear(); // 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
// Now that the prims are all cleaned up, there should be no constraints left // 'extents' is the largest XY that is handled in my region.
if (m_constraintCollection != null) public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
{ {
m_constraintCollection.Dispose(); TerrainManager.Combine(pScene, offset, extents);
m_constraintCollection = null;
} }
// Anything left in the unmanaged code should be cleaned out // Unhook all the combining that I know about.
BulletSimAPI.Shutdown(WorldID); public override void UnCombine(PhysicsScene pScene)
{
// Not logging any more TerrainManager.UnCombine(pScene);
PhysicsLogging.Close();
} }
#endregion // Terrain
public override Dictionary<uint, float> GetTopColliders() public override Dictionary<uint, float> GetTopColliders()
{ {
return new Dictionary<uint, float>(); return new Dictionary<uint, float>();
@ -833,14 +860,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// no locking because only called when physics engine is not busy // no locking because only called when physics engine is not busy
private void ProcessVehicles(float timeStep) 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 #endregion Vehicles
#region Parameters #region INI and command line parameter processing
delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
delegate float ParamGet(BSScene scene); delegate float ParamGet(BSScene scene);
@ -943,9 +970,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
10000.01f, 10000.01f,
(s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); }, (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
(s) => { return (float)s.m_maximumObjectMass; }, (s) => { return (float)s.MaximumObjectMass; },
(s,p,l,v) => { s.m_maximumObjectMass = v; } ), (s,p,l,v) => { s.MaximumObjectMass = v; } ),
new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
2200f, 2200f,
@ -1207,6 +1234,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; 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() private void BuildParameterTable()
{ {
if (SettableParameters.Length < ParameterDefinitions.Length) if (SettableParameters.Length < ParameterDefinitions.Length)
@ -1283,7 +1312,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
TaintedObject("BSScene.UpdateParameterSet", delegate() { TaintedObject("BSScene.UpdateParameterSet", delegate() {
foreach (uint lID in objectIDs) foreach (uint lID in objectIDs)
{ {
BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval); BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
} }
}); });
break; break;
@ -1301,7 +1330,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
string xparm = parm.ToLower(); string xparm = parm.ToLower();
float xval = val; float xval = val;
TaintedObject("BSScene.TaintedUpdateParameter", delegate() { TaintedObject("BSScene.TaintedUpdateParameter", delegate() {
BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval);
}); });
} }

View File

@ -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<Vector2, BulletBody> m_terrains;
private Dictionary<Vector2, BulletHeightMapInfo> 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<Vector2,BulletBody>();
m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
}
// 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<Vector2, BulletBody> 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);
}
}
}

View File

@ -33,6 +33,9 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin { namespace OpenSim.Region.Physics.BulletSPlugin {
// Classes to allow some type checking for the API // 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 struct BulletSim
{ {
public BulletSim(uint id, BSScene bss, IntPtr xx) { ID = id; scene = bss; Ptr = xx; } public BulletSim(uint id, BSScene bss, IntPtr xx) { ID = id; scene = bss; Ptr = xx; }
@ -42,6 +45,7 @@ public struct BulletSim
public IntPtr Ptr; public IntPtr Ptr;
} }
// An allocated Bullet btRigidBody
public struct BulletBody public struct BulletBody
{ {
public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; } public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; }
@ -49,12 +53,35 @@ public struct BulletBody
public uint ID; public uint ID;
} }
// An allocated Bullet btConstraint
public struct BulletConstraint public struct BulletConstraint
{ {
public BulletConstraint(IntPtr xx) { Ptr = xx; } public BulletConstraint(IntPtr xx) { Ptr = xx; }
public IntPtr Ptr; 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)] [StructLayout(LayoutKind.Sequential)]
public struct ConvexHull public struct ConvexHull
@ -230,6 +257,9 @@ public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
int maxCollisions, IntPtr collisionArray, int maxCollisions, IntPtr collisionArray,
int maxUpdates, IntPtr updateArray); int maxUpdates, IntPtr updateArray);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
@ -414,11 +444,22 @@ public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
// ===================================================================================== // =====================================================================================
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [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] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateTerrainBody2(uint id, public static extern IntPtr CreateTerrainBody2(uint id,
Vector3 minCoords, Vector3 maxCoords, float collisionMargin, 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); [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
// ===================================================================================== // =====================================================================================
@ -473,11 +514,16 @@ public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
// =====================================================================================
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [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] [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] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetPosition2(IntPtr obj); public static extern Vector3 GetPosition2(IntPtr obj);
@ -521,6 +567,9 @@ public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetFriction2(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] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetRestitution2(IntPtr obj, float val); public static extern bool SetRestitution2(IntPtr obj, float val);
@ -564,7 +613,7 @@ public static extern bool SetMargin2(IntPtr obj, float val);
public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj); public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [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] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpPhysicsStatistics2(IntPtr sim); public static extern void DumpPhysicsStatistics2(IntPtr sim);