diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Framework/TerrainData.cs | 320 |
1 files changed, 265 insertions, 55 deletions
diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs index 6b1be4e..d2e1c6a 100644 --- a/OpenSim/Framework/TerrainData.cs +++ b/OpenSim/Framework/TerrainData.cs | |||
@@ -28,6 +28,7 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.IO; | 30 | using System.IO; |
31 | using System.IO.Compression; | ||
31 | using System.Reflection; | 32 | using System.Reflection; |
32 | 33 | ||
33 | using OpenMetaverse; | 34 | using OpenMetaverse; |
@@ -48,6 +49,7 @@ namespace OpenSim.Framework | |||
48 | 49 | ||
49 | public abstract float this[int x, int y] { get; set; } | 50 | public abstract float this[int x, int y] { get; set; } |
50 | // Someday terrain will have caves | 51 | // Someday terrain will have caves |
52 | // at most holes :p | ||
51 | public abstract float this[int x, int y, int z] { get; set; } | 53 | public abstract float this[int x, int y, int z] { get; set; } |
52 | 54 | ||
53 | public abstract bool IsTaintedAt(int xx, int yy); | 55 | public abstract bool IsTaintedAt(int xx, int yy); |
@@ -72,8 +74,8 @@ namespace OpenSim.Framework | |||
72 | return new HeightmapTerrainData(pSizeX, pSizeY, pSizeZ, pFormatCode, pBlob); | 74 | return new HeightmapTerrainData(pSizeX, pSizeY, pSizeZ, pFormatCode, pBlob); |
73 | } | 75 | } |
74 | 76 | ||
75 | // return a special compressed representation of the heightmap in ints | 77 | // return a special compressed representation of the heightmap in ushort |
76 | public abstract int[] GetCompressedMap(); | 78 | public abstract float[] GetCompressedMap(); |
77 | public abstract float CompressionFactor { get; } | 79 | public abstract float CompressionFactor { get; } |
78 | 80 | ||
79 | public abstract float[] GetFloatsSerialized(); | 81 | public abstract float[] GetFloatsSerialized(); |
@@ -94,14 +96,18 @@ namespace OpenSim.Framework | |||
94 | { | 96 | { |
95 | // Terrain is 'double[256,256]' | 97 | // Terrain is 'double[256,256]' |
96 | Legacy256 = 11, | 98 | Legacy256 = 11, |
99 | |||
97 | // Terrain is 'int32, int32, float[,]' where the ints are X and Y dimensions | 100 | // Terrain is 'int32, int32, float[,]' where the ints are X and Y dimensions |
98 | // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256. | 101 | // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256. |
99 | Variable2D = 22, | 102 | Variable2D = 22, |
103 | Variable2DGzip = 23, | ||
104 | |||
100 | // Terrain is 'int32, int32, int32, int16[]' where the ints are X and Y dimensions | 105 | // Terrain is 'int32, int32, int32, int16[]' where the ints are X and Y dimensions |
101 | // and third int is the 'compression factor'. The heights are compressed as | 106 | // and third int is the 'compression factor'. The heights are compressed as |
102 | // "int compressedHeight = (int)(height * compressionFactor);" | 107 | // "ushort compressedHeight = (ushort)(height * compressionFactor);" |
103 | // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256. | 108 | // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256. |
104 | Compressed2D = 27, | 109 | Compressed2D = 27, |
110 | |||
105 | // A revision that is not listed above or any revision greater than this value is 'Legacy256'. | 111 | // A revision that is not listed above or any revision greater than this value is 'Legacy256'. |
106 | RevisionHigh = 1234 | 112 | RevisionHigh = 1234 |
107 | } | 113 | } |
@@ -109,7 +115,7 @@ namespace OpenSim.Framework | |||
109 | // Version of terrain that is a heightmap. | 115 | // Version of terrain that is a heightmap. |
110 | // This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge | 116 | // This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge |
111 | // of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer. | 117 | // of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer. |
112 | // The heighmap is kept as an array of integers. The integer values are converted to | 118 | // The heighmap is kept as an array of ushorts. The ushort values are converted to |
113 | // and from floats by TerrainCompressionFactor. | 119 | // and from floats by TerrainCompressionFactor. |
114 | public class HeightmapTerrainData : TerrainData | 120 | public class HeightmapTerrainData : TerrainData |
115 | { | 121 | { |
@@ -119,12 +125,12 @@ namespace OpenSim.Framework | |||
119 | // TerrainData.this[x, y] | 125 | // TerrainData.this[x, y] |
120 | public override float this[int x, int y] | 126 | public override float this[int x, int y] |
121 | { | 127 | { |
122 | get { return FromCompressedHeight(m_heightmap[x, y]); } | 128 | get { return m_heightmap[x, y]; } |
123 | set { | 129 | set |
124 | int newVal = ToCompressedHeight(value); | 130 | { |
125 | if (m_heightmap[x, y] != newVal) | 131 | if (m_heightmap[x, y] != value) |
126 | { | 132 | { |
127 | m_heightmap[x, y] = newVal; | 133 | m_heightmap[x, y] = value; |
128 | m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true; | 134 | m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true; |
129 | } | 135 | } |
130 | } | 136 | } |
@@ -164,10 +170,9 @@ namespace OpenSim.Framework | |||
164 | // TerrainData.ClearLand(float) | 170 | // TerrainData.ClearLand(float) |
165 | public override void ClearLand(float pHeight) | 171 | public override void ClearLand(float pHeight) |
166 | { | 172 | { |
167 | int flatHeight = ToCompressedHeight(pHeight); | ||
168 | for (int xx = 0; xx < SizeX; xx++) | 173 | for (int xx = 0; xx < SizeX; xx++) |
169 | for (int yy = 0; yy < SizeY; yy++) | 174 | for (int yy = 0; yy < SizeY; yy++) |
170 | m_heightmap[xx, yy] = flatHeight; | 175 | m_heightmap[xx, yy] = pHeight; |
171 | } | 176 | } |
172 | 177 | ||
173 | // Return 'true' of the patch that contains these region coordinates has been modified. | 178 | // Return 'true' of the patch that contains these region coordinates has been modified. |
@@ -177,13 +182,15 @@ namespace OpenSim.Framework | |||
177 | { | 182 | { |
178 | int tx = xx / Constants.TerrainPatchSize; | 183 | int tx = xx / Constants.TerrainPatchSize; |
179 | int ty = yy / Constants.TerrainPatchSize; | 184 | int ty = yy / Constants.TerrainPatchSize; |
180 | bool ret = m_taint[tx, ty]; | 185 | bool ret = m_taint[tx, ty]; |
181 | if (ret && clearOnTest) | 186 | if (ret && clearOnTest) |
182 | m_taint[tx, ty] = false; | 187 | m_taint[tx, ty] = false; |
183 | return ret; | 188 | return ret; |
184 | } | 189 | } |
185 | 190 | ||
186 | // Old form that clears the taint flag when we check it. | 191 | // Old form that clears the taint flag when we check it. |
192 | // ubit: this dangerus naming should be only check without clear | ||
193 | // keeping for old modules outthere | ||
187 | public override bool IsTaintedAt(int xx, int yy) | 194 | public override bool IsTaintedAt(int xx, int yy) |
188 | { | 195 | { |
189 | return IsTaintedAt(xx, yy, true /* clearOnTest */); | 196 | return IsTaintedAt(xx, yy, true /* clearOnTest */); |
@@ -202,8 +209,10 @@ namespace OpenSim.Framework | |||
202 | } | 209 | } |
203 | else | 210 | else |
204 | { | 211 | { |
205 | DBRevisionCode = (int)DBTerrainRevision.Compressed2D; | 212 | DBRevisionCode = (int)DBTerrainRevision.Variable2DGzip; |
206 | blob = ToCompressedTerrainSerialization(); | 213 | // DBRevisionCode = (int)DBTerrainRevision.Variable2D; |
214 | blob = ToCompressedTerrainSerializationV2DGzip(); | ||
215 | // blob = ToCompressedTerrainSerializationV2D(); | ||
207 | ret = true; | 216 | ret = true; |
208 | } | 217 | } |
209 | return ret; | 218 | return ret; |
@@ -214,9 +223,9 @@ namespace OpenSim.Framework | |||
214 | public override float CompressionFactor { get { return m_compressionFactor; } } | 223 | public override float CompressionFactor { get { return m_compressionFactor; } } |
215 | 224 | ||
216 | // TerrainData.GetCompressedMap | 225 | // TerrainData.GetCompressedMap |
217 | public override int[] GetCompressedMap() | 226 | public override float[] GetCompressedMap() |
218 | { | 227 | { |
219 | int[] newMap = new int[SizeX * SizeY]; | 228 | float[] newMap = new float[SizeX * SizeY]; |
220 | 229 | ||
221 | int ind = 0; | 230 | int ind = 0; |
222 | for (int xx = 0; xx < SizeX; xx++) | 231 | for (int xx = 0; xx < SizeX; xx++) |
@@ -230,7 +239,7 @@ namespace OpenSim.Framework | |||
230 | public override TerrainData Clone() | 239 | public override TerrainData Clone() |
231 | { | 240 | { |
232 | HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ); | 241 | HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ); |
233 | ret.m_heightmap = (int[,])this.m_heightmap.Clone(); | 242 | ret.m_heightmap = (float[,])this.m_heightmap.Clone(); |
234 | return ret; | 243 | return ret; |
235 | } | 244 | } |
236 | 245 | ||
@@ -247,7 +256,7 @@ namespace OpenSim.Framework | |||
247 | for (int jj = 0; jj < SizeY; jj++) | 256 | for (int jj = 0; jj < SizeY; jj++) |
248 | for (int ii = 0; ii < SizeX; ii++) | 257 | for (int ii = 0; ii < SizeX; ii++) |
249 | { | 258 | { |
250 | heights[idx++] = FromCompressedHeight(m_heightmap[ii, jj]); | 259 | heights[idx++] = m_heightmap[ii, jj]; |
251 | } | 260 | } |
252 | 261 | ||
253 | return heights; | 262 | return heights; |
@@ -259,7 +268,7 @@ namespace OpenSim.Framework | |||
259 | double[,] ret = new double[SizeX, SizeY]; | 268 | double[,] ret = new double[SizeX, SizeY]; |
260 | for (int xx = 0; xx < SizeX; xx++) | 269 | for (int xx = 0; xx < SizeX; xx++) |
261 | for (int yy = 0; yy < SizeY; yy++) | 270 | for (int yy = 0; yy < SizeY; yy++) |
262 | ret[xx, yy] = FromCompressedHeight(m_heightmap[xx, yy]); | 271 | ret[xx, yy] = (double)m_heightmap[xx, yy]; |
263 | 272 | ||
264 | return ret; | 273 | return ret; |
265 | } | 274 | } |
@@ -267,19 +276,40 @@ namespace OpenSim.Framework | |||
267 | 276 | ||
268 | // ============================================================= | 277 | // ============================================================= |
269 | 278 | ||
270 | private int[,] m_heightmap; | 279 | private float[,] m_heightmap; |
271 | // Remember subregions of the heightmap that has changed. | 280 | // Remember subregions of the heightmap that has changed. |
272 | private bool[,] m_taint; | 281 | private bool[,] m_taint; |
273 | 282 | ||
274 | // To save space (especially for large regions), keep the height as a short integer | ||
275 | // that is coded as the float height times the compression factor (usually '100' | 283 | // that is coded as the float height times the compression factor (usually '100' |
276 | // to make for two decimal points). | 284 | // to make for two decimal points). |
277 | public int ToCompressedHeight(double pHeight) | 285 | public short ToCompressedHeightshort(float pHeight) |
286 | { | ||
287 | // clamp into valid range | ||
288 | pHeight *= CompressionFactor; | ||
289 | if (pHeight < short.MinValue) | ||
290 | return short.MinValue; | ||
291 | else if (pHeight > short.MaxValue) | ||
292 | return short.MaxValue; | ||
293 | return (short)pHeight; | ||
294 | } | ||
295 | |||
296 | public ushort ToCompressedHeightushort(float pHeight) | ||
278 | { | 297 | { |
279 | return (int)(pHeight * CompressionFactor); | 298 | // clamp into valid range |
299 | pHeight *= CompressionFactor; | ||
300 | if (pHeight < ushort.MinValue) | ||
301 | return ushort.MinValue; | ||
302 | else if (pHeight > ushort.MaxValue) | ||
303 | return ushort.MaxValue; | ||
304 | return (ushort)pHeight; | ||
280 | } | 305 | } |
281 | 306 | ||
282 | public float FromCompressedHeight(int pHeight) | 307 | public float FromCompressedHeight(short pHeight) |
308 | { | ||
309 | return ((float)pHeight) / CompressionFactor; | ||
310 | } | ||
311 | |||
312 | public float FromCompressedHeight(ushort pHeight) | ||
283 | { | 313 | { |
284 | return ((float)pHeight) / CompressionFactor; | 314 | return ((float)pHeight) / CompressionFactor; |
285 | } | 315 | } |
@@ -293,12 +323,12 @@ namespace OpenSim.Framework | |||
293 | SizeZ = (int)Constants.RegionHeight; | 323 | SizeZ = (int)Constants.RegionHeight; |
294 | m_compressionFactor = 100.0f; | 324 | m_compressionFactor = 100.0f; |
295 | 325 | ||
296 | m_heightmap = new int[SizeX, SizeY]; | 326 | m_heightmap = new float[SizeX, SizeY]; |
297 | for (int ii = 0; ii < SizeX; ii++) | 327 | for (int ii = 0; ii < SizeX; ii++) |
298 | { | 328 | { |
299 | for (int jj = 0; jj < SizeY; jj++) | 329 | for (int jj = 0; jj < SizeY; jj++) |
300 | { | 330 | { |
301 | m_heightmap[ii, jj] = ToCompressedHeight(pTerrain[ii, jj]); | 331 | m_heightmap[ii, jj] = (float)pTerrain[ii, jj]; |
302 | 332 | ||
303 | } | 333 | } |
304 | } | 334 | } |
@@ -315,14 +345,15 @@ namespace OpenSim.Framework | |||
315 | SizeY = pY; | 345 | SizeY = pY; |
316 | SizeZ = pZ; | 346 | SizeZ = pZ; |
317 | m_compressionFactor = 100.0f; | 347 | m_compressionFactor = 100.0f; |
318 | m_heightmap = new int[SizeX, SizeY]; | 348 | m_heightmap = new float[SizeX, SizeY]; |
319 | m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize]; | 349 | m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize]; |
320 | // m_log.DebugFormat("{0} new by dimensions. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ); | 350 | // m_log.DebugFormat("{0} new by dimensions. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ); |
321 | ClearTaint(); | 351 | ClearTaint(); |
322 | ClearLand(0f); | 352 | ClearLand(0f); |
323 | } | 353 | } |
324 | 354 | ||
325 | public HeightmapTerrainData(int[] cmap, float pCompressionFactor, int pX, int pY, int pZ) : this(pX, pY, pZ) | 355 | public HeightmapTerrainData(float[] cmap, float pCompressionFactor, int pX, int pY, int pZ) |
356 | : this(pX, pY, pZ) | ||
326 | { | 357 | { |
327 | m_compressionFactor = pCompressionFactor; | 358 | m_compressionFactor = pCompressionFactor; |
328 | int ind = 0; | 359 | int ind = 0; |
@@ -333,12 +364,22 @@ namespace OpenSim.Framework | |||
333 | } | 364 | } |
334 | 365 | ||
335 | // Create a heighmap from a database blob | 366 | // Create a heighmap from a database blob |
336 | public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) : this(pSizeX, pSizeY, pSizeZ) | 367 | public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) |
368 | : this(pSizeX, pSizeY, pSizeZ) | ||
337 | { | 369 | { |
338 | switch ((DBTerrainRevision)pFormatCode) | 370 | switch ((DBTerrainRevision)pFormatCode) |
339 | { | 371 | { |
372 | case DBTerrainRevision.Variable2DGzip: | ||
373 | FromCompressedTerrainSerializationV2DGZip(pBlob); | ||
374 | m_log.DebugFormat("{0} HeightmapTerrainData create from Variable2DGzip serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); | ||
375 | break; | ||
376 | |||
377 | case DBTerrainRevision.Variable2D: | ||
378 | FromCompressedTerrainSerializationV2D(pBlob); | ||
379 | m_log.DebugFormat("{0} HeightmapTerrainData create from Variable2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); | ||
380 | break; | ||
340 | case DBTerrainRevision.Compressed2D: | 381 | case DBTerrainRevision.Compressed2D: |
341 | FromCompressedTerrainSerialization(pBlob); | 382 | FromCompressedTerrainSerialization2D(pBlob); |
342 | m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); | 383 | m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); |
343 | break; | 384 | break; |
344 | default: | 385 | default: |
@@ -373,50 +414,116 @@ namespace OpenSim.Framework | |||
373 | return ret; | 414 | return ret; |
374 | } | 415 | } |
375 | 416 | ||
376 | // Just create an array of doubles. Presumes the caller implicitly knows the size. | 417 | // Presumes the caller implicitly knows the size. |
377 | public void FromLegacyTerrainSerialization(byte[] pBlob) | 418 | public void FromLegacyTerrainSerialization(byte[] pBlob) |
378 | { | 419 | { |
379 | // In case database info doesn't match real terrain size, initialize the whole terrain. | 420 | // In case database info doesn't match real terrain size, initialize the whole terrain. |
380 | ClearLand(); | 421 | ClearLand(); |
381 | 422 | ||
382 | using (MemoryStream mstr = new MemoryStream(pBlob)) | 423 | try |
383 | { | 424 | { |
384 | using (BinaryReader br = new BinaryReader(mstr)) | 425 | using (MemoryStream mstr = new MemoryStream(pBlob)) |
385 | { | 426 | { |
386 | for (int xx = 0; xx < (int)Constants.RegionSize; xx++) | 427 | using (BinaryReader br = new BinaryReader(mstr)) |
387 | { | 428 | { |
388 | for (int yy = 0; yy < (int)Constants.RegionSize; yy++) | 429 | for (int xx = 0; xx < (int)Constants.RegionSize; xx++) |
389 | { | 430 | { |
390 | float val = (float)br.ReadDouble(); | 431 | for (int yy = 0; yy < (int)Constants.RegionSize; yy++) |
391 | if (xx < SizeX && yy < SizeY) | 432 | { |
392 | m_heightmap[xx, yy] = ToCompressedHeight(val); | 433 | float val = (float)br.ReadDouble(); |
434 | |||
435 | if (xx < SizeX && yy < SizeY) | ||
436 | m_heightmap[xx, yy] = val; | ||
437 | } | ||
393 | } | 438 | } |
394 | } | 439 | } |
395 | } | 440 | } |
396 | ClearTaint(); | ||
397 | } | 441 | } |
442 | catch | ||
443 | { | ||
444 | ClearLand(); | ||
445 | } | ||
446 | ClearTaint(); | ||
398 | } | 447 | } |
399 | 448 | ||
400 | // See the reader below. | 449 | |
401 | public Array ToCompressedTerrainSerialization() | 450 | // stores as variable2D |
451 | // int32 sizeX | ||
452 | // int32 sizeY | ||
453 | // float[,] array | ||
454 | |||
455 | public Array ToCompressedTerrainSerializationV2D() | ||
402 | { | 456 | { |
403 | Array ret = null; | 457 | Array ret = null; |
404 | using (MemoryStream str = new MemoryStream((3 * sizeof(Int32)) + (SizeX * SizeY * sizeof(Int16)))) | 458 | try |
405 | { | 459 | { |
406 | using (BinaryWriter bw = new BinaryWriter(str)) | 460 | using (MemoryStream str = new MemoryStream((2 * sizeof(Int32)) + (SizeX * SizeY * sizeof(float)))) |
461 | { | ||
462 | using (BinaryWriter bw = new BinaryWriter(str)) | ||
463 | { | ||
464 | bw.Write((Int32)SizeX); | ||
465 | bw.Write((Int32)SizeY); | ||
466 | for (int yy = 0; yy < SizeY; yy++) | ||
467 | for (int xx = 0; xx < SizeX; xx++) | ||
468 | { | ||
469 | // reduce to 1cm resolution | ||
470 | float val = (float)Math.Round(m_heightmap[xx, yy],2,MidpointRounding.ToEven); | ||
471 | bw.Write(val); | ||
472 | } | ||
473 | } | ||
474 | ret = str.ToArray(); | ||
475 | } | ||
476 | } | ||
477 | catch | ||
478 | { | ||
479 | |||
480 | } | ||
481 | |||
482 | m_log.DebugFormat("{0} V2D {1} bytes", | ||
483 | LogHeader, ret.Length); | ||
484 | |||
485 | return ret; | ||
486 | } | ||
487 | |||
488 | // as above with Gzip compression | ||
489 | public Array ToCompressedTerrainSerializationV2DGzip() | ||
490 | { | ||
491 | Array ret = null; | ||
492 | try | ||
493 | { | ||
494 | using (MemoryStream inp = new MemoryStream((2 * sizeof(Int32)) + (SizeX * SizeY * sizeof(float)))) | ||
407 | { | 495 | { |
408 | bw.Write((Int32)DBTerrainRevision.Compressed2D); | 496 | using (BinaryWriter bw = new BinaryWriter(inp)) |
409 | bw.Write((Int32)SizeX); | 497 | { |
410 | bw.Write((Int32)SizeY); | 498 | bw.Write((Int32)SizeX); |
411 | bw.Write((Int32)CompressionFactor); | 499 | bw.Write((Int32)SizeY); |
412 | for (int yy = 0; yy < SizeY; yy++) | 500 | for (int yy = 0; yy < SizeY; yy++) |
413 | for (int xx = 0; xx < SizeX; xx++) | 501 | for (int xx = 0; xx < SizeX; xx++) |
502 | { | ||
503 | bw.Write((float)m_heightmap[xx, yy]); | ||
504 | } | ||
505 | |||
506 | bw.Flush(); | ||
507 | inp.Seek(0, SeekOrigin.Begin); | ||
508 | |||
509 | using (MemoryStream outputStream = new MemoryStream()) | ||
414 | { | 510 | { |
415 | bw.Write((Int16)m_heightmap[xx, yy]); | 511 | using (GZipStream compressionStream = new GZipStream(outputStream, CompressionMode.Compress)) |
512 | { | ||
513 | inp.CopyStream(compressionStream, int.MaxValue); | ||
514 | compressionStream.Close(); | ||
515 | ret = outputStream.ToArray(); | ||
516 | } | ||
416 | } | 517 | } |
518 | } | ||
417 | } | 519 | } |
418 | ret = str.ToArray(); | ||
419 | } | 520 | } |
521 | catch | ||
522 | { | ||
523 | |||
524 | } | ||
525 | m_log.DebugFormat("{0} V2DGzip {1} bytes", | ||
526 | LogHeader, ret.Length); | ||
420 | return ret; | 527 | return ret; |
421 | } | 528 | } |
422 | 529 | ||
@@ -426,7 +533,7 @@ namespace OpenSim.Framework | |||
426 | // the forth int is the compression factor for the following int16s | 533 | // the forth int is the compression factor for the following int16s |
427 | // This is just sets heightmap info. The actual size of the region was set on this instance's | 534 | // This is just sets heightmap info. The actual size of the region was set on this instance's |
428 | // creation and any heights not initialized by theis blob are set to the default height. | 535 | // creation and any heights not initialized by theis blob are set to the default height. |
429 | public void FromCompressedTerrainSerialization(byte[] pBlob) | 536 | public void FromCompressedTerrainSerialization2D(byte[] pBlob) |
430 | { | 537 | { |
431 | Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor; | 538 | Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor; |
432 | 539 | ||
@@ -448,7 +555,7 @@ namespace OpenSim.Framework | |||
448 | { | 555 | { |
449 | for (int xx = 0; xx < hmSizeX; xx++) | 556 | for (int xx = 0; xx < hmSizeX; xx++) |
450 | { | 557 | { |
451 | Int16 val = br.ReadInt16(); | 558 | float val = FromCompressedHeight(br.ReadInt16()); |
452 | if (xx < SizeX && yy < SizeY) | 559 | if (xx < SizeX && yy < SizeY) |
453 | m_heightmap[xx, yy] = val; | 560 | m_heightmap[xx, yy] = val; |
454 | } | 561 | } |
@@ -456,9 +563,112 @@ namespace OpenSim.Framework | |||
456 | } | 563 | } |
457 | ClearTaint(); | 564 | ClearTaint(); |
458 | 565 | ||
459 | m_log.InfoFormat("{0} Read compressed 2d heightmap. Heightmap size=<{1},{2}>. Region size=<{3},{4}>. CompFact={5}", | 566 | m_log.DebugFormat("{0} Read (compressed2D) heightmap. Heightmap size=<{1},{2}>. Region size=<{3},{4}>. CompFact={5}", |
460 | LogHeader, hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor); | 567 | LogHeader, hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor); |
461 | } | 568 | } |
462 | } | 569 | } |
570 | |||
571 | // Initialize heightmap from blob consisting of: | ||
572 | // int32, int32, int32, float[] | ||
573 | // where the first int32 is format code, next two int32s are the X and y of heightmap data | ||
574 | // This is just sets heightmap info. The actual size of the region was set on this instance's | ||
575 | // creation and any heights not initialized by theis blob are set to the default height. | ||
576 | public void FromCompressedTerrainSerializationV2D(byte[] pBlob) | ||
577 | { | ||
578 | Int32 hmSizeX, hmSizeY; | ||
579 | try | ||
580 | { | ||
581 | using (MemoryStream mstr = new MemoryStream(pBlob)) | ||
582 | { | ||
583 | using (BinaryReader br = new BinaryReader(mstr)) | ||
584 | { | ||
585 | hmSizeX = br.ReadInt32(); | ||
586 | hmSizeY = br.ReadInt32(); | ||
587 | |||
588 | // In case database info doesn't match real terrain size, initialize the whole terrain. | ||
589 | ClearLand(); | ||
590 | |||
591 | for (int yy = 0; yy < hmSizeY; yy++) | ||
592 | { | ||
593 | for (int xx = 0; xx < hmSizeX; xx++) | ||
594 | { | ||
595 | float val = br.ReadSingle(); | ||
596 | if (xx < SizeX && yy < SizeY) | ||
597 | m_heightmap[xx, yy] = val; | ||
598 | } | ||
599 | } | ||
600 | } | ||
601 | } | ||
602 | } | ||
603 | catch (Exception e) | ||
604 | { | ||
605 | ClearTaint(); | ||
606 | m_log.ErrorFormat("{0} 2D error: {1} - terrain may be damaged", | ||
607 | LogHeader, e.Message); | ||
608 | return; | ||
609 | } | ||
610 | ClearTaint(); | ||
611 | |||
612 | m_log.DebugFormat("{0} V2D Heightmap size=<{1},{2}>. Region size=<{3},{4}>", | ||
613 | LogHeader, hmSizeX, hmSizeY, SizeX, SizeY); | ||
614 | |||
615 | } | ||
616 | |||
617 | // as above but Gzip compressed | ||
618 | public void FromCompressedTerrainSerializationV2DGZip(byte[] pBlob) | ||
619 | { | ||
620 | m_log.InfoFormat("{0} VD2Gzip {1} bytes input", | ||
621 | LogHeader, pBlob.Length); | ||
622 | |||
623 | Int32 hmSizeX, hmSizeY; | ||
624 | |||
625 | try | ||
626 | { | ||
627 | using (MemoryStream outputStream = new MemoryStream()) | ||
628 | { | ||
629 | using (MemoryStream inputStream = new MemoryStream(pBlob)) | ||
630 | { | ||
631 | using (GZipStream decompressionStream = new GZipStream(inputStream, CompressionMode.Decompress)) | ||
632 | { | ||
633 | decompressionStream.Flush(); | ||
634 | decompressionStream.CopyTo(outputStream); | ||
635 | } | ||
636 | } | ||
637 | |||
638 | outputStream.Seek(0, SeekOrigin.Begin); | ||
639 | |||
640 | using (BinaryReader br = new BinaryReader(outputStream)) | ||
641 | { | ||
642 | hmSizeX = br.ReadInt32(); | ||
643 | hmSizeY = br.ReadInt32(); | ||
644 | |||
645 | // In case database info doesn't match real terrain size, initialize the whole terrain. | ||
646 | ClearLand(); | ||
647 | |||
648 | for (int yy = 0; yy < hmSizeY; yy++) | ||
649 | { | ||
650 | for (int xx = 0; xx < hmSizeX; xx++) | ||
651 | { | ||
652 | float val = br.ReadSingle(); | ||
653 | if (xx < SizeX && yy < SizeY) | ||
654 | m_heightmap[xx, yy] = val; | ||
655 | } | ||
656 | } | ||
657 | } | ||
658 | } | ||
659 | } | ||
660 | catch( Exception e) | ||
661 | { | ||
662 | ClearTaint(); | ||
663 | m_log.ErrorFormat("{0} V2DGzip error: {1} - terrain may be damaged", | ||
664 | LogHeader, e.Message); | ||
665 | return; | ||
666 | } | ||
667 | |||
668 | ClearTaint(); | ||
669 | m_log.DebugFormat("{0} V2DGzip. Heightmap size=<{1},{2}>. Region size=<{3},{4}>", | ||
670 | LogHeader, hmSizeX, hmSizeY, SizeX, SizeY); | ||
671 | |||
672 | } | ||
463 | } | 673 | } |
464 | } | 674 | } |