diff options
author | onefang | 2019-09-11 16:36:50 +1000 |
---|---|---|
committer | onefang | 2019-09-11 16:36:50 +1000 |
commit | 50cd1ffd32f69228e566f2b0b89f86ea0d9fe489 (patch) | |
tree | 52f2ab0c04f1a5d7d6ac5dc872981b4b156447e7 /OpenSim/Framework/TerrainData.cs | |
parent | Renamed branch to SledjChisl. (diff) | |
parent | Bump to release flavour, build 0. (diff) | |
download | opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.zip opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.gz opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.bz2 opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.xz |
Merge branch 'SledjChisl'
Diffstat (limited to 'OpenSim/Framework/TerrainData.cs')
-rw-r--r-- | OpenSim/Framework/TerrainData.cs | 324 |
1 files changed, 268 insertions, 56 deletions
diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs index 6b1be4e..5cec2b5 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 */); |
@@ -194,6 +201,7 @@ namespace OpenSim.Framework | |||
194 | public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob) | 201 | public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob) |
195 | { | 202 | { |
196 | bool ret = false; | 203 | bool ret = false; |
204 | /* save all as Variable2DGzip | ||
197 | if (SizeX == Constants.RegionSize && SizeY == Constants.RegionSize) | 205 | if (SizeX == Constants.RegionSize && SizeY == Constants.RegionSize) |
198 | { | 206 | { |
199 | DBRevisionCode = (int)DBTerrainRevision.Legacy256; | 207 | DBRevisionCode = (int)DBTerrainRevision.Legacy256; |
@@ -202,10 +210,13 @@ namespace OpenSim.Framework | |||
202 | } | 210 | } |
203 | else | 211 | else |
204 | { | 212 | { |
205 | DBRevisionCode = (int)DBTerrainRevision.Compressed2D; | 213 | */ |
206 | blob = ToCompressedTerrainSerialization(); | 214 | DBRevisionCode = (int)DBTerrainRevision.Variable2DGzip; |
215 | // DBRevisionCode = (int)DBTerrainRevision.Variable2D; | ||
216 | blob = ToCompressedTerrainSerializationV2DGzip(); | ||
217 | // blob = ToCompressedTerrainSerializationV2D(); | ||
207 | ret = true; | 218 | ret = true; |
208 | } | 219 | // } |
209 | return ret; | 220 | return ret; |
210 | } | 221 | } |
211 | 222 | ||
@@ -214,9 +225,9 @@ namespace OpenSim.Framework | |||
214 | public override float CompressionFactor { get { return m_compressionFactor; } } | 225 | public override float CompressionFactor { get { return m_compressionFactor; } } |
215 | 226 | ||
216 | // TerrainData.GetCompressedMap | 227 | // TerrainData.GetCompressedMap |
217 | public override int[] GetCompressedMap() | 228 | public override float[] GetCompressedMap() |
218 | { | 229 | { |
219 | int[] newMap = new int[SizeX * SizeY]; | 230 | float[] newMap = new float[SizeX * SizeY]; |
220 | 231 | ||
221 | int ind = 0; | 232 | int ind = 0; |
222 | for (int xx = 0; xx < SizeX; xx++) | 233 | for (int xx = 0; xx < SizeX; xx++) |
@@ -230,7 +241,7 @@ namespace OpenSim.Framework | |||
230 | public override TerrainData Clone() | 241 | public override TerrainData Clone() |
231 | { | 242 | { |
232 | HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ); | 243 | HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ); |
233 | ret.m_heightmap = (int[,])this.m_heightmap.Clone(); | 244 | ret.m_heightmap = (float[,])this.m_heightmap.Clone(); |
234 | return ret; | 245 | return ret; |
235 | } | 246 | } |
236 | 247 | ||
@@ -247,7 +258,7 @@ namespace OpenSim.Framework | |||
247 | for (int jj = 0; jj < SizeY; jj++) | 258 | for (int jj = 0; jj < SizeY; jj++) |
248 | for (int ii = 0; ii < SizeX; ii++) | 259 | for (int ii = 0; ii < SizeX; ii++) |
249 | { | 260 | { |
250 | heights[idx++] = FromCompressedHeight(m_heightmap[ii, jj]); | 261 | heights[idx++] = m_heightmap[ii, jj]; |
251 | } | 262 | } |
252 | 263 | ||
253 | return heights; | 264 | return heights; |
@@ -259,7 +270,7 @@ namespace OpenSim.Framework | |||
259 | double[,] ret = new double[SizeX, SizeY]; | 270 | double[,] ret = new double[SizeX, SizeY]; |
260 | for (int xx = 0; xx < SizeX; xx++) | 271 | for (int xx = 0; xx < SizeX; xx++) |
261 | for (int yy = 0; yy < SizeY; yy++) | 272 | for (int yy = 0; yy < SizeY; yy++) |
262 | ret[xx, yy] = FromCompressedHeight(m_heightmap[xx, yy]); | 273 | ret[xx, yy] = (double)m_heightmap[xx, yy]; |
263 | 274 | ||
264 | return ret; | 275 | return ret; |
265 | } | 276 | } |
@@ -267,19 +278,40 @@ namespace OpenSim.Framework | |||
267 | 278 | ||
268 | // ============================================================= | 279 | // ============================================================= |
269 | 280 | ||
270 | private int[,] m_heightmap; | 281 | private float[,] m_heightmap; |
271 | // Remember subregions of the heightmap that has changed. | 282 | // Remember subregions of the heightmap that has changed. |
272 | private bool[,] m_taint; | 283 | private bool[,] m_taint; |
273 | 284 | ||
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' | 285 | // that is coded as the float height times the compression factor (usually '100' |
276 | // to make for two decimal points). | 286 | // to make for two decimal points). |
277 | public int ToCompressedHeight(double pHeight) | 287 | public short ToCompressedHeightshort(float pHeight) |
278 | { | 288 | { |
279 | return (int)(pHeight * CompressionFactor); | 289 | // clamp into valid range |
290 | pHeight *= CompressionFactor; | ||
291 | if (pHeight < short.MinValue) | ||
292 | return short.MinValue; | ||
293 | else if (pHeight > short.MaxValue) | ||
294 | return short.MaxValue; | ||
295 | return (short)pHeight; | ||
280 | } | 296 | } |
281 | 297 | ||
282 | public float FromCompressedHeight(int pHeight) | 298 | public ushort ToCompressedHeightushort(float pHeight) |
299 | { | ||
300 | // clamp into valid range | ||
301 | pHeight *= CompressionFactor; | ||
302 | if (pHeight < ushort.MinValue) | ||
303 | return ushort.MinValue; | ||
304 | else if (pHeight > ushort.MaxValue) | ||
305 | return ushort.MaxValue; | ||
306 | return (ushort)pHeight; | ||
307 | } | ||
308 | |||
309 | public float FromCompressedHeight(short pHeight) | ||
310 | { | ||
311 | return ((float)pHeight) / CompressionFactor; | ||
312 | } | ||
313 | |||
314 | public float FromCompressedHeight(ushort pHeight) | ||
283 | { | 315 | { |
284 | return ((float)pHeight) / CompressionFactor; | 316 | return ((float)pHeight) / CompressionFactor; |
285 | } | 317 | } |
@@ -293,12 +325,12 @@ namespace OpenSim.Framework | |||
293 | SizeZ = (int)Constants.RegionHeight; | 325 | SizeZ = (int)Constants.RegionHeight; |
294 | m_compressionFactor = 100.0f; | 326 | m_compressionFactor = 100.0f; |
295 | 327 | ||
296 | m_heightmap = new int[SizeX, SizeY]; | 328 | m_heightmap = new float[SizeX, SizeY]; |
297 | for (int ii = 0; ii < SizeX; ii++) | 329 | for (int ii = 0; ii < SizeX; ii++) |
298 | { | 330 | { |
299 | for (int jj = 0; jj < SizeY; jj++) | 331 | for (int jj = 0; jj < SizeY; jj++) |
300 | { | 332 | { |
301 | m_heightmap[ii, jj] = ToCompressedHeight(pTerrain[ii, jj]); | 333 | m_heightmap[ii, jj] = (float)pTerrain[ii, jj]; |
302 | 334 | ||
303 | } | 335 | } |
304 | } | 336 | } |
@@ -315,14 +347,15 @@ namespace OpenSim.Framework | |||
315 | SizeY = pY; | 347 | SizeY = pY; |
316 | SizeZ = pZ; | 348 | SizeZ = pZ; |
317 | m_compressionFactor = 100.0f; | 349 | m_compressionFactor = 100.0f; |
318 | m_heightmap = new int[SizeX, SizeY]; | 350 | m_heightmap = new float[SizeX, SizeY]; |
319 | m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize]; | 351 | 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); | 352 | // m_log.DebugFormat("{0} new by dimensions. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ); |
321 | ClearTaint(); | 353 | ClearTaint(); |
322 | ClearLand(0f); | 354 | ClearLand(0f); |
323 | } | 355 | } |
324 | 356 | ||
325 | public HeightmapTerrainData(int[] cmap, float pCompressionFactor, int pX, int pY, int pZ) : this(pX, pY, pZ) | 357 | public HeightmapTerrainData(float[] cmap, float pCompressionFactor, int pX, int pY, int pZ) |
358 | : this(pX, pY, pZ) | ||
326 | { | 359 | { |
327 | m_compressionFactor = pCompressionFactor; | 360 | m_compressionFactor = pCompressionFactor; |
328 | int ind = 0; | 361 | int ind = 0; |
@@ -333,12 +366,22 @@ namespace OpenSim.Framework | |||
333 | } | 366 | } |
334 | 367 | ||
335 | // Create a heighmap from a database blob | 368 | // Create a heighmap from a database blob |
336 | public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) : this(pSizeX, pSizeY, pSizeZ) | 369 | public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) |
370 | : this(pSizeX, pSizeY, pSizeZ) | ||
337 | { | 371 | { |
338 | switch ((DBTerrainRevision)pFormatCode) | 372 | switch ((DBTerrainRevision)pFormatCode) |
339 | { | 373 | { |
374 | case DBTerrainRevision.Variable2DGzip: | ||
375 | FromCompressedTerrainSerializationV2DGZip(pBlob); | ||
376 | m_log.DebugFormat("{0} HeightmapTerrainData create from Variable2DGzip serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); | ||
377 | break; | ||
378 | |||
379 | case DBTerrainRevision.Variable2D: | ||
380 | FromCompressedTerrainSerializationV2D(pBlob); | ||
381 | m_log.DebugFormat("{0} HeightmapTerrainData create from Variable2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); | ||
382 | break; | ||
340 | case DBTerrainRevision.Compressed2D: | 383 | case DBTerrainRevision.Compressed2D: |
341 | FromCompressedTerrainSerialization(pBlob); | 384 | FromCompressedTerrainSerialization2D(pBlob); |
342 | m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); | 385 | m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); |
343 | break; | 386 | break; |
344 | default: | 387 | default: |
@@ -373,50 +416,116 @@ namespace OpenSim.Framework | |||
373 | return ret; | 416 | return ret; |
374 | } | 417 | } |
375 | 418 | ||
376 | // Just create an array of doubles. Presumes the caller implicitly knows the size. | 419 | // Presumes the caller implicitly knows the size. |
377 | public void FromLegacyTerrainSerialization(byte[] pBlob) | 420 | public void FromLegacyTerrainSerialization(byte[] pBlob) |
378 | { | 421 | { |
379 | // In case database info doesn't match real terrain size, initialize the whole terrain. | 422 | // In case database info doesn't match real terrain size, initialize the whole terrain. |
380 | ClearLand(); | 423 | ClearLand(); |
381 | 424 | ||
382 | using (MemoryStream mstr = new MemoryStream(pBlob)) | 425 | try |
383 | { | 426 | { |
384 | using (BinaryReader br = new BinaryReader(mstr)) | 427 | using (MemoryStream mstr = new MemoryStream(pBlob)) |
385 | { | 428 | { |
386 | for (int xx = 0; xx < (int)Constants.RegionSize; xx++) | 429 | using (BinaryReader br = new BinaryReader(mstr)) |
387 | { | 430 | { |
388 | for (int yy = 0; yy < (int)Constants.RegionSize; yy++) | 431 | for (int xx = 0; xx < (int)Constants.RegionSize; xx++) |
389 | { | 432 | { |
390 | float val = (float)br.ReadDouble(); | 433 | for (int yy = 0; yy < (int)Constants.RegionSize; yy++) |
391 | if (xx < SizeX && yy < SizeY) | 434 | { |
392 | m_heightmap[xx, yy] = ToCompressedHeight(val); | 435 | float val = (float)br.ReadDouble(); |
436 | |||
437 | if (xx < SizeX && yy < SizeY) | ||
438 | m_heightmap[xx, yy] = val; | ||
439 | } | ||
393 | } | 440 | } |
394 | } | 441 | } |
395 | } | 442 | } |
396 | ClearTaint(); | ||
397 | } | 443 | } |
444 | catch | ||
445 | { | ||
446 | ClearLand(); | ||
447 | } | ||
448 | ClearTaint(); | ||
449 | } | ||
450 | |||
451 | |||
452 | // stores as variable2D | ||
453 | // int32 sizeX | ||
454 | // int32 sizeY | ||
455 | // float[,] array | ||
456 | |||
457 | public Array ToCompressedTerrainSerializationV2D() | ||
458 | { | ||
459 | Array ret = null; | ||
460 | try | ||
461 | { | ||
462 | using (MemoryStream str = new MemoryStream((2 * sizeof(Int32)) + (SizeX * SizeY * sizeof(float)))) | ||
463 | { | ||
464 | using (BinaryWriter bw = new BinaryWriter(str)) | ||
465 | { | ||
466 | bw.Write((Int32)SizeX); | ||
467 | bw.Write((Int32)SizeY); | ||
468 | for (int yy = 0; yy < SizeY; yy++) | ||
469 | for (int xx = 0; xx < SizeX; xx++) | ||
470 | { | ||
471 | // reduce to 1cm resolution | ||
472 | float val = (float)Math.Round(m_heightmap[xx, yy],2,MidpointRounding.ToEven); | ||
473 | bw.Write(val); | ||
474 | } | ||
475 | } | ||
476 | ret = str.ToArray(); | ||
477 | } | ||
478 | } | ||
479 | catch | ||
480 | { | ||
481 | |||
482 | } | ||
483 | |||
484 | m_log.DebugFormat("{0} V2D {1} bytes", | ||
485 | LogHeader, ret.Length); | ||
486 | |||
487 | return ret; | ||
398 | } | 488 | } |
399 | 489 | ||
400 | // See the reader below. | 490 | // as above with Gzip compression |
401 | public Array ToCompressedTerrainSerialization() | 491 | public Array ToCompressedTerrainSerializationV2DGzip() |
402 | { | 492 | { |
403 | Array ret = null; | 493 | Array ret = null; |
404 | using (MemoryStream str = new MemoryStream((3 * sizeof(Int32)) + (SizeX * SizeY * sizeof(Int16)))) | 494 | try |
405 | { | 495 | { |
406 | using (BinaryWriter bw = new BinaryWriter(str)) | 496 | using (MemoryStream inp = new MemoryStream((2 * sizeof(Int32)) + (SizeX * SizeY * sizeof(float)))) |
407 | { | 497 | { |
408 | bw.Write((Int32)DBTerrainRevision.Compressed2D); | 498 | using (BinaryWriter bw = new BinaryWriter(inp)) |
409 | bw.Write((Int32)SizeX); | 499 | { |
410 | bw.Write((Int32)SizeY); | 500 | bw.Write((Int32)SizeX); |
411 | bw.Write((Int32)CompressionFactor); | 501 | bw.Write((Int32)SizeY); |
412 | for (int yy = 0; yy < SizeY; yy++) | 502 | for (int yy = 0; yy < SizeY; yy++) |
413 | for (int xx = 0; xx < SizeX; xx++) | 503 | for (int xx = 0; xx < SizeX; xx++) |
504 | { | ||
505 | bw.Write((float)m_heightmap[xx, yy]); | ||
506 | } | ||
507 | |||
508 | bw.Flush(); | ||
509 | inp.Seek(0, SeekOrigin.Begin); | ||
510 | |||
511 | using (MemoryStream outputStream = new MemoryStream()) | ||
414 | { | 512 | { |
415 | bw.Write((Int16)m_heightmap[xx, yy]); | 513 | using (GZipStream compressionStream = new GZipStream(outputStream, CompressionMode.Compress)) |
514 | { | ||
515 | inp.CopyStream(compressionStream, int.MaxValue); | ||
516 | compressionStream.Close(); | ||
517 | ret = outputStream.ToArray(); | ||
518 | } | ||
416 | } | 519 | } |
520 | } | ||
417 | } | 521 | } |
418 | ret = str.ToArray(); | ||
419 | } | 522 | } |
523 | catch | ||
524 | { | ||
525 | |||
526 | } | ||
527 | m_log.DebugFormat("{0} V2DGzip {1} bytes", | ||
528 | LogHeader, ret.Length); | ||
420 | return ret; | 529 | return ret; |
421 | } | 530 | } |
422 | 531 | ||
@@ -426,7 +535,7 @@ namespace OpenSim.Framework | |||
426 | // the forth int is the compression factor for the following int16s | 535 | // 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 | 536 | // 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. | 537 | // creation and any heights not initialized by theis blob are set to the default height. |
429 | public void FromCompressedTerrainSerialization(byte[] pBlob) | 538 | public void FromCompressedTerrainSerialization2D(byte[] pBlob) |
430 | { | 539 | { |
431 | Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor; | 540 | Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor; |
432 | 541 | ||
@@ -448,7 +557,7 @@ namespace OpenSim.Framework | |||
448 | { | 557 | { |
449 | for (int xx = 0; xx < hmSizeX; xx++) | 558 | for (int xx = 0; xx < hmSizeX; xx++) |
450 | { | 559 | { |
451 | Int16 val = br.ReadInt16(); | 560 | float val = FromCompressedHeight(br.ReadInt16()); |
452 | if (xx < SizeX && yy < SizeY) | 561 | if (xx < SizeX && yy < SizeY) |
453 | m_heightmap[xx, yy] = val; | 562 | m_heightmap[xx, yy] = val; |
454 | } | 563 | } |
@@ -456,9 +565,112 @@ namespace OpenSim.Framework | |||
456 | } | 565 | } |
457 | ClearTaint(); | 566 | ClearTaint(); |
458 | 567 | ||
459 | m_log.InfoFormat("{0} Read compressed 2d heightmap. Heightmap size=<{1},{2}>. Region size=<{3},{4}>. CompFact={5}", | 568 | m_log.DebugFormat("{0} Read (compressed2D) heightmap. Heightmap size=<{1},{2}>. Region size=<{3},{4}>. CompFact={5}", |
460 | LogHeader, hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor); | 569 | LogHeader, hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor); |
461 | } | 570 | } |
462 | } | 571 | } |
572 | |||
573 | // Initialize heightmap from blob consisting of: | ||
574 | // int32, int32, int32, float[] | ||
575 | // where the first int32 is format code, next two int32s are the X and y of heightmap data | ||
576 | // This is just sets heightmap info. The actual size of the region was set on this instance's | ||
577 | // creation and any heights not initialized by theis blob are set to the default height. | ||
578 | public void FromCompressedTerrainSerializationV2D(byte[] pBlob) | ||
579 | { | ||
580 | Int32 hmSizeX, hmSizeY; | ||
581 | try | ||
582 | { | ||
583 | using (MemoryStream mstr = new MemoryStream(pBlob)) | ||
584 | { | ||
585 | using (BinaryReader br = new BinaryReader(mstr)) | ||
586 | { | ||
587 | hmSizeX = br.ReadInt32(); | ||
588 | hmSizeY = br.ReadInt32(); | ||
589 | |||
590 | // In case database info doesn't match real terrain size, initialize the whole terrain. | ||
591 | ClearLand(); | ||
592 | |||
593 | for (int yy = 0; yy < hmSizeY; yy++) | ||
594 | { | ||
595 | for (int xx = 0; xx < hmSizeX; xx++) | ||
596 | { | ||
597 | float val = br.ReadSingle(); | ||
598 | if (xx < SizeX && yy < SizeY) | ||
599 | m_heightmap[xx, yy] = val; | ||
600 | } | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | } | ||
605 | catch (Exception e) | ||
606 | { | ||
607 | ClearTaint(); | ||
608 | m_log.ErrorFormat("{0} 2D error: {1} - terrain may be damaged", | ||
609 | LogHeader, e.Message); | ||
610 | return; | ||
611 | } | ||
612 | ClearTaint(); | ||
613 | |||
614 | m_log.DebugFormat("{0} V2D Heightmap size=<{1},{2}>. Region size=<{3},{4}>", | ||
615 | LogHeader, hmSizeX, hmSizeY, SizeX, SizeY); | ||
616 | |||
617 | } | ||
618 | |||
619 | // as above but Gzip compressed | ||
620 | public void FromCompressedTerrainSerializationV2DGZip(byte[] pBlob) | ||
621 | { | ||
622 | m_log.InfoFormat("{0} VD2Gzip {1} bytes input", | ||
623 | LogHeader, pBlob.Length); | ||
624 | |||
625 | Int32 hmSizeX, hmSizeY; | ||
626 | |||
627 | try | ||
628 | { | ||
629 | using (MemoryStream outputStream = new MemoryStream()) | ||
630 | { | ||
631 | using (MemoryStream inputStream = new MemoryStream(pBlob)) | ||
632 | { | ||
633 | using (GZipStream decompressionStream = new GZipStream(inputStream, CompressionMode.Decompress)) | ||
634 | { | ||
635 | decompressionStream.Flush(); | ||
636 | decompressionStream.CopyTo(outputStream); | ||
637 | } | ||
638 | } | ||
639 | |||
640 | outputStream.Seek(0, SeekOrigin.Begin); | ||
641 | |||
642 | using (BinaryReader br = new BinaryReader(outputStream)) | ||
643 | { | ||
644 | hmSizeX = br.ReadInt32(); | ||
645 | hmSizeY = br.ReadInt32(); | ||
646 | |||
647 | // In case database info doesn't match real terrain size, initialize the whole terrain. | ||
648 | ClearLand(); | ||
649 | |||
650 | for (int yy = 0; yy < hmSizeY; yy++) | ||
651 | { | ||
652 | for (int xx = 0; xx < hmSizeX; xx++) | ||
653 | { | ||
654 | float val = br.ReadSingle(); | ||
655 | if (xx < SizeX && yy < SizeY) | ||
656 | m_heightmap[xx, yy] = val; | ||
657 | } | ||
658 | } | ||
659 | } | ||
660 | } | ||
661 | } | ||
662 | catch( Exception e) | ||
663 | { | ||
664 | ClearTaint(); | ||
665 | m_log.ErrorFormat("{0} V2DGzip error: {1} - terrain may be damaged", | ||
666 | LogHeader, e.Message); | ||
667 | return; | ||
668 | } | ||
669 | |||
670 | ClearTaint(); | ||
671 | m_log.DebugFormat("{0} V2DGzip. Heightmap size=<{1},{2}>. Region size=<{3},{4}>", | ||
672 | LogHeader, hmSizeX, hmSizeY, SizeX, SizeY); | ||
673 | |||
674 | } | ||
463 | } | 675 | } |
464 | } | 676 | } |