28 using System.Collections.Generic;
31 using OpenSim.Framework;
32 using OpenSim.Region.Framework;
33 using OpenSim.Region.PhysicsModules.SharedBase;
40 namespace OpenSim.
Region.PhysicsModule.BulletS
52 protected BSScene m_physicsScene {
get;
private set; }
54 public Vector3 TerrainBase {
get;
private set; }
55 public uint ID {
get;
private set; }
59 m_physicsScene = physicsScene;
60 TerrainBase = regionBase;
63 public abstract void Dispose();
64 public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
65 public abstract float GetWaterLevelAtXYZ(Vector3 pos);
71 static string LogHeader =
"[BULLETSIM TERRAIN MANAGER]";
75 public const float HEIGHT_INITIALIZATION = 24.987f;
76 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
77 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
78 public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
82 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
88 private BSScene m_physicsScene {
get; set; }
95 private Dictionary<Vector3, BSTerrainPhys> m_terrains;
98 private bool m_terrainModified =
false;
102 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
103 public uint HighestTerrainID {
get {
return m_terrainCount; } }
107 private Vector3 m_worldOffset;
110 private Vector3 m_worldMax;
111 private PhysicsScene MegaRegionParentPhysicsScene {
get; set; }
115 m_physicsScene = physicsScene;
116 DefaultRegionSize = regionSize;
118 m_terrains =
new Dictionary<Vector3,BSTerrainPhys>();
121 m_worldOffset = Vector3.Zero;
122 m_worldMax =
new Vector3(DefaultRegionSize);
123 MegaRegionParentPhysicsScene = null;
128 ReleaseGroundPlaneAndTerrain();
136 DetailLog(
"{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}",
BSScene.
DetailLogZero, m_physicsScene.RegionName);
138 BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
139 Vector3 groundPlaneAltitude =
new Vector3(0f, 0f, BSParam.TerrainGroundPlane);
140 m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
141 BSScene.GROUNDPLANE_ID, groundPlaneAltitude, Quaternion.Identity);
144 m_groundPlane.collisionType = CollisionType.Groundplane;
146 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
147 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
150 m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
156 m_terrains.Add(Vector3.Zero, initialTerrain);
163 DetailLog(
"{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}",
BSScene.
DetailLogZero, m_physicsScene.RegionName);
164 if (m_groundPlane.HasPhysicalBody)
166 if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
168 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
170 m_groundPlane.Clear();
181 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp
in m_terrains)
191 float[] localHeightMap = heightMap;
194 m_physicsScene.PostTaintObject(
"TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
196 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
199 ReleaseGroundPlaneAndTerrain();
202 if (MegaRegionParentPhysicsScene is
BSScene)
204 DetailLog(
"{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
205 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain(
206 BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
214 UpdateTerrain(
BSScene.
TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
222 private void AddMegaRegionChildTerrain(uint
id,
float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
225 m_physicsScene.PostTaintObject(
"TerrainManager.AddMegaRegionChild" + minCoords.ToString(),
id, delegate()
227 UpdateTerrain(
id, heightMap, minCoords, maxCoords);
240 private void UpdateTerrain(uint
id,
float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
246 float minZ = float.MaxValue;
247 float maxZ = float.MinValue;
248 foreach (
float height
in heightMap)
250 if (height < minZ) minZ = height;
251 if (height > maxZ) maxZ = height;
256 minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE;
261 DetailLog(
"{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}",
262 BSScene.DetailLogZero,
id, minCoords, maxCoords);
264 Vector3 terrainRegionBase =
new Vector3(minCoords.X, minCoords.Y, 0f);
268 BSTerrainPhys terrainPhys;
269 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
272 DetailLog(
"{0},BSTerrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
273 BSScene.DetailLogZero,
id, terrainRegionBase, minCoords, maxCoords);
276 m_terrains.Remove(terrainRegionBase);
278 terrainPhys.Dispose();
280 if (MegaRegionParentPhysicsScene == null)
283 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase,
id, heightMap, minCoords, maxCoords);
284 m_terrains.Add(terrainRegionBase, newTerrainPhys);
286 m_terrainModified =
true;
292 DetailLog(
"{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
295 ReleaseGroundPlaneAndTerrain();
307 uint newTerrainID = id;
308 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
309 newTerrainID = ++m_terrainCount;
311 DetailLog(
"{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
312 BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords);
313 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase,
id, heightMap, minCoords, maxCoords);
314 m_terrains.Add(terrainRegionBase, newTerrainPhys);
316 m_terrainModified =
true;
322 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint
id,
float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
324 m_physicsScene.Logger.DebugFormat(
"{0} Terrain for {1}/{2} created with {3}",
325 LogHeader, m_physicsScene.RegionName, terrainRegionBase,
326 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
327 BSTerrainPhys newTerrainPhys = null;
328 switch ((
int)BSParam.TerrainImplementation)
330 case (
int)BSTerrainPhys.TerrainImplementation.Heightmap:
331 newTerrainPhys =
new BSTerrainHeightmap(m_physicsScene, terrainRegionBase,
id,
332 heightMap, minCoords, maxCoords);
334 case (
int)BSTerrainPhys.TerrainImplementation.Mesh:
335 newTerrainPhys =
new BSTerrainMesh(m_physicsScene, terrainRegionBase,
id,
336 heightMap, minCoords, maxCoords);
339 m_physicsScene.Logger.ErrorFormat(
"{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
341 (int)BSParam.TerrainImplementation,
342 BSParam.TerrainImplementation,
343 m_physicsScene.RegionName, terrainRegionBase);
346 return newTerrainPhys;
352 Vector3 terrainBaseXYZ;
354 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
360 float edgeEpsilon = 0.1f;
365 if (ret.X < 0f || ret.Y < 0f)
367 ret.X = Util.Clamp<
float>(ret.X, 0f, 1000000f);
368 ret.Y = Util.Clamp<
float>(ret.Y, 0f, 1000000f);
369 DetailLog(
"{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
374 if (m_terrains.Count == 0)
377 int loopPrevention = 10;
378 Vector3 terrainBaseXYZ;
380 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
387 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
389 if (adjacentTerrainBase.X < terrainBaseXYZ.X)
392 ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon;
394 if (adjacentTerrainBase.Y < terrainBaseXYZ.Y)
397 ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon;
399 DetailLog(
"{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
402 if (loopPrevention-- < 0f)
407 DetailLog(
"{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop",
BSScene.
DetailLogZero);
421 private float lastHeightTX = 999999f;
422 private float lastHeightTY = 999999f;
423 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
430 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
432 m_terrainModified =
false;
436 float ret = HEIGHT_GETHEIGHT_RET;
438 Vector3 terrainBaseXYZ;
440 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
442 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
446 m_physicsScene.Logger.ErrorFormat(
"{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
447 LogHeader, m_physicsScene.RegionName, tX, tY);
448 DetailLog(
"{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
458 float ret = WATER_HEIGHT_GETHEIGHT_RET;
460 Vector3 terrainBaseXYZ;
462 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
464 ret = physTerrain.GetWaterLevelAtXYZ(pos);
468 m_physicsScene.Logger.ErrorFormat(
"{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
469 LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
476 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out
BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
480 Vector3 terrainBaseXYZ = Vector3.Zero;
481 if (pos.X < 0f || pos.Y < 0f)
484 terrainBaseXYZ =
new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
488 int offsetX = ((int)(pos.X / (
int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
489 int offsetY = ((
int)(pos.Y / (int)DefaultRegionSize.Y)) * (
int)DefaultRegionSize.Y;
490 terrainBaseXYZ =
new Vector3(offsetX, offsetY, 0f);
493 BSTerrainPhys physTerrain = null;
496 ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
498 outTerrainBase = terrainBaseXYZ;
499 outPhysTerrain = physTerrain;
505 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
507 Vector3 ret = pTerrainBase;
510 if (m_terrains.Count == 0)
514 ret.X = Util.Clamp<
float>(ret.X, 0f, 1000000f);
515 ret.Y = Util.Clamp<
float>(ret.Y, 0f, 1000000f);
521 while (ret.X > 0f || ret.Y > 0f)
525 ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
526 DetailLog(
"{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
527 if (m_terrains.ContainsKey(ret))
532 ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
533 DetailLog(
"{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
534 if (m_terrains.ContainsKey(ret))
558 m_worldOffset = offset;
559 m_worldMax = extents;
560 MegaRegionParentPhysicsScene = pScene;
565 m_worldMax = offset + DefaultRegionSize;
567 DetailLog(
"{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
579 private void DetailLog(
string msg, params Object[] args)
581 m_physicsScene.PhysicsLogging.Write(msg, args);
void SetTerrain(float[] heightMap)
Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
bool IsWithinKnownTerrain(Vector3 pos)
float GetTerrainHeightAtXYZ(Vector3 pos)
void UnCombine(PhysicsScene pScene)
BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
BSTerrainManager(BSScene physicsScene, Vector3 regionSize)
void CreateInitialGroundPlaneAndTerrain()
const string DetailLogZero
float GetWaterLevelAtXYZ(Vector3 pos)
void ReleaseGroundPlaneAndTerrain()