aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs212
1 files changed, 162 insertions, 50 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 2e9db39..c4807c4 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -50,14 +50,14 @@ public abstract class BSTerrainPhys : IDisposable
50 Mesh = 1 50 Mesh = 1
51 } 51 }
52 52
53 public BSScene PhysicsScene { get; private set; } 53 protected BSScene m_physicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this. 54 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; } 55 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; } 56 public uint ID { get; private set; }
57 57
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) 58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 { 59 {
60 PhysicsScene = physicsScene; 60 m_physicsScene = physicsScene;
61 TerrainBase = regionBase; 61 TerrainBase = regionBase;
62 ID = id; 62 ID = id;
63 } 63 }
@@ -86,7 +86,7 @@ public sealed class BSTerrainManager : IDisposable
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87 87
88 // The scene that I am part of 88 // The scene that I am part of
89 private BSScene PhysicsScene { get; set; } 89 private BSScene m_physicsScene { get; set; }
90 90
91 // The ground plane created to keep thing from falling to infinity. 91 // The ground plane created to keep thing from falling to infinity.
92 private BulletBody m_groundPlane; 92 private BulletBody m_groundPlane;
@@ -113,7 +113,7 @@ public sealed class BSTerrainManager : IDisposable
113 113
114 public BSTerrainManager(BSScene physicsScene) 114 public BSTerrainManager(BSScene physicsScene)
115 { 115 {
116 PhysicsScene = physicsScene; 116 m_physicsScene = physicsScene;
117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>(); 117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
118 118
119 // Assume one region of default size 119 // Assume one region of default size
@@ -132,32 +132,37 @@ public sealed class BSTerrainManager : IDisposable
132 // safe to call Bullet in real time. We hope no one is moving prims around yet. 132 // safe to call Bullet in real time. We hope no one is moving prims around yet.
133 public void CreateInitialGroundPlaneAndTerrain() 133 public void CreateInitialGroundPlaneAndTerrain()
134 { 134 {
135 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
135 // The ground plane is here to catch things that are trying to drop to negative infinity 136 // The ground plane is here to catch things that are trying to drop to negative infinity
136 BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); 137 BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
137 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, 138 m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
138 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); 139 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity);
139 140
140 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane); 141 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
141 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane); 142 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
142 // Ground plane does not move 143 // Ground plane does not move
143 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); 144 m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
144 // Everything collides with the ground plane. 145 // Everything collides with the ground plane.
145 m_groundPlane.collisionType = CollisionType.Groundplane; 146 m_groundPlane.collisionType = CollisionType.Groundplane;
146 m_groundPlane.ApplyCollisionMask(PhysicsScene); 147 m_groundPlane.ApplyCollisionMask(m_physicsScene);
147 148
148 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 150 lock (m_terrains)
150 m_terrains.Add(Vector3.Zero, initialTerrain); 151 {
152 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
153 m_terrains.Add(Vector3.Zero, initialTerrain);
154 }
151 } 155 }
152 156
153 // Release all the terrain structures we might have allocated 157 // Release all the terrain structures we might have allocated
154 public void ReleaseGroundPlaneAndTerrain() 158 public void ReleaseGroundPlaneAndTerrain()
155 { 159 {
160 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
156 if (m_groundPlane.HasPhysicalBody) 161 if (m_groundPlane.HasPhysicalBody)
157 { 162 {
158 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) 163 if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
159 { 164 {
160 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); 165 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
161 } 166 }
162 m_groundPlane.Clear(); 167 m_groundPlane.Clear();
163 } 168 }
@@ -183,7 +188,7 @@ public sealed class BSTerrainManager : IDisposable
183 float[] localHeightMap = heightMap; 188 float[] localHeightMap = heightMap;
184 // If there are multiple requests for changes to the same terrain between ticks, 189 // If there are multiple requests for changes to the same terrain between ticks,
185 // only do that last one. 190 // only do that last one.
186 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() 191 m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
187 { 192 {
188 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 193 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
189 { 194 {
@@ -193,11 +198,9 @@ public sealed class BSTerrainManager : IDisposable
193 // the terrain is added to our parent 198 // the terrain is added to our parent
194 if (MegaRegionParentPhysicsScene is BSScene) 199 if (MegaRegionParentPhysicsScene is BSScene)
195 { 200 {
196 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", 201 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
197 BSScene.DetailLogZero, m_worldOffset, m_worldMax); 202 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain(
198 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( 203 BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
199 BSScene.CHILDTERRAIN_ID, localHeightMap,
200 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
201 } 204 }
202 } 205 }
203 else 206 else
@@ -205,26 +208,36 @@ public sealed class BSTerrainManager : IDisposable
205 // If not doing the mega-prim thing, just change the terrain 208 // If not doing the mega-prim thing, just change the terrain
206 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); 209 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
207 210
208 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, 211 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
209 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
210 } 212 }
211 }); 213 });
212 } 214 }
213 215
214 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain 216 // Another region is calling this region and passing a terrain.
217 // A region that is not the mega-region root will pass its terrain to the root region so the root region
218 // physics engine will have all the terrains.
219 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
220 {
221 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
222 m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
223 {
224 UpdateTerrain(id, heightMap, minCoords, maxCoords);
225 });
226 }
227
228 // If called for terrain has has not been previously allocated, a new terrain will be built
215 // based on the passed information. The 'id' should be either the terrain id or 229 // based on the passed information. The 'id' should be either the terrain id or
216 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. 230 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
217 // The latter feature is for creating child terrains for mega-regions. 231 // The latter feature is for creating child terrains for mega-regions.
218 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new 232 // If there is an existing terrain body, a new
219 // terrain shape is created and added to the body. 233 // terrain shape is created and added to the body.
220 // This call is most often used to update the heightMap and parameters of the terrain. 234 // This call is most often used to update the heightMap and parameters of the terrain.
221 // (The above does suggest that some simplification/refactoring is in order.) 235 // (The above does suggest that some simplification/refactoring is in order.)
222 // Called during taint-time. 236 // Called during taint-time.
223 private void UpdateTerrain(uint id, float[] heightMap, 237 private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
224 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
225 { 238 {
226 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", 239 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}",
227 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); 240 BSScene.DetailLogZero, id, minCoords, maxCoords);
228 241
229 // Find high and low points of passed heightmap. 242 // Find high and low points of passed heightmap.
230 // The min and max passed in is usually the area objects can be in (maximum 243 // The min and max passed in is usually the area objects can be in (maximum
@@ -253,7 +266,7 @@ public sealed class BSTerrainManager : IDisposable
253 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) 266 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
254 { 267 {
255 // There is already a terrain in this spot. Free the old and build the new. 268 // There is already a terrain in this spot. Free the old and build the new.
256 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", 269 DetailLog("{0},BSTErrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
257 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); 270 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
258 271
259 // Remove old terrain from the collection 272 // Remove old terrain from the collection
@@ -263,6 +276,7 @@ public sealed class BSTerrainManager : IDisposable
263 276
264 if (MegaRegionParentPhysicsScene == null) 277 if (MegaRegionParentPhysicsScene == null)
265 { 278 {
279 // This terrain is not part of the mega-region scheme. Create vanilla terrain.
266 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 280 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
267 m_terrains.Add(terrainRegionBase, newTerrainPhys); 281 m_terrains.Add(terrainRegionBase, newTerrainPhys);
268 282
@@ -291,8 +305,8 @@ public sealed class BSTerrainManager : IDisposable
291 if (newTerrainID >= BSScene.CHILDTERRAIN_ID) 305 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
292 newTerrainID = ++m_terrainCount; 306 newTerrainID = ++m_terrainCount;
293 307
294 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", 308 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
295 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 309 BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords);
296 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 310 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
297 m_terrains.Add(terrainRegionBase, newTerrainPhys); 311 m_terrains.Add(terrainRegionBase, newTerrainPhys);
298 312
@@ -304,26 +318,26 @@ public sealed class BSTerrainManager : IDisposable
304 // TODO: redo terrain implementation selection to allow other base types than heightMap. 318 // TODO: redo terrain implementation selection to allow other base types than heightMap.
305 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) 319 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
306 { 320 {
307 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", 321 m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
308 LogHeader, PhysicsScene.RegionName, terrainRegionBase, 322 LogHeader, m_physicsScene.RegionName, terrainRegionBase,
309 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); 323 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
310 BSTerrainPhys newTerrainPhys = null; 324 BSTerrainPhys newTerrainPhys = null;
311 switch ((int)BSParam.TerrainImplementation) 325 switch ((int)BSParam.TerrainImplementation)
312 { 326 {
313 case (int)BSTerrainPhys.TerrainImplementation.Heightmap: 327 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
314 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, 328 newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id,
315 heightMap, minCoords, maxCoords); 329 heightMap, minCoords, maxCoords);
316 break; 330 break;
317 case (int)BSTerrainPhys.TerrainImplementation.Mesh: 331 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
318 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, 332 newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id,
319 heightMap, minCoords, maxCoords); 333 heightMap, minCoords, maxCoords);
320 break; 334 break;
321 default: 335 default:
322 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", 336 m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
323 LogHeader, 337 LogHeader,
324 (int)BSParam.TerrainImplementation, 338 (int)BSParam.TerrainImplementation,
325 BSParam.TerrainImplementation, 339 BSParam.TerrainImplementation,
326 PhysicsScene.RegionName, terrainRegionBase); 340 m_physicsScene.RegionName, terrainRegionBase);
327 break; 341 break;
328 } 342 }
329 return newTerrainPhys; 343 return newTerrainPhys;
@@ -337,6 +351,53 @@ public sealed class BSTerrainManager : IDisposable
337 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); 351 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
338 } 352 }
339 353
354 // Return a new position that is over known terrain if the position is outside our terrain.
355 public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
356 {
357 Vector3 ret = pPos;
358
359 // First, base addresses are never negative so correct for that possible problem.
360 if (ret.X < 0f || ret.Y < 0f)
361 {
362 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
363 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
364 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
365 BSScene.DetailLogZero, pPos, ret);
366 }
367
368 // Can't do this function if we don't know about any terrain.
369 if (m_terrains.Count == 0)
370 return ret;
371
372 int loopPrevention = 10;
373 Vector3 terrainBaseXYZ;
374 BSTerrainPhys physTerrain;
375 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
376 {
377 // The passed position is not within a known terrain area.
378 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
379
380 // Must be off the top of a region. Find an adjacent region to move into.
381 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
382
383 ret.X = Math.Min(ret.X, adjacentTerrainBase.X + (ret.X % DefaultRegionSize.X));
384 ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + (ret.X % DefaultRegionSize.Y));
385 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
386 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
387
388 if (loopPrevention-- < 0f)
389 {
390 // The 'while' is a little dangerous so this prevents looping forever if the
391 // mapping of the terrains ever gets messed up (like nothing at <0,0>) or
392 // the list of terrains is in transition.
393 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
394 break;
395 }
396 }
397
398 return ret;
399 }
400
340 // Given an X and Y, find the height of the terrain. 401 // Given an X and Y, find the height of the terrain.
341 // Since we could be handling multiple terrains for a mega-region, 402 // Since we could be handling multiple terrains for a mega-region,
342 // the base of the region is calcuated assuming all regions are 403 // the base of the region is calcuated assuming all regions are
@@ -368,8 +429,8 @@ public sealed class BSTerrainManager : IDisposable
368 } 429 }
369 else 430 else
370 { 431 {
371 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 432 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
372 LogHeader, PhysicsScene.RegionName, tX, tY); 433 LogHeader, m_physicsScene.RegionName, tX, tY);
373 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", 434 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
374 BSScene.DetailLogZero, pos, terrainBaseXYZ); 435 BSScene.DetailLogZero, pos, terrainBaseXYZ);
375 } 436 }
@@ -390,8 +451,8 @@ public sealed class BSTerrainManager : IDisposable
390 } 451 }
391 else 452 else
392 { 453 {
393 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", 454 m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
394 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); 455 LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
395 } 456 }
396 return ret; 457 return ret;
397 } 458 }
@@ -400,18 +461,69 @@ public sealed class BSTerrainManager : IDisposable
400 // the descriptor class and the 'base' fo the addresses therein. 461 // the descriptor class and the 'base' fo the addresses therein.
401 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) 462 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
402 { 463 {
403 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 464 bool ret = false;
404 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; 465
405 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); 466 Vector3 terrainBaseXYZ = Vector3.Zero;
467 if (pos.X < 0f || pos.Y < 0f)
468 {
469 // We don't handle negative addresses so just make up a base that will not be found.
470 terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
471 }
472 else
473 {
474 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
475 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
476 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
477 }
406 478
407 BSTerrainPhys physTerrain = null; 479 BSTerrainPhys physTerrain = null;
408 lock (m_terrains) 480 lock (m_terrains)
409 { 481 {
410 m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); 482 ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
411 } 483 }
412 outTerrainBase = terrainBaseXYZ; 484 outTerrainBase = terrainBaseXYZ;
413 outPhysTerrain = physTerrain; 485 outPhysTerrain = physTerrain;
414 return (physTerrain != null); 486 return ret;
487 }
488
489 // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
490 // this one. Usually used to return an out of bounds object to a known place.
491 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
492 {
493 Vector3 ret = pTerrainBase;
494
495 // Can't do this function if we don't know about any terrain.
496 if (m_terrains.Count == 0)
497 return ret;
498
499 // Just some sanity
500 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
501 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
502 ret.Z = 0f;
503
504 lock (m_terrains)
505 {
506 // Once down to the <0,0> region, we have to be done.
507 while (ret.X > 0f || ret.Y > 0f)
508 {
509 if (ret.X > 0f)
510 {
511 ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
512 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
513 if (m_terrains.ContainsKey(ret))
514 break;
515 }
516 if (ret.Y > 0f)
517 {
518 ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
519 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
520 if (m_terrains.ContainsKey(ret))
521 break;
522 }
523 }
524 }
525
526 return ret;
415 } 527 }
416 528
417 // Although no one seems to check this, I do support combining. 529 // Although no one seems to check this, I do support combining.
@@ -452,7 +564,7 @@ public sealed class BSTerrainManager : IDisposable
452 564
453 private void DetailLog(string msg, params Object[] args) 565 private void DetailLog(string msg, params Object[] args)
454 { 566 {
455 PhysicsScene.PhysicsLogging.Write(msg, args); 567 m_physicsScene.PhysicsLogging.Write(msg, args);
456 } 568 }
457} 569}
458} 570}