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.cs493
1 files changed, 493 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
new file mode 100755
index 0000000..70aa429
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -0,0 +1,493 @@
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.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public class BSTerrainManager
44{
45 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
46
47 // These height values are fractional so the odd values will be
48 // noticable when debugging.
49 public const float HEIGHT_INITIALIZATION = 24.987f;
50 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
51 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
52
53 // If the min and max height are equal, we reduce the min by this
54 // amount to make sure that a bounding box is built for the terrain.
55 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
56
57 public const float TERRAIN_COLLISION_MARGIN = 0.0f;
58
59 // Until the whole simulator is changed to pass us the region size, we rely on constants.
60 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
61
62 // The scene that I am part of
63 private BSScene PhysicsScene { get; set; }
64
65 // The ground plane created to keep thing from falling to infinity.
66 private BulletBody m_groundPlane;
67
68 // If doing mega-regions, if we're region zero we will be managing multiple
69 // region terrains since region zero does the physics for the whole mega-region.
70 private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps;
71
72 // True of the terrain has been modified.
73 // Used to force recalculation of terrain height after terrain has been modified
74 private bool m_terrainModified;
75
76 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
77 // This is incremented before assigning to new region so it is the last ID allocated.
78 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
79 public uint HighestTerrainID { get {return m_terrainCount; } }
80
81 // If doing mega-regions, this holds our offset from region zero of
82 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
83 private Vector3 m_worldOffset;
84 // If the parent region (region 0), this is the extent of the combined regions
85 // relative to the origin of region zero
86 private Vector3 m_worldMax;
87 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
88
89 public BSTerrainManager(BSScene physicsScene)
90 {
91 PhysicsScene = physicsScene;
92 m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
93 m_terrainModified = false;
94
95 // Assume one region of default size
96 m_worldOffset = Vector3.Zero;
97 m_worldMax = new Vector3(DefaultRegionSize);
98 MegaRegionParentPhysicsScene = null;
99 }
100
101 // Create the initial instance of terrain and the underlying ground plane.
102 // The objects are allocated in the unmanaged space and the pointers are tracked
103 // by the managed code.
104 // The terrains and the groundPlane are not added to the list of PhysObjects.
105 // This is called from the initialization routine so we presume it is
106 // safe to call Bullet in real time. We hope no one is moving prims around yet.
107 public void CreateInitialGroundPlaneAndTerrain()
108 {
109 // The ground plane is here to catch things that are trying to drop to negative infinity
110 BulletShape groundPlaneShape = new BulletShape(
111 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN),
112 ShapeData.PhysicsShapeType.SHAPE_GROUNDPLANE);
113 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
114 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
115 Vector3.Zero, Quaternion.Identity));
116 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
117 // Everything collides with the ground plane.
118 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
119 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
120
121 Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE);
122 Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION);
123 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
124 float[] initialMap = new float[totalHeights];
125 for (int ii = 0; ii < totalHeights; ii++)
126 {
127 initialMap[ii] = HEIGHT_INITIALIZATION;
128 }
129 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords, true);
130 }
131
132 // Release all the terrain structures we might have allocated
133 public void ReleaseGroundPlaneAndTerrain()
134 {
135 if (m_groundPlane.ptr != IntPtr.Zero)
136 {
137 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
138 {
139 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
140 }
141 m_groundPlane.ptr = IntPtr.Zero;
142 }
143
144 ReleaseTerrain();
145 }
146
147 // Release all the terrain we have allocated
148 public void ReleaseTerrain()
149 {
150 foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps)
151 {
152 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr))
153 {
154 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr);
155 BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
156 }
157 }
158 m_heightMaps.Clear();
159 }
160
161 // The simulator wants to set a new heightmap for the terrain.
162 public void SetTerrain(float[] heightMap) {
163 float[] localHeightMap = heightMap;
164 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
165 {
166 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
167 {
168 // If a child of a mega-region, we shouldn't have any terrain allocated for us
169 ReleaseGroundPlaneAndTerrain();
170 // If doing the mega-prim stuff and we are the child of the zero region,
171 // the terrain is added to our parent
172 if (MegaRegionParentPhysicsScene is BSScene)
173 {
174 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
175 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
176 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID,
177 localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true);
178 }
179 }
180 else
181 {
182 // If not doing the mega-prim thing, just change the terrain
183 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
184
185 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap,
186 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
187 }
188 });
189 }
190
191 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain
192 // based on the passed information. The 'id' should be either the terrain id or
193 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
194 // The latter feature is for creating child terrains for mega-regions.
195 // If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0)
196 // then a new body and shape is created and the mapInfo is filled.
197 // This call is used for doing the initial terrain creation.
198 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
199 // terrain shape is created and added to the body.
200 // This call is most often used to update the heightMap and parameters of the terrain.
201 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
202 // calling this routine from initialization or taint-time routines) or whether to delay
203 // all the unmanaged activities to taint-time.
204 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool atTaintTime)
205 {
206 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},atTaintTime={3}",
207 BSScene.DetailLogZero, minCoords, maxCoords, atTaintTime);
208
209 float minZ = float.MaxValue;
210 float maxZ = float.MinValue;
211 Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y);
212
213 int heightMapSize = heightMap.Length;
214 for (int ii = 0; ii < heightMapSize; ii++)
215 {
216 float height = heightMap[ii];
217 if (height < minZ) minZ = height;
218 if (height > maxZ) maxZ = height;
219 }
220
221 // The shape of the terrain is from its base to its extents.
222 minCoords.Z = minZ;
223 maxCoords.Z = maxZ;
224
225 BulletHeightMapInfo mapInfo;
226 if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo))
227 {
228 // If this is terrain we know about, it's easy to update
229
230 mapInfo.heightMap = heightMap;
231 mapInfo.minCoords = minCoords;
232 mapInfo.maxCoords = maxCoords;
233 mapInfo.minZ = minZ;
234 mapInfo.maxZ = maxZ;
235 mapInfo.sizeX = maxCoords.X - minCoords.X;
236 mapInfo.sizeY = maxCoords.Y - minCoords.Y;
237 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
238 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
239
240 BSScene.TaintCallback rebuildOperation = delegate()
241 {
242 if (MegaRegionParentPhysicsScene != null)
243 {
244 // It's possible that Combine() was called after this code was queued.
245 // If we are a child of combined regions, we don't create any terrain for us.
246 DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
247
248 // Get rid of any terrain that may have been allocated for us.
249 ReleaseGroundPlaneAndTerrain();
250
251 // I hate doing this, but just bail
252 return;
253 }
254
255 if (mapInfo.terrainBody.ptr != IntPtr.Zero)
256 {
257 // Updating an existing terrain.
258 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
259 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
260
261 // Remove from the dynamics world because we're going to mangle this object
262 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
263
264 // Get rid of the old terrain
265 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
266 BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
267 mapInfo.Ptr = IntPtr.Zero;
268
269 /*
270 // NOTE: This routine is half here because I can't get the terrain shape replacement
271 // to work. In the short term, the above three lines completely delete the old
272 // terrain and the code below recreates one from scratch.
273 // Hopefully the Bullet community will help me out on this one.
274
275 // First, release the old collision shape (there is only one terrain)
276 BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr);
277
278 // Fill the existing height map info with the new location and size information
279 BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID,
280 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
281
282 // Create a terrain shape based on the new info
283 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
284
285 // Stuff the shape into the existing terrain body
286 BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr);
287 */
288 }
289 // else
290 {
291 // Creating a new terrain.
292 DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}",
293 BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
294
295 mapInfo.ID = id;
296 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
297 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
298
299 // The terrain object initial position is at the center of the object
300 Vector3 centerPos;
301 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
302 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
303 centerPos.Z = minZ + ((maxZ - minZ) / 2f);
304
305 // Create the terrain shape from the mapInfo
306 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
307 ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
308
309 mapInfo.terrainBody = new BulletBody(mapInfo.ID,
310 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
311 id, centerPos, Quaternion.Identity));
312 }
313
314 // Make sure the entry is in the heightmap table
315 m_heightMaps[terrainRegionBase] = mapInfo;
316
317 // Set current terrain attributes
318 BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
319 BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
320 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
321 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
322
323 BulletSimAPI.SetMassProps2(mapInfo.terrainBody.ptr, 0f, Vector3.Zero);
324 BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.ptr);
325
326 // Return the new terrain to the world of physical objects
327 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
328
329 // redo its bounding box now that it is in the world
330 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
331
332 BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr,
333 (uint)CollisionFilterGroups.TerrainFilter,
334 (uint)CollisionFilterGroups.TerrainMask);
335
336 // Make sure the new shape is processed.
337 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
338 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
339
340 m_terrainModified = true;
341 };
342
343 // There is the option to do the changes now (we're already in 'taint time'), or
344 // to do the Bullet operations later.
345 if (atTaintTime)
346 rebuildOperation();
347 else
348 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
349 }
350 else
351 {
352 // We don't know about this terrain so either we are creating a new terrain or
353 // our mega-prim child is giving us a new terrain to add to the phys world
354
355 // if this is a child terrain, calculate a unique terrain id
356 uint newTerrainID = id;
357 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
358 newTerrainID = ++m_terrainCount;
359
360 float[] heightMapX = heightMap;
361 Vector3 minCoordsX = minCoords;
362 Vector3 maxCoordsX = maxCoords;
363
364 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
365 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
366
367 // Code that must happen at taint-time
368 BSScene.TaintCallback createOperation = delegate()
369 {
370 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
371 // Create a new mapInfo that will be filled with the new info
372 mapInfo = new BulletHeightMapInfo(id, heightMapX,
373 BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID,
374 minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
375 // Put the unfilled heightmap info into the collection of same
376 m_heightMaps.Add(terrainRegionBase, mapInfo);
377 // Build the terrain
378 UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
379
380 m_terrainModified = true;
381 };
382
383 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
384 if (atTaintTime)
385 createOperation();
386 else
387 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
388 }
389 }
390
391 // Someday we will have complex terrain with caves and tunnels
392 public float GetTerrainHeightAtXYZ(Vector3 loc)
393 {
394 // For the moment, it's flat and convex
395 return GetTerrainHeightAtXY(loc.X, loc.Y);
396 }
397
398 // Given an X and Y, find the height of the terrain.
399 // Since we could be handling multiple terrains for a mega-region,
400 // the base of the region is calcuated assuming all regions are
401 // the same size and that is the default.
402 // Once the heightMapInfo is found, we have all the information to
403 // compute the offset into the array.
404 private float lastHeightTX = 999999f;
405 private float lastHeightTY = 999999f;
406 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
407 private float GetTerrainHeightAtXY(float tX, float tY)
408 {
409 // You'd be surprized at the number of times this routine is called
410 // with the same parameters as last time.
411 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
412 return lastHeight;
413
414 lastHeightTX = tX;
415 lastHeightTY = tY;
416 float ret = HEIGHT_GETHEIGHT_RET;
417
418 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
419 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
420 Vector2 terrainBaseXY = new Vector2(offsetX, offsetY);
421
422 BulletHeightMapInfo mapInfo;
423 if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo))
424 {
425 float regionX = tX - offsetX;
426 float regionY = tY - offsetY;
427 int mapIndex = (int)regionY * (int)mapInfo.sizeY + (int)regionX;
428 try
429 {
430 ret = mapInfo.heightMap[mapIndex];
431 }
432 catch
433 {
434 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
435 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}",
436 LogHeader, terrainBaseXY, regionX, regionY);
437 ret = HEIGHT_GETHEIGHT_RET;
438 }
439 // DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXY,bX={1},baseY={2},szX={3},szY={4},regX={5},regY={6},index={7},ht={8}",
440 // BSScene.DetailLogZero, offsetX, offsetY, mapInfo.sizeX, mapInfo.sizeY, regionX, regionY, mapIndex, ret);
441 }
442 else
443 {
444 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
445 LogHeader, PhysicsScene.RegionName, tX, tY);
446 }
447 m_terrainModified = false;
448 lastHeight = ret;
449 return ret;
450 }
451
452 // Although no one seems to check this, I do support combining.
453 public bool SupportsCombining()
454 {
455 return true;
456 }
457
458 // This routine is called two ways:
459 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
460 // extent of the combined regions. This is to inform the parent of the size
461 // of the combined regions.
462 // and one with 'offset' as the offset of the child region to the base region,
463 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
464 // child of its relative base and new parent.
465 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
466 {
467 m_worldOffset = offset;
468 m_worldMax = extents;
469 MegaRegionParentPhysicsScene = pScene;
470 if (pScene != null)
471 {
472 // We are a child.
473 // We want m_worldMax to be the highest coordinate of our piece of terrain.
474 m_worldMax = offset + DefaultRegionSize;
475 }
476 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
477 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
478 }
479
480 // Unhook all the combining that I know about.
481 public void UnCombine(PhysicsScene pScene)
482 {
483 // Just like ODE, for the moment a NOP
484 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
485 }
486
487
488 private void DetailLog(string msg, params Object[] args)
489 {
490 PhysicsScene.PhysicsLogging.Write(msg, args);
491 }
492}
493}