aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs307
1 files changed, 307 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..28c1940
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -0,0 +1,307 @@
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 BSScene m_physicsScene;
48
49 private BulletBody m_groundPlane;
50
51 // If doing mega-regions, if we're region zero we will be managing multiple
52 // region terrains since region zero does the physics for the whole mega-region.
53 private Dictionary<Vector2, BulletBody> m_terrains;
54 private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps;
55
56 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
57 // This is incremented before assigning to new region so it is the last ID allocated.
58 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
59 public uint HighestTerrainID { get {return m_terrainCount; } }
60
61 // If doing mega-regions, this holds our offset from region zero of
62 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
63 private Vector3 m_worldOffset = Vector3.Zero;
64 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
65 private PhysicsScene m_parentScene = null;
66
67 public BSTerrainManager(BSScene physicsScene)
68 {
69 m_physicsScene = physicsScene;
70 m_terrains = new Dictionary<Vector2,BulletBody>();
71 m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
72 }
73
74 // Create the initial instance of terrain and the underlying ground plane.
75 // The objects are allocated in the unmanaged space and the pointers are tracked
76 // by the managed code.
77 // The terrains and the groundPlane are not added to the list of PhysObjects.
78 // This is called from the initialization routine so we presume it is
79 // safe to call Bullet in real time. We hope no one is moving around prim yet.
80 public void CreateInitialGroundPlaneAndTerrain()
81 {
82 // The ground plane is here to catch things that are trying to drop to negative infinity
83 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
84 BulletSimAPI.CreateGroundPlaneBody2(BSScene.GROUNDPLANE_ID, 1f, 0.4f));
85 BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr);
86
87 Vector3 minTerrainCoords = new Vector3(0f, 0f, 24f);
88 Vector3 maxTerrainCoords = new Vector3(Constants.RegionSize, Constants.RegionSize, 25f);
89 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
90 float[] initialMap = new float[totalHeights];
91 for (int ii = 0; ii < totalHeights; ii++)
92 {
93 initialMap[ii] = 25f;
94 }
95 CreateNewTerrainSegment(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords);
96 }
97
98 public void ReleaseGroundPlaneAndTerrain()
99 {
100 if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr))
101 {
102 BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, m_groundPlane.Ptr);
103 }
104 m_groundPlane.Ptr = IntPtr.Zero;
105
106 foreach (KeyValuePair<Vector2, BulletBody> kvp in m_terrains)
107 {
108 if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, kvp.Value.Ptr))
109 {
110 BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, kvp.Value.Ptr);
111 BulletSimAPI.ReleaseHeightmapInfo2(m_heightMaps[kvp.Key].Ptr);
112 }
113 }
114 m_terrains.Clear();
115 m_heightMaps.Clear();
116 }
117
118 // Create a new terrain description. This is used for mega-regions where
119 // the children of region zero give region zero all of the terrain
120 // segments since region zero does all the physics for the mega-region.
121 // Call at taint time!!
122 public void CreateNewTerrainSegment(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
123 {
124 // The Z coordinates are recalculated to be the min and max height of the terrain
125 // itself. The caller may have passed us the real region extent.
126 float minZ = float.MaxValue;
127 float maxZ = float.MinValue;
128 int hSize = heightMap.Length;
129 for (int ii = 0; ii < hSize; ii++)
130 {
131 minZ = heightMap[ii] < minZ ? heightMap[ii] : minZ;
132 maxZ = heightMap[ii] > maxZ ? heightMap[ii] : maxZ;
133 }
134 minCoords.Z = minZ;
135 maxCoords.Z = maxZ;
136 // If the terrain is flat, make a difference so we get a good bounding box
137 if (minZ == maxZ)
138 minZ -= 0.2f;
139 Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y);
140
141 // Create the heightmap data structure in the unmanaged space
142 BulletHeightMapInfo mapInfo = new BulletHeightMapInfo(
143 BulletSimAPI.CreateHeightmap2(minCoords, maxCoords, heightMap), heightMap);
144 mapInfo.terrainRegionBase = terrainRegionBase;
145 mapInfo.maxRegionExtent = maxCoords;
146 mapInfo.minZ = minZ;
147 mapInfo.maxZ = maxZ;
148 mapInfo.sizeX = maxCoords.X - minCoords.X;
149 mapInfo.sizeY = maxCoords.Y - minCoords.Y;
150
151 DetailLog("{0},BSScene.CreateNewTerrainSegment,call,minZ={1},maxZ={2},hMapPtr={3},minC={4},maxC={5}",
152 BSScene.DetailLogZero, minZ, maxZ, mapInfo.Ptr, minCoords, maxCoords);
153 // Create the terrain body from that heightmap
154 BulletBody terrainBody = new BulletBody(id, BulletSimAPI.CreateTerrainBody2(id, mapInfo.Ptr, 0.01f));
155
156 BulletSimAPI.SetFriction2(terrainBody.Ptr, m_physicsScene.Params.terrainFriction);
157 BulletSimAPI.SetHitFraction2(terrainBody.Ptr, m_physicsScene.Params.terrainHitFraction);
158 BulletSimAPI.SetRestitution2(terrainBody.Ptr, m_physicsScene.Params.terrainRestitution);
159 BulletSimAPI.SetCollisionFlags2(terrainBody.Ptr, CollisionFlags.CF_STATIC_OBJECT);
160 BulletSimAPI.Activate2(terrainBody.Ptr, true);
161
162 // Add the new terrain to the dynamics world
163 BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, terrainBody.Ptr);
164 BulletSimAPI.UpdateSingleAabb2(m_physicsScene.World.Ptr, terrainBody.Ptr);
165
166
167 // Add the created terrain to the management set. If we are doing mega-regions,
168 // the terrains of our children will be added.
169 m_terrains.Add(terrainRegionBase, terrainBody);
170 m_heightMaps.Add(terrainRegionBase, mapInfo);
171 }
172
173 public void SetTerrain(float[] heightMap) {
174 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
175 {
176 // If doing the mega-prim stuff and we are the child of the zero region,
177 // the terrain is really added to our parent
178 if (m_parentScene is BSScene)
179 {
180 ((BSScene)m_parentScene).TerrainManager.SetTerrain(heightMap, m_worldOffset);
181 }
182 }
183 else
184 {
185 // if not doing the mega-prim thing, just change the terrain
186 SetTerrain(heightMap, m_worldOffset);
187 }
188 }
189
190 private void SetTerrain(float[] heightMap, Vector3 tOffset)
191 {
192 float minZ = float.MaxValue;
193 float maxZ = float.MinValue;
194
195 // Copy heightMap local and compute some statistics.
196 // Not really sure if we need to do this deep copy but, given
197 // the magic that happens to make the closure for taint
198 // below, I don't want there to be any problem with sharing
199 // locations of there are multiple calls to this routine
200 // within one tick.
201 int heightMapSize = heightMap.Length;
202 float[] localHeightMap = new float[heightMapSize];
203 for (int ii = 0; ii < heightMapSize; ii++)
204 {
205 float height = heightMap[ii];
206 if (height < minZ) minZ = height;
207 if (height > maxZ) maxZ = height;
208 localHeightMap[ii] = height;
209 }
210
211 Vector2 terrainRegionBase = new Vector2(tOffset.X, tOffset.Y);
212 BulletHeightMapInfo mapInfo;
213 if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo))
214 {
215 // If this is terrain we know about, it's easy to update
216 mapInfo.heightMap = localHeightMap;
217 m_physicsScene.TaintedObject("BSScene.SetTerrain:UpdateExisting", delegate()
218 {
219 DetailLog("{0},SetTerrain:UpdateExisting,baseX={1},baseY={2},minZ={3},maxZ={4}",
220 BSScene.DetailLogZero, tOffset.X, tOffset.Y, minZ, maxZ);
221 BulletSimAPI.UpdateHeightMap2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.heightMap);
222 });
223 }
224 else
225 {
226 // Our mega-prim child is giving us a new terrain to add to the phys world
227 uint newTerrainID = ++m_terrainCount;
228
229 Vector3 minCoords = tOffset;
230 minCoords.Z = minZ;
231 Vector3 maxCoords = new Vector3(tOffset.X + Constants.RegionSize,
232 tOffset.Y + Constants.RegionSize,
233 maxZ);
234 m_physicsScene.TaintedObject("BSScene.SetTerrain:NewTerrain", delegate()
235 {
236 DetailLog("{0},SetTerrain:NewTerrain,baseX={1},baseY={2}", BSScene.DetailLogZero, tOffset.X, tOffset.Y);
237 CreateNewTerrainSegment(newTerrainID, heightMap, minCoords, maxCoords);
238 });
239 }
240 }
241
242 // Someday we will have complex terrain with caves and tunnels
243 // For the moment, it's flat and convex
244 public float GetTerrainHeightAtXYZ(Vector3 loc)
245 {
246 return GetTerrainHeightAtXY(loc.X, loc.Y);
247 }
248
249 // Given an X and Y, find the height of the terrain.
250 // Since we could be handling multiple terrains for a mega-region,
251 // the base of the region is calcuated assuming all regions are
252 // the same size and that is the default.
253 // Once the heightMapInfo is found, we have all the information to
254 // compute the offset into the array.
255 public float GetTerrainHeightAtXY(float tX, float tY)
256 {
257 float ret = 30f;
258
259 int offsetX = ((int)(tX / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
260 int offsetY = ((int)(tY / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
261 Vector2 terrainBaseXY = new Vector2(offsetX, offsetY);
262
263 BulletHeightMapInfo mapInfo;
264 if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo))
265 {
266 float regionX = tX - offsetX;
267 float regionY = tY - offsetY;
268 regionX = regionX > mapInfo.sizeX ? 0 : regionX;
269 regionY = regionY > mapInfo.sizeY ? 0 : regionY;
270 ret = mapInfo.heightMap[(int)(regionX * mapInfo.sizeX + regionY)];
271 }
272 else
273 {
274 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: x={1}, y={2}",
275 LogHeader, tX, tY);
276 }
277 return ret;
278 }
279
280 // Although no one seems to check this, I do support combining.
281 public bool SupportsCombining()
282 {
283 return true;
284 }
285 // This call says I am a child to region zero in a mega-region. 'pScene' is that
286 // of region zero, 'offset' is my offset from regions zero's origin, and
287 // 'extents' is the largest XY that is handled in my region.
288 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
289 {
290 m_worldOffset = offset;
291 WorldExtents = new Vector2(extents.X, extents.Y);
292 m_parentScene = pScene;
293 }
294
295 // Unhook all the combining that I know about.
296 public void UnCombine(PhysicsScene pScene)
297 {
298 // Just like ODE, for the moment a NOP
299 }
300
301
302 private void DetailLog(string msg, params Object[] args)
303 {
304 m_physicsScene.PhysicsLogging.Write(msg, args);
305 }
306}
307}