diff options
Diffstat (limited to 'OpenSim/Framework')
-rw-r--r-- | OpenSim/Framework/TerrainData.cs | 251 |
1 files changed, 221 insertions, 30 deletions
diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs index d0eddc6..cc5b8f5 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; |
@@ -102,6 +103,11 @@ namespace OpenSim.Framework | |||
102 | // "ushort compressedHeight = (ushort)(height * compressionFactor);" | 103 | // "ushort compressedHeight = (ushort)(height * compressionFactor);" |
103 | // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256. | 104 | // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256. |
104 | Compressed2D = 27, | 105 | Compressed2D = 27, |
106 | // as Compressed2D but using ushort[] in place of int16[] | ||
107 | Compressed2Du = 28, | ||
108 | // as Compressed2D but using ushort[] in place of int16[] with Gzip compression | ||
109 | Compressed2DuGzip = 29, | ||
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 | } |
@@ -120,7 +126,8 @@ namespace OpenSim.Framework | |||
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 FromCompressedHeight(m_heightmap[x, y]); } |
123 | set { | 129 | set |
130 | { | ||
124 | ushort newVal = ToCompressedHeight(value); | 131 | ushort newVal = ToCompressedHeight(value); |
125 | if (m_heightmap[x, y] != newVal) | 132 | if (m_heightmap[x, y] != newVal) |
126 | { | 133 | { |
@@ -177,7 +184,7 @@ namespace OpenSim.Framework | |||
177 | { | 184 | { |
178 | int tx = xx / Constants.TerrainPatchSize; | 185 | int tx = xx / Constants.TerrainPatchSize; |
179 | int ty = yy / Constants.TerrainPatchSize; | 186 | int ty = yy / Constants.TerrainPatchSize; |
180 | bool ret = m_taint[tx, ty]; | 187 | bool ret = m_taint[tx, ty]; |
181 | if (ret && clearOnTest) | 188 | if (ret && clearOnTest) |
182 | m_taint[tx, ty] = false; | 189 | m_taint[tx, ty] = false; |
183 | return ret; | 190 | return ret; |
@@ -202,8 +209,8 @@ namespace OpenSim.Framework | |||
202 | } | 209 | } |
203 | else | 210 | else |
204 | { | 211 | { |
205 | DBRevisionCode = (int)DBTerrainRevision.Compressed2D; | 212 | DBRevisionCode = (int)DBTerrainRevision.Compressed2DuGzip; |
206 | blob = ToCompressedTerrainSerialization(); | 213 | blob = ToCompressedTerrainSerializationGzip(); |
207 | ret = true; | 214 | ret = true; |
208 | } | 215 | } |
209 | return ret; | 216 | return ret; |
@@ -276,6 +283,11 @@ namespace OpenSim.Framework | |||
276 | // to make for two decimal points). | 283 | // to make for two decimal points). |
277 | public ushort ToCompressedHeight(double pHeight) | 284 | public ushort ToCompressedHeight(double pHeight) |
278 | { | 285 | { |
286 | // clamp into valid range | ||
287 | if (pHeight < 0) | ||
288 | pHeight = 0; | ||
289 | else if (pHeight > 655.35f) | ||
290 | pHeight = 655.35f; | ||
279 | return (ushort)(pHeight * CompressionFactor); | 291 | return (ushort)(pHeight * CompressionFactor); |
280 | } | 292 | } |
281 | 293 | ||
@@ -322,7 +334,8 @@ namespace OpenSim.Framework | |||
322 | ClearLand(0f); | 334 | ClearLand(0f); |
323 | } | 335 | } |
324 | 336 | ||
325 | public HeightmapTerrainData(ushort[] cmap, float pCompressionFactor, int pX, int pY, int pZ) : this(pX, pY, pZ) | 337 | public HeightmapTerrainData(ushort[] cmap, float pCompressionFactor, int pX, int pY, int pZ) |
338 | : this(pX, pY, pZ) | ||
326 | { | 339 | { |
327 | m_compressionFactor = pCompressionFactor; | 340 | m_compressionFactor = pCompressionFactor; |
328 | int ind = 0; | 341 | int ind = 0; |
@@ -333,12 +346,21 @@ namespace OpenSim.Framework | |||
333 | } | 346 | } |
334 | 347 | ||
335 | // Create a heighmap from a database blob | 348 | // Create a heighmap from a database blob |
336 | public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) : this(pSizeX, pSizeY, pSizeZ) | 349 | public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) |
350 | : this(pSizeX, pSizeY, pSizeZ) | ||
337 | { | 351 | { |
338 | switch ((DBTerrainRevision)pFormatCode) | 352 | switch ((DBTerrainRevision)pFormatCode) |
339 | { | 353 | { |
340 | case DBTerrainRevision.Compressed2D: | 354 | case DBTerrainRevision.Compressed2DuGzip: |
355 | FromCompressedTerrainSerializationGZip(pBlob); | ||
356 | m_log.DebugFormat("{0} HeightmapTerrainData create from Gzip Compressed2D (unsigned shorts) serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); | ||
357 | break; | ||
358 | case DBTerrainRevision.Compressed2Du: | ||
341 | FromCompressedTerrainSerialization(pBlob); | 359 | FromCompressedTerrainSerialization(pBlob); |
360 | m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D (unsigned shorts) serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); | ||
361 | break; | ||
362 | case DBTerrainRevision.Compressed2D: | ||
363 | FromCompressedTerrainSerialization2D(pBlob); | ||
342 | m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); | 364 | m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); |
343 | break; | 365 | break; |
344 | default: | 366 | default: |
@@ -379,44 +401,132 @@ namespace OpenSim.Framework | |||
379 | // In case database info doesn't match real terrain size, initialize the whole terrain. | 401 | // In case database info doesn't match real terrain size, initialize the whole terrain. |
380 | ClearLand(); | 402 | ClearLand(); |
381 | 403 | ||
382 | using (MemoryStream mstr = new MemoryStream(pBlob)) | 404 | try |
383 | { | 405 | { |
384 | using (BinaryReader br = new BinaryReader(mstr)) | 406 | using (MemoryStream mstr = new MemoryStream(pBlob)) |
385 | { | 407 | { |
386 | for (int xx = 0; xx < (int)Constants.RegionSize; xx++) | 408 | using (BinaryReader br = new BinaryReader(mstr)) |
387 | { | 409 | { |
388 | for (int yy = 0; yy < (int)Constants.RegionSize; yy++) | 410 | for (int xx = 0; xx < (int)Constants.RegionSize; xx++) |
389 | { | 411 | { |
390 | float val = (float)br.ReadDouble(); | 412 | for (int yy = 0; yy < (int)Constants.RegionSize; yy++) |
391 | if (xx < SizeX && yy < SizeY) | 413 | { |
392 | m_heightmap[xx, yy] = ToCompressedHeight(val); | 414 | float val = (float)br.ReadDouble(); |
415 | |||
416 | if (xx < SizeX && yy < SizeY) | ||
417 | m_heightmap[xx, yy] = ToCompressedHeight(val); | ||
418 | } | ||
393 | } | 419 | } |
394 | } | 420 | } |
395 | } | 421 | } |
396 | ClearTaint(); | ||
397 | } | 422 | } |
423 | catch | ||
424 | { | ||
425 | ClearLand(); | ||
426 | } | ||
427 | ClearTaint(); | ||
428 | } | ||
429 | |||
430 | public Array ToCompressedTerrainSerialization2D() | ||
431 | { | ||
432 | Array ret = null; | ||
433 | try | ||
434 | { | ||
435 | using (MemoryStream str = new MemoryStream((4 * sizeof(Int32)) + (SizeX * SizeY * sizeof(ushort)))) | ||
436 | { | ||
437 | using (BinaryWriter bw = new BinaryWriter(str)) | ||
438 | { | ||
439 | bw.Write((Int32)DBTerrainRevision.Compressed2D); | ||
440 | bw.Write((Int32)SizeX); | ||
441 | bw.Write((Int32)SizeY); | ||
442 | bw.Write((Int32)CompressionFactor); | ||
443 | for (int yy = 0; yy < SizeY; yy++) | ||
444 | for (int xx = 0; xx < SizeX; xx++) | ||
445 | { | ||
446 | bw.Write((Int16)m_heightmap[xx, yy]); | ||
447 | } | ||
448 | } | ||
449 | ret = str.ToArray(); | ||
450 | } | ||
451 | } | ||
452 | catch | ||
453 | { | ||
454 | |||
455 | } | ||
456 | return ret; | ||
398 | } | 457 | } |
399 | 458 | ||
400 | // See the reader below. | 459 | // See the reader below. |
401 | public Array ToCompressedTerrainSerialization() | 460 | public Array ToCompressedTerrainSerialization() |
402 | { | 461 | { |
403 | Array ret = null; | 462 | Array ret = null; |
404 | using (MemoryStream str = new MemoryStream((3 * sizeof(Int32)) + (SizeX * SizeY * sizeof(ushort)))) | 463 | try |
405 | { | 464 | { |
406 | using (BinaryWriter bw = new BinaryWriter(str)) | 465 | using (MemoryStream str = new MemoryStream((4 * sizeof(Int32)) + (SizeX * SizeY * sizeof(ushort)))) |
407 | { | 466 | { |
408 | bw.Write((Int32)DBTerrainRevision.Compressed2D); | 467 | using (BinaryWriter bw = new BinaryWriter(str)) |
409 | bw.Write((Int32)SizeX); | 468 | { |
410 | bw.Write((Int32)SizeY); | 469 | bw.Write((Int32)DBTerrainRevision.Compressed2Du); |
411 | bw.Write((Int32)CompressionFactor); | 470 | bw.Write((Int32)SizeX); |
412 | for (int yy = 0; yy < SizeY; yy++) | 471 | bw.Write((Int32)SizeY); |
413 | for (int xx = 0; xx < SizeX; xx++) | 472 | bw.Write((Int32)CompressionFactor); |
473 | for (int yy = 0; yy < SizeY; yy++) | ||
474 | for (int xx = 0; xx < SizeX; xx++) | ||
475 | { | ||
476 | bw.Write((ushort)m_heightmap[xx, yy]); | ||
477 | } | ||
478 | } | ||
479 | ret = str.ToArray(); | ||
480 | } | ||
481 | } | ||
482 | catch | ||
483 | { | ||
484 | |||
485 | } | ||
486 | return ret; | ||
487 | } | ||
488 | |||
489 | // as above with Gzip compression | ||
490 | public Array ToCompressedTerrainSerializationGzip() | ||
491 | { | ||
492 | Array ret = null; | ||
493 | try | ||
494 | { | ||
495 | using (MemoryStream inp = new MemoryStream((4 * sizeof(Int32)) + (SizeX * SizeY * sizeof(ushort)))) | ||
496 | { | ||
497 | using (BinaryWriter bw = new BinaryWriter(inp)) | ||
498 | { | ||
499 | bw.Write((Int32)DBTerrainRevision.Compressed2DuGzip); | ||
500 | bw.Write((Int32)SizeX); | ||
501 | bw.Write((Int32)SizeY); | ||
502 | bw.Write((Int32)CompressionFactor); | ||
503 | for (int yy = 0; yy < SizeY; yy++) | ||
504 | for (int xx = 0; xx < SizeX; xx++) | ||
505 | { | ||
506 | bw.Write((ushort)m_heightmap[xx, yy]); | ||
507 | } | ||
508 | |||
509 | bw.Flush(); | ||
510 | inp.Seek(0,SeekOrigin.Begin); | ||
511 | |||
512 | using (MemoryStream outputStream = new MemoryStream()) | ||
414 | { | 513 | { |
415 | bw.Write((ushort)m_heightmap[xx, yy]); | 514 | using (GZipStream compressionStream = new GZipStream(outputStream, CompressionMode.Compress)) |
515 | { | ||
516 | inp.CopyStream(compressionStream, int.MaxValue); | ||
517 | compressionStream.Close(); | ||
518 | ret = outputStream.ToArray(); | ||
519 | } | ||
416 | } | 520 | } |
521 | } | ||
417 | } | 522 | } |
418 | ret = str.ToArray(); | ||
419 | } | 523 | } |
524 | catch | ||
525 | { | ||
526 | |||
527 | } | ||
528 | m_log.InfoFormat("{0} terrain GZiped to {1} bytes (compressed2Dus)", | ||
529 | LogHeader, ret.Length); | ||
420 | return ret; | 530 | return ret; |
421 | } | 531 | } |
422 | 532 | ||
@@ -426,7 +536,7 @@ namespace OpenSim.Framework | |||
426 | // the forth int is the compression factor for the following int16s | 536 | // 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 | 537 | // 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. | 538 | // creation and any heights not initialized by theis blob are set to the default height. |
429 | public void FromCompressedTerrainSerialization(byte[] pBlob) | 539 | public void FromCompressedTerrainSerialization2D(byte[] pBlob) |
430 | { | 540 | { |
431 | Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor; | 541 | Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor; |
432 | 542 | ||
@@ -448,17 +558,98 @@ namespace OpenSim.Framework | |||
448 | { | 558 | { |
449 | for (int xx = 0; xx < hmSizeX; xx++) | 559 | for (int xx = 0; xx < hmSizeX; xx++) |
450 | { | 560 | { |
451 | ushort val = br.ReadUInt16(); | 561 | short val = br.ReadInt16(); |
562 | if (val < 0) | ||
563 | val = 0; | ||
452 | if (xx < SizeX && yy < SizeY) | 564 | if (xx < SizeX && yy < SizeY) |
453 | m_heightmap[xx, yy] = val; | 565 | m_heightmap[xx, yy] = (ushort)val; |
454 | } | 566 | } |
455 | } | 567 | } |
456 | } | 568 | } |
457 | ClearTaint(); | 569 | ClearTaint(); |
458 | 570 | ||
459 | m_log.InfoFormat("{0} Read compressed 2d heightmap. Heightmap size=<{1},{2}>. Region size=<{3},{4}>. CompFact={5}", | 571 | m_log.InfoFormat("{0} Read (compressed2D) heightmap. Heightmap size=<{1},{2}>. Region size=<{3},{4}>. CompFact={5}", |
460 | LogHeader, hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor); | 572 | LogHeader, hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor); |
461 | } | 573 | } |
462 | } | 574 | } |
575 | |||
576 | // Initialize heightmap from blob consisting of: | ||
577 | // int32, int32, int32, int32, ushort[] | ||
578 | // where the first int32 is format code, next two int32s are the X and y of heightmap data and | ||
579 | // the forth int is the compression factor for the following int16s | ||
580 | // This is just sets heightmap info. The actual size of the region was set on this instance's | ||
581 | // creation and any heights not initialized by theis blob are set to the default height. | ||
582 | public void FromCompressedTerrainSerialization(byte[] pBlob) | ||
583 | { | ||
584 | Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor; | ||
585 | try | ||
586 | { | ||
587 | using (MemoryStream mstr = new MemoryStream(pBlob)) | ||
588 | { | ||
589 | using (BinaryReader br = new BinaryReader(mstr)) | ||
590 | { | ||
591 | hmFormatCode = br.ReadInt32(); | ||
592 | hmSizeX = br.ReadInt32(); | ||
593 | hmSizeY = br.ReadInt32(); | ||
594 | hmCompressionFactor = br.ReadInt32(); | ||
595 | |||
596 | m_compressionFactor = hmCompressionFactor; | ||
597 | |||
598 | // In case database info doesn't match real terrain size, initialize the whole terrain. | ||
599 | ClearLand(); | ||
600 | |||
601 | for (int yy = 0; yy < hmSizeY; yy++) | ||
602 | { | ||
603 | for (int xx = 0; xx < hmSizeX; xx++) | ||
604 | { | ||
605 | ushort val = br.ReadUInt16(); | ||
606 | if (xx < SizeX && yy < SizeY) | ||
607 | m_heightmap[xx, yy] = val; | ||
608 | } | ||
609 | } | ||
610 | } | ||
611 | } | ||
612 | } | ||
613 | catch (Exception e) | ||
614 | { | ||
615 | ClearTaint(); | ||
616 | m_log.ErrorFormat("{0} Read (compressed2Dus) terrain error: {1} - terrain may be damaged", | ||
617 | LogHeader,e.Message); | ||
618 | return; | ||
619 | } | ||
620 | ClearTaint(); | ||
621 | |||
622 | m_log.InfoFormat("{0} Read compressed2D terrain. Heightmap size=<{1},{2}>. Region size=<{3},{4}>. CompFact={5}", | ||
623 | LogHeader, hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor); | ||
624 | |||
625 | } | ||
626 | |||
627 | // as above but Gzip compressed | ||
628 | public void FromCompressedTerrainSerializationGZip(byte[] pBlob) | ||
629 | { | ||
630 | m_log.InfoFormat("{0} GZip {1} bytes for terrain", | ||
631 | LogHeader,pBlob.Length); | ||
632 | byte[] gzipout = null; | ||
633 | try | ||
634 | { | ||
635 | using (MemoryStream inputStream = new MemoryStream(pBlob)) | ||
636 | { | ||
637 | using (GZipStream decompressionStream = new GZipStream(inputStream, CompressionMode.Decompress)) | ||
638 | { | ||
639 | using (MemoryStream outputStream = new MemoryStream()) | ||
640 | { | ||
641 | decompressionStream.Flush(); | ||
642 | decompressionStream.CopyTo(outputStream); | ||
643 | gzipout = outputStream.ToArray(); | ||
644 | } | ||
645 | } | ||
646 | } | ||
647 | } | ||
648 | catch | ||
649 | { | ||
650 | } | ||
651 | |||
652 | FromCompressedTerrainSerialization(gzipout); | ||
653 | } | ||
463 | } | 654 | } |
464 | } | 655 | } |