From 30714c044eec6dc16e94a98fb7bc56e32bd0df7b Mon Sep 17 00:00:00 2001 From: Teravus Ovares Date: Sun, 13 Jan 2008 22:11:49 +0000 Subject: [PATCH] * HeightField handling update in ODE. Should improve the terrain pits. So far, only windows lib updated. Need to do the Linux version. * Update also checked into opensim-libs --- OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 125 +++++++++++++++++- bin/ode.dll | Bin 630784 -> 630784 bytes 2 files changed, 118 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index bfc16fd57a..47839ca2b9 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs @@ -85,8 +85,9 @@ namespace OpenSim.Region.Physics.OdePlugin private static float metersInSpace = 29.9f; private IntPtr contactgroup; private IntPtr LandGeom = (IntPtr) 0; - private double[] _heightmap; + private float[] _heightmap; private float[] _origheightmap; + private d.NearCallback nearCallback; public d.TriCallback triCallback; public d.TriArrayCallback triArrayCallback; @@ -185,7 +186,7 @@ namespace OpenSim.Region.Physics.OdePlugin } // zero out a heightmap array float array (single dimention [flattened])) - _heightmap = new double[514*514]; + _heightmap = new float[514*514]; // Zero out the prim spaces array (we split our space into smaller spaces so @@ -1152,8 +1153,118 @@ namespace OpenSim.Region.Physics.OdePlugin get { return (false); // for now we won't be multithreaded } } + public float[] ResizeTerrain512NearestNeighbour(float[] heightMap) + { + float[] returnarr = new float[262144]; + float[,] resultarr = new float[m_regionWidth, m_regionHeight]; - public float[] ResizeTerrain512(float[] heightMap) + // Filling out the array into it's multi-dimentional components + for (int y = 0; y < m_regionHeight; y++) + { + for (int x = 0; x < m_regionWidth; x++) + { + resultarr[y, x] = heightMap[y * m_regionWidth + x]; + } + } + + // Resize using Nearest Neighbour + + // This particular way is quick but it only works on a multiple of the original + + // The idea behind this method can be described with the following diagrams + // second pass and third pass happen in the same loop really.. just separated + // them to show what this does. + + // First Pass + // ResultArr: + // 1,1,1,1,1,1 + // 1,1,1,1,1,1 + // 1,1,1,1,1,1 + // 1,1,1,1,1,1 + // 1,1,1,1,1,1 + // 1,1,1,1,1,1 + + // Second Pass + // ResultArr2: + // 1,,1,,1,,1,,1,,1, + // ,,,,,,,,,, + // 1,,1,,1,,1,,1,,1, + // ,,,,,,,,,, + // 1,,1,,1,,1,,1,,1, + // ,,,,,,,,,, + // 1,,1,,1,,1,,1,,1, + // ,,,,,,,,,, + // 1,,1,,1,,1,,1,,1, + // ,,,,,,,,,, + // 1,,1,,1,,1,,1,,1, + + // Third pass fills in the blanks + // ResultArr2: + // 1,1,1,1,1,1,1,1,1,1,1,1 + // 1,1,1,1,1,1,1,1,1,1,1,1 + // 1,1,1,1,1,1,1,1,1,1,1,1 + // 1,1,1,1,1,1,1,1,1,1,1,1 + // 1,1,1,1,1,1,1,1,1,1,1,1 + // 1,1,1,1,1,1,1,1,1,1,1,1 + // 1,1,1,1,1,1,1,1,1,1,1,1 + // 1,1,1,1,1,1,1,1,1,1,1,1 + // 1,1,1,1,1,1,1,1,1,1,1,1 + // 1,1,1,1,1,1,1,1,1,1,1,1 + // 1,1,1,1,1,1,1,1,1,1,1,1 + + // X,Y = . + // X+1,y = ^ + // X,Y+1 = * + // X+1,Y+1 = # + + // Filling in like this; + // .* + // ^# + // 1st . + // 2nd * + // 3rd ^ + // 4th # + // on single loop. + + float[,] resultarr2 = new float[512, 512]; + for (int y = 0; y < m_regionHeight; y++) + { + for (int x = 0; x < m_regionWidth; x++) + { + resultarr2[y * 2, x * 2] = resultarr[y, x]; + + if (y < m_regionHeight) + { + resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x]; + } + if (x < m_regionWidth) + { + resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x]; + } + if (x < m_regionWidth && y < m_regionHeight) + { + resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x]; + } + } + } + //Flatten out the array + int i = 0; + for (int y = 0; y < 512; y++) + { + for (int x = 0; x < 512; x++) + { + if (resultarr2[y, x] <= 0) + returnarr[i] = 0.0000001f; + else + returnarr[i] = resultarr2[y, x]; + + i++; + } + } + + return returnarr; + } + public float[] ResizeTerrain512Interpolation(float[] heightMap) { float[] returnarr = new float[262144]; float[,] resultarr = new float[m_regionWidth,m_regionHeight]; @@ -1315,11 +1426,11 @@ namespace OpenSim.Region.Physics.OdePlugin const uint heightmapHeightSamples = 2*m_regionHeight + 2; const float scale = 1.0f; const float offset = 0.0f; - const float thickness = 2.0f; + const float thickness = 0.2f; const int wrap = 0; //Double resolution - heightMap = ResizeTerrain512(heightMap); + heightMap = ResizeTerrain512Interpolation(heightMap); for (int x = 0; x < heightmapWidthSamples; x++) { for (int y = 0; y < heightmapHeightSamples; y++) @@ -1327,7 +1438,7 @@ namespace OpenSim.Region.Physics.OdePlugin int xx = Util.Clip(x - 1, 0, 511); int yy = Util.Clip(y - 1, 0, 511); - double val = (double) heightMap[yy*512 + xx]; + float val = heightMap[yy*512 + xx]; _heightmap[x*heightmapHeightSamples + y] = val; } } @@ -1339,7 +1450,7 @@ namespace OpenSim.Region.Physics.OdePlugin d.SpaceRemove(space, LandGeom); } IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); - d.GeomHeightfieldDataBuildDouble(HeightmapData, _heightmap, 0, heightmapWidth, heightmapHeight, + d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, heightmapWidth, heightmapHeight, (int) heightmapWidthSamples, (int) heightmapHeightSamples, scale, offset, thickness, wrap); d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight); diff --git a/bin/ode.dll b/bin/ode.dll index f657c5a7ece25c216097a1920d34bea8d1cca0ed..5c1990dca4d7ce620e3de2becea5b6b215d75a5b 100644 GIT binary patch delta 18126 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