diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/TerrainChannel.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/TerrainChannel.cs | 271 |
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 | ||
28 | using OpenSim.Framework; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | using System; | 28 | using System; |
29 | using System.IO; | ||
31 | using System.Text; | 30 | using System.Text; |
31 | using System.Reflection; | ||
32 | using System.Xml; | 32 | using System.Xml; |
33 | using System.IO; | ||
34 | using System.Xml.Serialization; | 33 | using System.Xml.Serialization; |
35 | 34 | ||
35 | using OpenSim.Data; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | |||
39 | using log4net; | ||
40 | |||
36 | namespace OpenSim.Region.Framework.Scenes | 41 | namespace 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 | } |