aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes
diff options
context:
space:
mode:
authorRobert Adams2015-03-27 19:32:50 -0700
committerRobert Adams2015-03-27 19:32:50 -0700
commitbedafb8fae9898ef0c5fc6470236ee7244e616a9 (patch)
tree618728d92dad56dd587c243892d966b9ff9ea89b /OpenSim/Region/Framework/Scenes
parentvarregion: restore checkAgentAccessToRegion routine in EntityTransferModule. (diff)
downloadopensim-SC-bedafb8fae9898ef0c5fc6470236ee7244e616a9.zip
opensim-SC-bedafb8fae9898ef0c5fc6470236ee7244e616a9.tar.gz
opensim-SC-bedafb8fae9898ef0c5fc6470236ee7244e616a9.tar.bz2
opensim-SC-bedafb8fae9898ef0c5fc6470236ee7244e616a9.tar.xz
varregion: refactor use of 'double heightmap[,]' into references to new class TerrainData
and push the implementation from Scene into the database readers and writers.
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainChannel.cs352
2 files changed, 248 insertions, 108 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 03270d7..f5458c1 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1935,7 +1935,7 @@ namespace OpenSim.Region.Framework.Scenes
1935 { 1935 {
1936 try 1936 try
1937 { 1937 {
1938 double[,] map = SimulationDataService.LoadTerrain(RegionInfo.RegionID); 1938 TerrainData map = SimulationDataService.LoadTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
1939 if (map == null) 1939 if (map == null)
1940 { 1940 {
1941 // This should be in the Terrain module, but it isn't because 1941 // This should be in the Terrain module, but it isn't because
@@ -1946,7 +1946,7 @@ namespace OpenSim.Region.Framework.Scenes
1946 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); 1946 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
1947 1947
1948 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); 1948 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
1949 Heightmap = new TerrainChannel(m_InitialTerrain); 1949 Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
1950 1950
1951 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); 1951 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
1952 } 1952 }
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
index b6e0a97..3d563a6 100644
--- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
+++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
@@ -25,14 +25,21 @@
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 OpenMetaverse;
40
41using log4net;
42
36namespace OpenSim.Region.Framework.Scenes 43namespace OpenSim.Region.Framework.Scenes
37{ 44{
38 /// <summary> 45 /// <summary>
@@ -40,140 +47,136 @@ namespace OpenSim.Region.Framework.Scenes
40 /// </summary> 47 /// </summary>
41 public class TerrainChannel : ITerrainChannel 48 public class TerrainChannel : ITerrainChannel
42 { 49 {
43 private readonly bool[,] taint; 50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 private double[,] map; 51 private static string LogHeader = "[TERRAIN CHANNEL]";
45 52
53 protected TerrainData m_terrainData;
54
55 public int Width { get { return m_terrainData.SizeX; } } // X dimension
56 // Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y
57 public int Height { get { return m_terrainData.SizeY; } } // Y dimension
58 public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension
59
60 // Default, not-often-used builder
46 public TerrainChannel() 61 public TerrainChannel()
47 { 62 {
48 map = new double[Constants.RegionSize, Constants.RegionSize]; 63 m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
49 taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; 64 FlatLand();
50 65 // PinHeadIsland();
51 PinHeadIsland();
52 } 66 }
53 67
54 public TerrainChannel(String type) 68 // Create terrain of given size
69 public TerrainChannel(int pX, int pY)
55 { 70 {
56 map = new double[Constants.RegionSize, Constants.RegionSize]; 71 m_terrainData = new HeightmapTerrainData(pX, pY, (int)Constants.RegionHeight);
57 taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; 72 }
58 73
74 // Create terrain of specified size and initialize with specified terrain.
75 // TODO: join this with the terrain initializers.
76 public TerrainChannel(String type, int pX, int pY, int pZ)
77 {
78 m_terrainData = new HeightmapTerrainData(pX, pY, pZ);
59 if (type.Equals("flat")) 79 if (type.Equals("flat"))
60 FlatLand(); 80 FlatLand();
61 else 81 else
62 PinHeadIsland(); 82 PinHeadIsland();
63 } 83 }
64 84
65 public TerrainChannel(double[,] import) 85 // Create channel passed a heightmap and expected dimensions of the region.
86 // The heightmap might not fit the passed size so accomodations must be made.
87 public TerrainChannel(double[,] pM, int pSizeX, int pSizeY, int pAltitude)
66 { 88 {
67 map = import; 89 int hmSizeX = pM.GetLength(0);
68 taint = new bool[import.GetLength(0),import.GetLength(1)]; 90 int hmSizeY = pM.GetLength(1);
69 }
70 91
71 public TerrainChannel(bool createMap) 92 m_terrainData = new HeightmapTerrainData(pSizeX, pSizeY, pAltitude);
72 { 93
73 if (createMap) 94 for (int xx = 0; xx < pSizeX; xx++)
74 { 95 for (int yy = 0; yy < pSizeY; yy++)
75 map = new double[Constants.RegionSize,Constants.RegionSize]; 96 if (xx > hmSizeX || yy > hmSizeY)
76 taint = new bool[Constants.RegionSize / 16,Constants.RegionSize / 16]; 97 m_terrainData[xx, yy] = TerrainData.DefaultTerrainHeight;
77 } 98 else
99 m_terrainData[xx, yy] = (float)pM[xx, yy];
78 } 100 }
79 101
80 public TerrainChannel(int w, int h) 102 public TerrainChannel(TerrainData pTerrData)
81 { 103 {
82 map = new double[w,h]; 104 m_terrainData = pTerrData;
83 taint = new bool[w / 16,h / 16];
84 } 105 }
85 106
86 #region ITerrainChannel Members 107 #region ITerrainChannel Members
87 108
88 public int Width 109 // ITerrainChannel.MakeCopy()
110 public ITerrainChannel MakeCopy()
89 { 111 {
90 get { return map.GetLength(0); } 112 return this.Copy();
91 } 113 }
92 114
93 public int Height 115 // ITerrainChannel.GetTerrainData()
116 public TerrainData GetTerrainData()
94 { 117 {
95 get { return map.GetLength(1); } 118 return m_terrainData;
96 } 119 }
97 120
98 public ITerrainChannel MakeCopy() 121 // ITerrainChannel.GetFloatsSerialized()
122 // This one dimensional version is ordered so height = map[y*sizeX+x];
123 // DEPRECATED: don't use this function as it does not retain the dimensions of the terrain
124 // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256.
125 public float[] GetFloatsSerialised()
99 { 126 {
100 TerrainChannel copy = new TerrainChannel(false); 127 return m_terrainData.GetFloatsSerialized();
101 copy.map = (double[,]) map.Clone();
102
103 return copy;
104 } 128 }
105 129
106 public float[] GetFloatsSerialised() 130 // ITerrainChannel.GetDoubles()
131 public double[,] GetDoubles()
107 { 132 {
108 // Move the member variables into local variables, calling 133 double[,] heights = new double[Width, Height];
109 // member variables 256*256 times gets expensive
110 int w = Width;
111 int h = Height;
112 float[] heights = new float[w * h];
113 134
114 int i, j; // map coordinates
115 int idx = 0; // index into serialized array 135 int idx = 0; // index into serialized array
116 for (i = 0; i < h; i++) 136 for (int ii = 0; ii < Width; ii++)
117 { 137 {
118 for (j = 0; j < w; j++) 138 for (int jj = 0; jj < Height; jj++)
119 { 139 {
120 heights[idx++] = (float)map[j, i]; 140 heights[ii, jj] = (double)m_terrainData[ii, jj];
141 idx++;
121 } 142 }
122 } 143 }
123 144
124 return heights; 145 return heights;
125 } 146 }
126 147
127 public double[,] GetDoubles() 148 // ITerrainChannel.this[x,y]
128 {
129 return map;
130 }
131
132 public double this[int x, int y] 149 public double this[int x, int y]
133 { 150 {
134 get 151 get {
135 { 152 if (x < 0 || x >= Width || y < 0 || y >= Height)
136 if (x < 0) x = 0; 153 return 0;
137 if (y < 0) y = 0; 154 return (double)m_terrainData[x, y];
138 if (x >= (int)Constants.RegionSize) x = (int)Constants.RegionSize - 1;
139 if (y >= (int)Constants.RegionSize) y = (int)Constants.RegionSize - 1;
140
141 return map[x, y];
142 } 155 }
143 set 156 set
144 { 157 {
145 // Will "fix" terrain hole problems. Although not fantastically.
146 if (Double.IsNaN(value) || Double.IsInfinity(value)) 158 if (Double.IsNaN(value) || Double.IsInfinity(value))
147 return; 159 return;
148 160
149 if (map[x, y] != value) 161 m_terrainData[x, y] = (float)value;
150 {
151 taint[x / 16, y / 16] = true;
152 map[x, y] = value;
153 }
154 } 162 }
155 } 163 }
156 164
157 public bool Tainted(int x, int y) 165 // ITerrainChannel.GetHieghtAtXYZ(x, y, z)
166 public float GetHeightAtXYZ(float x, float y, float z)
158 { 167 {
159 if (taint[x / 16, y / 16]) 168 if (x < 0 || x >= Width || y < 0 || y >= Height)
160 { 169 return 0;
161 taint[x / 16, y / 16] = false; 170 return m_terrainData[(int)x, (int)y];
162 return true;
163 }
164 return false;
165 } 171 }
166 172
167 #endregion 173 // ITerrainChannel.Tainted()
168 174 public bool Tainted(int x, int y)
169 public TerrainChannel Copy()
170 { 175 {
171 TerrainChannel copy = new TerrainChannel(false); 176 return m_terrainData.IsTaintedAt(x, y);
172 copy.map = (double[,]) map.Clone();
173
174 return copy;
175 } 177 }
176 178
179 // ITerrainChannel.SaveToXmlString()
177 public string SaveToXmlString() 180 public string SaveToXmlString()
178 { 181 {
179 XmlWriterSettings settings = new XmlWriterSettings(); 182 XmlWriterSettings settings = new XmlWriterSettings();
@@ -189,13 +192,7 @@ namespace OpenSim.Region.Framework.Scenes
189 } 192 }
190 } 193 }
191 194
192 private void WriteXml(XmlWriter writer) 195 // ITerrainChannel.LoadFromXmlString()
193 {
194 writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
195 ToXml(writer);
196 writer.WriteEndElement();
197 }
198
199 public void LoadFromXmlString(string data) 196 public void LoadFromXmlString(string data)
200 { 197 {
201 StringReader sr = new StringReader(data); 198 StringReader sr = new StringReader(data);
@@ -207,12 +204,124 @@ namespace OpenSim.Region.Framework.Scenes
207 sr.Close(); 204 sr.Close();
208 } 205 }
209 206
207 // ITerrainChannel.Merge
208 public void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement)
209 {
210 m_log.DebugFormat("{0} Merge. inSize=<{1},{2}>, disp={3}, rot={4}, rotDisp={5}, outSize=<{6},{7}>", LogHeader,
211 newTerrain.Width, newTerrain.Height,
212 displacement, radianRotation, rotationDisplacement,
213 m_terrainData.SizeX, m_terrainData.SizeY);
214 for (int xx = 0; xx < newTerrain.Width; xx++)
215 {
216 for (int yy = 0; yy < newTerrain.Height; yy++)
217 {
218 int dispX = (int)displacement.X;
219 int dispY = (int)displacement.Y;
220 float newHeight = (float)newTerrain[xx, yy] + displacement.Z;
221 if (radianRotation == 0)
222 {
223 // If no rotation, place the new height in the specified location
224 dispX += xx;
225 dispY += yy;
226 if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
227 {
228 m_terrainData[dispX, dispY] = newHeight;
229 }
230 }
231 else
232 {
233 // If rotating, we have to smooth the result because the conversion
234 // to ints will mean heightmap entries will not get changed
235 // First compute the rotation location for the new height.
236 dispX += (int)(rotationDisplacement.X
237 + ((float)xx - rotationDisplacement.X) * Math.Cos(radianRotation)
238 - ((float)yy - rotationDisplacement.Y) * Math.Sin(radianRotation) );
239
240 dispY += (int)(rotationDisplacement.Y
241 + ((float)xx - rotationDisplacement.X) * Math.Sin(radianRotation)
242 + ((float)yy - rotationDisplacement.Y) * Math.Cos(radianRotation) );
243
244 if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
245 {
246 float oldHeight = m_terrainData[dispX, dispY];
247 // Smooth the heights around this location if the old height is far from this one
248 for (int sxx = dispX - 2; sxx < dispX + 2; sxx++)
249 {
250 for (int syy = dispY - 2; syy < dispY + 2; syy++)
251 {
252 if (sxx >= 0 && sxx < m_terrainData.SizeX && syy >= 0 && syy < m_terrainData.SizeY)
253 {
254 if (sxx == dispX && syy == dispY)
255 {
256 // Set height for the exact rotated point
257 m_terrainData[dispX, dispY] = newHeight;
258 }
259 else
260 {
261 if (Math.Abs(m_terrainData[sxx, syy] - newHeight) > 1f)
262 {
263 // If the adjacent height is far off, force it to this height
264 m_terrainData[sxx, syy] = newHeight;
265 }
266 }
267 }
268 }
269 }
270 }
271
272 if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
273 {
274 m_terrainData[dispX, dispY] = (float)newTerrain[xx, yy];
275 }
276 }
277 }
278 }
279 }
280
281 #endregion
282
283 public TerrainChannel Copy()
284 {
285 TerrainChannel copy = new TerrainChannel();
286 copy.m_terrainData = m_terrainData.Clone();
287 return copy;
288 }
289
290 private void WriteXml(XmlWriter writer)
291 {
292 if (Width == Constants.RegionSize && Height == Constants.RegionSize)
293 {
294 // Downward compatibility for legacy region terrain maps.
295 // If region is exactly legacy size, return the old format XML.
296 writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
297 ToXml(writer);
298 writer.WriteEndElement();
299 }
300 else
301 {
302 // New format XML that includes width and length.
303 writer.WriteStartElement(String.Empty, "TerrainMap2", String.Empty);
304 ToXml2(writer);
305 writer.WriteEndElement();
306 }
307 }
308
210 private void ReadXml(XmlReader reader) 309 private void ReadXml(XmlReader reader)
211 { 310 {
212 reader.ReadStartElement("TerrainMap"); 311 // Check the first element. If legacy element, use the legacy reader.
213 FromXml(reader); 312 if (reader.IsStartElement("TerrainMap"))
313 {
314 reader.ReadStartElement("TerrainMap");
315 FromXml(reader);
316 }
317 else
318 {
319 reader.ReadStartElement("TerrainMap2");
320 FromXml2(reader);
321 }
214 } 322 }
215 323
324 // Write legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
216 private void ToXml(XmlWriter xmlWriter) 325 private void ToXml(XmlWriter xmlWriter)
217 { 326 {
218 float[] mapData = GetFloatsSerialised(); 327 float[] mapData = GetFloatsSerialised();
@@ -226,12 +335,15 @@ namespace OpenSim.Region.Framework.Scenes
226 serializer.Serialize(xmlWriter, buffer); 335 serializer.Serialize(xmlWriter, buffer);
227 } 336 }
228 337
338 // Read legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
229 private void FromXml(XmlReader xmlReader) 339 private void FromXml(XmlReader xmlReader)
230 { 340 {
231 XmlSerializer serializer = new XmlSerializer(typeof(byte[])); 341 XmlSerializer serializer = new XmlSerializer(typeof(byte[]));
232 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader); 342 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
233 int index = 0; 343 int index = 0;
234 344
345 m_terrainData = new HeightmapTerrainData(Height, Width, (int)Constants.RegionHeight);
346
235 for (int y = 0; y < Height; y++) 347 for (int y = 0; y < Height; y++)
236 { 348 {
237 for (int x = 0; x < Width; x++) 349 for (int x = 0; x < Width; x++)
@@ -244,35 +356,63 @@ namespace OpenSim.Region.Framework.Scenes
244 } 356 }
245 } 357 }
246 358
359 private class TerrainChannelXMLPackage
360 {
361 public int Version;
362 public int SizeX;
363 public int SizeY;
364 public int SizeZ;
365 public float CompressionFactor;
366 public int[] Map;
367 public TerrainChannelXMLPackage(int pX, int pY, int pZ, float pCompressionFactor, int[] pMap)
368 {
369 Version = 1;
370 SizeX = pX;
371 SizeY = pY;
372 SizeZ = pZ;
373 CompressionFactor = pCompressionFactor;
374 Map = pMap;
375 }
376 }
377
378 // New terrain serialization format that includes the width and length.
379 private void ToXml2(XmlWriter xmlWriter)
380 {
381 TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_terrainData.CompressionFactor,
382 m_terrainData.GetCompressedMap());
383 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
384 serializer.Serialize(xmlWriter, package);
385 }
386
387 // New terrain serialization format that includes the width and length.
388 private void FromXml2(XmlReader xmlReader)
389 {
390 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
391 TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader);
392 m_terrainData = new HeightmapTerrainData(package.Map, package.CompressionFactor, package.SizeX, package.SizeY, package.SizeZ);
393 }
394
395 // Fill the heightmap with the center bump terrain
247 private void PinHeadIsland() 396 private void PinHeadIsland()
248 { 397 {
249 int x; 398 for (int x = 0; x < Width; x++)
250 for (x = 0; x < Constants.RegionSize; x++)
251 { 399 {
252 int y; 400 for (int y = 0; y < Height; y++)
253 for (y = 0; y < Constants.RegionSize; y++)
254 { 401 {
255 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; 402 m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10;
256 double spherFacA = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01; 403 float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d);
257 double spherFacB = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001; 404 float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d);
258 if (map[x, y] < spherFacA) 405 if (m_terrainData[x, y]< spherFacA)
259 map[x, y] = spherFacA; 406 m_terrainData[x, y]= spherFacA;
260 if (map[x, y] < spherFacB) 407 if (m_terrainData[x, y]< spherFacB)
261 map[x, y] = spherFacB; 408 m_terrainData[x, y] = spherFacB;
262 } 409 }
263 } 410 }
264 } 411 }
265 412
266 private void FlatLand() 413 private void FlatLand()
267 { 414 {
268 int x; 415 m_terrainData.ClearLand();
269 for (x = 0; x < Constants.RegionSize; x++)
270 {
271 int y;
272 for (y = 0; y < Constants.RegionSize; y++)
273 map[x, y] = 21;
274 }
275 } 416 }
276
277 } 417 }
278} 418}