diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index e76d8a45ac..fa21233f6a 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -39,8 +39,7 @@ public class BSCharacter : BSPhysObject private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly string LogHeader = "[BULLETS CHAR]"; - private BSScene _scene; - public BSScene Scene { get { return _scene; } } + public BSScene Scene { get; private set; } private String _avName; // private bool _stopped; private Vector3 _size; @@ -92,7 +91,7 @@ public class BSCharacter : BSPhysObject { _localID = localID; _avName = avName; - _scene = parent_scene; + Scene = parent_scene; _position = pos; _size = size; _flying = isFlying; @@ -101,11 +100,11 @@ public class BSCharacter : BSPhysObject _buoyancy = ComputeBuoyancyFromFlying(isFlying); // The dimensions of the avatar capsule are kept in the scale. // Physics creates a unit capsule which is scaled by the physics engine. - _scale = new Vector3(_scene.Params.avatarCapsuleRadius, _scene.Params.avatarCapsuleRadius, size.Z); - _density = _scene.Params.avatarDensity; + _scale = new Vector3(Scene.Params.avatarCapsuleRadius, Scene.Params.avatarCapsuleRadius, size.Z); + _density = Scene.Params.avatarDensity; 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.ID = _localID; @@ -117,19 +116,19 @@ public class BSCharacter : BSPhysObject shapeData.Mass = _mass; shapeData.Buoyancy = _buoyancy; shapeData.Static = ShapeData.numericFalse; - shapeData.Friction = _scene.Params.avatarFriction; - shapeData.Restitution = _scene.Params.avatarRestitution; + shapeData.Friction = Scene.Params.avatarFriction; + shapeData.Restitution = Scene.Params.avatarRestitution; // do actual create at taint time - _scene.TaintedObject("BSCharacter.create", delegate() + Scene.TaintedObject("BSCharacter.create", delegate() { 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# - 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) BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); }); @@ -141,9 +140,9 @@ public class BSCharacter : BSPhysObject public override void Destroy() { 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(); - _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 { get { - // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); + // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID); return _position; } set { _position = value; PositionSanityCheck(); - _scene.TaintedObject("BSCharacter.setPosition", delegate() + Scene.TaintedObject("BSCharacter.setPosition", delegate() { 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); }); } } @@ -229,10 +228,8 @@ public class BSCharacter : BSPhysObject float terrainHeight = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); if (Position.Z < terrainHeight) { - DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); - Vector3 newPos = _position; - newPos.Z = terrainHeight + 2.0f; - _position = newPos; + DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); + _position.Z = terrainHeight + 2.0f; 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 // 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); - BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); + BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation); }); ret = true; } @@ -301,10 +298,10 @@ public class BSCharacter : BSPhysObject set { _velocity = value; // 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); - BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity); + BulletSimAPI.SetObjectVelocity(Scene.WorldID, _localID, _velocity); }); } } @@ -327,10 +324,10 @@ public class BSCharacter : BSPhysObject set { _orientation = value; // 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); - BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); + // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID); + BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation); }); } } @@ -367,11 +364,11 @@ public class BSCharacter : BSPhysObject set { _throttleUpdates = value; } } public override bool IsColliding { - get { return (_collidingStep == _scene.SimulationStep); } + get { return (_collidingStep == Scene.SimulationStep); } set { _isColliding = value; } } public override bool CollidingGround { - get { return (_collidingGroundStep == _scene.SimulationStep); } + get { return (_collidingGroundStep == Scene.SimulationStep); } set { _collidingGround = value; } } public override bool CollidingObj { @@ -393,10 +390,10 @@ public class BSCharacter : BSPhysObject public override float Buoyancy { get { return _buoyancy; } set { _buoyancy = value; - _scene.TaintedObject("BSCharacter.setBuoyancy", delegate() + Scene.TaintedObject("BSCharacter.setBuoyancy", delegate() { 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.Z += force.Z; // 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); 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. 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}", - LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, - entprop.Acceleration, entprop.RotationalVelocity, heightHere); + LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity, heightHere); } // 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); // The following makes IsColliding() and IsCollidingGround() work - _collidingStep = _scene.SimulationStep; + _collidingStep = Scene.SimulationStep; if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID) { - _collidingGroundStep = _scene.SimulationStep; + _collidingGroundStep = Scene.SimulationStep; } // DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith); // throttle collisions to the rate specified in the subscription if (_subscribedEventsMs != 0) { - int nowTime = _scene.SimulationNowTime; + int nowTime = Scene.SimulationNowTime; if (nowTime >= _nextCollisionOkTime) { _nextCollisionOkTime = nowTime + _subscribedEventsMs; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 7b4802ed4a..2f55ba42ba 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -232,15 +232,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters } // If Debug logging level, enable logging from the unmanaged code + m_DebugLogCallbackHandle = null; if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) { m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 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); else 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 @@ -257,7 +257,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.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 // 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); - // Note: choose one of the two following lines - // BulletSimAPI.CreateInitialGroundPlaneAndTerrain(WorldID); TerrainManager = new BSTerrainManager(this); TerrainManager.CreateInitialGroundPlaneAndTerrain(); @@ -378,7 +377,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 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); return actor; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 28c1940164..733d9c260d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs @@ -44,8 +44,22 @@ public class BSTerrainManager { 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; + // The ground plane created to keep thing from falling to infinity. private BulletBody m_groundPlane; // If doing mega-regions, if we're region zero we will be managing multiple @@ -53,6 +67,10 @@ public class BSTerrainManager private Dictionary m_terrains; private Dictionary 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. // This is incremented before assigning to new region so it is the last ID allocated. private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1; @@ -69,6 +87,7 @@ public class BSTerrainManager m_physicsScene = physicsScene; m_terrains = new Dictionary(); m_heightMaps = new Dictionary(); + m_terrainModified = false; } // Create the initial instance of terrain and the underlying ground plane. @@ -80,17 +99,18 @@ public class BSTerrainManager public void CreateInitialGroundPlaneAndTerrain() { // 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, - 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); - Vector3 minTerrainCoords = new Vector3(0f, 0f, 24f); - Vector3 maxTerrainCoords = new Vector3(Constants.RegionSize, Constants.RegionSize, 25f); + Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE); + Vector3 maxTerrainCoords = new Vector3(Constants.RegionSize, Constants.RegionSize, HEIGHT_INITIALIZATION); int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; float[] initialMap = new float[totalHeights]; for (int ii = 0; ii < totalHeights; ii++) { - initialMap[ii] = 25f; + initialMap[ii] = HEIGHT_INITIALIZATION; } CreateNewTerrainSegment(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords); } @@ -108,7 +128,7 @@ public class BSTerrainManager 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); + BulletSimAPI.ReleaseHeightMapInfo2(m_heightMaps[kvp.Key].Ptr); } } m_terrains.Clear(); @@ -128,30 +148,41 @@ public class BSTerrainManager 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; + float height = heightMap[ii]; + 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; 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); + BulletHeightMapInfo mapInfo = new BulletHeightMapInfo(id, heightMap, + BulletSimAPI.CreateHeightMapInfo2(id, minCoords, maxCoords, heightMap, TERRAIN_COLLISION_MARGIN)); mapInfo.terrainRegionBase = terrainRegionBase; - mapInfo.maxRegionExtent = maxCoords; + mapInfo.minCoords = minCoords; + mapInfo.maxCoords = maxCoords; mapInfo.minZ = minZ; mapInfo.maxZ = maxZ; mapInfo.sizeX = maxCoords.X - minCoords.X; 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}", 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)); + // Create the terrain shape from the mapInfo + 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.SetHitFraction2(terrainBody.Ptr, m_physicsScene.Params.terrainHitFraction); @@ -163,11 +194,12 @@ public class BSTerrainManager 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); + + m_terrainModified = true; } public void SetTerrain(float[] heightMap) { @@ -191,34 +223,57 @@ public class BSTerrainManager { float minZ = float.MaxValue; 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; - 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); + // 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; 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 - 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); + // 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 @@ -226,11 +281,6 @@ public class BSTerrainManager // 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); @@ -240,9 +290,9 @@ public class BSTerrainManager } // Someday we will have complex terrain with caves and tunnels - // For the moment, it's flat and convex public float GetTerrainHeightAtXYZ(Vector3 loc) { + // For the moment, it's flat and convex return GetTerrainHeightAtXY(loc.X, loc.Y); } @@ -252,9 +302,19 @@ public class BSTerrainManager // 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. + private float lastHeightTX = 999999f; + private float lastHeightTY = 999999f; + private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; 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 offsetY = ((int)(tY / (int)Constants.RegionSize)) * (int)Constants.RegionSize; @@ -265,15 +325,20 @@ public class BSTerrainManager { 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)]; + if (regionX > mapInfo.sizeX) regionX = 0; + if (regionY > mapInfo.sizeY) regionY = 0; + 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 { m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: x={1}, y={2}", LogHeader, tX, tY); } + lastHeight = ret; return ret; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index 3b319fbffe..804d2eacc8 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs @@ -38,13 +38,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin { // The physics engine controller class created at initialization public struct BulletSim { - public BulletSim(uint id, BSScene bss, IntPtr xx) { ID = id; scene = bss; Ptr = xx; } - public uint ID; + public BulletSim(uint worldId, BSScene bss, IntPtr xx) { worldID = worldId; scene = bss; Ptr = xx; } + public uint worldID; // The scene is only in here so very low level routines have a handle to print debug/error messages public BSScene scene; public IntPtr Ptr; } +public struct BulletShape +{ + public BulletShape(IntPtr xx) { Ptr = xx; } + public IntPtr Ptr; +} + // An allocated Bullet btRigidBody public struct BulletBody { @@ -66,18 +72,22 @@ public struct BulletConstraint // than making copies. public class BulletHeightMapInfo { - public BulletHeightMapInfo(IntPtr xx, float[] hm) { + public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) { + ID = id; Ptr = xx; heightMap = hm; 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; sizeX = sizeY = 256f; } + public uint ID; public IntPtr Ptr; public float[] heightMap; public Vector2 terrainRegionBase; - public Vector3 maxRegionExtent; + public Vector3 minCoords; + public Vector3 maxCoords; public float sizeX, sizeY; public float minZ, maxZ; } @@ -248,6 +258,10 @@ public enum ConstraintParamAxis : int // =============================================================================== 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] [return: MarshalAs(UnmanagedType.LPStr)] public static extern string GetVersion(); @@ -255,7 +269,8 @@ public static extern string GetVersion(); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, int maxCollisions, IntPtr collisionArray, - int maxUpdates, IntPtr updateArray); + int maxUpdates, IntPtr updateArray, + DebugLogCallback logRoutine); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 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(); // Log a debug message -[UnmanagedFunctionPointer(CallingConvention.Cdecl)] -public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 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); [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] public static extern void Shutdown2(IntPtr sim); @@ -442,25 +455,31 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 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] -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] -public static extern IntPtr CreateTerrainBody2(uint id, - IntPtr heightMapInfo, - float collisionMargin); +public static extern IntPtr FillHeightMapInfo2(IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords, + [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateHeightmap2(Vector3 minCoords, Vector3 maxCoords, - [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); +public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo); [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] -public static extern void UpdateHeightMap2(IntPtr world, IntPtr heightMapInfo, - [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); +public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo); // ===================================================================================== [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]