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). --- OpenSim/Framework/Constants.cs | 2 +- OpenSim/Framework/TerrainData.cs | 113 +++++++++++++++++++++++++++++++++++---- 2 files changed, 103 insertions(+), 12 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Constants.cs b/OpenSim/Framework/Constants.cs index 7979132..9ddb34b 100644 --- a/OpenSim/Framework/Constants.cs +++ b/OpenSim/Framework/Constants.cs @@ -40,7 +40,7 @@ namespace OpenSim.Framework public const float TerrainCompression = 100.0f; // Since terrain is stored in 16x16 heights, regions must be a multiple of this number and that is the minimum public const int MinRegionSize = 16; - public const byte TerrainPatchSize = 16; + public const int TerrainPatchSize = 16; public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f"; diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs index 8cb1aef..bee6814 100644 --- a/OpenSim/Framework/TerrainData.cs +++ b/OpenSim/Framework/TerrainData.cs @@ -44,9 +44,19 @@ namespace OpenSim.Framework // Someday terrain will have caves public abstract float this[int x, int y, int z] { get; set; } + public bool IsTainted { get; protected set; } + public abstract bool IsTaintedAt(int xx, int yy); + public abstract void ClearTaint(); + // Return a representation of this terrain for storing as a blob in the database. // Returns 'true' to say blob was stored in the 'out' locations. public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob); + + // return a special compressed representation of the heightmap in shorts + public abstract short[] GetCompressedMap(); + public abstract void SetCompressedMap(short[] cmap); + + public abstract TerrainData Clone(); } // The terrain is stored as a blob in the database with a 'revision' field. @@ -72,13 +82,23 @@ namespace OpenSim.Framework // Version of terrain that is a heightmap. // This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge // of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer. + // The heighmap is kept as an array of short integers. The integer values are converted to + // and from floats by TerrainCompressionFactor. public class HeightmapTerrainData : TerrainData { // TerrainData.this[x, y] public override float this[int x, int y] { - get { return m_heightmap[x * SizeX + y]; } - set { m_heightmap[x * SizeX + y] = value; } + get { return FromCompressedHeight(m_heightmap[x, y]); } + set { + short newVal = ToCompressedHeight(value); + if (m_heightmap[x, y] != newVal) + { + m_heightmap[x, y] = newVal; + m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true; + + } + } } // TerrainData.this[x, y, z] @@ -88,6 +108,20 @@ namespace OpenSim.Framework set { this[x, y] = value; } } + // TerrainData.ClearTaint + public override void ClearTaint() + { + IsTainted = false; + for (int ii = 0; ii < m_taint.GetLength(0); ii++) + for (int jj = 0; jj < m_taint.GetLength(1); jj++) + m_taint[ii, jj] = false; + } + + public override bool IsTaintedAt(int xx, int yy) + { + return m_taint[xx / Constants.TerrainPatchSize, yy / Constants.TerrainPatchSize]; + } + // TerrainData.GetDatabaseBlob // The user wants something to store in the database. public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob) @@ -96,7 +130,53 @@ namespace OpenSim.Framework blob = LegacyTerrainSerialization(); return false; } - private float[] m_heightmap; + + public override short[] GetCompressedMap() + { + short[] newMap = new short[SizeX * SizeY]; + + int ind = 0; + for (int xx = 0; xx < SizeX; xx++) + for (int yy = 0; yy < SizeY; yy++) + newMap[ind++] = m_heightmap[xx, yy]; + + return newMap; + + } + public override void SetCompressedMap(short[] cmap) + { + int ind = 0; + for (int xx = 0; xx < SizeX; xx++) + for (int yy = 0; yy < SizeY; yy++) + m_heightmap[xx, yy] = cmap[ind++]; + } + + // TerrainData.Clone + public override TerrainData Clone() + { + HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ); + ret.m_heightmap = (short[,])this.m_heightmap.Clone(); + return ret; + } + + // ============================================================= + + private short[,] m_heightmap; + // Remember subregions of the heightmap that has changed. + private bool[,] m_taint; + + // 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 static short ToCompressedHeight(double pHeight) + { + return (short)(pHeight * Constants.TerrainCompression); + } + + public static float FromCompressedHeight(short pHeight) + { + return ((float)pHeight) / Constants.TerrainCompression; + } // To keep with the legacy theme, this can be created with the way terrain // used to passed around as. @@ -106,26 +186,37 @@ namespace OpenSim.Framework SizeY = pTerrain.GetLength(1); SizeZ = (int)Constants.RegionHeight; - int idx = 0; - m_heightmap = new float[SizeX * SizeY]; + m_heightmap = new short[SizeX, SizeY]; for (int ii = 0; ii < SizeX; ii++) { for (int jj = 0; jj < SizeY; jj++) { - m_heightmap[idx++] = (float)pTerrain[ii, jj]; + m_heightmap[ii, jj] = ToCompressedHeight(pTerrain[ii, jj]); } } + + m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize]; + ClearTaint(); } - public HeightmapTerrainData(float[] pHeightmap, int pX, int pY, int pZ) + // Create underlying structures but don't initialize the heightmap assuming the caller will immediately do that + public HeightmapTerrainData(int pX, int pY, int pZ) { - m_heightmap = pHeightmap; SizeX = pX; SizeY = pY; SizeZ = pZ; + m_heightmap = new short[SizeX, SizeY]; + m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize]; + ClearTaint(); } + public HeightmapTerrainData(short[] cmap, int pX, int pY, int pZ) : this(pX, pY, pZ) + { + SetCompressedMap(cmap); + } + + // Just create an array of doubles. Presumes the caller implicitly knows the size. public Array LegacyTerrainSerialization() { @@ -135,12 +226,12 @@ namespace OpenSim.Framework using (BinaryWriter bw = new BinaryWriter(str)) { // TODO: COMPATIBILITY - Add byte-order conversions - for (int ii = 0; ii < m_heightmap.Length; ii++) + for (int ii = 0; ii < SizeX; ii++) + for (int jj = 0; jj < SizeY; jj++) { - double height = (double)m_heightmap[ii]; + double height = this[ii, jj]; if (height == 0.0) height = double.Epsilon; - bw.Write(height); } } -- cgit v1.1