aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
diff options
context:
space:
mode:
authorRobert Adams2015-09-08 04:54:16 -0700
committerRobert Adams2015-09-08 04:54:16 -0700
commite5367d822be9b05e74c859afe2d2956a3e95aa33 (patch)
treee904050a30715df587aa527d7f313755177726a7 /OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
parentadd lost admin_reset_land method (diff)
parentDeleted access control spec from [LoginService] section of standalone config.... (diff)
downloadopensim-SC_OLD-e5367d822be9b05e74c859afe2d2956a3e95aa33.zip
opensim-SC_OLD-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.gz
opensim-SC_OLD-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.bz2
opensim-SC_OLD-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.xz
Merge of ubitworkvarnew with opensim/master as of 20150905.
This integrates the OpenSim refactoring to make physics, etc into modules. AVN physics hasn't been moved to new location. Does not compile yet. Merge branch 'osmaster' into mbworknew1
Diffstat (limited to 'OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs')
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs584
1 files changed, 584 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
new file mode 100755
index 0000000..d11baa6
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
@@ -0,0 +1,584 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.PhysicsModules.SharedBase;
34
35using Nini.Config;
36using log4net;
37
38using OpenMetaverse;
39
40namespace OpenSim.Region.PhysicsModule.BulletS
41{
42
43// The physical implementation of the terrain is wrapped in this class.
44public abstract class BSTerrainPhys : IDisposable
45{
46 public enum TerrainImplementation
47 {
48 Heightmap = 0,
49 Mesh = 1
50 }
51
52 protected BSScene m_physicsScene { get; private set; }
53 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
54 public Vector3 TerrainBase { get; private set; }
55 public uint ID { get; private set; }
56
57 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
58 {
59 m_physicsScene = physicsScene;
60 TerrainBase = regionBase;
61 ID = id;
62 }
63 public abstract void Dispose();
64 public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
65 public abstract float GetWaterLevelAtXYZ(Vector3 pos);
66}
67
68// ==========================================================================================
69public sealed class BSTerrainManager : IDisposable
70{
71 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
72
73 // These height values are fractional so the odd values will be
74 // noticable when debugging.
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;
79
80 // If the min and max height are equal, we reduce the min by this
81 // amount to make sure that a bounding box is built for the terrain.
82 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
83
84 // Until the whole simulator is changed to pass us the region size, we rely on constants.
85 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
86
87 // The scene that I am part of
88 private BSScene m_physicsScene { get; set; }
89
90 // The ground plane created to keep thing from falling to infinity.
91 private BulletBody m_groundPlane;
92
93 // If doing mega-regions, if we're region zero we will be managing multiple
94 // region terrains since region zero does the physics for the whole mega-region.
95 private Dictionary<Vector3, BSTerrainPhys> m_terrains;
96
97 // Flags used to know when to recalculate the height.
98 private bool m_terrainModified = false;
99
100 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
101 // This is incremented before assigning to new region so it is the last ID allocated.
102 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
103 public uint HighestTerrainID { get {return m_terrainCount; } }
104
105 // If doing mega-regions, this holds our offset from region zero of
106 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
107 private Vector3 m_worldOffset;
108 // If the parent region (region 0), this is the extent of the combined regions
109 // relative to the origin of region zero
110 private Vector3 m_worldMax;
111 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
112
113 public BSTerrainManager(BSScene physicsScene, Vector3 regionSize)
114 {
115 m_physicsScene = physicsScene;
116 DefaultRegionSize = regionSize;
117
118 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
119
120 // Assume one region of default size
121 m_worldOffset = Vector3.Zero;
122 m_worldMax = new Vector3(DefaultRegionSize);
123 MegaRegionParentPhysicsScene = null;
124 }
125
126 public void Dispose()
127 {
128 ReleaseGroundPlaneAndTerrain();
129 }
130
131 // Create the initial instance of terrain and the underlying ground plane.
132 // This is called from the initialization routine so we presume it is
133 // safe to call Bullet in real time. We hope no one is moving prims around yet.
134 public void CreateInitialGroundPlaneAndTerrain()
135 {
136 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
137 // The ground plane is here to catch things that are trying to drop to negative infinity
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);
142
143 // Everything collides with the ground plane.
144 m_groundPlane.collisionType = CollisionType.Groundplane;
145
146 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
147 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
148
149 // Ground plane does not move
150 m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
151
152 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
153 lock (m_terrains)
154 {
155 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
156 m_terrains.Add(Vector3.Zero, initialTerrain);
157 }
158 }
159
160 // Release all the terrain structures we might have allocated
161 public void ReleaseGroundPlaneAndTerrain()
162 {
163 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
164 if (m_groundPlane.HasPhysicalBody)
165 {
166 if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
167 {
168 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
169 }
170 m_groundPlane.Clear();
171 }
172
173 ReleaseTerrain();
174 }
175
176 // Release all the terrain we have allocated
177 public void ReleaseTerrain()
178 {
179 lock (m_terrains)
180 {
181 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
182 {
183 kvp.Value.Dispose();
184 }
185 m_terrains.Clear();
186 }
187 }
188
189 // The simulator wants to set a new heightmap for the terrain.
190 public void SetTerrain(float[] heightMap) {
191 float[] localHeightMap = heightMap;
192 // If there are multiple requests for changes to the same terrain between ticks,
193 // only do that last one.
194 m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
195 {
196 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
197 {
198 // If a child of a mega-region, we shouldn't have any terrain allocated for us
199 ReleaseGroundPlaneAndTerrain();
200 // If doing the mega-prim stuff and we are the child of the zero region,
201 // the terrain is added to our parent
202 if (MegaRegionParentPhysicsScene is BSScene)
203 {
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);
207 }
208 }
209 else
210 {
211 // If not doing the mega-prim thing, just change the terrain
212 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
213
214 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
215 }
216 });
217 }
218
219 // Another region is calling this region and passing a terrain.
220 // A region that is not the mega-region root will pass its terrain to the root region so the root region
221 // physics engine will have all the terrains.
222 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
223 {
224 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
225 m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
226 {
227 UpdateTerrain(id, heightMap, minCoords, maxCoords);
228 });
229 }
230
231 // If called for terrain has has not been previously allocated, a new terrain will be built
232 // based on the passed information. The 'id' should be either the terrain id or
233 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
234 // The latter feature is for creating child terrains for mega-regions.
235 // If there is an existing terrain body, a new
236 // terrain shape is created and added to the body.
237 // This call is most often used to update the heightMap and parameters of the terrain.
238 // (The above does suggest that some simplification/refactoring is in order.)
239 // Called during taint-time.
240 private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
241 {
242 // Find high and low points of passed heightmap.
243 // The min and max passed in is usually the area objects can be in (maximum
244 // object height, for instance). The terrain wants the bounding box for the
245 // terrain so replace passed min and max Z with the actual terrain min/max Z.
246 float minZ = float.MaxValue;
247 float maxZ = float.MinValue;
248 foreach (float height in heightMap)
249 {
250 if (height < minZ) minZ = height;
251 if (height > maxZ) maxZ = height;
252 }
253 if (minZ == maxZ)
254 {
255 // If min and max are the same, reduce min a little bit so a good bounding box is created.
256 minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE;
257 }
258 minCoords.Z = minZ;
259 maxCoords.Z = maxZ;
260
261 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}",
262 BSScene.DetailLogZero, id, minCoords, maxCoords);
263
264 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
265
266 lock (m_terrains)
267 {
268 BSTerrainPhys terrainPhys;
269 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
270 {
271 // There is already a terrain in this spot. Free the old and build the new.
272 DetailLog("{0},BSTerrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
273 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, maxCoords);
274
275 // Remove old terrain from the collection
276 m_terrains.Remove(terrainRegionBase);
277 // Release any physical memory it may be using.
278 terrainPhys.Dispose();
279
280 if (MegaRegionParentPhysicsScene == null)
281 {
282 // This terrain is not part of the mega-region scheme. Create vanilla terrain.
283 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
284 m_terrains.Add(terrainRegionBase, newTerrainPhys);
285
286 m_terrainModified = true;
287 }
288 else
289 {
290 // It's possible that Combine() was called after this code was queued.
291 // If we are a child of combined regions, we don't create any terrain for us.
292 DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
293
294 // Get rid of any terrain that may have been allocated for us.
295 ReleaseGroundPlaneAndTerrain();
296
297 // I hate doing this, but just bail
298 return;
299 }
300 }
301 else
302 {
303 // We don't know about this terrain so either we are creating a new terrain or
304 // our mega-prim child is giving us a new terrain to add to the phys world
305
306 // if this is a child terrain, calculate a unique terrain id
307 uint newTerrainID = id;
308 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
309 newTerrainID = ++m_terrainCount;
310
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);
315
316 m_terrainModified = true;
317 }
318 }
319 }
320
321 // TODO: redo terrain implementation selection to allow other base types than heightMap.
322 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
323 {
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)
329 {
330 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
331 newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id,
332 heightMap, minCoords, maxCoords);
333 break;
334 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
335 newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id,
336 heightMap, minCoords, maxCoords);
337 break;
338 default:
339 m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
340 LogHeader,
341 (int)BSParam.TerrainImplementation,
342 BSParam.TerrainImplementation,
343 m_physicsScene.RegionName, terrainRegionBase);
344 break;
345 }
346 return newTerrainPhys;
347 }
348
349 // Return 'true' of this position is somewhere in known physical terrain space
350 public bool IsWithinKnownTerrain(Vector3 pos)
351 {
352 Vector3 terrainBaseXYZ;
353 BSTerrainPhys physTerrain;
354 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
355 }
356
357 // Return a new position that is over known terrain if the position is outside our terrain.
358 public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
359 {
360 float edgeEpsilon = 0.1f;
361
362 Vector3 ret = pPos;
363
364 // First, base addresses are never negative so correct for that possible problem.
365 if (ret.X < 0f || ret.Y < 0f)
366 {
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}",
370 BSScene.DetailLogZero, pPos, ret);
371 }
372
373 // Can't do this function if we don't know about any terrain.
374 if (m_terrains.Count == 0)
375 return ret;
376
377 int loopPrevention = 10;
378 Vector3 terrainBaseXYZ;
379 BSTerrainPhys physTerrain;
380 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
381 {
382 // The passed position is not within a known terrain area.
383 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
384
385 // Must be off the top of a region. Find an adjacent region to move into.
386 // The returned terrain is always 'lower'. That is, closer to <0,0>.
387 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
388
389 if (adjacentTerrainBase.X < terrainBaseXYZ.X)
390 {
391 // moving down into a new region in the X dimension. New position will be the max in the new base.
392 ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon;
393 }
394 if (adjacentTerrainBase.Y < terrainBaseXYZ.Y)
395 {
396 // moving down into a new region in the X dimension. New position will be the max in the new base.
397 ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon;
398 }
399 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
400 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
401
402 if (loopPrevention-- < 0f)
403 {
404 // The 'while' is a little dangerous so this prevents looping forever if the
405 // mapping of the terrains ever gets messed up (like nothing at <0,0>) or
406 // the list of terrains is in transition.
407 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
408 break;
409 }
410 }
411
412 return ret;
413 }
414
415 // Given an X and Y, find the height of the terrain.
416 // Since we could be handling multiple terrains for a mega-region,
417 // the base of the region is calcuated assuming all regions are
418 // the same size and that is the default.
419 // Once the heightMapInfo is found, we have all the information to
420 // compute the offset into the array.
421 private float lastHeightTX = 999999f;
422 private float lastHeightTY = 999999f;
423 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
424 public float GetTerrainHeightAtXYZ(Vector3 pos)
425 {
426 float tX = pos.X;
427 float tY = pos.Y;
428 // You'd be surprized at the number of times this routine is called
429 // with the same parameters as last time.
430 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
431 return lastHeight;
432 m_terrainModified = false;
433
434 lastHeightTX = tX;
435 lastHeightTY = tY;
436 float ret = HEIGHT_GETHEIGHT_RET;
437
438 Vector3 terrainBaseXYZ;
439 BSTerrainPhys physTerrain;
440 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
441 {
442 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
443 }
444 else
445 {
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}",
449 BSScene.DetailLogZero, pos, terrainBaseXYZ);
450 }
451
452 lastHeight = ret;
453 return ret;
454 }
455
456 public float GetWaterLevelAtXYZ(Vector3 pos)
457 {
458 float ret = WATER_HEIGHT_GETHEIGHT_RET;
459
460 Vector3 terrainBaseXYZ;
461 BSTerrainPhys physTerrain;
462 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
463 {
464 ret = physTerrain.GetWaterLevelAtXYZ(pos);
465 }
466 else
467 {
468 m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
469 LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
470 }
471 return ret;
472 }
473
474 // Given an address, return 'true' of there is a description of that terrain and output
475 // the descriptor class and the 'base' fo the addresses therein.
476 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
477 {
478 bool ret = false;
479
480 Vector3 terrainBaseXYZ = Vector3.Zero;
481 if (pos.X < 0f || pos.Y < 0f)
482 {
483 // We don't handle negative addresses so just make up a base that will not be found.
484 terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
485 }
486 else
487 {
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);
491 }
492
493 BSTerrainPhys physTerrain = null;
494 lock (m_terrains)
495 {
496 ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
497 }
498 outTerrainBase = terrainBaseXYZ;
499 outPhysTerrain = physTerrain;
500 return ret;
501 }
502
503 // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
504 // this one. Usually used to return an out of bounds object to a known place.
505 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
506 {
507 Vector3 ret = pTerrainBase;
508
509 // Can't do this function if we don't know about any terrain.
510 if (m_terrains.Count == 0)
511 return ret;
512
513 // Just some sanity
514 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
515 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
516 ret.Z = 0f;
517
518 lock (m_terrains)
519 {
520 // Once down to the <0,0> region, we have to be done.
521 while (ret.X > 0f || ret.Y > 0f)
522 {
523 if (ret.X > 0f)
524 {
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))
528 break;
529 }
530 if (ret.Y > 0f)
531 {
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))
535 break;
536 }
537 }
538 }
539
540 return ret;
541 }
542
543 // Although no one seems to check this, I do support combining.
544 public bool SupportsCombining()
545 {
546 return true;
547 }
548
549 // This routine is called two ways:
550 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
551 // extent of the combined regions. This is to inform the parent of the size
552 // of the combined regions.
553 // and one with 'offset' as the offset of the child region to the base region,
554 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
555 // child of its relative base and new parent.
556 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
557 {
558 m_worldOffset = offset;
559 m_worldMax = extents;
560 MegaRegionParentPhysicsScene = pScene;
561 if (pScene != null)
562 {
563 // We are a child.
564 // We want m_worldMax to be the highest coordinate of our piece of terrain.
565 m_worldMax = offset + DefaultRegionSize;
566 }
567 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
568 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
569 }
570
571 // Unhook all the combining that I know about.
572 public void UnCombine(PhysicsScene pScene)
573 {
574 // Just like ODE, we don't do anything yet.
575 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
576 }
577
578
579 private void DetailLog(string msg, params Object[] args)
580 {
581 m_physicsScene.PhysicsLogging.Write(msg, args);
582 }
583}
584}