aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/TerrainChannel.cs')
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainChannel.cs271
1 files changed, 168 insertions, 103 deletions
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}