diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | 356 |
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 | ||