aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes')
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs28
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneManager.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs6
-rw-r--r--OpenSim/Region/Framework/Scenes/SimStatsReporter.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainChannel.cs271
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainCompressor.cs949
6 files changed, 1137 insertions, 123 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 7772f94..e2880e3 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1107,8 +1107,8 @@ namespace OpenSim.Region.Framework.Scenes
1107 if (RegionInfo.RegionHandle != otherRegion.RegionHandle) 1107 if (RegionInfo.RegionHandle != otherRegion.RegionHandle)
1108 { 1108 {
1109 // If these are cast to INT because long + negative values + abs returns invalid data 1109 // If these are cast to INT because long + negative values + abs returns invalid data
1110 int resultX = Math.Abs((int)xcell - (int)RegionInfo.RegionLocX); 1110 int resultX = Math.Abs((int)xcell - (int)RegionInfo.LegacyRegionLocX);
1111 int resultY = Math.Abs((int)ycell - (int)RegionInfo.RegionLocY); 1111 int resultY = Math.Abs((int)ycell - (int)RegionInfo.LegacyRegionLocY);
1112 if (resultX <= 1 && resultY <= 1) 1112 if (resultX <= 1 && resultY <= 1)
1113 { 1113 {
1114 // Let the grid service module know, so this can be cached 1114 // Let the grid service module know, so this can be cached
@@ -1183,8 +1183,8 @@ namespace OpenSim.Region.Framework.Scenes
1183 /// </returns> 1183 /// </returns>
1184 public int HaveNeighbor(Cardinals car, ref int[] fix) 1184 public int HaveNeighbor(Cardinals car, ref int[] fix)
1185 { 1185 {
1186 uint neighbourx = RegionInfo.RegionLocX; 1186 uint neighbourx = RegionInfo.LegacyRegionLocX;
1187 uint neighboury = RegionInfo.RegionLocY; 1187 uint neighboury = RegionInfo.LegacyRegionLocY;
1188 1188
1189 int dir = (int)car; 1189 int dir = (int)car;
1190 1190
@@ -1204,8 +1204,8 @@ namespace OpenSim.Region.Framework.Scenes
1204 1204
1205 if (neighbourRegion == null) 1205 if (neighbourRegion == null)
1206 { 1206 {
1207 fix[0] = (int)(RegionInfo.RegionLocX - neighbourx); 1207 fix[0] = (int)(RegionInfo.LegacyRegionLocX - neighbourx);
1208 fix[1] = (int)(RegionInfo.RegionLocY - neighboury); 1208 fix[1] = (int)(RegionInfo.LegacyRegionLocY - neighboury);
1209 return dir * (-1); 1209 return dir * (-1);
1210 } 1210 }
1211 else 1211 else
@@ -1905,13 +1905,13 @@ namespace OpenSim.Region.Framework.Scenes
1905 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); 1905 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
1906 1906
1907 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); 1907 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
1908 Heightmap = new TerrainChannel(m_InitialTerrain); 1908 Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
1909 1909
1910 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); 1910 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
1911 } 1911 }
1912 else 1912 else
1913 { 1913 {
1914 Heightmap = new TerrainChannel(map); 1914 Heightmap = new TerrainChannel(map, RegionInfo.RegionSizeZ);
1915 } 1915 }
1916 } 1916 }
1917 catch (IOException e) 1917 catch (IOException e)
@@ -4371,8 +4371,8 @@ namespace OpenSim.Region.Framework.Scenes
4371 { 4371 {
4372 uint rRegionX = (uint)(cAgentData.RegionHandle >> 40); 4372 uint rRegionX = (uint)(cAgentData.RegionHandle >> 40);
4373 uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8); 4373 uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8);
4374 uint tRegionX = RegionInfo.RegionLocX; 4374 uint tRegionX = RegionInfo.LegacyRegionLocX;
4375 uint tRegionY = RegionInfo.RegionLocY; 4375 uint tRegionY = RegionInfo.LegacyRegionLocY;
4376 //Send Data to ScenePresence 4376 //Send Data to ScenePresence
4377 childAgentUpdate.UpdateChildAgent(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY); 4377 childAgentUpdate.UpdateChildAgent(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
4378 // Not Implemented: 4378 // Not Implemented:
@@ -4600,13 +4600,13 @@ namespace OpenSim.Region.Framework.Scenes
4600 ScenePresence sp = GetScenePresence(remoteClient.AgentId); 4600 ScenePresence sp = GetScenePresence(remoteClient.AgentId);
4601 if (sp != null) 4601 if (sp != null)
4602 { 4602 {
4603 uint regionX = RegionInfo.RegionLocX; 4603 uint regionX = RegionInfo.LegacyRegionLocX;
4604 uint regionY = RegionInfo.RegionLocY; 4604 uint regionY = RegionInfo.LegacyRegionLocY;
4605 4605
4606 Utils.LongToUInts(regionHandle, out regionX, out regionY); 4606 Utils.LongToUInts(regionHandle, out regionX, out regionY);
4607 4607
4608 int shiftx = (int) regionX - (int) RegionInfo.RegionLocX * (int)Constants.RegionSize; 4608 int shiftx = (int) regionX - (int) RegionInfo.LegacyRegionLocX * (int)Constants.RegionSize;
4609 int shifty = (int) regionY - (int) RegionInfo.RegionLocY * (int)Constants.RegionSize; 4609 int shifty = (int) regionY - (int) RegionInfo.LegacyRegionLocY * (int)Constants.RegionSize;
4610 4610
4611 position.X += shiftx; 4611 position.X += shiftx;
4612 position.Y += shifty; 4612 position.Y += shifty;
diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs
index 28f7896..2677989 100644
--- a/OpenSim/Region/Framework/Scenes/SceneManager.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs
@@ -445,8 +445,8 @@ namespace OpenSim.Region.Framework.Scenes
445 { 445 {
446 foreach (Scene mscene in m_localScenes) 446 foreach (Scene mscene in m_localScenes)
447 { 447 {
448 if (mscene.RegionInfo.RegionLocX == locX && 448 if (mscene.RegionInfo.LegacyRegionLocX == locX &&
449 mscene.RegionInfo.RegionLocY == locY) 449 mscene.RegionInfo.LegacyRegionLocY == locY)
450 { 450 {
451 scene = mscene; 451 scene = mscene;
452 return true; 452 return true;
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 7243db1..297ee5f 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -710,7 +710,7 @@ namespace OpenSim.Region.Framework.Scenes
710 Utils.LongToUInts(handle, out x, out y); 710 Utils.LongToUInts(handle, out x, out y);
711 x = x / Constants.RegionSize; 711 x = x / Constants.RegionSize;
712 y = y / Constants.RegionSize; 712 y = y / Constants.RegionSize;
713 if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY)) 713 if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.LegacyRegionLocX, y, Scene.RegionInfo.LegacyRegionLocY))
714 { 714 {
715 old.Add(handle); 715 old.Add(handle);
716 } 716 }
@@ -2094,8 +2094,8 @@ namespace OpenSim.Region.Framework.Scenes
2094// } 2094// }
2095 2095
2096 // Get terrain height for sub-region in a megaregion if necessary 2096 // Get terrain height for sub-region in a megaregion if necessary
2097 int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X); 2097 int X = (int)((m_scene.RegionInfo.RegionWorldLocX) + pos.X);
2098 int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y); 2098 int Y = (int)((m_scene.RegionInfo.RegionWorldLocY) + pos.Y);
2099 GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y); 2099 GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y);
2100 // If X and Y is NaN, target_region will be null 2100 // If X and Y is NaN, target_region will be null
2101 if (target_region == null) 2101 if (target_region == null)
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
index 95f9caf..67998a0 100644
--- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
+++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -437,7 +437,7 @@ namespace OpenSim.Region.Framework.Scenes
437 437
438 SimStats simStats 438 SimStats simStats
439 = new SimStats( 439 = new SimStats(
440 ReportingRegion.RegionLocX, ReportingRegion.RegionLocY, regionFlags, (uint)m_objectCapacity, 440 ReportingRegion.LegacyRegionLocX, ReportingRegion.LegacyRegionLocY, regionFlags, (uint)m_objectCapacity,
441 rb, sb, m_scene.RegionInfo.originRegionID); 441 rb, sb, m_scene.RegionInfo.originRegionID);
442 442
443 handlerSendStatResult = OnSendStatsResult; 443 handlerSendStatResult = OnSendStatsResult;
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
index c0ca48e..65e890f 100644
--- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
+++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
@@ -25,14 +25,19 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using OpenSim.Framework;
29using OpenSim.Region.Framework.Interfaces;
30using System; 28using System;
29using System.IO;
31using System.Text; 30using System.Text;
31using System.Reflection;
32using System.Xml; 32using System.Xml;
33using System.IO;
34using System.Xml.Serialization; 33using System.Xml.Serialization;
35 34
35using OpenSim.Data;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38
39using log4net;
40
36namespace OpenSim.Region.Framework.Scenes 41namespace OpenSim.Region.Framework.Scenes
37{ 42{
38 /// <summary> 43 /// <summary>
@@ -40,132 +45,115 @@ namespace OpenSim.Region.Framework.Scenes
40 /// </summary> 45 /// </summary>
41 public class TerrainChannel : ITerrainChannel 46 public class TerrainChannel : ITerrainChannel
42 { 47 {
43 private readonly bool[,] taint; 48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 private double[,] map; 49 private static string LogHeader = "[TERRAIN CHANNEL]";
50
51 protected TerrainData m_terrainData;
45 52
53 public int Width { get { return m_terrainData.SizeX; } } // X dimension
54 // Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y
55 public int Height { get { return m_terrainData.SizeY; } } // Y dimension
56 public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension
57
58 // Default, not-often-used builder
46 public TerrainChannel() 59 public TerrainChannel()
47 { 60 {
48 map = new double[Constants.RegionSize, Constants.RegionSize]; 61 m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
49 taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; 62 FlatLand();
50 63 // PinHeadIsland();
51 PinHeadIsland();
52 } 64 }
53 65
54 public TerrainChannel(String type) 66 // Create terrain of given size
67 public TerrainChannel(int pX, int pY)
55 { 68 {
56 map = new double[Constants.RegionSize, Constants.RegionSize]; 69 m_terrainData = new HeightmapTerrainData(pX, pY, (int)Constants.RegionHeight);
57 taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; 70 }
58 71
72 // Create terrain of specified size and initialize with specified terrain.
73 // TODO: join this with the terrain initializers.
74 public TerrainChannel(String type, int pX, int pY, int pZ)
75 {
76 m_terrainData = new HeightmapTerrainData(pX, pY, pZ);
59 if (type.Equals("flat")) 77 if (type.Equals("flat"))
60 FlatLand(); 78 FlatLand();
61 else 79 else
62 PinHeadIsland(); 80 PinHeadIsland();
63 } 81 }
64 82
65 public TerrainChannel(double[,] import) 83 public TerrainChannel(double[,] pM, uint pAltitude)
66 {
67 map = import;
68 taint = new bool[import.GetLength(0),import.GetLength(1)];
69 }
70
71 public TerrainChannel(bool createMap)
72 { 84 {
73 if (createMap) 85 m_terrainData = new HeightmapTerrainData(pM);
74 {
75 map = new double[Constants.RegionSize,Constants.RegionSize];
76 taint = new bool[Constants.RegionSize / 16,Constants.RegionSize / 16];
77 }
78 }
79
80 public TerrainChannel(int w, int h)
81 {
82 map = new double[w,h];
83 taint = new bool[w / 16,h / 16];
84 } 86 }
85 87
86 #region ITerrainChannel Members 88 #region ITerrainChannel Members
87 89
88 public int Width 90 // ITerrainChannel.MakeCopy()
91 public ITerrainChannel MakeCopy()
89 { 92 {
90 get { return map.GetLength(0); } 93 return this.Copy();
91 } 94 }
92 95
93 public int Height 96 // ITerrainChannel.GetTerrainData()
97 public TerrainData GetTerrainData()
94 { 98 {
95 get { return map.GetLength(1); } 99 return m_terrainData;
96 } 100 }
97 101
98 public ITerrainChannel MakeCopy() 102 // ITerrainChannel.GetFloatsSerialized()
103 // NOTICE that the one dimensional form is ordered by Y!!
104 public float[] GetFloatsSerialised()
99 { 105 {
100 TerrainChannel copy = new TerrainChannel(false); 106 int points = Width * Height;
101 copy.map = (double[,]) map.Clone(); 107 float[] heights = new float[points];
102 108
103 return copy; 109 int idx = 0;
110 for (int ii = 0; ii < Height; ii++)
111 for (int jj = 0; jj < Width; jj++)
112 heights[idx++] = m_terrainData[jj, ii];
113
114 return heights;
104 } 115 }
105 116
106 public float[] GetFloatsSerialised() 117 // ITerrainChannel.GetDoubles()
118 public double[,] GetDoubles()
107 { 119 {
108 // Move the member variables into local variables, calling
109 // member variables 256*256 times gets expensive
110 int w = Width; 120 int w = Width;
111 int h = Height; 121 int l = Height;
112 float[] heights = new float[w * h]; 122 double[,] heights = new double[w, l];
113 123
114 int i, j; // map coordinates
115 int idx = 0; // index into serialized array 124 int idx = 0; // index into serialized array
116 for (i = 0; i < h; i++) 125 for (int ii = 0; ii < w; ii++)
117 { 126 {
118 for (j = 0; j < w; j++) 127 for (int jj = 0; jj < l; jj++)
119 { 128 {
120 heights[idx++] = (float)map[j, i]; 129 heights[ii, jj] = (double)m_terrainData[ii, jj];
130 idx++;
121 } 131 }
122 } 132 }
123 133
124 return heights; 134 return heights;
125 } 135 }
126 136
127 public double[,] GetDoubles() 137 // ITerrainChannel.this[x,y]
128 {
129 return map;
130 }
131
132 public double this[int x, int y] 138 public double this[int x, int y]
133 { 139 {
134 get { return map[x, y]; } 140 get { return (double)m_terrainData[x, y]; }
135 set 141 set
136 { 142 {
137 // Will "fix" terrain hole problems. Although not fantastically.
138 if (Double.IsNaN(value) || Double.IsInfinity(value)) 143 if (Double.IsNaN(value) || Double.IsInfinity(value))
139 return; 144 return;
140 145
141 if (map[x, y] != value) 146 m_terrainData[x, y] = (float)value;
142 {
143 taint[x / 16, y / 16] = true;
144 map[x, y] = value;
145 }
146 } 147 }
147 } 148 }
148 149
150 // ITerrainChannel.Tainted()
149 public bool Tainted(int x, int y) 151 public bool Tainted(int x, int y)
150 { 152 {
151 if (taint[x / 16, y / 16]) 153 return m_terrainData.IsTaintedAt(x, y);
152 {
153 taint[x / 16, y / 16] = false;
154 return true;
155 }
156 return false;
157 }
158
159 #endregion
160
161 public TerrainChannel Copy()
162 {
163 TerrainChannel copy = new TerrainChannel(false);
164 copy.map = (double[,]) map.Clone();
165
166 return copy;
167 } 154 }
168 155
156 // ITerrainChannel.SaveToXmlString()
169 public string SaveToXmlString() 157 public string SaveToXmlString()
170 { 158 {
171 XmlWriterSettings settings = new XmlWriterSettings(); 159 XmlWriterSettings settings = new XmlWriterSettings();
@@ -181,13 +169,7 @@ namespace OpenSim.Region.Framework.Scenes
181 } 169 }
182 } 170 }
183 171
184 private void WriteXml(XmlWriter writer) 172 // ITerrainChannel.LoadFromXmlString()
185 {
186 writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
187 ToXml(writer);
188 writer.WriteEndElement();
189 }
190
191 public void LoadFromXmlString(string data) 173 public void LoadFromXmlString(string data)
192 { 174 {
193 StringReader sr = new StringReader(data); 175 StringReader sr = new StringReader(data);
@@ -199,12 +181,65 @@ namespace OpenSim.Region.Framework.Scenes
199 sr.Close(); 181 sr.Close();
200 } 182 }
201 183
184 #endregion
185
186 /*
187 // To save space (especially for large regions), keep the height as a short integer
188 // that is coded as the float height times the compression factor (usually '100'
189 // to make for two decimal points).
190 public static short ToCompressedHeight(double pHeight)
191 {
192 return (short)(pHeight * Constants.TerrainCompression);
193 }
194
195 public static float FromCompressedHeight(short pHeight)
196 {
197 return ((float)pHeight) / Constants.TerrainCompression;
198 }
199 */
200
201 public TerrainChannel Copy()
202 {
203 TerrainChannel copy = new TerrainChannel();
204 copy.m_terrainData = m_terrainData.Clone();
205 return copy;
206 }
207
208 private void WriteXml(XmlWriter writer)
209 {
210 if (Width == Constants.RegionSize && Height == Constants.RegionSize)
211 {
212 // Downward compatibility for legacy region terrain maps.
213 // If region is exactly legacy size, return the old format XML.
214 writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
215 ToXml(writer);
216 writer.WriteEndElement();
217 }
218 else
219 {
220 // New format XML that includes width and length.
221 writer.WriteStartElement(String.Empty, "TerrainMap2", String.Empty);
222 ToXml2(writer);
223 writer.WriteEndElement();
224 }
225 }
226
202 private void ReadXml(XmlReader reader) 227 private void ReadXml(XmlReader reader)
203 { 228 {
204 reader.ReadStartElement("TerrainMap"); 229 // Check the first element. If legacy element, use the legacy reader.
205 FromXml(reader); 230 if (reader.IsStartElement("TerrainMap"))
231 {
232 reader.ReadStartElement("TerrainMap");
233 FromXml(reader);
234 }
235 else
236 {
237 reader.ReadStartElement("TerrainMap2");
238 FromXml2(reader);
239 }
206 } 240 }
207 241
242 // Write legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
208 private void ToXml(XmlWriter xmlWriter) 243 private void ToXml(XmlWriter xmlWriter)
209 { 244 {
210 float[] mapData = GetFloatsSerialised(); 245 float[] mapData = GetFloatsSerialised();
@@ -218,12 +253,15 @@ namespace OpenSim.Region.Framework.Scenes
218 serializer.Serialize(xmlWriter, buffer); 253 serializer.Serialize(xmlWriter, buffer);
219 } 254 }
220 255
256 // Read legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
221 private void FromXml(XmlReader xmlReader) 257 private void FromXml(XmlReader xmlReader)
222 { 258 {
223 XmlSerializer serializer = new XmlSerializer(typeof(byte[])); 259 XmlSerializer serializer = new XmlSerializer(typeof(byte[]));
224 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader); 260 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
225 int index = 0; 261 int index = 0;
226 262
263 m_terrainData = new HeightmapTerrainData(Width, Height, Altitude);
264
227 for (int y = 0; y < Height; y++) 265 for (int y = 0; y < Height; y++)
228 { 266 {
229 for (int x = 0; x < Width; x++) 267 for (int x = 0; x < Width; x++)
@@ -236,35 +274,62 @@ namespace OpenSim.Region.Framework.Scenes
236 } 274 }
237 } 275 }
238 276
277 private class TerrainChannelXMLPackage
278 {
279 public int Version;
280 public int SizeX;
281 public int SizeY;
282 public int SizeZ;
283 public short[] Map;
284 public TerrainChannelXMLPackage(int pX, int pY, int pZ, short[] pMap)
285 {
286 Version = 1;
287 SizeX = pX;
288 SizeY = pY;
289 SizeZ = pZ;
290 Map = pMap;
291 }
292 }
293
294 // New terrain serialization format that includes the width and length.
295 private void ToXml2(XmlWriter xmlWriter)
296 {
297 TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_terrainData.GetCompressedMap());
298 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
299 serializer.Serialize(xmlWriter, package);
300 }
301
302 // New terrain serialization format that includes the width and length.
303 private void FromXml2(XmlReader xmlReader)
304 {
305 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
306 TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader);
307 m_terrainData = new HeightmapTerrainData(package.Map, package.SizeX, package.SizeY, package.SizeZ);
308 }
309
310 // Fill the heightmap with the center bump terrain
239 private void PinHeadIsland() 311 private void PinHeadIsland()
240 { 312 {
241 int x; 313 for (int x = 0; x < Width; x++)
242 for (x = 0; x < Constants.RegionSize; x++)
243 { 314 {
244 int y; 315 for (int y = 0; y < Height; y++)
245 for (y = 0; y < Constants.RegionSize; y++)
246 { 316 {
247 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; 317 m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10;
248 double spherFacA = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01; 318 float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d);
249 double spherFacB = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001; 319 float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d);
250 if (map[x, y] < spherFacA) 320 if (m_terrainData[x, y]< spherFacA)
251 map[x, y] = spherFacA; 321 m_terrainData[x, y]= spherFacA;
252 if (map[x, y] < spherFacB) 322 if (m_terrainData[x, y]< spherFacB)
253 map[x, y] = spherFacB; 323 m_terrainData[x, y] = spherFacB;
254 } 324 }
255 } 325 }
256 } 326 }
257 327
258 private void FlatLand() 328 private void FlatLand()
259 { 329 {
260 int x; 330 for (int xx = 0; xx < Width; xx++)
261 for (x = 0; x < Constants.RegionSize; x++) 331 for (int yy = 0; yy < Height; yy++)
262 { 332 m_terrainData[xx, yy] = 21;
263 int y;
264 for (y = 0; y < Constants.RegionSize; y++)
265 map[x, y] = 21;
266 }
267 } 333 }
268
269 } 334 }
270} 335}
diff --git a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
new file mode 100644
index 0000000..511745d
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
@@ -0,0 +1,949 @@
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 copyright
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 */
27
28/* Freely adapted from the Aurora version of the terrain compressor.
29 * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/
30 */
31
32using System;
33using System.Reflection;
34
35using log4net;
36
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Scenes;
40
41using OpenMetaverse;
42using OpenMetaverse.Packets;
43
44namespace OpenSim.Region.ClientStack.LindenUDP
45{
46 public static class OpenSimTerrainCompressor
47 {
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49 private static string LogHeader = "[TERRAIN COMPRESSOR]";
50
51 public const int END_OF_PATCHES = 97;
52
53 private const float OO_SQRT2 = 0.7071067811865475244008443621049f;
54 private const int STRIDE = 264;
55
56 private const int ZERO_CODE = 0x0;
57 private const int ZERO_EOB = 0x2;
58 private const int POSITIVE_VALUE = 0x6;
59 private const int NEGATIVE_VALUE = 0x7;
60
61 private static readonly float[] DequantizeTable16 =
62 new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
63
64 private static readonly float[] DequantizeTable32 =
65 new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
66
67 private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
68 //private static readonly float[] CosineTable32 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize];
69 private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
70 private static readonly int[] CopyMatrix32 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
71
72 private static readonly float[] QuantizeTable16 =
73 new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
74
75 static OpenSimTerrainCompressor()
76 {
77 // Initialize the decompression tables
78 BuildDequantizeTable16();
79 SetupCosines16();
80 BuildCopyMatrix16();
81 BuildQuantizeTable16();
82 }
83
84 // Unused: left for historical reference.
85 public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, byte type, int pRegionSizeX,
86 int pRegionSizeY)
87 {
88 LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
89
90 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
91 {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
92
93 // Should be enough to fit even the most poorly packed data
94 byte[] data = new byte[patches.Length*Constants.TerrainPatchSize*Constants.TerrainPatchSize*2];
95 BitPack bitpack = new BitPack(data, 0);
96 bitpack.PackBits(header.Stride, 16);
97 bitpack.PackBits(header.PatchSize, 8);
98 bitpack.PackBits(type, 8);
99
100 foreach (TerrainPatch t in patches)
101 CreatePatch(bitpack, t.Data, t.X, t.Y, pRegionSizeX, pRegionSizeY);
102
103 bitpack.PackBits(END_OF_PATCHES, 8);
104
105 layer.LayerData.Data = new byte[bitpack.BytePos + 1];
106 Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
107
108 return layer;
109 }
110
111 // Legacy land packet generation gluing old land representation (heights) to compressed representation.
112 // This is an intermediate step in converting terrain into a variable sized heightmap. Some of the
113 // routines (like IClientAPI) only pass the float array of heights around. This entry
114 // converts that legacy representation into the more compact represenation used in
115 // TerrainChannel. Someday fix the plumbing between here and the scene.
116 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY)
117 {
118 int[] xPieces = new int[1];
119 int[] yPieces = new int[1];
120 xPieces[0] = patchX; // patch X dimension
121 yPieces[0] = patchY;
122
123 m_log.DebugFormat("{0} CreateLandPacket. patchX={1}, patchY={2}, sizeX={3}, sizeY={4}",
124 LogHeader, patchX, patchY, terrData.SizeX, terrData.SizeY);
125
126 return CreateLandPacket(terrData, xPieces, yPieces, (int)TerrainPatch.LayerType.Land);
127 }
128
129 /// <summary>
130 /// Creates a LayerData packet for compressed land data given a full
131 /// simulator heightmap and an array of indices of patches to compress
132 /// </summary>
133 /// <param name="heightmap">
134 /// A 256 * 256 array of floating point values
135 /// specifying the height at each meter in the simulator
136 /// </param>
137 /// <param name="x">
138 /// Array of indexes in the 16x16 grid of patches
139 /// for this simulator. For example if 1 and 17 are specified, patches
140 /// x=1,y=0 and x=1,y=1 are sent
141 /// </param>
142 /// <param name="y">
143 /// Array of indexes in the 16x16 grid of patches
144 /// for this simulator. For example if 1 and 17 are specified, patches
145 /// x=1,y=0 and x=1,y=1 are sent
146 /// </param>
147 /// <param name="type"></param>
148 /// <param name="pRegionSizeX"></param>
149 /// <param name="pRegionSizeY"></param>
150 /// <returns></returns>
151 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type)
152 {
153 LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
154
155 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
156 {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
157
158 byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2];
159 BitPack bitpack = new BitPack(data, 0);
160 bitpack.PackBits(header.Stride, 16);
161 bitpack.PackBits(header.PatchSize, 8);
162 bitpack.PackBits(type, 8);
163
164 for (int i = 0; i < x.Length; i++)
165 CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]);
166
167 bitpack.PackBits(END_OF_PATCHES, 8);
168
169 layer.LayerData.Data = new byte[bitpack.BytePos + 1];
170 Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
171
172 return layer;
173 }
174
175 // Unused: left for historical reference.
176 public static void CreatePatch(BitPack output, float[] patchData, int x, int y, int pRegionSizeX, int pRegionSizeY)
177 {
178 TerrainPatch.Header header = PrescanPatch(patchData);
179 header.QuantWBits = 136;
180 if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
181 {
182 header.PatchIDs = (y & 0xFFFF);
183 header.PatchIDs += (x << 16);
184 }
185 else
186 {
187 header.PatchIDs = (y & 0x1F);
188 header.PatchIDs += (x << 5);
189 }
190
191 // NOTE: No idea what prequant and postquant should be or what they do
192
193 int wbits;
194 int[] patch = CompressPatch(patchData, header, 10, out wbits);
195 wbits = EncodePatchHeader(output, header, patch, Constants.RegionSize, Constants.RegionSize, wbits);
196 EncodePatch(output, patch, 0, wbits);
197 }
198
199 /// <summary>
200 /// Add a patch of terrain to a BitPacker
201 /// </summary>
202 /// <param name="output">BitPacker to write the patch to</param>
203 /// <param name="heightmap">
204 /// Heightmap of the simulator. Presumed to be an sizeX*sizeY array.
205 /// </param>
206 /// <param name="patchX">
207 /// X offset of the patch to create.
208 /// </param>
209 /// <param name="patchY">
210 /// Y offset of the patch to create.
211 /// </param>
212 /// <param name="pRegionSizeX"></param>
213 /// <param name="pRegionSizeY"></param>
214 public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY)
215 {
216 TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY);
217 header.QuantWBits = 136;
218
219 // If larger than legacy region size, pack patch X and Y info differently.
220 if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
221 {
222 header.PatchIDs = (patchY & 0xFFFF);
223 header.PatchIDs += (patchX << 16);
224 }
225 else
226 {
227 header.PatchIDs = (patchY & 0x1F);
228 header.PatchIDs += (patchX << 5);
229 }
230
231 // NOTE: No idea what prequant and postquant should be or what they do
232 int wbits;
233 int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits);
234 wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits);
235 EncodePatch(output, patch, 0, wbits);
236 }
237
238 private static TerrainPatch.Header PrescanPatch(float[] patch)
239 {
240 TerrainPatch.Header header = new TerrainPatch.Header();
241 float zmax = -99999999.0f;
242 float zmin = 99999999.0f;
243
244 for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
245 {
246 float val = patch[i];
247 if (val > zmax) zmax = val;
248 if (val < zmin) zmin = val;
249 }
250
251 header.DCOffset = zmin;
252 header.Range = (int) ((zmax - zmin) + 1.0f);
253
254 return header;
255 }
256
257 // Scan the height info we're returning and return a patch packet header for this patch.
258 private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY)
259 {
260 TerrainPatch.Header header = new TerrainPatch.Header();
261 float zmax = -99999999.0f;
262 float zmin = 99999999.0f;
263
264 for (int j = patchY*16; j < (patchY + 1)*16; j++)
265 {
266 for (int i = patchX*16; i < (patchX + 1)*16; i++)
267 {
268 // short val = heightmap[j*pRegionSizeX + i];
269 float val = terrData[j, i];
270 if (val > zmax) zmax = val;
271 if (val < zmin) zmin = val;
272 }
273 }
274
275 // Since the the min and max values are the shorts, rescale to be real values.
276 // TODO: all this logic should go into the class wrapping the short values.
277 header.DCOffset = zmin;
278 header.Range = (int)(zmax - zmin + 1.0f);
279
280 return header;
281 }
282
283 public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack)
284 {
285 TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)};
286
287 // Quantized word bits
288 if (header.QuantWBits == END_OF_PATCHES)
289 return header;
290
291 // DC offset
292 header.DCOffset = bitpack.UnpackFloat();
293
294 // Range
295 header.Range = bitpack.UnpackBits(16);
296
297 // Patch IDs (10 bits)
298 header.PatchIDs = bitpack.UnpackBits(10);
299
300 // Word bits
301 header.WordBits = (uint) ((header.QuantWBits & 0x0f) + 2);
302
303 return header;
304 }
305
306 private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, uint pRegionSizeX,
307 uint pRegionSizeY, int wbits)
308 {
309 /*
310 int temp;
311 int wbits = (header.QuantWBits & 0x0f) + 2;
312 uint maxWbits = (uint)wbits + 5;
313 uint minWbits = ((uint)wbits >> 1);
314 int wbitsMaxValue;
315 */
316 // goal is to determ minimum number of bits to use so all data fits
317 /*
318 wbits = (int)minWbits;
319 wbitsMaxValue = (1 << wbits);
320
321 for (int i = 0; i < patch.Length; i++)
322 {
323 temp = patch[i];
324 if (temp != 0)
325 {
326 // Get the absolute value
327 if (temp < 0) temp *= -1;
328
329 no coments..
330
331 for (int j = (int)maxWbits; j > (int)minWbits; j--)
332 {
333 if ((temp & (1 << j)) != 0)
334 {
335 if (j > wbits) wbits = j;
336 break;
337 }
338 }
339
340 while (temp > wbitsMaxValue)
341 {
342 wbits++;
343 if (wbits == maxWbits)
344 goto Done;
345 wbitsMaxValue = 1 << wbits;
346 }
347 }
348 }
349
350 Done:
351
352 // wbits += 1;
353 */
354 // better check
355 if (wbits > 17)
356 wbits = 16;
357 else if (wbits < 3)
358 wbits = 3;
359
360 header.QuantWBits &= 0xf0;
361
362 header.QuantWBits |= (wbits - 2);
363
364 output.PackBits(header.QuantWBits, 8);
365 output.PackFloat(header.DCOffset);
366 output.PackBits(header.Range, 16);
367 if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
368 output.PackBits(header.PatchIDs, 32);
369 else
370 output.PackBits(header.PatchIDs, 10);
371
372 return wbits;
373 }
374
375 private static void IDCTColumn16(float[] linein, float[] lineout, int column)
376 {
377 for (int n = 0; n < Constants.TerrainPatchSize; n++)
378 {
379 float total = OO_SQRT2*linein[column];
380
381 for (int u = 1; u < Constants.TerrainPatchSize; u++)
382 {
383 int usize = u*Constants.TerrainPatchSize;
384 total += linein[usize + column]*CosineTable16[usize + n];
385 }
386
387 lineout[Constants.TerrainPatchSize*n + column] = total;
388 }
389 }
390
391 private static void IDCTLine16(float[] linein, float[] lineout, int line)
392 {
393 const float oosob = 2.0f/Constants.TerrainPatchSize;
394 int lineSize = line*Constants.TerrainPatchSize;
395
396 for (int n = 0; n < Constants.TerrainPatchSize; n++)
397 {
398 float total = OO_SQRT2*linein[lineSize];
399
400 for (int u = 1; u < Constants.TerrainPatchSize; u++)
401 {
402 total += linein[lineSize + u]*CosineTable16[u*Constants.TerrainPatchSize + n];
403 }
404
405 lineout[lineSize + n] = total*oosob;
406 }
407 }
408
409/*
410 private static void DCTLine16(float[] linein, float[] lineout, int line)
411 {
412 float total = 0.0f;
413 int lineSize = line * Constants.TerrainPatchSize;
414
415 for (int n = 0; n < Constants.TerrainPatchSize; n++)
416 {
417 total += linein[lineSize + n];
418 }
419
420 lineout[lineSize] = OO_SQRT2 * total;
421
422 int uptr = 0;
423 for (int u = 1; u < Constants.TerrainPatchSize; u++)
424 {
425 total = 0.0f;
426 uptr += Constants.TerrainPatchSize;
427
428 for (int n = 0; n < Constants.TerrainPatchSize; n++)
429 {
430 total += linein[lineSize + n] * CosineTable16[uptr + n];
431 }
432
433 lineout[lineSize + u] = total;
434 }
435 }
436*/
437
438 private static void DCTLine16(float[] linein, float[] lineout, int line)
439 {
440 // outputs transpose data (lines exchanged with coluns )
441 // so to save a bit of cpu when doing coluns
442 float total = 0.0f;
443 int lineSize = line*Constants.TerrainPatchSize;
444
445 for (int n = 0; n < Constants.TerrainPatchSize; n++)
446 {
447 total += linein[lineSize + n];
448 }
449
450 lineout[line] = OO_SQRT2*total;
451
452 for (int u = Constants.TerrainPatchSize;
453 u < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
454 u += Constants.TerrainPatchSize)
455 {
456 total = 0.0f;
457 for (int ptrn = lineSize, ptru = u; ptrn < lineSize + Constants.TerrainPatchSize; ptrn++,ptru++)
458 {
459 total += linein[ptrn]*CosineTable16[ptru];
460 }
461
462 lineout[line + u] = total;
463 }
464 }
465
466
467 /*
468 private static void DCTColumn16(float[] linein, int[] lineout, int column)
469 {
470 float total = 0.0f;
471 // const float oosob = 2.0f / Constants.TerrainPatchSize;
472
473 for (int n = 0; n < Constants.TerrainPatchSize; n++)
474 {
475 total += linein[Constants.TerrainPatchSize * n + column];
476 }
477
478 // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
479 lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * QuantizeTable16[column]);
480
481 for (int uptr = Constants.TerrainPatchSize; uptr < Constants.TerrainPatchSize * Constants.TerrainPatchSize; uptr += Constants.TerrainPatchSize)
482 {
483 total = 0.0f;
484
485 for (int n = 0; n < Constants.TerrainPatchSize; n++)
486 {
487 total += linein[Constants.TerrainPatchSize * n + column] * CosineTable16[uptr + n];
488 }
489
490 // lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
491 lineout[CopyMatrix16[uptr + column]] = (int)(total * QuantizeTable16[uptr + column]);
492 }
493 }
494 */
495
496 private static void DCTColumn16(float[] linein, int[] lineout, int column)
497 {
498 // input columns are in fact stored in lines now
499
500 float total = 0.0f;
501// const float oosob = 2.0f / Constants.TerrainPatchSize;
502 int inlinesptr = Constants.TerrainPatchSize*column;
503
504 for (int n = 0; n < Constants.TerrainPatchSize; n++)
505 {
506 total += linein[inlinesptr + n];
507 }
508
509 // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
510 lineout[CopyMatrix16[column]] = (int) (OO_SQRT2*total*QuantizeTable16[column]);
511
512 for (int uptr = Constants.TerrainPatchSize;
513 uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
514 uptr += Constants.TerrainPatchSize)
515 {
516 total = 0.0f;
517
518 for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
519 {
520 total += linein[n]*CosineTable16[ptru];
521 }
522
523// lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
524 lineout[CopyMatrix16[uptr + column]] = (int) (total*QuantizeTable16[uptr + column]);
525 }
526 }
527
528 private static int DCTColumn16Wbits(float[] linein, int[] lineout, int column, int wbits, int maxwbits)
529 {
530 // input columns are in fact stored in lines now
531
532 bool dowbits = wbits != maxwbits;
533 int wbitsMaxValue = 1 << wbits;
534
535 float total = 0.0f;
536 // const float oosob = 2.0f / Constants.TerrainPatchSize;
537 int inlinesptr = Constants.TerrainPatchSize*column;
538
539 for (int n = 0; n < Constants.TerrainPatchSize; n++)
540 {
541 total += linein[inlinesptr + n];
542 }
543
544 // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
545 int tmp = (int) (OO_SQRT2*total*QuantizeTable16[column]);
546 lineout[CopyMatrix16[column]] = tmp;
547
548 if (dowbits)
549 {
550 if (tmp < 0) tmp *= -1;
551 while (tmp > wbitsMaxValue)
552 {
553 wbits++;
554 wbitsMaxValue = 1 << wbits;
555 if (wbits == maxwbits)
556 {
557 dowbits = false;
558 break;
559 }
560 }
561 }
562
563 for (int uptr = Constants.TerrainPatchSize;
564 uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
565 uptr += Constants.TerrainPatchSize)
566 {
567 total = 0.0f;
568
569 for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
570 {
571 total += linein[n]*CosineTable16[ptru];
572 }
573
574 tmp = (int) (total*QuantizeTable16[uptr + column]);
575 lineout[CopyMatrix16[uptr + column]] = tmp;
576
577 if (dowbits)
578 {
579 if (tmp < 0) tmp *= -1;
580 while (tmp > wbitsMaxValue)
581 {
582 wbits++;
583 wbitsMaxValue = 1 << wbits;
584 if (wbits == maxwbits)
585 {
586 dowbits = false;
587 break;
588 }
589 }
590 }
591 }
592 return wbits;
593 }
594
595 public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size)
596 {
597 for (int n = 0; n < size*size; n++)
598 {
599 // ?
600 int temp = bitpack.UnpackBits(1);
601 if (temp != 0)
602 {
603 // Value or EOB
604 temp = bitpack.UnpackBits(1);
605 if (temp != 0)
606 {
607 // Value
608 temp = bitpack.UnpackBits(1);
609 if (temp != 0)
610 {
611 // Negative
612 temp = bitpack.UnpackBits((int) header.WordBits);
613 patches[n] = temp*-1;
614 }
615 else
616 {
617 // Positive
618 temp = bitpack.UnpackBits((int) header.WordBits);
619 patches[n] = temp;
620 }
621 }
622 else
623 {
624 // Set the rest to zero
625 // TODO: This might not be necessary
626 for (int o = n; o < size*size; o++)
627 {
628 patches[o] = 0;
629 }
630 break;
631 }
632 }
633 else
634 {
635 patches[n] = 0;
636 }
637 }
638 }
639
640 private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits)
641 {
642 int maxwbitssize = (1 << wbits) - 1;
643
644 if (postquant > Constants.TerrainPatchSize*Constants.TerrainPatchSize || postquant < 0)
645 {
646 Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error);
647 return;
648 }
649
650 if (postquant != 0) patch[Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant] = 0;
651
652 for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
653 {
654 int temp = patch[i];
655
656 if (temp == 0)
657 {
658 bool eob = true;
659
660 for (int j = i; j < Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant; j++)
661 {
662 if (patch[j] != 0)
663 {
664 eob = false;
665 break;
666 }
667 }
668
669 if (eob)
670 {
671 output.PackBits(ZERO_EOB, 2);
672 return;
673 }
674 output.PackBits(ZERO_CODE, 1);
675 }
676 else
677 {
678 if (temp < 0)
679 {
680 temp *= -1;
681
682 if (temp > maxwbitssize) temp = maxwbitssize;
683
684 output.PackBits(NEGATIVE_VALUE, 3);
685 output.PackBits(temp, wbits);
686 }
687 else
688 {
689 if (temp > maxwbitssize) temp = maxwbitssize;
690
691 output.PackBits(POSITIVE_VALUE, 3);
692 output.PackBits(temp, wbits);
693 }
694 }
695 }
696 }
697
698 public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group)
699 {
700 float[] block = new float[group.PatchSize*group.PatchSize];
701 float[] output = new float[group.PatchSize*group.PatchSize];
702 int prequant = (header.QuantWBits >> 4) + 2;
703 int quantize = 1 << prequant;
704 float ooq = 1.0f/quantize;
705 float mult = ooq*header.Range;
706 float addval = mult*(1 << (prequant - 1)) + header.DCOffset;
707
708 if (group.PatchSize == Constants.TerrainPatchSize)
709 {
710 for (int n = 0; n < Constants.TerrainPatchSize*Constants.TerrainPatchSize; n++)
711 {
712 block[n] = patches[CopyMatrix16[n]]*DequantizeTable16[n];
713 }
714
715 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
716
717 for (int o = 0; o < Constants.TerrainPatchSize; o++)
718 IDCTColumn16(block, ftemp, o);
719 for (int o = 0; o < Constants.TerrainPatchSize; o++)
720 IDCTLine16(ftemp, block, o);
721 }
722 else
723 {
724 for (int n = 0; n < Constants.TerrainPatchSize*2*Constants.TerrainPatchSize*2; n++)
725 {
726 block[n] = patches[CopyMatrix32[n]]*DequantizeTable32[n];
727 }
728
729 Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error);
730 }
731
732 for (int j = 0; j < block.Length; j++)
733 {
734 output[j] = block[j]*mult + addval;
735 }
736
737 return output;
738 }
739
740 private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits)
741 {
742 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
743 int wordsize = (prequant - 2) & 0x0f;
744 float oozrange = 1.0f/header.Range;
745 float range = (1 << prequant);
746 float premult = oozrange*range;
747 float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
748
749 header.QuantWBits = wordsize;
750 header.QuantWBits |= wordsize << 4;
751
752 int k = 0;
753 for (int j = 0; j < Constants.TerrainPatchSize; j++)
754 {
755 for (int i = 0; i < Constants.TerrainPatchSize; i++)
756 block[k++] = patchData[j*Constants.TerrainPatchSize + i]*premult - sub;
757 }
758
759 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
760 int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
761
762
763 int maxWbits = prequant + 5;
764 wbits = (prequant >> 1);
765
766 for (int o = 0; o < Constants.TerrainPatchSize; o++)
767 DCTLine16(block, ftemp, o);
768 for (int o = 0; o < Constants.TerrainPatchSize; o++)
769 wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
770
771 return itemp;
772 }
773
774 private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant, out int wbits)
775 {
776 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
777 float oozrange = 1.0f/header.Range;
778 float range = (1 << prequant);
779 float premult = oozrange*range;
780 float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
781 int wordsize = (prequant - 2) & 0x0f;
782
783 header.QuantWBits = wordsize;
784 header.QuantWBits |= wordsize << 4;
785
786 int k = 0;
787 for (int j = 0; j < Constants.TerrainPatchSize; j++)
788 {
789 for (int i = 0; i < Constants.TerrainPatchSize; i++)
790 block[k++] = patchData[j, i]*premult - sub;
791 }
792
793 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
794 int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
795
796 int maxWbits = prequant + 5;
797 wbits = (prequant >> 1);
798
799 for (int o = 0; o < Constants.TerrainPatchSize; o++)
800 DCTLine16(block, ftemp, o);
801 for (int o = 0; o < Constants.TerrainPatchSize; o++)
802 wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
803
804 return itemp;
805 }
806
807 private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header,
808 int prequant, out int wbits)
809 {
810 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
811 int wordsize = prequant;
812 float oozrange = 1.0f/header.Range;
813 float range = (1 << prequant);
814 float premult = oozrange*range;
815 float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
816
817 header.QuantWBits = wordsize - 2;
818 header.QuantWBits |= (prequant - 2) << 4;
819
820 int k = 0;
821
822 int jPatchLimit = patchY;
823 if (patchY >= (terrData.SizeY / Constants.TerrainPatchSize))
824 {
825 jPatchLimit = (int)(terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize;
826 }
827 jPatchLimit = (jPatchLimit + 1) * Constants.TerrainPatchSize;
828
829 int iPatchLimit = patchX;
830 if (patchX >= (terrData.SizeX / Constants.TerrainPatchSize))
831 {
832 iPatchLimit = (int)(terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize;
833 }
834 iPatchLimit = (iPatchLimit + 1) * Constants.TerrainPatchSize;
835
836 for (int j = patchY * Constants.TerrainPatchSize; j < jPatchLimit; j++)
837 {
838 for (int i = patchX * Constants.TerrainPatchSize; i < iPatchLimit; i++)
839 {
840 // block[k++] = (heightmap[j*pRegionSizeX + i])*premult - sub;
841 block[k++] = terrData[j, i] - sub;
842 }
843 }
844
845 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
846 int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
847
848 int maxWbits = prequant + 5;
849 wbits = (prequant >> 1);
850
851 for (int o = 0; o < Constants.TerrainPatchSize; o++)
852 DCTLine16(block, ftemp, o);
853 for (int o = 0; o < Constants.TerrainPatchSize; o++)
854 wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
855
856 return itemp;
857 }
858
859 #region Initialization
860
861 private static void BuildDequantizeTable16()
862 {
863 for (int j = 0; j < Constants.TerrainPatchSize; j++)
864 {
865 for (int i = 0; i < Constants.TerrainPatchSize; i++)
866 {
867 DequantizeTable16[j*Constants.TerrainPatchSize + i] = 1.0f + 2.0f*(i + j);
868 }
869 }
870 }
871
872 private static void BuildQuantizeTable16()
873 {
874 const float oosob = 2.0f/Constants.TerrainPatchSize;
875 for (int j = 0; j < Constants.TerrainPatchSize; j++)
876 {
877 for (int i = 0; i < Constants.TerrainPatchSize; i++)
878 {
879// QuantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j));
880 QuantizeTable16[j*Constants.TerrainPatchSize + i] = oosob/(1.0f + 2.0f*(i + (float) j));
881 }
882 }
883 }
884
885 private static void SetupCosines16()
886 {
887 const float hposz = (float) Math.PI*0.5f/Constants.TerrainPatchSize;
888
889 for (int u = 0; u < Constants.TerrainPatchSize; u++)
890 {
891 for (int n = 0; n < Constants.TerrainPatchSize; n++)
892 {
893 CosineTable16[u*Constants.TerrainPatchSize + n] = (float) Math.Cos((2.0f*n + 1.0f)*u*hposz);
894 }
895 }
896 }
897
898 private static void BuildCopyMatrix16()
899 {
900 bool diag = false;
901 bool right = true;
902 int i = 0;
903 int j = 0;
904 int count = 0;
905
906 while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize)
907 {
908 CopyMatrix16[j*Constants.TerrainPatchSize + i] = count++;
909
910 if (!diag)
911 {
912 if (right)
913 {
914 if (i < Constants.TerrainPatchSize - 1) i++;
915 else j++;
916
917 right = false;
918 diag = true;
919 }
920 else
921 {
922 if (j < Constants.TerrainPatchSize - 1) j++;
923 else i++;
924
925 right = true;
926 diag = true;
927 }
928 }
929 else
930 {
931 if (right)
932 {
933 i++;
934 j--;
935 if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false;
936 }
937 else
938 {
939 i--;
940 j++;
941 if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false;
942 }
943 }
944 }
945 }
946
947 #endregion Initialization
948 }
949} \ No newline at end of file