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.cs356
1 files changed, 224 insertions, 132 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 733d9c2..ab45f8f 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -54,17 +54,19 @@ public class BSTerrainManager
54 // amount to make sure that a bounding box is built for the terrain. 54 // amount to make sure that a bounding box is built for the terrain.
55 public const float HEIGHT_EQUAL_FUDGE = 0.2f; 55 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
56 56
57 public const float TERRAIN_COLLISION_MARGIN = 0.2f; 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, 0f);
58 61
59 // The scene that I am part of 62 // The scene that I am part of
60 BSScene m_physicsScene; 63 private BSScene m_physicsScene;
61 64
62 // The ground plane created to keep thing from falling to infinity. 65 // The ground plane created to keep thing from falling to infinity.
63 private BulletBody m_groundPlane; 66 private BulletBody m_groundPlane;
64 67
65 // If doing mega-regions, if we're region zero we will be managing multiple 68 // If doing mega-regions, if we're region zero we will be managing multiple
66 // region terrains since region zero does the physics for the whole mega-region. 69 // region terrains since region zero does the physics for the whole mega-region.
67 private Dictionary<Vector2, BulletBody> m_terrains;
68 private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps; 70 private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps;
69 71
70 // True of the terrain has been modified. 72 // True of the terrain has been modified.
@@ -78,16 +80,22 @@ public class BSTerrainManager
78 80
79 // If doing mega-regions, this holds our offset from region zero of 81 // If doing mega-regions, this holds our offset from region zero of
80 // the mega-regions. "parentScene" points to the PhysicsScene of region zero. 82 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
81 private Vector3 m_worldOffset = Vector3.Zero; 83 private Vector3 m_worldOffset;
82 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); 84 // If the parent region (region 0), this is the extent of the combined regions
83 private PhysicsScene m_parentScene = null; 85 // relative to the origin of region zero
86 private Vector3 m_worldMax;
87 private PhysicsScene m_parentScene;
84 88
85 public BSTerrainManager(BSScene physicsScene) 89 public BSTerrainManager(BSScene physicsScene)
86 { 90 {
87 m_physicsScene = physicsScene; 91 m_physicsScene = physicsScene;
88 m_terrains = new Dictionary<Vector2,BulletBody>();
89 m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>(); 92 m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
90 m_terrainModified = false; 93 m_terrainModified = false;
94
95 // Assume one region of default size
96 m_worldOffset = Vector3.Zero;
97 m_worldMax = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, 4096f);
98 m_parentScene = null;
91 } 99 }
92 100
93 // Create the initial instance of terrain and the underlying ground plane. 101 // Create the initial instance of terrain and the underlying ground plane.
@@ -95,7 +103,7 @@ public class BSTerrainManager
95 // by the managed code. 103 // by the managed code.
96 // The terrains and the groundPlane are not added to the list of PhysObjects. 104 // The terrains and the groundPlane are not added to the list of PhysObjects.
97 // This is called from the initialization routine so we presume it is 105 // This is called from the initialization routine so we presume it is
98 // safe to call Bullet in real time. We hope no one is moving around prim yet. 106 // safe to call Bullet in real time. We hope no one is moving prims around yet.
99 public void CreateInitialGroundPlaneAndTerrain() 107 public void CreateInitialGroundPlaneAndTerrain()
100 { 108 {
101 // The ground plane is here to catch things that are trying to drop to negative infinity 109 // The ground plane is here to catch things that are trying to drop to negative infinity
@@ -105,125 +113,91 @@ public class BSTerrainManager
105 BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr); 113 BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr);
106 114
107 Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE); 115 Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE);
108 Vector3 maxTerrainCoords = new Vector3(Constants.RegionSize, Constants.RegionSize, HEIGHT_INITIALIZATION); 116 Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION);
109 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; 117 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
110 float[] initialMap = new float[totalHeights]; 118 float[] initialMap = new float[totalHeights];
111 for (int ii = 0; ii < totalHeights; ii++) 119 for (int ii = 0; ii < totalHeights; ii++)
112 { 120 {
113 initialMap[ii] = HEIGHT_INITIALIZATION; 121 initialMap[ii] = HEIGHT_INITIALIZATION;
114 } 122 }
115 CreateNewTerrainSegment(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords); 123 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords, true);
116 } 124 }
117 125
126 // Release all the terrain structures we might have allocated
118 public void ReleaseGroundPlaneAndTerrain() 127 public void ReleaseGroundPlaneAndTerrain()
119 { 128 {
120 if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr)) 129 if (m_groundPlane.Ptr != IntPtr.Zero)
121 { 130 {
122 BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, m_groundPlane.Ptr); 131 if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr))
123 }
124 m_groundPlane.Ptr = IntPtr.Zero;
125
126 foreach (KeyValuePair<Vector2, BulletBody> kvp in m_terrains)
127 {
128 if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, kvp.Value.Ptr))
129 { 132 {
130 BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, kvp.Value.Ptr); 133 BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, m_groundPlane.Ptr);
131 BulletSimAPI.ReleaseHeightMapInfo2(m_heightMaps[kvp.Key].Ptr);
132 } 134 }
135 m_groundPlane.Ptr = IntPtr.Zero;
133 } 136 }
134 m_terrains.Clear(); 137
135 m_heightMaps.Clear(); 138 ReleaseTerrain();
136 } 139 }
137 140
138 // Create a new terrain description. This is used for mega-regions where 141 // Release all the terrain we have allocated
139 // the children of region zero give region zero all of the terrain 142 public void ReleaseTerrain()
140 // segments since region zero does all the physics for the mega-region.
141 // Call at taint time!!
142 public void CreateNewTerrainSegment(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
143 { 143 {
144 // The Z coordinates are recalculated to be the min and max height of the terrain 144 foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps)
145 // itself. The caller may have passed us the real region extent.
146 float minZ = float.MaxValue;
147 float maxZ = float.MinValue;
148 int hSize = heightMap.Length;
149 for (int ii = 0; ii < hSize; ii++)
150 { 145 {
151 float height = heightMap[ii]; 146 if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, kvp.Value.terrainBody.Ptr))
152 if (height < minZ) minZ = height; 147 {
153 if (height > maxZ) maxZ = height; 148 BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, kvp.Value.terrainBody.Ptr);
149 BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
150 }
154 } 151 }
155 // If the terrain is flat, make a difference so we get a bounding box 152 m_heightMaps.Clear();
156 if (minZ == maxZ)
157 minZ -= HEIGHT_EQUAL_FUDGE;
158
159 minCoords.Z = minZ;
160 maxCoords.Z = maxZ;
161 Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y);
162
163 // Create the heightmap data structure in the unmanaged space
164 BulletHeightMapInfo mapInfo = new BulletHeightMapInfo(id, heightMap,
165 BulletSimAPI.CreateHeightMapInfo2(id, minCoords, maxCoords, heightMap, TERRAIN_COLLISION_MARGIN));
166 mapInfo.terrainRegionBase = terrainRegionBase;
167 mapInfo.minCoords = minCoords;
168 mapInfo.maxCoords = maxCoords;
169 mapInfo.minZ = minZ;
170 mapInfo.maxZ = maxZ;
171 mapInfo.sizeX = maxCoords.X - minCoords.X;
172 mapInfo.sizeY = maxCoords.Y - minCoords.Y;
173
174 Vector3 centerPos;
175 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
176 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
177 centerPos.Z = minZ + (maxZ - minZ) / 2f;
178
179 DetailLog("{0},BSScene.CreateNewTerrainSegment,call,minZ={1},maxZ={2},hMapPtr={3},minC={4},maxC={5}",
180 BSScene.DetailLogZero, minZ, maxZ, mapInfo.Ptr, minCoords, maxCoords);
181 // Create the terrain shape from the mapInfo
182 BulletShape terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
183
184 BulletBody terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2(terrainShape.Ptr,
185 centerPos, Quaternion.Identity));
186
187 BulletSimAPI.SetFriction2(terrainBody.Ptr, m_physicsScene.Params.terrainFriction);
188 BulletSimAPI.SetHitFraction2(terrainBody.Ptr, m_physicsScene.Params.terrainHitFraction);
189 BulletSimAPI.SetRestitution2(terrainBody.Ptr, m_physicsScene.Params.terrainRestitution);
190 BulletSimAPI.SetCollisionFlags2(terrainBody.Ptr, CollisionFlags.CF_STATIC_OBJECT);
191 BulletSimAPI.Activate2(terrainBody.Ptr, true);
192
193 // Add the new terrain to the dynamics world
194 BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, terrainBody.Ptr);
195 BulletSimAPI.UpdateSingleAabb2(m_physicsScene.World.Ptr, terrainBody.Ptr);
196
197 // Add the created terrain to the management set. If we are doing mega-regions,
198 // the terrains of our children will be added.
199 m_terrains.Add(terrainRegionBase, terrainBody);
200 m_heightMaps.Add(terrainRegionBase, mapInfo);
201
202 m_terrainModified = true;
203 } 153 }
204 154
155 // The simulator wants to set a new heightmap for the terrain.
205 public void SetTerrain(float[] heightMap) { 156 public void SetTerrain(float[] heightMap) {
206 if (m_worldOffset != Vector3.Zero && m_parentScene != null) 157 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
207 { 158 {
159 // If a child of a mega-region, we shouldn't have any terrain allocated for us
160 ReleaseGroundPlaneAndTerrain();
208 // If doing the mega-prim stuff and we are the child of the zero region, 161 // If doing the mega-prim stuff and we are the child of the zero region,
209 // the terrain is really added to our parent 162 // the terrain is added to our parent
210 if (m_parentScene is BSScene) 163 if (m_parentScene is BSScene)
211 { 164 {
212 ((BSScene)m_parentScene).TerrainManager.SetTerrain(heightMap, m_worldOffset); 165 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
166 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
167 ((BSScene)m_parentScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID,
168 heightMap, m_worldOffset, m_worldOffset+DefaultRegionSize, false);
213 } 169 }
214 } 170 }
215 else 171 else
216 { 172 {
217 // if not doing the mega-prim thing, just change the terrain 173 // If not doing the mega-prim thing, just change the terrain
218 SetTerrain(heightMap, m_worldOffset); 174 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
175
176 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, heightMap, m_worldOffset, m_worldOffset+DefaultRegionSize, false);
219 } 177 }
220 } 178 }
221 179
222 private void SetTerrain(float[] heightMap, Vector3 tOffset) 180 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain
181 // based on the passed information. The 'id' should be either the terrain id or
182 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
183 // The latter feature is for creating child terrains for mega-regions.
184 // If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0)
185 // then a new body and shape is created and the mapInfo is filled.
186 // This call is used for doing the initial terrain creation.
187 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
188 // terrain shape is created and added to the body.
189 // This call is most often used to update the heightMap and parameters of the terrain.
190 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
191 // calling this routine from initialization or taint-time routines) or whether to delay
192 // all the unmanaged activities to taint-time.
193 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool doNow)
223 { 194 {
195 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},doNow={3}",
196 BSScene.DetailLogZero, minCoords, maxCoords, doNow);
197
224 float minZ = float.MaxValue; 198 float minZ = float.MaxValue;
225 float maxZ = float.MinValue; 199 float maxZ = float.MinValue;
226 Vector2 terrainRegionBase = new Vector2(tOffset.X, tOffset.Y); 200 Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y);
227 201
228 int heightMapSize = heightMap.Length; 202 int heightMapSize = heightMap.Length;
229 for (int ii = 0; ii < heightMapSize; ii++) 203 for (int ii = 0; ii < heightMapSize; ii++)
@@ -234,58 +208,162 @@ public class BSTerrainManager
234 } 208 }
235 209
236 // The shape of the terrain is from its base to its extents. 210 // The shape of the terrain is from its base to its extents.
237 Vector3 minCoords, maxCoords;
238 minCoords = tOffset;
239 minCoords.Z = minZ; 211 minCoords.Z = minZ;
240 maxCoords = tOffset;
241 maxCoords.X += Constants.RegionSize;
242 maxCoords.Y += Constants.RegionSize;
243 maxCoords.Z = maxZ; 212 maxCoords.Z = maxZ;
244 213
245 BulletBody terrainBody;
246 BulletHeightMapInfo mapInfo; 214 BulletHeightMapInfo mapInfo;
247 if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo)) 215 if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo))
248 { 216 {
249 terrainBody = m_terrains[terrainRegionBase];
250 // Copy heightMap local and compute some statistics.
251 for (int ii = 0; ii < heightMapSize; ii++)
252 {
253 mapInfo.heightMap[ii] = heightMap[ii];
254 }
255
256 // If this is terrain we know about, it's easy to update 217 // If this is terrain we know about, it's easy to update
257 m_physicsScene.TaintedObject("BSScene.SetTerrain:UpdateExisting", delegate() 218
219 mapInfo.heightMap = heightMap;
220 mapInfo.minCoords = minCoords;
221 mapInfo.maxCoords = maxCoords;
222 mapInfo.minZ = minZ;
223 mapInfo.maxZ = maxZ;
224 mapInfo.sizeX = maxCoords.X - minCoords.X;
225 mapInfo.sizeY = maxCoords.Y - minCoords.Y;
226 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
227 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
228
229 BSScene.TaintCallback rebuildOperation = delegate()
258 { 230 {
259 DetailLog("{0},SetTerrain:UpdateExisting,baseX={1},baseY={2},minZ={3},maxZ={4}", 231 if (m_parentScene != null)
260 BSScene.DetailLogZero, tOffset.X, tOffset.Y, minZ, maxZ); 232 {
261 // Fill the existing height map info with the new location and size information 233 // It's possible that Combine() was called after this code was queued.
262 BulletSimAPI.FillHeightMapInfo2(mapInfo.Ptr, mapInfo.ID, minCoords, maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN); 234 // If we are a child of combined regions, we don't create any terrain for us.
235 DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
263 236
264 // Create a terrain shape based on the new info 237 // Get rid of any terrain that may have been allocated for us.
265 BulletShape terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr)); 238 ReleaseGroundPlaneAndTerrain();
266 239
267 // Swap the shape in the terrain body (this also deletes the old shape) 240 // I hate doing this, but just bail
268 bool success = BulletSimAPI.ReplaceBodyShape2(m_physicsScene.World.Ptr, terrainBody.Ptr, terrainShape.Ptr); 241 return;
242 }
269 243
270 if (!success) 244 if (mapInfo.terrainBody.Ptr != IntPtr.Zero)
271 { 245 {
272 DetailLog("{0},SetTerrain:UpdateExisting,Failed", BSScene.DetailLogZero); 246 // Updating an existing terrain.
273 m_physicsScene.Logger.ErrorFormat("{0} Failed updating terrain heightmap. Region={1}", 247 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
274 LogHeader, m_physicsScene.RegionName); 248 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
275 249
250 // Remove from the dynamics world because we're going to mangle this object
251 BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr);
252
253 // Get rid of the old terrain
254 BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr);
255 BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
256 mapInfo.Ptr = IntPtr.Zero;
257
258 /*
259 // NOTE: This routine is half here because I can't get the terrain shape replacement
260 // to work. In the short term, the above three lines completely delete the old
261 // terrain and the code below recreates one from scratch.
262 // Hopefully the Bullet community will help me out on this one.
263
264 // First, release the old collision shape (there is only one terrain)
265 BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr);
266
267 // Fill the existing height map info with the new location and size information
268 BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID,
269 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
270
271 // Create a terrain shape based on the new info
272 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
273
274 // Stuff the shape into the existing terrain body
275 BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr);
276 */
276 } 277 }
277 }); 278 // else
279 {
280 // Creating a new terrain.
281 DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}",
282 BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
283
284 mapInfo.ID = id;
285 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.ID,
286 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
287
288 // The terrain object initial position is at the center of the object
289 Vector3 centerPos;
290 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
291 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
292 centerPos.Z = minZ + ((maxZ - minZ) / 2f);
293
294 // Create the terrain shape from the mapInfo
295 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
296
297 mapInfo.terrainBody = new BulletBody(mapInfo.ID,
298 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.Ptr,
299 centerPos, Quaternion.Identity));
300 }
301
302 // Make sure the entry is in the heightmap table
303 m_heightMaps[terrainRegionBase] = mapInfo;
304
305 // Set current terrain attributes
306 BulletSimAPI.SetFriction2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainFriction);
307 BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainHitFraction);
308 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainRestitution);
309 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.Ptr, CollisionFlags.CF_STATIC_OBJECT);
310
311 BulletSimAPI.SetMassProps2(mapInfo.terrainBody.Ptr, 0f, Vector3.Zero);
312 BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.Ptr);
313
314 // Return the new terrain to the world of physical objects
315 BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr);
316
317 // redo its bounding box now that it is in the world
318 BulletSimAPI.UpdateSingleAabb2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr);
319
320 // Make sure the new shape is processed.
321 BulletSimAPI.Activate2(mapInfo.terrainBody.Ptr, true);
322 };
323
324 // There is the option to do the changes now (we're already in 'taint time'), or
325 // to do the Bullet operations later.
326 if (doNow)
327 rebuildOperation();
328 else
329 m_physicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
278 } 330 }
279 else 331 else
280 { 332 {
281 // Our mega-prim child is giving us a new terrain to add to the phys world 333 // We don't know about this terrain so either we are creating a new terrain or
282 uint newTerrainID = ++m_terrainCount; 334 // our mega-prim child is giving us a new terrain to add to the phys world
283 335
284 m_physicsScene.TaintedObject("BSScene.SetTerrain:NewTerrain", delegate() 336 // if this is a child terrain, calculate a unique terrain id
337 uint newTerrainID = id;
338 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
339 newTerrainID = ++m_terrainCount;
340
341 float[] heightMapX = heightMap;
342 Vector3 minCoordsX = minCoords;
343 Vector3 maxCoordsX = maxCoords;
344
345 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
346 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
347
348 // Code that must happen at taint-time
349 BSScene.TaintCallback createOperation = delegate()
285 { 350 {
286 DetailLog("{0},SetTerrain:NewTerrain,baseX={1},baseY={2}", BSScene.DetailLogZero, tOffset.X, tOffset.Y); 351 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
287 CreateNewTerrainSegment(newTerrainID, heightMap, minCoords, maxCoords); 352 // Create a new mapInfo that will be filled with the new info
288 }); 353 mapInfo = new BulletHeightMapInfo(id, heightMapX,
354 BulletSimAPI.CreateHeightMapInfo2(m_physicsScene.World.Ptr, newTerrainID,
355 minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
356 // Put the unfilled heightmap info into the collection of same
357 m_heightMaps.Add(terrainRegionBase, mapInfo);
358 // Build the terrain
359 UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
360 };
361
362 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
363 if (doNow)
364 createOperation();
365 else
366 m_physicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
289 } 367 }
290 } 368 }
291 369
@@ -316,8 +394,8 @@ public class BSTerrainManager
316 lastHeightTY = tY; 394 lastHeightTY = tY;
317 float ret = HEIGHT_GETHEIGHT_RET; 395 float ret = HEIGHT_GETHEIGHT_RET;
318 396
319 int offsetX = ((int)(tX / (int)Constants.RegionSize)) * (int)Constants.RegionSize; 397 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
320 int offsetY = ((int)(tY / (int)Constants.RegionSize)) * (int)Constants.RegionSize; 398 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
321 Vector2 terrainBaseXY = new Vector2(offsetX, offsetY); 399 Vector2 terrainBaseXY = new Vector2(offsetX, offsetY);
322 400
323 BulletHeightMapInfo mapInfo; 401 BulletHeightMapInfo mapInfo;
@@ -335,8 +413,8 @@ public class BSTerrainManager
335 } 413 }
336 else 414 else
337 { 415 {
338 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: x={1}, y={2}", 416 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
339 LogHeader, tX, tY); 417 LogHeader, m_physicsScene.RegionName, tX, tY);
340 } 418 }
341 lastHeight = ret; 419 lastHeight = ret;
342 return ret; 420 return ret;
@@ -347,20 +425,34 @@ public class BSTerrainManager
347 { 425 {
348 return true; 426 return true;
349 } 427 }
350 // This call says I am a child to region zero in a mega-region. 'pScene' is that 428
351 // of region zero, 'offset' is my offset from regions zero's origin, and 429 // This routine is called two ways:
352 // 'extents' is the largest XY that is handled in my region. 430 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
431 // extent of the combined regions. This is to inform the parent of the size
432 // of the combined regions.
433 // and one with 'offset' as the offset of the child region to the base region,
434 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
435 // child of its relative base and new parent.
353 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) 436 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
354 { 437 {
355 m_worldOffset = offset; 438 m_worldOffset = offset;
356 WorldExtents = new Vector2(extents.X, extents.Y); 439 m_worldMax = extents;
357 m_parentScene = pScene; 440 m_parentScene = pScene;
441 if (pScene != null)
442 {
443 // We are a child.
444 // We want m_worldMax to be the highest coordinate of our piece of terrain.
445 m_worldMax = offset + DefaultRegionSize;
446 }
447 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
448 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
358 } 449 }
359 450
360 // Unhook all the combining that I know about. 451 // Unhook all the combining that I know about.
361 public void UnCombine(PhysicsScene pScene) 452 public void UnCombine(PhysicsScene pScene)
362 { 453 {
363 // Just like ODE, for the moment a NOP 454 // Just like ODE, for the moment a NOP
455 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
364 } 456 }
365 457
366 458