public override void SetTerrain (ITerrainChannel channel, short[] heightMap) { m_channel = channel; bool needToCreateHeightmapinODE = false; short[] _heightmap; if (!ODETerrainHeightFieldHeights.TryGetValue (RegionTerrain, out _heightmap)) { needToCreateHeightmapinODE = true;//We don't have any terrain yet, we need to generate one _heightmap = new short[((m_region.RegionSizeX + 3) * (m_region.RegionSizeY + 3))]; } int heightmapWidth = m_region.RegionSizeX + 2; int heightmapHeight = m_region.RegionSizeY + 2; int heightmapWidthSamples = m_region.RegionSizeX + 3; // + one to complete the 256m + 2 margins each side int heightmapHeightSamples = m_region.RegionSizeY + 3; float hfmin = 2000; float hfmax = -2000; for (int x = 0; x < heightmapWidthSamples; x++) { for (int y = 0; y < heightmapHeightSamples; y++) { //Some notes on this part //xx and yy are used for the original heightmap, as we are offsetting the new one by 1 // so we subtract one so that we can put the heightmap in correctly int xx = x - 1; if(xx < 0) xx = 0; if(xx > m_region.RegionSizeX - 1) xx = m_region.RegionSizeX - 1; int yy = y - 1; if (yy < 0) yy = 0; if (yy > m_region.RegionSizeY - 1) yy = m_region.RegionSizeY - 1; short val = heightMap[yy * m_region.RegionSizeX + xx]; //ODE is evil... flip x and y _heightmap[(x * heightmapHeightSamples) + y] = val; hfmin = (val < hfmin) ? val : hfmin; hfmax = (val > hfmax) ? val : hfmax; } } needToCreateHeightmapinODE = true;//ODE seems to have issues with not rebuilding :( TerrainHeightFieldHeights.Remove (RegionTerrain); TerrainHeightFieldlimits.Remove (RegionTerrain); ODETerrainHeightFieldHeights.Remove (RegionTerrain); if (RegionTerrain != IntPtr.Zero) { d.SpaceRemove (space, RegionTerrain); d.GeomDestroy (RegionTerrain); } if (!needToCreateHeightmapinODE) { TerrainHeightFieldHeights.Remove (RegionTerrain); TerrainHeightFieldlimits.Remove (RegionTerrain); ODETerrainHeightFieldHeights.Remove (RegionTerrain); float[] heighlimits = new float[2]; heighlimits[0] = hfmin; heighlimits[1] = hfmax; TerrainHeightFieldHeights.Add (RegionTerrain, heightMap); TerrainHeightFieldlimits.Add (RegionTerrain, heighlimits); ODETerrainHeightFieldHeights.Add (RegionTerrain, _heightmap); return;//If we have already done this once, we don't need to do it again } lock (OdeLock) { const float scale = (1f / (float)Constants.TerrainCompression); const float offset = 0.0f; float thickness = (float)hfmin; const int wrap = 0; IntPtr HeightmapData = d.GeomHeightfieldDataCreate (); GC.AddMemoryPressure (_heightmap.Length);//Add the memory pressure properly (note: should we be doing this since we have it in managed memory?) //Do NOT copy it! Otherwise, it'll copy the terrain into unmanaged memory where we can't release it each time d.GeomHeightfieldDataBuildShort (HeightmapData, _heightmap, 0, heightmapHeight, heightmapWidth, heightmapHeightSamples, heightmapWidthSamples, scale, offset, thickness, wrap); d.GeomHeightfieldDataSetBounds (HeightmapData, hfmin, (float)hfmax + 1.0f); RegionTerrain = d.CreateHeightfield (space, HeightmapData, 1); if (RegionTerrain != IntPtr.Zero) { d.GeomSetCategoryBits (RegionTerrain, (int)(CollisionCategories.Land)); d.GeomSetCollideBits (RegionTerrain, (int)(CollisionCategories.Space)); } NullObjectPhysicsActor terrainActor = new NullObjectPhysicsActor (); actor_name_map[RegionTerrain] = terrainActor; d.Matrix3 R = new d.Matrix3 (); Quaternion q1 = Quaternion.CreateFromAxisAngle (new Vector3 (1, 0, 0), 1.5707f); Quaternion q2 = Quaternion.CreateFromAxisAngle (new Vector3 (0, 1, 0), 1.5707f); q1 = q1 * q2; Vector3 v3; float angle; q1.GetAxisAngle (out v3, out angle); d.RFromAxisAndAngle (out R, v3.X, v3.Y, v3.Z, angle); d.GeomSetRotation (RegionTerrain, ref R); d.GeomSetPosition (RegionTerrain, (m_region.RegionSizeX * 0.5f), (m_region.RegionSizeY * 0.5f), 0); float[] heighlimits = new float[2]; heighlimits[0] = hfmin; heighlimits[1] = hfmax; TerrainHeightFieldHeights.Add (RegionTerrain, heightMap); ODETerrainHeightFieldHeights.Add (RegionTerrain, _heightmap); TerrainHeightFieldlimits.Add (RegionTerrain, heighlimits); } }
/* needs fixing if really needed public float[] ResizeTerrain512NearestNeighbor(float[] heightMap) { float[] returnarr = new float[262144]; float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y]; // Filling out the array into its multi-dimensional components for (int y = 0; y < WorldExtents.Y; y++) { for (int x = 0; x < WorldExtents.X; x++) { resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x]; } } // Resize using Nearest Neighbor // 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 < WorldExtents.Y; y++) { for (int x = 0; x < WorldExtents.X; x++) { resultarr2[y * 2, x * 2] = resultarr[y, x]; if (y < WorldExtents.Y) { resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x]; } if (x < WorldExtents.X) { resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x]; } if (x < WorldExtents.X && y < WorldExtents.Y) { 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[512, 512]; // Filling out the array into its multi-dimensional components for (int y = 0; y < Constants.RegionSize; y++) { for (int x = 0; x < Constants.RegionSize; x++) { resultarr[y, x] = heightMap[y * m_region.RegionSizeX + x]; } } // Resize using interpolation // 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_region.RegionSizeY; y++) { for (int x = 0; x < m_region.RegionSizeX; x++) { resultarr2[y * 2, x * 2] = resultarr[y, x]; if (y < m_region.RegionSizeY) { if (y + 1 < m_region.RegionSizeY) { if (x + 1 < m_region.RegionSizeX) { resultarr2[(y * 2) + 1, x * 2] = ((resultarr[y, x] + resultarr[y + 1, x] + resultarr[y, x + 1] + resultarr[y + 1, x + 1]) / 4); } else { resultarr2[(y * 2) + 1, x * 2] = ((resultarr[y, x] + resultarr[y + 1, x]) / 2); } } else { resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x]; } } if (x < m_region.RegionSizeX) { if (x + 1 < m_region.RegionSizeX) { if (y + 1 < m_region.RegionSizeY) { resultarr2[y * 2, (x * 2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] + resultarr[y, x + 1] + resultarr[y + 1, x + 1]) / 4); } else { resultarr2[y * 2, (x * 2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1]) / 2); } } else { resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x]; } } if (x < m_region.RegionSizeX && y < m_region.RegionSizeY) { if ((x + 1 < m_region.RegionSizeX) && (y + 1 < m_region.RegionSizeY)) { resultarr2[(y * 2) + 1, (x * 2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] + resultarr[y, x + 1] + resultarr[y + 1, x + 1]) / 4); } else { 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 (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x])) { m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0"); resultarr2[y, x] = 0; } returnarr[i] = resultarr2[y, x]; i++; } } return returnarr; } */ #endregion public override void SetTerrain (short[] heightMap) { short[] _heightmap; if(!ODETerrainHeightFieldHeights.TryGetValue(RegionTerrain, out _heightmap)) _heightmap = new short[((m_region.RegionSizeX + 3) * (m_region.RegionSizeY + 3))]; int heightmapWidth = m_region.RegionSizeX + 2; int heightmapHeight = m_region.RegionSizeY + 2; int heightmapWidthSamples = m_region.RegionSizeX + 3; // + one to complete the 256m + 2 margins each side int heightmapHeightSamples = m_region.RegionSizeY + 3; float hfmin = 2000; float hfmax = -2000; for (int x = 0; x < heightmapWidthSamples; x++) { for (int y = 0; y < heightmapHeightSamples; y++) { //Some notes on this part //xx and yy are used for the original heightmap, as we are offsetting the new one by 1 // so we subtract one so that we can put the heightmap in correctly int xx = Util.Clip (x - 1, 0, m_region.RegionSizeX - 1); int yy = Util.Clip (y - 1, 0, m_region.RegionSizeY - 1); short val = heightMap[yy * m_region.RegionSizeX + xx]; //ODE is evil... flip x and y _heightmap[(x * heightmapHeightSamples) + y] = val; hfmin = (val < hfmin) ? val : hfmin; hfmax = (val > hfmax) ? val : hfmax; } } lock (OdeLock) { if (RegionTerrain != IntPtr.Zero) { d.SpaceRemove (space, RegionTerrain); d.GeomDestroy (RegionTerrain); } TerrainHeightFieldHeights.Remove (RegionTerrain); ODETerrainHeightFieldHeights.Remove (RegionTerrain); TerrainHeightFieldlimits.Remove (RegionTerrain); actor_name_map.Remove (RegionTerrain); geom_name_map.Remove (RegionTerrain); const float scale = (1f / (float)Constants.TerrainCompression); const float offset = 0.0f; float thickness = (float)hfmin; const int wrap = 0; IntPtr HeightmapData = d.GeomHeightfieldDataCreate (); d.GeomHeightfieldDataBuildShort (HeightmapData, _heightmap, 0, heightmapHeight, heightmapWidth, heightmapHeightSamples, heightmapWidthSamples, scale, offset, thickness, wrap); d.GeomHeightfieldDataSetBounds (HeightmapData, hfmin, (float)hfmax + 1.0f); RegionTerrain = d.CreateHeightfield (space, HeightmapData, 1); if (RegionTerrain != IntPtr.Zero) { d.GeomSetCategoryBits (RegionTerrain, (int)(CollisionCategories.Land)); d.GeomSetCollideBits (RegionTerrain, (int)(CollisionCategories.Space)); } geom_name_map[RegionTerrain] = "Terrain"; NullObjectPhysicsActor terrainActor = new NullObjectPhysicsActor() { PhysicsActorType = (int)ActorTypes.Ground }; actor_name_map[RegionTerrain] = terrainActor; d.Matrix3 R = new d.Matrix3 (); Quaternion q1 = Quaternion.CreateFromAxisAngle (new Vector3 (1, 0, 0), 1.5707f); Quaternion q2 = Quaternion.CreateFromAxisAngle (new Vector3 (0, 1, 0), 1.5707f); q1 = q1 * q2; Vector3 v3; float angle; q1.GetAxisAngle (out v3, out angle); d.RFromAxisAndAngle (out R, v3.X, v3.Y, v3.Z, angle); d.GeomSetRotation (RegionTerrain, ref R); d.GeomSetPosition (RegionTerrain, (m_region.RegionSizeX * 0.5f), (m_region.RegionSizeY * 0.5f), 0); float[] heighlimits = new float[2]; heighlimits[0] = hfmin; heighlimits[1] = hfmax; TerrainHeightFieldHeights.Add (RegionTerrain, heightMap); ODETerrainHeightFieldHeights.Add (RegionTerrain, _heightmap); TerrainHeightFieldlimits.Add (RegionTerrain, heighlimits); } }