From 7416809077227f35ab70ed44060e51f2bcf66937 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Wed, 2 Oct 2013 16:59:37 -0700
Subject: varregion: plug in TerrainData class and modify TerrainModule and
LLClientView to use same. This passes a terrain info class around rather than
passing a one dimensional array thus allowing variable regions. Update the
database storage for variable region sizes. This should be downward
compatible (same format for 256x256 regions).
---
.../Framework/Interfaces/ISimulationDataStore.cs | 20 ---
.../Region/Framework/Interfaces/ITerrainChannel.cs | 12 +-
OpenSim/Region/Framework/Scenes/Scene.cs | 2 +-
OpenSim/Region/Framework/Scenes/TerrainChannel.cs | 145 ++++++++-------------
.../Region/Framework/Scenes/TerrainCompressor.cs | 59 ++++-----
5 files changed, 90 insertions(+), 148 deletions(-)
(limited to 'OpenSim/Region/Framework')
diff --git a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs
index 847d245..5ba5b31 100644
--- a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs
+++ b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs
@@ -136,24 +136,4 @@ namespace OpenSim.Region.Framework.Interfaces
void Shutdown();
}
- // The terrain is stored as a blob in the database with a 'revision' field.
- // Some implementations of terrain storage would fill the revision field with
- // the time the terrain was stored. When real revisions were added and this
- // feature removed, that left some old entries with the time in the revision
- // field.
- // Thus, if revision is greater than 'RevisionHigh' then terrain db entry is
- // left over and it is presumed to be 'Legacy256'.
- // Numbers are arbitrary and are chosen to to reduce possible mis-interpretation.
- // If a revision does not match any of these, it is assumed to be Legacy256.
- public enum DBTerrainRevision
- {
- // Terrain is 'double[256,256]'
- Legacy256 = 11,
- // Terrain is 'int32, int32, float[,]' where the shorts are X and Y dimensions
- // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
- Variable2D = 22,
- // A revision that is not listed above or any revision greater than this value is 'Legacy256'.
- RevisionHigh = 1234
- }
-
}
diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs
index 3c060a4..cc8a236 100644
--- a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs
+++ b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs
@@ -25,6 +25,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+using OpenSim.Framework;
+
namespace OpenSim.Region.Framework.Interfaces
{
public interface ITerrainChannel
@@ -35,18 +37,20 @@ namespace OpenSim.Region.Framework.Interfaces
double this[int x, int y] { get; set; }
+ // Return the packaged terrain data for passing into lower levels of communication
+ TerrainData GetTerrainData();
+
///
/// Squash the entire heightmap into a single dimensioned array
///
///
float[] GetFloatsSerialised();
- // Get version of map as a single dimensioned array and each value compressed
- // into an int (compressedHeight = (int)(floatHeight * Constants.TerrainCompression);)
- // This is done to make the map smaller as it can get pretty larger for variable sized regions.
- short[] GetCompressedMap();
double[,] GetDoubles();
+
+ // Check if a location has been updated. Clears the taint flag as a side effect.
bool Tainted(int x, int y);
+
ITerrainChannel MakeCopy();
string SaveToXmlString();
void LoadFromXmlString(string data);
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 49e32c6..e2880e3 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1905,7 +1905,7 @@ namespace OpenSim.Region.Framework.Scenes
m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
- Heightmap = new TerrainChannel(m_InitialTerrain, RegionInfo.RegionSizeX, RegionInfo.RegionSizeY, RegionInfo.RegionSizeZ);
+ Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
}
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
index fef93bf..65e890f 100644
--- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
+++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
@@ -25,14 +25,19 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-using OpenSim.Framework;
-using OpenSim.Region.Framework.Interfaces;
using System;
+using System.IO;
using System.Text;
+using System.Reflection;
using System.Xml;
-using System.IO;
using System.Xml.Serialization;
+using OpenSim.Data;
+using OpenSim.Framework;
+using OpenSim.Region.Framework.Interfaces;
+
+using log4net;
+
namespace OpenSim.Region.Framework.Scenes
{
///
@@ -40,18 +45,20 @@ namespace OpenSim.Region.Framework.Scenes
///
public class TerrainChannel : ITerrainChannel
{
- protected bool[,] m_taint;
- protected short[] m_map;
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private static string LogHeader = "[TERRAIN CHANNEL]";
- public int Width { get; private set; } // X dimension
+ protected TerrainData m_terrainData;
+
+ public int Width { get { return m_terrainData.SizeX; } } // X dimension
// Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y
- public int Height { get; private set; } // Y dimension
- public int Altitude { get; private set; } // Y dimension
+ public int Height { get { return m_terrainData.SizeY; } } // Y dimension
+ public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension
// Default, not-often-used builder
public TerrainChannel()
{
- InitializeStructures(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight, false);
+ m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
FlatLand();
// PinHeadIsland();
}
@@ -59,27 +66,23 @@ namespace OpenSim.Region.Framework.Scenes
// Create terrain of given size
public TerrainChannel(int pX, int pY)
{
- InitializeStructures((uint)pX, (uint)pY, Constants.RegionHeight, true);
+ m_terrainData = new HeightmapTerrainData(pX, pY, (int)Constants.RegionHeight);
}
// Create terrain of specified size and initialize with specified terrain.
// TODO: join this with the terrain initializers.
- public TerrainChannel(String type, uint pX, uint pY, uint pZ)
+ public TerrainChannel(String type, int pX, int pY, int pZ)
{
- InitializeStructures(pX, pY, pZ, false);
+ m_terrainData = new HeightmapTerrainData(pX, pY, pZ);
if (type.Equals("flat"))
FlatLand();
else
PinHeadIsland();
}
- public TerrainChannel(double[,] pM, uint pH)
+ public TerrainChannel(double[,] pM, uint pAltitude)
{
- InitializeStructures((uint)pM.GetLength(0), (uint)pM.GetLength(1), pH, false);
- int idx = 0;
- for (int ii = 0; ii < Height; ii++)
- for (int jj = 0; jj < Width; jj++)
- m_map[idx++] = ToCompressedHeight(pM[ii, jj]);
+ m_terrainData = new HeightmapTerrainData(pM);
}
#region ITerrainChannel Members
@@ -90,20 +93,23 @@ namespace OpenSim.Region.Framework.Scenes
return this.Copy();
}
- // ITerrainChannel.GetCompressedMap()
- public short[] GetCompressedMap()
+ // ITerrainChannel.GetTerrainData()
+ public TerrainData GetTerrainData()
{
- return m_map;
+ return m_terrainData;
}
// ITerrainChannel.GetFloatsSerialized()
+ // NOTICE that the one dimensional form is ordered by Y!!
public float[] GetFloatsSerialised()
{
int points = Width * Height;
float[] heights = new float[points];
- for (int ii = 0; ii < points; ii++)
- heights[ii] = FromCompressedHeight(m_map[ii]);
+ int idx = 0;
+ for (int ii = 0; ii < Height; ii++)
+ for (int jj = 0; jj < Width; jj++)
+ heights[idx++] = m_terrainData[jj, ii];
return heights;
}
@@ -116,11 +122,11 @@ namespace OpenSim.Region.Framework.Scenes
double[,] heights = new double[w, l];
int idx = 0; // index into serialized array
- for (int ii = 0; ii < l; ii++)
+ for (int ii = 0; ii < w; ii++)
{
- for (int jj = 0; jj < w; jj++)
+ for (int jj = 0; jj < l; jj++)
{
- heights[ii, jj] = (double)FromCompressedHeight(m_map[idx]);
+ heights[ii, jj] = (double)m_terrainData[ii, jj];
idx++;
}
}
@@ -131,31 +137,20 @@ namespace OpenSim.Region.Framework.Scenes
// ITerrainChannel.this[x,y]
public double this[int x, int y]
{
- get { return m_map[x * Width + y]; }
+ get { return (double)m_terrainData[x, y]; }
set
{
- // Will "fix" terrain hole problems. Although not fantastically.
if (Double.IsNaN(value) || Double.IsInfinity(value))
return;
- int idx = x * Width + y;
- if (m_map[idx] != value)
- {
- m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true;
- m_map[idx] = ToCompressedHeight(value);
- }
+ m_terrainData[x, y] = (float)value;
}
}
// ITerrainChannel.Tainted()
public bool Tainted(int x, int y)
{
- if (m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize])
- {
- m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = false;
- return true;
- }
- return false;
+ return m_terrainData.IsTaintedAt(x, y);
}
// ITerrainChannel.SaveToXmlString()
@@ -188,49 +183,25 @@ namespace OpenSim.Region.Framework.Scenes
#endregion
- private void InitializeStructures(uint pX, uint pY, uint pZ, bool shouldInitializeHeightmap)
- {
- Width = (int)pX;
- Height = (int)pY;
- Altitude = (int)pZ;
- m_map = new short[Width * Height];
- m_taint = new bool[Width / Constants.TerrainPatchSize, Height / Constants.TerrainPatchSize];
- ClearTaint();
- if (shouldInitializeHeightmap)
- {
- FlatLand();
- }
- }
-
- public void ClearTaint()
- {
- for (int ii = 0; ii < Width / Constants.TerrainPatchSize; ii++)
- for (int jj = 0; jj < Height / Constants.TerrainPatchSize; jj++)
- m_taint[ii, jj] = false;
- }
-
+ /*
// To save space (especially for large regions), keep the height as a short integer
// that is coded as the float height times the compression factor (usually '100'
// to make for two decimal points).
- public short ToCompressedHeight(double pHeight)
+ public static short ToCompressedHeight(double pHeight)
{
return (short)(pHeight * Constants.TerrainCompression);
}
- public float FromCompressedHeight(short pHeight)
+ public static float FromCompressedHeight(short pHeight)
{
return ((float)pHeight) / Constants.TerrainCompression;
}
+ */
public TerrainChannel Copy()
{
TerrainChannel copy = new TerrainChannel();
- copy.m_map = (short[])m_map.Clone();
- copy.m_taint = (bool[,])m_taint.Clone();
- copy.Width = Width;
- copy.Height = Height;
- copy.Altitude = Altitude;
-
+ copy.m_terrainData = m_terrainData.Clone();
return copy;
}
@@ -289,6 +260,8 @@ namespace OpenSim.Region.Framework.Scenes
byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
int index = 0;
+ m_terrainData = new HeightmapTerrainData(Width, Height, Altitude);
+
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
@@ -321,7 +294,7 @@ namespace OpenSim.Region.Framework.Scenes
// New terrain serialization format that includes the width and length.
private void ToXml2(XmlWriter xmlWriter)
{
- TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_map);
+ TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_terrainData.GetCompressedMap());
XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
serializer.Serialize(xmlWriter, package);
}
@@ -331,38 +304,32 @@ namespace OpenSim.Region.Framework.Scenes
{
XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader);
- Width = package.SizeX;
- Height = package.SizeY;
- Altitude = package.SizeZ;
- m_map = package.Map;
+ m_terrainData = new HeightmapTerrainData(package.Map, package.SizeX, package.SizeY, package.SizeZ);
}
// Fill the heightmap with the center bump terrain
private void PinHeadIsland()
{
- int x;
- for (x = 0; x < Width; x++)
+ for (int x = 0; x < Width; x++)
{
- int y;
- for (y = 0; y < Height; y++)
+ for (int y = 0; y < Height; y++)
{
- int idx = x * (int)Width + y;
- m_map[idx] = ToCompressedHeight(TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10);
- short spherFacA = ToCompressedHeight(TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01);
- short spherFacB = ToCompressedHeight(TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001);
- if (m_map[idx] < spherFacA)
- m_map[idx] = spherFacA;
- if (m_map[idx] < spherFacB)
- m_map[idx] = spherFacB;
+ m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10;
+ float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d);
+ float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d);
+ if (m_terrainData[x, y]< spherFacA)
+ m_terrainData[x, y]= spherFacA;
+ if (m_terrainData[x, y]< spherFacB)
+ m_terrainData[x, y] = spherFacB;
}
}
}
private void FlatLand()
{
- short flatHeight = ToCompressedHeight(21);
- for (int ii = 0; ii < m_map.Length; ii++)
- m_map[ii] = flatHeight;
+ for (int xx = 0; xx < Width; xx++)
+ for (int yy = 0; yy < Height; yy++)
+ m_terrainData[xx, yy] = 21;
}
}
}
diff --git a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
index 2e856bc..511745d 100644
--- a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
+++ b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
@@ -113,22 +113,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// routines (like IClientAPI) only pass the float array of heights around. This entry
// converts that legacy representation into the more compact represenation used in
// TerrainChannel. Someday fix the plumbing between here and the scene.
- public static LayerDataPacket CreateLandPacket(float[] heightmap, int patchX, int patchY, uint sizeX, uint sizeY)
+ public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY)
{
int[] xPieces = new int[1];
int[] yPieces = new int[1];
-
- short[] newmap = new short[heightmap.Length];
- for (int ii = 0; ii < heightmap.Length; ii++)
- newmap[ii] = TerrainChannel.ToCompressedHeight(heightmap[ii]);
-
xPieces[0] = patchX; // patch X dimension
yPieces[0] = patchY;
m_log.DebugFormat("{0} CreateLandPacket. patchX={1}, patchY={2}, sizeX={3}, sizeY={4}",
- LogHeader, patchX, patchY, sizeX, sizeY);
+ LogHeader, patchX, patchY, terrData.SizeX, terrData.SizeY);
- return CreateLandPacket(newmap, xPieces, yPieces, (int)TerrainPatch.LayerType.Land, sizeX, sizeY);
+ return CreateLandPacket(terrData, xPieces, yPieces, (int)TerrainPatch.LayerType.Land);
}
///
@@ -153,8 +148,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
///
///
///
- public static LayerDataPacket CreateLandPacket(short[] heightmap, int[] x, int[] y, byte type,
- uint pRegionSizeX, uint pRegionSizeY)
+ public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type)
{
LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
@@ -168,7 +162,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
bitpack.PackBits(type, 8);
for (int i = 0; i < x.Length; i++)
- CreatePatchFromHeightmap(bitpack, heightmap, x[i], y[i], pRegionSizeX, pRegionSizeY);
+ CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]);
bitpack.PackBits(END_OF_PATCHES, 8);
@@ -217,14 +211,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
///
///
///
- public static void CreatePatchFromHeightmap(BitPack output, short[] heightmap, int patchX, int patchY,
- uint pRegionSizeX, uint pRegionSizeY)
+ public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY)
{
- TerrainPatch.Header header = PrescanPatch(heightmap, patchX, patchY, pRegionSizeX, pRegionSizeY);
+ TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY);
header.QuantWBits = 136;
// If larger than legacy region size, pack patch X and Y info differently.
- if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
+ if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
{
header.PatchIDs = (patchY & 0xFFFF);
header.PatchIDs += (patchX << 16);
@@ -237,8 +230,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// NOTE: No idea what prequant and postquant should be or what they do
int wbits;
- int[] patch = CompressPatch(heightmap, patchX, patchY, header, 10, pRegionSizeX, pRegionSizeY, out wbits);
- wbits = EncodePatchHeader(output, header, patch, pRegionSizeX, pRegionSizeY, wbits);
+ int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits);
+ wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits);
EncodePatch(output, patch, 0, wbits);
}
@@ -262,19 +255,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
// Scan the height info we're returning and return a patch packet header for this patch.
- // TODO. Why are patches ordered Y,X rather than X,Y?
- private static TerrainPatch.Header PrescanPatch(short[] heightmap, int patchX, int patchY,
- uint pRegionSizeX, uint pRegionSizeY)
+ private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY)
{
TerrainPatch.Header header = new TerrainPatch.Header();
- short zmax = -32767;
- short zmin = 32767;
+ float zmax = -99999999.0f;
+ float zmin = 99999999.0f;
for (int j = patchY*16; j < (patchY + 1)*16; j++)
{
for (int i = patchX*16; i < (patchX + 1)*16; i++)
{
- short val = heightmap[j*pRegionSizeX + i];
+ // short val = heightmap[j*pRegionSizeX + i];
+ float val = terrData[j, i];
if (val > zmax) zmax = val;
if (val < zmin) zmin = val;
}
@@ -282,8 +274,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Since the the min and max values are the shorts, rescale to be real values.
// TODO: all this logic should go into the class wrapping the short values.
- header.DCOffset = TerrainChannel.FromCompressedHeight(zmin);
- header.Range = (int)(TerrainChannel.FromCompressedHeight(zmax) - TerrainChannel.FromCompressedHeight(zmin) + 1.0f);
+ header.DCOffset = zmin;
+ header.Range = (int)(zmax - zmin + 1.0f);
return header;
}
@@ -812,8 +804,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return itemp;
}
- private static int[] CompressPatch(short[] heightmap, int patchX, int patchY, TerrainPatch.Header header,
- int prequant, uint pRegionSizeX, uint pRegionSizeY, out int wbits)
+ private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header,
+ int prequant, out int wbits)
{
float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
int wordsize = prequant;
@@ -827,19 +819,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
int k = 0;
- premult /= Constants.TerrainCompression; // put here short to float factor
-
int jPatchLimit = patchY;
- if (patchY >= (pRegionSizeY / Constants.TerrainPatchSize))
+ if (patchY >= (terrData.SizeY / Constants.TerrainPatchSize))
{
- jPatchLimit = (int)(pRegionSizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize;
+ jPatchLimit = (int)(terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize;
}
jPatchLimit = (jPatchLimit + 1) * Constants.TerrainPatchSize;
int iPatchLimit = patchX;
- if (patchX >= (pRegionSizeX / Constants.TerrainPatchSize))
+ if (patchX >= (terrData.SizeX / Constants.TerrainPatchSize))
{
- iPatchLimit = (int)(pRegionSizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize;
+ iPatchLimit = (int)(terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize;
}
iPatchLimit = (iPatchLimit + 1) * Constants.TerrainPatchSize;
@@ -847,7 +837,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
for (int i = patchX * Constants.TerrainPatchSize; i < iPatchLimit; i++)
{
- block[k++] = (heightmap[j*pRegionSizeX + i])*premult - sub;
+ // block[k++] = (heightmap[j*pRegionSizeX + i])*premult - sub;
+ block[k++] = terrData[j, i] - sub;
}
}
--
cgit v1.1