aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs174
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs257
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs73
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs4
4 files changed, 327 insertions, 181 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
new file mode 100755
index 0000000..3bb63cd
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -0,0 +1,174 @@
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 sealed class BSTerrainHeightmap : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
46
47 BulletHeightMapInfo m_mapInfo;
48
49 public BSTerrainHeightmap(BSScene physicsScene, uint id, Vector3 regionSize)
50 : base(physicsScene)
51 {
52 Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE);
53 Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION);
54 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
55 float[] initialMap = new float[totalHeights];
56 for (int ii = 0; ii < totalHeights; ii++)
57 {
58 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
59 }
60 m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero);
61 m_mapInfo.minCoords = minTerrainCoords;
62 m_mapInfo.maxCoords = maxTerrainCoords;
63 // Don't have to free any previous since we just got here.
64 BuildHeightmapTerrain();
65 }
66
67 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z
68 // are the high and low points of the heightmap).
69 public BSTerrainHeightmap(BSScene physicsScene, uint id, float[] initialMap,
70 Vector3 minCoords, Vector3 maxCoords)
71 : base(physicsScene)
72 {
73 m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero);
74 m_mapInfo.minCoords = minCoords;
75 m_mapInfo.maxCoords = maxCoords;
76 m_mapInfo.minZ = minCoords.Z;
77 m_mapInfo.maxZ = maxCoords.Z;
78
79 // Don't have to free any previous since we just got here.
80 BuildHeightmapTerrain();
81 }
82
83 public override void Dispose()
84 {
85 ReleaseHeightMapTerrain();
86 }
87
88 // Using the information in m_mapInfo, create the physical representation of the heightmap.
89 private void BuildHeightmapTerrain()
90 {
91 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
92 m_mapInfo.minCoords, m_mapInfo.maxCoords,
93 m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN);
94
95 // Create the terrain shape from the mapInfo
96 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
97 PhysicsShapeType.SHAPE_TERRAIN);
98
99 // The terrain object initial position is at the center of the object
100 Vector3 centerPos;
101 centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f);
102 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
103 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
104
105 m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID,
106 BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr,
107 m_mapInfo.ID, centerPos, Quaternion.Identity));
108
109 // Set current terrain attributes
110 BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
111 BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
112 BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
113 BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
114
115 // Return the new terrain to the world of physical objects
116 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
117
118 // redo its bounding box now that it is in the world
119 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
120
121 BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr,
122 (uint)CollisionFilterGroups.TerrainFilter,
123 (uint)CollisionFilterGroups.TerrainMask);
124
125 // Make it so the terrain will not move or be considered for movement.
126 BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
127
128 return;
129 }
130
131 // If there is information in m_mapInfo pointing to physical structures, release same.
132 private void ReleaseHeightMapTerrain()
133 {
134 if (m_mapInfo != null)
135 {
136 if (m_mapInfo.terrainBody.ptr != IntPtr.Zero)
137 {
138 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr))
139 {
140 // Frees both the body and the shape.
141 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
142 BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr);
143 }
144 }
145 }
146 m_mapInfo = null;
147 }
148
149 // The passed position is relative to the base of the region.
150 public override float GetHeightAtXYZ(Vector3 pos)
151 {
152 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
153
154 int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X;
155 try
156 {
157 ret = m_mapInfo.heightMap[mapIndex];
158 }
159 catch
160 {
161 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
162 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
163 LogHeader, m_mapInfo.terrainRegionBase, pos);
164 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
165 }
166 return ret;
167 }
168
169 public override Vector3 TerrainBase
170 {
171 get { return m_mapInfo.terrainRegionBase; }
172 }
173}
174}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index cc28e4d..db04299 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -40,6 +40,22 @@ using OpenMetaverse;
40 40
41namespace OpenSim.Region.Physics.BulletSPlugin 41namespace OpenSim.Region.Physics.BulletSPlugin
42{ 42{
43
44// The physical implementation of the terrain is wrapped in this class.
45public abstract class BSTerrainPhys : IDisposable
46{
47 public BSScene PhysicsScene { get; private set; }
48
49 public BSTerrainPhys(BSScene physicsScene)
50 {
51 PhysicsScene = physicsScene;
52 }
53 public abstract void Dispose();
54 public abstract float GetHeightAtXYZ(Vector3 pos);
55 public abstract Vector3 TerrainBase { get; }
56}
57
58// ==========================================================================================
43public sealed class BSTerrainManager 59public sealed class BSTerrainManager
44{ 60{
45 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; 61 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
@@ -67,11 +83,10 @@ public sealed class BSTerrainManager
67 83
68 // If doing mega-regions, if we're region zero we will be managing multiple 84 // 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. 85 // region terrains since region zero does the physics for the whole mega-region.
70 private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps; 86 private Dictionary<Vector3, BSTerrainPhys> m_terrains;
71 87
72 // True of the terrain has been modified. 88 // Flags used to know when to recalculate the height.
73 // Used to force recalculation of terrain height after terrain has been modified 89 private bool m_terrainModified = false;
74 private bool m_terrainModified;
75 90
76 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. 91 // 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. 92 // This is incremented before assigning to new region so it is the last ID allocated.
@@ -89,8 +104,7 @@ public sealed class BSTerrainManager
89 public BSTerrainManager(BSScene physicsScene) 104 public BSTerrainManager(BSScene physicsScene)
90 { 105 {
91 PhysicsScene = physicsScene; 106 PhysicsScene = physicsScene;
92 m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>(); 107 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
93 m_terrainModified = false;
94 108
95 // Assume one region of default size 109 // Assume one region of default size
96 m_worldOffset = Vector3.Zero; 110 m_worldOffset = Vector3.Zero;
@@ -99,9 +113,6 @@ public sealed class BSTerrainManager
99 } 113 }
100 114
101 // Create the initial instance of terrain and the underlying ground plane. 115 // 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 116 // 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. 117 // safe to call Bullet in real time. We hope no one is moving prims around yet.
107 public void CreateInitialGroundPlaneAndTerrain() 118 public void CreateInitialGroundPlaneAndTerrain()
@@ -121,15 +132,9 @@ public sealed class BSTerrainManager
121 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, 132 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
122 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); 133 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
123 134
124 Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE); 135 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
125 Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION); 136 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, BSScene.TERRAIN_ID, DefaultRegionSize);
126 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; 137 m_terrains.Add(Vector3.Zero, initialTerrain);
127 float[] initialMap = new float[totalHeights];
128 for (int ii = 0; ii < totalHeights; ii++)
129 {
130 initialMap[ii] = HEIGHT_INITIALIZATION;
131 }
132 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords, true);
133 } 138 }
134 139
135 // Release all the terrain structures we might have allocated 140 // Release all the terrain structures we might have allocated
@@ -150,15 +155,11 @@ public sealed class BSTerrainManager
150 // Release all the terrain we have allocated 155 // Release all the terrain we have allocated
151 public void ReleaseTerrain() 156 public void ReleaseTerrain()
152 { 157 {
153 foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps) 158 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
154 { 159 {
155 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr)) 160 kvp.Value.Dispose();
156 {
157 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr);
158 BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
159 }
160 } 161 }
161 m_heightMaps.Clear(); 162 m_terrains.Clear();
162 } 163 }
163 164
164 // The simulator wants to set a new heightmap for the terrain. 165 // The simulator wants to set a new heightmap for the terrain.
@@ -176,8 +177,9 @@ public sealed class BSTerrainManager
176 { 177 {
177 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", 178 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
178 BSScene.DetailLogZero, m_worldOffset, m_worldMax); 179 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
179 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID, 180 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
180 localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true); 181 BSScene.CHILDTERRAIN_ID, localHeightMap,
182 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
181 } 183 }
182 } 184 }
183 else 185 else
@@ -185,7 +187,7 @@ public sealed class BSTerrainManager
185 // If not doing the mega-prim thing, just change the terrain 187 // If not doing the mega-prim thing, just change the terrain
186 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); 188 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
187 189
188 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap, 190 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
189 m_worldOffset, m_worldOffset + DefaultRegionSize, true); 191 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
190 } 192 }
191 }); 193 });
@@ -195,56 +197,60 @@ public sealed class BSTerrainManager
195 // based on the passed information. The 'id' should be either the terrain id or 197 // based on the passed information. The 'id' should be either the terrain id or
196 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. 198 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
197 // The latter feature is for creating child terrains for mega-regions. 199 // The latter feature is for creating child terrains for mega-regions.
198 // If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0)
199 // then a new body and shape is created and the mapInfo is filled.
200 // This call is used for doing the initial terrain creation.
201 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new 200 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
202 // terrain shape is created and added to the body. 201 // terrain shape is created and added to the body.
203 // This call is most often used to update the heightMap and parameters of the terrain. 202 // This call is most often used to update the heightMap and parameters of the terrain.
204 // (The above does suggest that some simplification/refactoring is in order.) 203 // (The above does suggest that some simplification/refactoring is in order.)
205 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 204 private void UpdateTerrain(uint id, float[] heightMap,
205 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
206 { 206 {
207 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}", 207 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
208 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); 208 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
209 209
210 // Find high and low points of passed heightmap.
211 // The min and max passed in are usually the region objects can exist in (maximum
212 // object height, for instance). The terrain wants the bounding box for the
213 // terrain so we replace passed min and max Z with the actual terrain min/max Z.
214 // limit, for
210 float minZ = float.MaxValue; 215 float minZ = float.MaxValue;
211 float maxZ = float.MinValue; 216 float maxZ = float.MinValue;
212 Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y); 217 foreach (float height in heightMap)
213
214 int heightMapSize = heightMap.Length;
215 for (int ii = 0; ii < heightMapSize; ii++)
216 { 218 {
217 float height = heightMap[ii];
218 if (height < minZ) minZ = height; 219 if (height < minZ) minZ = height;
219 if (height > maxZ) maxZ = height; 220 if (height > maxZ) maxZ = height;
220 } 221 }
221
222 // The shape of the terrain is from its base to its extents.
223 minCoords.Z = minZ; 222 minCoords.Z = minZ;
224 maxCoords.Z = maxZ; 223 maxCoords.Z = maxZ;
225 224
226 BulletHeightMapInfo mapInfo; 225 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
227 if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo)) 226
227 BSTerrainPhys terrainPhys;
228 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
228 { 229 {
229 // If this is terrain we know about, it's easy to update 230 // If this is terrain we know about, it's easy to update
230 231
231 mapInfo.heightMap = heightMap; 232 DetailLog("{0},UpdateTerrain:UpdateExisting,call,terrainBase={1}", BSScene.DetailLogZero, terrainRegionBase);
232 mapInfo.minCoords = minCoords; 233
233 mapInfo.maxCoords = maxCoords; 234 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
234 mapInfo.minZ = minZ;
235 mapInfo.maxZ = maxZ;
236 mapInfo.sizeX = maxCoords.X - minCoords.X;
237 mapInfo.sizeY = maxCoords.Y - minCoords.Y;
238 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
239 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
240
241 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:UpdateExisting", delegate()
242 { 235 {
243 if (MegaRegionParentPhysicsScene != null) 236 // Remove old terrain from the collection
237 m_terrains.Remove(terrainPhys.TerrainBase);
238 // Release any physical memory it may be using.
239 terrainPhys.Dispose();
240
241 if (MegaRegionParentPhysicsScene == null)
242 {
243 BSTerrainPhys newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, id,
244 heightMap, minCoords, maxCoords);
245 m_terrains.Add(terrainRegionBase, newTerrainPhys);
246
247 m_terrainModified = true;
248 }
249 else
244 { 250 {
245 // It's possible that Combine() was called after this code was queued. 251 // It's possible that Combine() was called after this code was queued.
246 // If we are a child of combined regions, we don't create any terrain for us. 252 // If we are a child of combined regions, we don't create any terrain for us.
247 DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); 253 DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
248 254
249 // Get rid of any terrain that may have been allocated for us. 255 // Get rid of any terrain that may have been allocated for us.
250 ReleaseGroundPlaneAndTerrain(); 256 ReleaseGroundPlaneAndTerrain();
@@ -252,91 +258,6 @@ public sealed class BSTerrainManager
252 // I hate doing this, but just bail 258 // I hate doing this, but just bail
253 return; 259 return;
254 } 260 }
255
256 if (mapInfo.terrainBody.ptr != IntPtr.Zero)
257 {
258 // Updating an existing terrain.
259 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
260 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
261
262 // Remove from the dynamics world because we're going to mangle this object
263 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
264
265 // Get rid of the old terrain
266 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
267 BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
268 mapInfo.Ptr = IntPtr.Zero;
269
270 /*
271 // NOTE: This routine is half here because I can't get the terrain shape replacement
272 // to work. In the short term, the above three lines completely delete the old
273 // terrain and the code below recreates one from scratch.
274 // Hopefully the Bullet community will help me out on this one.
275
276 // First, release the old collision shape (there is only one terrain)
277 BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr);
278
279 // Fill the existing height map info with the new location and size information
280 BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID,
281 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
282
283 // Create a terrain shape based on the new info
284 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
285
286 // Stuff the shape into the existing terrain body
287 BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr);
288 */
289 }
290 // else
291 {
292 // Creating a new terrain.
293 DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}",
294 BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
295
296 mapInfo.ID = id;
297 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
298 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
299
300 // Create the terrain shape from the mapInfo
301 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
302 PhysicsShapeType.SHAPE_TERRAIN);
303
304 // The terrain object initial position is at the center of the object
305 Vector3 centerPos;
306 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
307 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
308 centerPos.Z = minZ + ((maxZ - minZ) / 2f);
309
310 mapInfo.terrainBody = new BulletBody(mapInfo.ID,
311 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
312 id, centerPos, Quaternion.Identity));
313 }
314
315 // Make sure the entry is in the heightmap table
316 m_heightMaps[terrainRegionBase] = mapInfo;
317
318 // Set current terrain attributes
319 BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
320 BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
321 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
322 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
323
324 // Return the new terrain to the world of physical objects
325 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
326
327 // redo its bounding box now that it is in the world
328 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
329
330 BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr,
331 (uint)CollisionFilterGroups.TerrainFilter,
332 (uint)CollisionFilterGroups.TerrainMask);
333
334 // Make sure the new shape is processed.
335 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
336 // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
337 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
338
339 m_terrainModified = true;
340 }); 261 });
341 } 262 }
342 else 263 else
@@ -353,34 +274,23 @@ public sealed class BSTerrainManager
353 Vector3 minCoordsX = minCoords; 274 Vector3 minCoordsX = minCoords;
354 Vector3 maxCoordsX = maxCoords; 275 Vector3 maxCoordsX = maxCoords;
355 276
356 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", 277 DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
357 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 278 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
358 279
359 // Code that must happen at taint-time 280 // Code that must happen at taint-time
360 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:NewTerrain", delegate() 281 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate()
361 { 282 {
362 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y); 283 DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}",
363 // Create a new mapInfo that will be filled with the new info 284 BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y);
364 mapInfo = new BulletHeightMapInfo(id, heightMapX, 285 BSTerrainPhys newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, newTerrainID,
365 BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID, 286 heightMapX, minCoordsX, maxCoordsX);
366 minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN)); 287 m_terrains.Add(terrainRegionBase, newTerrainPhys);
367 // Put the unfilled heightmap info into the collection of same
368 m_heightMaps.Add(terrainRegionBase, mapInfo);
369 // Build the terrain
370 UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
371 288
372 m_terrainModified = true; 289 m_terrainModified = true;
373 }); 290 });
374 } 291 }
375 } 292 }
376 293
377 // Someday we will have complex terrain with caves and tunnels
378 public float GetTerrainHeightAtXYZ(Vector3 loc)
379 {
380 // For the moment, it's flat and convex
381 return GetTerrainHeightAtXY(loc.X, loc.Y);
382 }
383
384 // Given an X and Y, find the height of the terrain. 294 // Given an X and Y, find the height of the terrain.
385 // Since we could be handling multiple terrains for a mega-region, 295 // Since we could be handling multiple terrains for a mega-region,
386 // the base of the region is calcuated assuming all regions are 296 // the base of the region is calcuated assuming all regions are
@@ -390,8 +300,10 @@ public sealed class BSTerrainManager
390 private float lastHeightTX = 999999f; 300 private float lastHeightTX = 999999f;
391 private float lastHeightTY = 999999f; 301 private float lastHeightTY = 999999f;
392 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; 302 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
393 private float GetTerrainHeightAtXY(float tX, float tY) 303 public float GetTerrainHeightAtXYZ(Vector3 loc)
394 { 304 {
305 float tX = loc.X;
306 float tY = loc.Y;
395 // You'd be surprized at the number of times this routine is called 307 // You'd be surprized at the number of times this routine is called
396 // with the same parameters as last time. 308 // with the same parameters as last time.
397 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) 309 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
@@ -403,27 +315,14 @@ public sealed class BSTerrainManager
403 315
404 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 316 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
405 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; 317 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
406 Vector2 terrainBaseXY = new Vector2(offsetX, offsetY); 318 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
407 319
408 BulletHeightMapInfo mapInfo; 320 BSTerrainPhys physTerrain;
409 if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo)) 321 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
410 { 322 {
411 float regionX = tX - offsetX; 323 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ);
412 float regionY = tY - offsetY; 324 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}",
413 int mapIndex = (int)regionY * (int)mapInfo.sizeY + (int)regionX; 325 BSScene.DetailLogZero, loc, terrainBaseXYZ, ret);
414 try
415 {
416 ret = mapInfo.heightMap[mapIndex];
417 }
418 catch
419 {
420 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
421 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}",
422 LogHeader, terrainBaseXY, regionX, regionY);
423 ret = HEIGHT_GETHEIGHT_RET;
424 }
425 // DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXY,bX={1},baseY={2},szX={3},szY={4},regX={5},regY={6},index={7},ht={8}",
426 // BSScene.DetailLogZero, offsetX, offsetY, mapInfo.sizeX, mapInfo.sizeY, regionX, regionY, mapIndex, ret);
427 } 326 }
428 else 327 else
429 { 328 {
@@ -466,7 +365,7 @@ public sealed class BSTerrainManager
466 // Unhook all the combining that I know about. 365 // Unhook all the combining that I know about.
467 public void UnCombine(PhysicsScene pScene) 366 public void UnCombine(PhysicsScene pScene)
468 { 367 {
469 // Just like ODE, for the moment a NOP 368 // Just like ODE, we don't do anything yet.
470 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); 369 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
471 } 370 }
472 371
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
new file mode 100755
index 0000000..387c78b
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -0,0 +1,73 @@
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 sealed class BSTerrainMesh : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN MESH]";
46
47 public BSTerrainMesh(BSScene physicsScene, uint id, Vector3 regionSize)
48 : base(physicsScene)
49 {
50 }
51
52 public BSTerrainMesh(BSScene physicsScene /* parameters for making mesh */)
53 : base(physicsScene)
54 {
55 }
56
57 public override void Dispose()
58 {
59 return;
60 }
61
62 public override float GetHeightAtXYZ(Vector3 pos)
63 {
64 return 12345f;
65 }
66
67 public override Vector3 TerrainBase
68 {
69 get { return Vector3.Zero; }
70 }
71
72}
73}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 407d6d7..bab3b3d 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -152,7 +152,7 @@ public class BulletHeightMapInfo
152 ID = id; 152 ID = id;
153 Ptr = xx; 153 Ptr = xx;
154 heightMap = hm; 154 heightMap = hm;
155 terrainRegionBase = new Vector2(0f, 0f); 155 terrainRegionBase = Vector3.Zero;
156 minCoords = new Vector3(100f, 100f, 25f); 156 minCoords = new Vector3(100f, 100f, 25f);
157 maxCoords = new Vector3(101f, 101f, 26f); 157 maxCoords = new Vector3(101f, 101f, 26f);
158 minZ = maxZ = 0f; 158 minZ = maxZ = 0f;
@@ -161,7 +161,7 @@ public class BulletHeightMapInfo
161 public uint ID; 161 public uint ID;
162 public IntPtr Ptr; 162 public IntPtr Ptr;
163 public float[] heightMap; 163 public float[] heightMap;
164 public Vector2 terrainRegionBase; 164 public Vector3 terrainRegionBase;
165 public Vector3 minCoords; 165 public Vector3 minCoords;
166 public Vector3 maxCoords; 166 public Vector3 maxCoords;
167 public float sizeX, sizeY; 167 public float sizeX, sizeY;