aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs
diff options
context:
space:
mode:
authorRobert Adams2015-09-08 04:54:16 -0700
committerRobert Adams2015-09-08 04:54:16 -0700
commite5367d822be9b05e74c859afe2d2956a3e95aa33 (patch)
treee904050a30715df587aa527d7f313755177726a7 /OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs
parentadd lost admin_reset_land method (diff)
parentDeleted access control spec from [LoginService] section of standalone config.... (diff)
downloadopensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.zip
opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.gz
opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.bz2
opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.xz
Merge of ubitworkvarnew with opensim/master as of 20150905.
This integrates the OpenSim refactoring to make physics, etc into modules. AVN physics hasn't been moved to new location. Does not compile yet. Merge branch 'osmaster' into mbworknew1
Diffstat (limited to 'OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs')
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs440
1 files changed, 440 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs
new file mode 100755
index 0000000..cd59b65
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs
@@ -0,0 +1,440 @@
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.PhysicsModules.SharedBase;
34
35using Nini.Config;
36using log4net;
37
38using OpenMetaverse;
39
40namespace OpenSim.Region.PhysicsModule.BulletS
41{
42public sealed class BSTerrainMesh : BSTerrainPhys
43{
44 static string LogHeader = "[BULLETSIM TERRAIN MESH]";
45
46 private float[] m_savedHeightMap;
47 int m_sizeX;
48 int m_sizeY;
49
50 BulletShape m_terrainShape;
51 BulletBody m_terrainBody;
52
53 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
54 : base(physicsScene, regionBase, id)
55 {
56 }
57
58 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */)
59 : base(physicsScene, regionBase, id)
60 {
61 }
62
63 // Create terrain mesh from a heightmap.
64 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
65 Vector3 minCoords, Vector3 maxCoords)
66 : base(physicsScene, regionBase, id)
67 {
68 int indicesCount;
69 int[] indices;
70 int verticesCount;
71 float[] vertices;
72
73 m_savedHeightMap = initialMap;
74
75 m_sizeX = (int)(maxCoords.X - minCoords.X);
76 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
77
78 bool meshCreationSuccess = false;
79 if (BSParam.TerrainMeshMagnification == 1)
80 {
81 // If a magnification of one, use the old routine that is tried and true.
82 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene,
83 initialMap, m_sizeX, m_sizeY, // input size
84 Vector3.Zero, // base for mesh
85 out indicesCount, out indices, out verticesCount, out vertices);
86 }
87 else
88 {
89 // Other magnifications use the newer routine
90 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene,
91 initialMap, m_sizeX, m_sizeY, // input size
92 BSParam.TerrainMeshMagnification,
93 physicsScene.TerrainManager.DefaultRegionSize,
94 Vector3.Zero, // base for mesh
95 out indicesCount, out indices, out verticesCount, out vertices);
96 }
97 if (!meshCreationSuccess)
98 {
99 // DISASTER!!
100 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
101 m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
102 // Something is very messed up and a crash is in our future.
103 return;
104 }
105
106 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
107 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
108
109 m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices);
110 if (!m_terrainShape.HasPhysicalShape)
111 {
112 // DISASTER!!
113 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
114 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
115 // Something is very messed up and a crash is in our future.
116 return;
117 }
118
119 Vector3 pos = regionBase;
120 Quaternion rot = Quaternion.Identity;
121
122 m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
123 if (!m_terrainBody.HasPhysicalBody)
124 {
125 // DISASTER!!
126 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
127 // Something is very messed up and a crash is in our future.
128 return;
129 }
130 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
131
132 // Set current terrain attributes
133 m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
134 m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
135 m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
136 m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
137 m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
138
139 // Static objects are not very massive.
140 m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
141
142 // Put the new terrain to the world of physical objects
143 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody);
144
145 // Redo its bounding box now that it is in the world
146 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody);
147
148 m_terrainBody.collisionType = CollisionType.Terrain;
149 m_terrainBody.ApplyCollisionMask(m_physicsScene);
150
151 if (BSParam.UseSingleSidedMeshes)
152 {
153 m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
154 m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
155 }
156
157 // Make it so the terrain will not move or be considered for movement.
158 m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
159 }
160
161 public override void Dispose()
162 {
163 if (m_terrainBody.HasPhysicalBody)
164 {
165 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody);
166 // Frees both the body and the shape.
167 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody);
168 m_terrainBody.Clear();
169 m_terrainShape.Clear();
170 }
171 }
172
173 public override float GetTerrainHeightAtXYZ(Vector3 pos)
174 {
175 // For the moment use the saved heightmap to get the terrain height.
176 // TODO: raycast downward to find the true terrain below the position.
177 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
178
179 int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
180 try
181 {
182 ret = m_savedHeightMap[mapIndex];
183 }
184 catch
185 {
186 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
187 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
188 LogHeader, TerrainBase, pos);
189 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
190 }
191 return ret;
192 }
193
194 // The passed position is relative to the base of the region.
195 public override float GetWaterLevelAtXYZ(Vector3 pos)
196 {
197 return m_physicsScene.SimpleWaterLevel;
198 }
199
200 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
201 // Return 'true' if successfully created.
202 public static bool ConvertHeightmapToMesh( BSScene physicsScene,
203 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
204 Vector3 extentBase, // base to be added to all vertices
205 out int indicesCountO, out int[] indicesO,
206 out int verticesCountO, out float[] verticesO)
207 {
208 bool ret = false;
209
210 int indicesCount = 0;
211 int verticesCount = 0;
212 int[] indices = new int[0];
213 float[] vertices = new float[0];
214
215 // Simple mesh creation which assumes magnification == 1.
216 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
217
218 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
219 // from zero to <= sizeX). The triangle indices are then generated as two triangles
220 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
221 // column of vertices are used to complete the triangles of the last row and column
222 // of the heightmap.
223 try
224 {
225 // One vertice per heightmap value plus the vertices off the side and bottom edge.
226 int totalVertices = (sizeX + 1) * (sizeY + 1);
227 vertices = new float[totalVertices * 3];
228 int totalIndices = sizeX * sizeY * 6;
229 indices = new int[totalIndices];
230
231 if (physicsScene != null)
232 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}",
233 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase);
234 float minHeight = float.MaxValue;
235 // Note that sizeX+1 vertices are created since there is land between this and the next region.
236 for (int yy = 0; yy <= sizeY; yy++)
237 {
238 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
239 {
240 int offset = yy * sizeX + xx;
241 // Extend the height with the height from the last row or column
242 if (yy == sizeY) offset -= sizeX;
243 if (xx == sizeX) offset -= 1;
244 float height = heightMap[offset];
245 minHeight = Math.Min(minHeight, height);
246 vertices[verticesCount + 0] = (float)xx + extentBase.X;
247 vertices[verticesCount + 1] = (float)yy + extentBase.Y;
248 vertices[verticesCount + 2] = height + extentBase.Z;
249 verticesCount += 3;
250 }
251 }
252 verticesCount = verticesCount / 3;
253
254 for (int yy = 0; yy < sizeY; yy++)
255 {
256 for (int xx = 0; xx < sizeX; xx++)
257 {
258 int offset = yy * (sizeX + 1) + xx;
259 // Each vertices is presumed to be the upper left corner of a box of two triangles
260 indices[indicesCount + 0] = offset;
261 indices[indicesCount + 1] = offset + 1;
262 indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
263 indices[indicesCount + 3] = offset + 1;
264 indices[indicesCount + 4] = offset + sizeX + 2;
265 indices[indicesCount + 5] = offset + sizeX + 1;
266 indicesCount += 6;
267 }
268 }
269
270 ret = true;
271 }
272 catch (Exception e)
273 {
274 if (physicsScene != null)
275 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
276 LogHeader, physicsScene.RegionName, extentBase, e);
277 }
278
279 indicesCountO = indicesCount;
280 indicesO = indices;
281 verticesCountO = verticesCount;
282 verticesO = vertices;
283
284 return ret;
285 }
286
287 private class HeightMapGetter
288 {
289 private float[] m_heightMap;
290 private int m_sizeX;
291 private int m_sizeY;
292 public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY)
293 {
294 m_heightMap = pHeightMap;
295 m_sizeX = pSizeX;
296 m_sizeY = pSizeY;
297 }
298 // The heightmap is extended as an infinite plane at the last height
299 public float GetHeight(int xx, int yy)
300 {
301 int offset = 0;
302 // Extend the height with the height from the last row or column
303 if (yy >= m_sizeY)
304 if (xx >= m_sizeX)
305 offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1);
306 else
307 offset = (m_sizeY - 1) * m_sizeX + xx;
308 else
309 if (xx >= m_sizeX)
310 offset = yy * m_sizeX + (m_sizeX - 1);
311 else
312 offset = yy * m_sizeX + xx;
313
314 return m_heightMap[offset];
315 }
316 }
317
318 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
319 // Version that handles magnification.
320 // Return 'true' if successfully created.
321 public static bool ConvertHeightmapToMesh2( BSScene physicsScene,
322 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
323 int magnification, // number of vertices per heighmap step
324 Vector3 extent, // dimensions of the output mesh
325 Vector3 extentBase, // base to be added to all vertices
326 out int indicesCountO, out int[] indicesO,
327 out int verticesCountO, out float[] verticesO)
328 {
329 bool ret = false;
330
331 int indicesCount = 0;
332 int verticesCount = 0;
333 int[] indices = new int[0];
334 float[] vertices = new float[0];
335
336 HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY);
337
338 // The vertices dimension of the output mesh
339 int meshX = sizeX * magnification;
340 int meshY = sizeY * magnification;
341 // The output size of one mesh step
342 float meshXStep = extent.X / meshX;
343 float meshYStep = extent.Y / meshY;
344
345 // Create an array of vertices that is meshX+1 by meshY+1 (note the loop
346 // from zero to <= meshX). The triangle indices are then generated as two triangles
347 // per heightmap point. There are meshX by meshY of these squares. The extra row and
348 // column of vertices are used to complete the triangles of the last row and column
349 // of the heightmap.
350 try
351 {
352 // Vertices for the output heightmap plus one on the side and bottom to complete triangles
353 int totalVertices = (meshX + 1) * (meshY + 1);
354 vertices = new float[totalVertices * 3];
355 int totalIndices = meshX * meshY * 6;
356 indices = new int[totalIndices];
357
358 if (physicsScene != null)
359 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}",
360 BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY),
361 totalVertices, totalIndices, extentBase);
362
363 float minHeight = float.MaxValue;
364 // Note that sizeX+1 vertices are created since there is land between this and the next region.
365 // Loop through the output vertices and compute the mediun height in between the input vertices
366 for (int yy = 0; yy <= meshY; yy++)
367 {
368 for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
369 {
370 float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point
371 int stepY = (int)offsetY;
372 float fractionalY = offsetY - (float)stepY;
373 float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point
374 int stepX = (int)offsetX;
375 float fractionalX = offsetX - (float)stepX;
376
377 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}",
378 // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY);
379
380 // get the four corners of the heightmap square the mesh point is in
381 float heightUL = hmap.GetHeight(stepX , stepY );
382 float heightUR = hmap.GetHeight(stepX + 1, stepY );
383 float heightLL = hmap.GetHeight(stepX , stepY + 1);
384 float heightLR = hmap.GetHeight(stepX + 1, stepY + 1);
385
386 // bilinear interplolation
387 float height = heightUL * (1 - fractionalX) * (1 - fractionalY)
388 + heightUR * fractionalX * (1 - fractionalY)
389 + heightLL * (1 - fractionalX) * fractionalY
390 + heightLR * fractionalX * fractionalY;
391
392 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}",
393 // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height);
394
395 minHeight = Math.Min(minHeight, height);
396
397 vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X;
398 vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y;
399 vertices[verticesCount + 2] = height + extentBase.Z;
400 verticesCount += 3;
401 }
402 }
403 // The number of vertices generated
404 verticesCount /= 3;
405
406 // Loop through all the heightmap squares and create indices for the two triangles for that square
407 for (int yy = 0; yy < meshY; yy++)
408 {
409 for (int xx = 0; xx < meshX; xx++)
410 {
411 int offset = yy * (meshX + 1) + xx;
412 // Each vertices is presumed to be the upper left corner of a box of two triangles
413 indices[indicesCount + 0] = offset;
414 indices[indicesCount + 1] = offset + 1;
415 indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column
416 indices[indicesCount + 3] = offset + 1;
417 indices[indicesCount + 4] = offset + meshX + 2;
418 indices[indicesCount + 5] = offset + meshX + 1;
419 indicesCount += 6;
420 }
421 }
422
423 ret = true;
424 }
425 catch (Exception e)
426 {
427 if (physicsScene != null)
428 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
429 LogHeader, physicsScene.RegionName, extentBase, e);
430 }
431
432 indicesCountO = indicesCount;
433 indicesO = indices;
434 verticesCountO = verticesCount;
435 verticesO = vertices;
436
437 return ret;
438 }
439}
440}