BulletSim: clean up some variable naming for consistancy.

Update DLL API for new terrain and shape/body pattern methods.
Terrain creation and modification uses new shape/body pattern.
Move debug logging callback set to initialization call so logging
   is per physics engine.
integration
Robert Adams 2012-08-29 09:20:09 -07:00
parent d3adf9b2b3
commit ae852bb873
4 changed files with 183 additions and 102 deletions

View File

@ -39,8 +39,7 @@ public class BSCharacter : BSPhysObject
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS CHAR]"; private static readonly string LogHeader = "[BULLETS CHAR]";
private BSScene _scene; public BSScene Scene { get; private set; }
public BSScene Scene { get { return _scene; } }
private String _avName; private String _avName;
// private bool _stopped; // private bool _stopped;
private Vector3 _size; private Vector3 _size;
@ -92,7 +91,7 @@ public class BSCharacter : BSPhysObject
{ {
_localID = localID; _localID = localID;
_avName = avName; _avName = avName;
_scene = parent_scene; Scene = parent_scene;
_position = pos; _position = pos;
_size = size; _size = size;
_flying = isFlying; _flying = isFlying;
@ -101,11 +100,11 @@ public class BSCharacter : BSPhysObject
_buoyancy = ComputeBuoyancyFromFlying(isFlying); _buoyancy = ComputeBuoyancyFromFlying(isFlying);
// The dimensions of the avatar capsule are kept in the scale. // The dimensions of the avatar capsule are kept in the scale.
// Physics creates a unit capsule which is scaled by the physics engine. // Physics creates a unit capsule which is scaled by the physics engine.
_scale = new Vector3(_scene.Params.avatarCapsuleRadius, _scene.Params.avatarCapsuleRadius, size.Z); _scale = new Vector3(Scene.Params.avatarCapsuleRadius, Scene.Params.avatarCapsuleRadius, size.Z);
_density = _scene.Params.avatarDensity; _density = Scene.Params.avatarDensity;
ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale
Linkset = new BSLinkset(_scene, this); Linkset = new BSLinkset(Scene, this);
ShapeData shapeData = new ShapeData(); ShapeData shapeData = new ShapeData();
shapeData.ID = _localID; shapeData.ID = _localID;
@ -117,19 +116,19 @@ public class BSCharacter : BSPhysObject
shapeData.Mass = _mass; shapeData.Mass = _mass;
shapeData.Buoyancy = _buoyancy; shapeData.Buoyancy = _buoyancy;
shapeData.Static = ShapeData.numericFalse; shapeData.Static = ShapeData.numericFalse;
shapeData.Friction = _scene.Params.avatarFriction; shapeData.Friction = Scene.Params.avatarFriction;
shapeData.Restitution = _scene.Params.avatarRestitution; shapeData.Restitution = Scene.Params.avatarRestitution;
// do actual create at taint time // do actual create at taint time
_scene.TaintedObject("BSCharacter.create", delegate() Scene.TaintedObject("BSCharacter.create", delegate()
{ {
DetailLog("{0},BSCharacter.create", _localID); DetailLog("{0},BSCharacter.create", _localID);
BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData); BulletSimAPI.CreateObject(Scene.WorldID, shapeData);
// Set the buoyancy for flying. This will be refactored when all the settings happen in C# // Set the buoyancy for flying. This will be refactored when all the settings happen in C#
BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy); BulletSimAPI.SetObjectBuoyancy(Scene.WorldID, LocalID, _buoyancy);
Body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); Body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(Scene.World.Ptr, LocalID));
// avatars get all collisions no matter what (makes walking on ground and such work) // avatars get all collisions no matter what (makes walking on ground and such work)
BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
}); });
@ -141,9 +140,9 @@ public class BSCharacter : BSPhysObject
public override void Destroy() public override void Destroy()
{ {
DetailLog("{0},BSCharacter.Destroy", LocalID); DetailLog("{0},BSCharacter.Destroy", LocalID);
_scene.TaintedObject("BSCharacter.destroy", delegate() Scene.TaintedObject("BSCharacter.destroy", delegate()
{ {
BulletSimAPI.DestroyObject(_scene.WorldID, _localID); BulletSimAPI.DestroyObject(Scene.WorldID, _localID);
}); });
} }
@ -172,9 +171,9 @@ public class BSCharacter : BSPhysObject
ComputeAvatarVolumeAndMass(); ComputeAvatarVolumeAndMass();
_scene.TaintedObject("BSCharacter.setSize", delegate() Scene.TaintedObject("BSCharacter.setSize", delegate()
{ {
BulletSimAPI.SetObjectScaleMass(_scene.WorldID, LocalID, _scale, _mass, true); BulletSimAPI.SetObjectScaleMass(Scene.WorldID, LocalID, _scale, _mass, true);
}); });
} }
@ -203,17 +202,17 @@ public class BSCharacter : BSPhysObject
public override Vector3 Position { public override Vector3 Position {
get { get {
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
return _position; return _position;
} }
set { set {
_position = value; _position = value;
PositionSanityCheck(); PositionSanityCheck();
_scene.TaintedObject("BSCharacter.setPosition", delegate() Scene.TaintedObject("BSCharacter.setPosition", delegate()
{ {
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation);
}); });
} }
} }
@ -230,9 +229,7 @@ public class BSCharacter : BSPhysObject
if (Position.Z < terrainHeight) if (Position.Z < terrainHeight)
{ {
DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
Vector3 newPos = _position; _position.Z = terrainHeight + 2.0f;
newPos.Z = terrainHeight + 2.0f;
_position = newPos;
ret = true; ret = true;
} }
@ -250,10 +247,10 @@ public class BSCharacter : BSPhysObject
{ {
// The new position value must be pushed into the physics engine but we can't // The new position value must be pushed into the physics engine but we can't
// just assign to "Position" because of potential call loops. // just assign to "Position" because of potential call loops.
_scene.TaintedObject("BSCharacter.PositionSanityCheck", delegate() Scene.TaintedObject("BSCharacter.PositionSanityCheck", delegate()
{ {
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation);
}); });
ret = true; ret = true;
} }
@ -301,10 +298,10 @@ public class BSCharacter : BSPhysObject
set { set {
_velocity = value; _velocity = value;
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
_scene.TaintedObject("BSCharacter.setVelocity", delegate() Scene.TaintedObject("BSCharacter.setVelocity", delegate()
{ {
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity); BulletSimAPI.SetObjectVelocity(Scene.WorldID, _localID, _velocity);
}); });
} }
} }
@ -327,10 +324,10 @@ public class BSCharacter : BSPhysObject
set { set {
_orientation = value; _orientation = value;
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
_scene.TaintedObject("BSCharacter.setOrientation", delegate() Scene.TaintedObject("BSCharacter.setOrientation", delegate()
{ {
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation);
}); });
} }
} }
@ -367,11 +364,11 @@ public class BSCharacter : BSPhysObject
set { _throttleUpdates = value; } set { _throttleUpdates = value; }
} }
public override bool IsColliding { public override bool IsColliding {
get { return (_collidingStep == _scene.SimulationStep); } get { return (_collidingStep == Scene.SimulationStep); }
set { _isColliding = value; } set { _isColliding = value; }
} }
public override bool CollidingGround { public override bool CollidingGround {
get { return (_collidingGroundStep == _scene.SimulationStep); } get { return (_collidingGroundStep == Scene.SimulationStep); }
set { _collidingGround = value; } set { _collidingGround = value; }
} }
public override bool CollidingObj { public override bool CollidingObj {
@ -393,10 +390,10 @@ public class BSCharacter : BSPhysObject
public override float Buoyancy { public override float Buoyancy {
get { return _buoyancy; } get { return _buoyancy; }
set { _buoyancy = value; set { _buoyancy = value;
_scene.TaintedObject("BSCharacter.setBuoyancy", delegate() Scene.TaintedObject("BSCharacter.setBuoyancy", delegate()
{ {
DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy); BulletSimAPI.SetObjectBuoyancy(Scene.WorldID, LocalID, _buoyancy);
}); });
} }
} }
@ -440,7 +437,7 @@ public class BSCharacter : BSPhysObject
_force.Y += force.Y; _force.Y += force.Y;
_force.Z += force.Z; _force.Z += force.Z;
// m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
_scene.TaintedObject("BSCharacter.AddForce", delegate() Scene.TaintedObject("BSCharacter.AddForce", delegate()
{ {
DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
BulletSimAPI.AddObjectForce2(Body.Ptr, _force); BulletSimAPI.AddObjectForce2(Body.Ptr, _force);
@ -524,10 +521,9 @@ public class BSCharacter : BSPhysObject
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds. // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
PositionSanityCheck2(); PositionSanityCheck2();
float heightHere = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); // just for debug float heightHere = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); // only for debug
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}", 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, _position, _orientation, _velocity, _acceleration, _rotationalVelocity, heightHere);
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
@ -539,16 +535,16 @@ public class BSCharacter : BSPhysObject
// m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith); // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
// The following makes IsColliding() and IsCollidingGround() work // The following makes IsColliding() and IsCollidingGround() work
_collidingStep = _scene.SimulationStep; _collidingStep = Scene.SimulationStep;
if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID) if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
{ {
_collidingGroundStep = _scene.SimulationStep; _collidingGroundStep = Scene.SimulationStep;
} }
// DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith); // DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith);
// throttle collisions to the rate specified in the subscription // throttle collisions to the rate specified in the subscription
if (_subscribedEventsMs != 0) { if (_subscribedEventsMs != 0) {
int nowTime = _scene.SimulationNowTime; int nowTime = Scene.SimulationNowTime;
if (nowTime >= _nextCollisionOkTime) { if (nowTime >= _nextCollisionOkTime) {
_nextCollisionOkTime = nowTime + _subscribedEventsMs; _nextCollisionOkTime = nowTime + _subscribedEventsMs;

View File

@ -232,15 +232,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
} }
// If Debug logging level, enable logging from the unmanaged code // If Debug logging level, enable logging from the unmanaged code
m_DebugLogCallbackHandle = null;
if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
{ {
m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
if (PhysicsLogging.Enabled) if (PhysicsLogging.Enabled)
// The handle is saved in a variable to make sure it doesn't get freed after this call
m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
else else
m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
// The handle is saved in a variable to make sure it doesn't get freed after this call
BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
} }
// Get the version of the DLL // Get the version of the DLL
@ -257,7 +257,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
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(),
m_DebugLogCallbackHandle);
// 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.
@ -265,8 +266,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
Constraints = new BSConstraintCollection(World); Constraints = new BSConstraintCollection(World);
// Note: choose one of the two following lines
// BulletSimAPI.CreateInitialGroundPlaneAndTerrain(WorldID);
TerrainManager = new BSTerrainManager(this); TerrainManager = new BSTerrainManager(this);
TerrainManager.CreateInitialGroundPlaneAndTerrain(); TerrainManager.CreateInitialGroundPlaneAndTerrain();
@ -378,7 +377,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
lock (PhysObjects) PhysObjects.Add(localID, actor); lock (PhysObjects) PhysObjects.Add(localID, actor);
// Remove kludge someday // TODO: Remove kludge someday.
// We must generate a collision for avatars whether they collide or not.
// This is required by OpenSim to update avatar animations, etc.
lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Add(actor); lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Add(actor);
return actor; return actor;

View File

@ -44,8 +44,22 @@ public class BSTerrainManager
{ {
static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
// These height values are fractional so the odd values will be
// noticable when debugging.
public const float HEIGHT_INITIALIZATION = 24.987f;
public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
public const float HEIGHT_GETHEIGHT_RET = 24.765f;
// If the min and max height are equal, we reduce the min by this
// amount to make sure that a bounding box is built for the terrain.
public const float HEIGHT_EQUAL_FUDGE = 0.2f;
public const float TERRAIN_COLLISION_MARGIN = 0.2f;
// The scene that I am part of
BSScene m_physicsScene; BSScene m_physicsScene;
// The ground plane created to keep thing from falling to infinity.
private BulletBody m_groundPlane; private BulletBody m_groundPlane;
// If doing mega-regions, if we're region zero we will be managing multiple // If doing mega-regions, if we're region zero we will be managing multiple
@ -53,6 +67,10 @@ public class BSTerrainManager
private Dictionary<Vector2, BulletBody> m_terrains; private Dictionary<Vector2, BulletBody> m_terrains;
private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps; private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps;
// True of the terrain has been modified.
// Used to force recalculation of terrain height after terrain has been modified
private bool m_terrainModified;
// If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. // 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. // This is incremented before assigning to new region so it is the last ID allocated.
private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1; private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
@ -69,6 +87,7 @@ public class BSTerrainManager
m_physicsScene = physicsScene; m_physicsScene = physicsScene;
m_terrains = new Dictionary<Vector2,BulletBody>(); m_terrains = new Dictionary<Vector2,BulletBody>();
m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>(); m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
m_terrainModified = false;
} }
// Create the initial instance of terrain and the underlying ground plane. // Create the initial instance of terrain and the underlying ground plane.
@ -80,17 +99,18 @@ public class BSTerrainManager
public void CreateInitialGroundPlaneAndTerrain() public void CreateInitialGroundPlaneAndTerrain()
{ {
// The ground plane is here to catch things that are trying to drop to negative infinity // The ground plane is here to catch things that are trying to drop to negative infinity
BulletShape groundPlaneShape = new BulletShape(BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN));
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
BulletSimAPI.CreateGroundPlaneBody2(BSScene.GROUNDPLANE_ID, 1f, 0.4f)); BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.Ptr, Vector3.Zero, Quaternion.Identity));
BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr); BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr);
Vector3 minTerrainCoords = new Vector3(0f, 0f, 24f); Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE);
Vector3 maxTerrainCoords = new Vector3(Constants.RegionSize, Constants.RegionSize, 25f); Vector3 maxTerrainCoords = new Vector3(Constants.RegionSize, Constants.RegionSize, HEIGHT_INITIALIZATION);
int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
float[] initialMap = new float[totalHeights]; float[] initialMap = new float[totalHeights];
for (int ii = 0; ii < totalHeights; ii++) for (int ii = 0; ii < totalHeights; ii++)
{ {
initialMap[ii] = 25f; initialMap[ii] = HEIGHT_INITIALIZATION;
} }
CreateNewTerrainSegment(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords); CreateNewTerrainSegment(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords);
} }
@ -108,7 +128,7 @@ public class BSTerrainManager
if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, kvp.Value.Ptr)) if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, kvp.Value.Ptr))
{ {
BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, kvp.Value.Ptr); BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, kvp.Value.Ptr);
BulletSimAPI.ReleaseHeightmapInfo2(m_heightMaps[kvp.Key].Ptr); BulletSimAPI.ReleaseHeightMapInfo2(m_heightMaps[kvp.Key].Ptr);
} }
} }
m_terrains.Clear(); m_terrains.Clear();
@ -128,30 +148,41 @@ public class BSTerrainManager
int hSize = heightMap.Length; int hSize = heightMap.Length;
for (int ii = 0; ii < hSize; ii++) for (int ii = 0; ii < hSize; ii++)
{ {
minZ = heightMap[ii] < minZ ? heightMap[ii] : minZ; float height = heightMap[ii];
maxZ = heightMap[ii] > maxZ ? heightMap[ii] : maxZ; if (height < minZ) minZ = height;
if (height > maxZ) maxZ = height;
} }
// If the terrain is flat, make a difference so we get a bounding box
if (minZ == maxZ)
minZ -= HEIGHT_EQUAL_FUDGE;
minCoords.Z = minZ; minCoords.Z = minZ;
maxCoords.Z = maxZ; 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); Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y);
// Create the heightmap data structure in the unmanaged space // Create the heightmap data structure in the unmanaged space
BulletHeightMapInfo mapInfo = new BulletHeightMapInfo( BulletHeightMapInfo mapInfo = new BulletHeightMapInfo(id, heightMap,
BulletSimAPI.CreateHeightmap2(minCoords, maxCoords, heightMap), heightMap); BulletSimAPI.CreateHeightMapInfo2(id, minCoords, maxCoords, heightMap, TERRAIN_COLLISION_MARGIN));
mapInfo.terrainRegionBase = terrainRegionBase; mapInfo.terrainRegionBase = terrainRegionBase;
mapInfo.maxRegionExtent = maxCoords; mapInfo.minCoords = minCoords;
mapInfo.maxCoords = maxCoords;
mapInfo.minZ = minZ; mapInfo.minZ = minZ;
mapInfo.maxZ = maxZ; mapInfo.maxZ = maxZ;
mapInfo.sizeX = maxCoords.X - minCoords.X; mapInfo.sizeX = maxCoords.X - minCoords.X;
mapInfo.sizeY = maxCoords.Y - minCoords.Y; mapInfo.sizeY = maxCoords.Y - minCoords.Y;
Vector3 centerPos;
centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
centerPos.Z = minZ + (maxZ - minZ) / 2f;
DetailLog("{0},BSScene.CreateNewTerrainSegment,call,minZ={1},maxZ={2},hMapPtr={3},minC={4},maxC={5}", DetailLog("{0},BSScene.CreateNewTerrainSegment,call,minZ={1},maxZ={2},hMapPtr={3},minC={4},maxC={5}",
BSScene.DetailLogZero, minZ, maxZ, mapInfo.Ptr, minCoords, maxCoords); BSScene.DetailLogZero, minZ, maxZ, mapInfo.Ptr, minCoords, maxCoords);
// Create the terrain body from that heightmap // Create the terrain shape from the mapInfo
BulletBody terrainBody = new BulletBody(id, BulletSimAPI.CreateTerrainBody2(id, mapInfo.Ptr, 0.01f)); BulletShape terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
BulletBody terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2(terrainShape.Ptr,
centerPos, Quaternion.Identity));
BulletSimAPI.SetFriction2(terrainBody.Ptr, m_physicsScene.Params.terrainFriction); BulletSimAPI.SetFriction2(terrainBody.Ptr, m_physicsScene.Params.terrainFriction);
BulletSimAPI.SetHitFraction2(terrainBody.Ptr, m_physicsScene.Params.terrainHitFraction); BulletSimAPI.SetHitFraction2(terrainBody.Ptr, m_physicsScene.Params.terrainHitFraction);
@ -163,11 +194,12 @@ public class BSTerrainManager
BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, terrainBody.Ptr); BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, terrainBody.Ptr);
BulletSimAPI.UpdateSingleAabb2(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, // Add the created terrain to the management set. If we are doing mega-regions,
// the terrains of our children will be added. // the terrains of our children will be added.
m_terrains.Add(terrainRegionBase, terrainBody); m_terrains.Add(terrainRegionBase, terrainBody);
m_heightMaps.Add(terrainRegionBase, mapInfo); m_heightMaps.Add(terrainRegionBase, mapInfo);
m_terrainModified = true;
} }
public void SetTerrain(float[] heightMap) { public void SetTerrain(float[] heightMap) {
@ -191,34 +223,57 @@ public class BSTerrainManager
{ {
float minZ = float.MaxValue; float minZ = float.MaxValue;
float maxZ = float.MinValue; float maxZ = float.MinValue;
Vector2 terrainRegionBase = new Vector2(tOffset.X, tOffset.Y);
// 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; int heightMapSize = heightMap.Length;
float[] localHeightMap = new float[heightMapSize];
for (int ii = 0; ii < heightMapSize; ii++) for (int ii = 0; ii < heightMapSize; ii++)
{ {
float height = heightMap[ii]; float height = heightMap[ii];
if (height < minZ) minZ = height; if (height < minZ) minZ = height;
if (height > maxZ) maxZ = height; if (height > maxZ) maxZ = height;
localHeightMap[ii] = height;
} }
Vector2 terrainRegionBase = new Vector2(tOffset.X, tOffset.Y); // The shape of the terrain is from its base to its extents.
Vector3 minCoords, maxCoords;
minCoords = tOffset;
minCoords.Z = minZ;
maxCoords = tOffset;
maxCoords.X += Constants.RegionSize;
maxCoords.Y += Constants.RegionSize;
maxCoords.Z = maxZ;
BulletBody terrainBody;
BulletHeightMapInfo mapInfo; BulletHeightMapInfo mapInfo;
if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo)) if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo))
{ {
terrainBody = m_terrains[terrainRegionBase];
// Copy heightMap local and compute some statistics.
for (int ii = 0; ii < heightMapSize; ii++)
{
mapInfo.heightMap[ii] = heightMap[ii];
}
// If this is terrain we know about, it's easy to update // If this is terrain we know about, it's easy to update
mapInfo.heightMap = localHeightMap;
m_physicsScene.TaintedObject("BSScene.SetTerrain:UpdateExisting", delegate() m_physicsScene.TaintedObject("BSScene.SetTerrain:UpdateExisting", delegate()
{ {
DetailLog("{0},SetTerrain:UpdateExisting,baseX={1},baseY={2},minZ={3},maxZ={4}", DetailLog("{0},SetTerrain:UpdateExisting,baseX={1},baseY={2},minZ={3},maxZ={4}",
BSScene.DetailLogZero, tOffset.X, tOffset.Y, minZ, maxZ); BSScene.DetailLogZero, tOffset.X, tOffset.Y, minZ, maxZ);
BulletSimAPI.UpdateHeightMap2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.heightMap); // Fill the existing height map info with the new location and size information
BulletSimAPI.FillHeightMapInfo2(mapInfo.Ptr, mapInfo.ID, minCoords, maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
// Create a terrain shape based on the new info
BulletShape terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
// Swap the shape in the terrain body (this also deletes the old shape)
bool success = BulletSimAPI.ReplaceBodyShape2(m_physicsScene.World.Ptr, terrainBody.Ptr, terrainShape.Ptr);
if (!success)
{
DetailLog("{0},SetTerrain:UpdateExisting,Failed", BSScene.DetailLogZero);
m_physicsScene.Logger.ErrorFormat("{0} Failed updating terrain heightmap. Region={1}",
LogHeader, m_physicsScene.RegionName);
}
}); });
} }
else else
@ -226,11 +281,6 @@ public class BSTerrainManager
// Our mega-prim child is giving us a new terrain to add to the phys world // Our mega-prim child is giving us a new terrain to add to the phys world
uint newTerrainID = ++m_terrainCount; 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() m_physicsScene.TaintedObject("BSScene.SetTerrain:NewTerrain", delegate()
{ {
DetailLog("{0},SetTerrain:NewTerrain,baseX={1},baseY={2}", BSScene.DetailLogZero, tOffset.X, tOffset.Y); DetailLog("{0},SetTerrain:NewTerrain,baseX={1},baseY={2}", BSScene.DetailLogZero, tOffset.X, tOffset.Y);
@ -240,9 +290,9 @@ public class BSTerrainManager
} }
// Someday we will have complex terrain with caves and tunnels // Someday we will have complex terrain with caves and tunnels
// For the moment, it's flat and convex
public float GetTerrainHeightAtXYZ(Vector3 loc) public float GetTerrainHeightAtXYZ(Vector3 loc)
{ {
// For the moment, it's flat and convex
return GetTerrainHeightAtXY(loc.X, loc.Y); return GetTerrainHeightAtXY(loc.X, loc.Y);
} }
@ -252,9 +302,19 @@ public class BSTerrainManager
// the same size and that is the default. // the same size and that is the default.
// Once the heightMapInfo is found, we have all the information to // Once the heightMapInfo is found, we have all the information to
// compute the offset into the array. // compute the offset into the array.
private float lastHeightTX = 999999f;
private float lastHeightTY = 999999f;
private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
public float GetTerrainHeightAtXY(float tX, float tY) public float GetTerrainHeightAtXY(float tX, float tY)
{ {
float ret = 30f; // You'd be surprized at the number of times this routine is called
// with the same parameters as last time.
if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
return lastHeight;
lastHeightTX = tX;
lastHeightTY = tY;
float ret = HEIGHT_GETHEIGHT_RET;
int offsetX = ((int)(tX / (int)Constants.RegionSize)) * (int)Constants.RegionSize; int offsetX = ((int)(tX / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
int offsetY = ((int)(tY / (int)Constants.RegionSize)) * (int)Constants.RegionSize; int offsetY = ((int)(tY / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
@ -265,15 +325,20 @@ public class BSTerrainManager
{ {
float regionX = tX - offsetX; float regionX = tX - offsetX;
float regionY = tY - offsetY; float regionY = tY - offsetY;
regionX = regionX > mapInfo.sizeX ? 0 : regionX; if (regionX > mapInfo.sizeX) regionX = 0;
regionY = regionY > mapInfo.sizeY ? 0 : regionY; if (regionY > mapInfo.sizeY) regionY = 0;
ret = mapInfo.heightMap[(int)(regionX * mapInfo.sizeX + regionY)]; int mapIndex = (int)regionY * (int)mapInfo.sizeY + (int)regionX;
ret = mapInfo.heightMap[mapIndex];
m_terrainModified = false;
DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXY,bX={1},baseY={2},szX={3},szY={4},regX={5},regY={6},index={7},ht={8}",
BSScene.DetailLogZero, offsetX, offsetY, mapInfo.sizeX, mapInfo.sizeY, regionX, regionY, mapIndex, ret);
} }
else else
{ {
m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: x={1}, y={2}", m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: x={1}, y={2}",
LogHeader, tX, tY); LogHeader, tX, tY);
} }
lastHeight = ret;
return ret; return ret;
} }

View File

@ -38,13 +38,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin {
// The physics engine controller class created at initialization // 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 worldId, BSScene bss, IntPtr xx) { worldID = worldId; scene = bss; Ptr = xx; }
public uint ID; public uint worldID;
// The scene is only in here so very low level routines have a handle to print debug/error messages // The scene is only in here so very low level routines have a handle to print debug/error messages
public BSScene scene; public BSScene scene;
public IntPtr Ptr; public IntPtr Ptr;
} }
public struct BulletShape
{
public BulletShape(IntPtr xx) { Ptr = xx; }
public IntPtr Ptr;
}
// An allocated Bullet btRigidBody // An allocated Bullet btRigidBody
public struct BulletBody public struct BulletBody
{ {
@ -66,18 +72,22 @@ public struct BulletConstraint
// than making copies. // than making copies.
public class BulletHeightMapInfo public class BulletHeightMapInfo
{ {
public BulletHeightMapInfo(IntPtr xx, float[] hm) { public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
ID = id;
Ptr = xx; Ptr = xx;
heightMap = hm; heightMap = hm;
terrainRegionBase = new Vector2(0f, 0f); terrainRegionBase = new Vector2(0f, 0f);
maxRegionExtent = new Vector3(100f, 100f, 25f); minCoords = new Vector3(100f, 100f, 25f);
maxCoords = new Vector3(101f, 101f, 26f);
minZ = maxZ = 0f; minZ = maxZ = 0f;
sizeX = sizeY = 256f; sizeX = sizeY = 256f;
} }
public uint ID;
public IntPtr Ptr; public IntPtr Ptr;
public float[] heightMap; public float[] heightMap;
public Vector2 terrainRegionBase; public Vector2 terrainRegionBase;
public Vector3 maxRegionExtent; public Vector3 minCoords;
public Vector3 maxCoords;
public float sizeX, sizeY; public float sizeX, sizeY;
public float minZ, maxZ; public float minZ, maxZ;
} }
@ -248,6 +258,10 @@ public enum ConstraintParamAxis : int
// =============================================================================== // ===============================================================================
static class BulletSimAPI { static class BulletSimAPI {
// Link back to the managed code for outputting log messages
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.LPStr)] [return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetVersion(); public static extern string GetVersion();
@ -255,7 +269,8 @@ public static extern string GetVersion();
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, 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,
DebugLogCallback logRoutine);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID); public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID);
@ -372,8 +387,6 @@ public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
public static extern void DumpBulletStatistics(); public static extern void DumpBulletStatistics();
// Log a debug message // Log a debug message
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetDebugLogCallback(DebugLogCallback callback); public static extern void SetDebugLogCallback(DebugLogCallback callback);
@ -407,7 +420,7 @@ public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetHeightmap2(IntPtr world, float[] heightmap); public static extern void SetHeightMap2(IntPtr world, float[] heightmap);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void Shutdown2(IntPtr sim); public static extern void Shutdown2(IntPtr sim);
@ -442,25 +455,31 @@ public static extern IntPtr BuildNativeShape2(IntPtr world,
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, Vector3 pos, Quaternion rot);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, Vector3 pos, Quaternion rot);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool ReplaceBodyShape2(IntPtr sim, IntPtr obj, IntPtr shape);
// ===================================================================================== // =====================================================================================
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateGroundPlaneBody2(uint id, float height, float collisionMargin); public static extern IntPtr CreateHeightMapInfo2(uint id, Vector3 minCoords, Vector3 maxCoords,
[MarshalAs(UnmanagedType.LPArray)] float[] heightMap, 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 FillHeightMapInfo2(IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords,
IntPtr heightMapInfo, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
float collisionMargin);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateHeightmap2(Vector3 minCoords, Vector3 maxCoords, public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo);
[MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool ReleaseHeightmapInfo2(IntPtr heightMapInfo); public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void UpdateHeightMap2(IntPtr world, IntPtr heightMapInfo, public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo);
[MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
// ===================================================================================== // =====================================================================================
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]