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.cs280
1 files changed, 189 insertions, 91 deletions
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
index c0ca48e..fef93bf 100644
--- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
+++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
@@ -40,132 +40,125 @@ namespace OpenSim.Region.Framework.Scenes
40 /// </summary> 40 /// </summary>
41 public class TerrainChannel : ITerrainChannel 41 public class TerrainChannel : ITerrainChannel
42 { 42 {
43 private readonly bool[,] taint; 43 protected bool[,] m_taint;
44 private double[,] map; 44 protected short[] m_map;
45 45
46 public int Width { get; private set; } // X dimension
47 // Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y
48 public int Height { get; private set; } // Y dimension
49 public int Altitude { get; private set; } // Y dimension
50
51 // Default, not-often-used builder
46 public TerrainChannel() 52 public TerrainChannel()
47 { 53 {
48 map = new double[Constants.RegionSize, Constants.RegionSize]; 54 InitializeStructures(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight, false);
49 taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; 55 FlatLand();
50 56 // PinHeadIsland();
51 PinHeadIsland();
52 } 57 }
53 58
54 public TerrainChannel(String type) 59 // Create terrain of given size
60 public TerrainChannel(int pX, int pY)
55 { 61 {
56 map = new double[Constants.RegionSize, Constants.RegionSize]; 62 InitializeStructures((uint)pX, (uint)pY, Constants.RegionHeight, true);
57 taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; 63 }
58 64
65 // Create terrain of specified size and initialize with specified terrain.
66 // TODO: join this with the terrain initializers.
67 public TerrainChannel(String type, uint pX, uint pY, uint pZ)
68 {
69 InitializeStructures(pX, pY, pZ, false);
59 if (type.Equals("flat")) 70 if (type.Equals("flat"))
60 FlatLand(); 71 FlatLand();
61 else 72 else
62 PinHeadIsland(); 73 PinHeadIsland();
63 } 74 }
64 75
65 public TerrainChannel(double[,] import) 76 public TerrainChannel(double[,] pM, uint pH)
66 {
67 map = import;
68 taint = new bool[import.GetLength(0),import.GetLength(1)];
69 }
70
71 public TerrainChannel(bool createMap)
72 {
73 if (createMap)
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 { 77 {
82 map = new double[w,h]; 78 InitializeStructures((uint)pM.GetLength(0), (uint)pM.GetLength(1), pH, false);
83 taint = new bool[w / 16,h / 16]; 79 int idx = 0;
80 for (int ii = 0; ii < Height; ii++)
81 for (int jj = 0; jj < Width; jj++)
82 m_map[idx++] = ToCompressedHeight(pM[ii, jj]);
84 } 83 }
85 84
86 #region ITerrainChannel Members 85 #region ITerrainChannel Members
87 86
88 public int Width 87 // ITerrainChannel.MakeCopy()
88 public ITerrainChannel MakeCopy()
89 { 89 {
90 get { return map.GetLength(0); } 90 return this.Copy();
91 } 91 }
92 92
93 public int Height 93 // ITerrainChannel.GetCompressedMap()
94 public short[] GetCompressedMap()
94 { 95 {
95 get { return map.GetLength(1); } 96 return m_map;
96 } 97 }
97 98
98 public ITerrainChannel MakeCopy() 99 // ITerrainChannel.GetFloatsSerialized()
100 public float[] GetFloatsSerialised()
99 { 101 {
100 TerrainChannel copy = new TerrainChannel(false); 102 int points = Width * Height;
101 copy.map = (double[,]) map.Clone(); 103 float[] heights = new float[points];
102 104
103 return copy; 105 for (int ii = 0; ii < points; ii++)
106 heights[ii] = FromCompressedHeight(m_map[ii]);
107
108 return heights;
104 } 109 }
105 110
106 public float[] GetFloatsSerialised() 111 // ITerrainChannel.GetDoubles()
112 public double[,] GetDoubles()
107 { 113 {
108 // Move the member variables into local variables, calling
109 // member variables 256*256 times gets expensive
110 int w = Width; 114 int w = Width;
111 int h = Height; 115 int l = Height;
112 float[] heights = new float[w * h]; 116 double[,] heights = new double[w, l];
113 117
114 int i, j; // map coordinates
115 int idx = 0; // index into serialized array 118 int idx = 0; // index into serialized array
116 for (i = 0; i < h; i++) 119 for (int ii = 0; ii < l; ii++)
117 { 120 {
118 for (j = 0; j < w; j++) 121 for (int jj = 0; jj < w; jj++)
119 { 122 {
120 heights[idx++] = (float)map[j, i]; 123 heights[ii, jj] = (double)FromCompressedHeight(m_map[idx]);
124 idx++;
121 } 125 }
122 } 126 }
123 127
124 return heights; 128 return heights;
125 } 129 }
126 130
127 public double[,] GetDoubles() 131 // ITerrainChannel.this[x,y]
128 {
129 return map;
130 }
131
132 public double this[int x, int y] 132 public double this[int x, int y]
133 { 133 {
134 get { return map[x, y]; } 134 get { return m_map[x * Width + y]; }
135 set 135 set
136 { 136 {
137 // Will "fix" terrain hole problems. Although not fantastically. 137 // Will "fix" terrain hole problems. Although not fantastically.
138 if (Double.IsNaN(value) || Double.IsInfinity(value)) 138 if (Double.IsNaN(value) || Double.IsInfinity(value))
139 return; 139 return;
140 140
141 if (map[x, y] != value) 141 int idx = x * Width + y;
142 if (m_map[idx] != value)
142 { 143 {
143 taint[x / 16, y / 16] = true; 144 m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true;
144 map[x, y] = value; 145 m_map[idx] = ToCompressedHeight(value);
145 } 146 }
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 if (m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize])
152 { 154 {
153 taint[x / 16, y / 16] = false; 155 m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = false;
154 return true; 156 return true;
155 } 157 }
156 return false; 158 return false;
157 } 159 }
158 160
159 #endregion 161 // ITerrainChannel.SaveToXmlString()
160
161 public TerrainChannel Copy()
162 {
163 TerrainChannel copy = new TerrainChannel(false);
164 copy.map = (double[,]) map.Clone();
165
166 return copy;
167 }
168
169 public string SaveToXmlString() 162 public string SaveToXmlString()
170 { 163 {
171 XmlWriterSettings settings = new XmlWriterSettings(); 164 XmlWriterSettings settings = new XmlWriterSettings();
@@ -181,13 +174,7 @@ namespace OpenSim.Region.Framework.Scenes
181 } 174 }
182 } 175 }
183 176
184 private void WriteXml(XmlWriter writer) 177 // 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) 178 public void LoadFromXmlString(string data)
192 { 179 {
193 StringReader sr = new StringReader(data); 180 StringReader sr = new StringReader(data);
@@ -199,12 +186,89 @@ namespace OpenSim.Region.Framework.Scenes
199 sr.Close(); 186 sr.Close();
200 } 187 }
201 188
189 #endregion
190
191 private void InitializeStructures(uint pX, uint pY, uint pZ, bool shouldInitializeHeightmap)
192 {
193 Width = (int)pX;
194 Height = (int)pY;
195 Altitude = (int)pZ;
196 m_map = new short[Width * Height];
197 m_taint = new bool[Width / Constants.TerrainPatchSize, Height / Constants.TerrainPatchSize];
198 ClearTaint();
199 if (shouldInitializeHeightmap)
200 {
201 FlatLand();
202 }
203 }
204
205 public void ClearTaint()
206 {
207 for (int ii = 0; ii < Width / Constants.TerrainPatchSize; ii++)
208 for (int jj = 0; jj < Height / Constants.TerrainPatchSize; jj++)
209 m_taint[ii, jj] = false;
210 }
211
212 // To save space (especially for large regions), keep the height as a short integer
213 // that is coded as the float height times the compression factor (usually '100'
214 // to make for two decimal points).
215 public short ToCompressedHeight(double pHeight)
216 {
217 return (short)(pHeight * Constants.TerrainCompression);
218 }
219
220 public float FromCompressedHeight(short pHeight)
221 {
222 return ((float)pHeight) / Constants.TerrainCompression;
223 }
224
225 public TerrainChannel Copy()
226 {
227 TerrainChannel copy = new TerrainChannel();
228 copy.m_map = (short[])m_map.Clone();
229 copy.m_taint = (bool[,])m_taint.Clone();
230 copy.Width = Width;
231 copy.Height = Height;
232 copy.Altitude = Altitude;
233
234 return copy;
235 }
236
237 private void WriteXml(XmlWriter writer)
238 {
239 if (Width == Constants.RegionSize && Height == Constants.RegionSize)
240 {
241 // Downward compatibility for legacy region terrain maps.
242 // If region is exactly legacy size, return the old format XML.
243 writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
244 ToXml(writer);
245 writer.WriteEndElement();
246 }
247 else
248 {
249 // New format XML that includes width and length.
250 writer.WriteStartElement(String.Empty, "TerrainMap2", String.Empty);
251 ToXml2(writer);
252 writer.WriteEndElement();
253 }
254 }
255
202 private void ReadXml(XmlReader reader) 256 private void ReadXml(XmlReader reader)
203 { 257 {
204 reader.ReadStartElement("TerrainMap"); 258 // Check the first element. If legacy element, use the legacy reader.
205 FromXml(reader); 259 if (reader.IsStartElement("TerrainMap"))
260 {
261 reader.ReadStartElement("TerrainMap");
262 FromXml(reader);
263 }
264 else
265 {
266 reader.ReadStartElement("TerrainMap2");
267 FromXml2(reader);
268 }
206 } 269 }
207 270
271 // Write legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
208 private void ToXml(XmlWriter xmlWriter) 272 private void ToXml(XmlWriter xmlWriter)
209 { 273 {
210 float[] mapData = GetFloatsSerialised(); 274 float[] mapData = GetFloatsSerialised();
@@ -218,6 +282,7 @@ namespace OpenSim.Region.Framework.Scenes
218 serializer.Serialize(xmlWriter, buffer); 282 serializer.Serialize(xmlWriter, buffer);
219 } 283 }
220 284
285 // Read legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
221 private void FromXml(XmlReader xmlReader) 286 private void FromXml(XmlReader xmlReader)
222 { 287 {
223 XmlSerializer serializer = new XmlSerializer(typeof(byte[])); 288 XmlSerializer serializer = new XmlSerializer(typeof(byte[]));
@@ -236,35 +301,68 @@ namespace OpenSim.Region.Framework.Scenes
236 } 301 }
237 } 302 }
238 303
304 private class TerrainChannelXMLPackage
305 {
306 public int Version;
307 public int SizeX;
308 public int SizeY;
309 public int SizeZ;
310 public short[] Map;
311 public TerrainChannelXMLPackage(int pX, int pY, int pZ, short[] pMap)
312 {
313 Version = 1;
314 SizeX = pX;
315 SizeY = pY;
316 SizeZ = pZ;
317 Map = pMap;
318 }
319 }
320
321 // New terrain serialization format that includes the width and length.
322 private void ToXml2(XmlWriter xmlWriter)
323 {
324 TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_map);
325 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
326 serializer.Serialize(xmlWriter, package);
327 }
328
329 // New terrain serialization format that includes the width and length.
330 private void FromXml2(XmlReader xmlReader)
331 {
332 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
333 TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader);
334 Width = package.SizeX;
335 Height = package.SizeY;
336 Altitude = package.SizeZ;
337 m_map = package.Map;
338 }
339
340 // Fill the heightmap with the center bump terrain
239 private void PinHeadIsland() 341 private void PinHeadIsland()
240 { 342 {
241 int x; 343 int x;
242 for (x = 0; x < Constants.RegionSize; x++) 344 for (x = 0; x < Width; x++)
243 { 345 {
244 int y; 346 int y;
245 for (y = 0; y < Constants.RegionSize; y++) 347 for (y = 0; y < Height; y++)
246 { 348 {
247 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; 349 int idx = x * (int)Width + y;
248 double spherFacA = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01; 350 m_map[idx] = ToCompressedHeight(TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10);
249 double spherFacB = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001; 351 short spherFacA = ToCompressedHeight(TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01);
250 if (map[x, y] < spherFacA) 352 short spherFacB = ToCompressedHeight(TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001);
251 map[x, y] = spherFacA; 353 if (m_map[idx] < spherFacA)
252 if (map[x, y] < spherFacB) 354 m_map[idx] = spherFacA;
253 map[x, y] = spherFacB; 355 if (m_map[idx] < spherFacB)
356 m_map[idx] = spherFacB;
254 } 357 }
255 } 358 }
256 } 359 }
257 360
258 private void FlatLand() 361 private void FlatLand()
259 { 362 {
260 int x; 363 short flatHeight = ToCompressedHeight(21);
261 for (x = 0; x < Constants.RegionSize; x++) 364 for (int ii = 0; ii < m_map.Length; ii++)
262 { 365 m_map[ii] = flatHeight;
263 int y;
264 for (y = 0; y < Constants.RegionSize; y++)
265 map[x, y] = 21;
266 }
267 } 366 }
268
269 } 367 }
270} 368}