aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Framework/TerrainData.cs251
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs49
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainChannel.cs6
3 files changed, 269 insertions, 37 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 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.IO; 30using System.IO;
31using System.IO.Compression;
31using System.Reflection; 32using System.Reflection;
32 33
33using OpenMetaverse; 34using 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}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index 118c8f8..135fe50 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -1349,6 +1349,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1349 double desiredMin = (double)args[0]; 1349 double desiredMin = (double)args[0];
1350 double desiredMax = (double)args[1]; 1350 double desiredMax = (double)args[1];
1351 1351
1352 if (desiredMin < 0 || desiredMin > 655.35
1353 || desiredMax < 0 || desiredMax > 655.35)
1354 {
1355 m_log.Error("desired Min and Max must be in range 0.0 to 655.0m");
1356 return;
1357 }
1358
1352 // determine desired scaling factor 1359 // determine desired scaling factor
1353 double desiredRange = desiredMax - desiredMin; 1360 double desiredRange = desiredMax - desiredMin;
1354 //m_log.InfoFormat("Desired {0}, {1} = {2}", new Object[] { desiredMin, desiredMax, desiredRange }); 1361 //m_log.InfoFormat("Desired {0}, {1} = {2}", new Object[] { desiredMin, desiredMax, desiredRange });
@@ -1405,45 +1412,69 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1405 1412
1406 private void InterfaceElevateTerrain(Object[] args) 1413 private void InterfaceElevateTerrain(Object[] args)
1407 { 1414 {
1415 double val = (double)args[0];
1416 if (val < 0 || val > 655.35)
1417 {
1418 m_log.Error("elevation must be in range 0.0 to 655.0m");
1419 return;
1420 }
1421
1408 int x, y; 1422 int x, y;
1409 for (x = 0; x < m_channel.Width; x++) 1423 for (x = 0; x < m_channel.Width; x++)
1410 for (y = 0; y < m_channel.Height; y++) 1424 for (y = 0; y < m_channel.Height; y++)
1411 m_channel[x, y] += (double) args[0]; 1425 m_channel[x, y] += val;
1412 } 1426 }
1413 1427
1414 private void InterfaceMultiplyTerrain(Object[] args) 1428 private void InterfaceMultiplyTerrain(Object[] args)
1415 { 1429 {
1416 int x, y; 1430 int x, y;
1431 double val = (double)args[0];
1432
1417 for (x = 0; x < m_channel.Width; x++) 1433 for (x = 0; x < m_channel.Width; x++)
1418 for (y = 0; y < m_channel.Height; y++) 1434 for (y = 0; y < m_channel.Height; y++)
1419 m_channel[x, y] *= (double) args[0]; 1435 m_channel[x, y] *= val;
1420 } 1436 }
1421 1437
1422 private void InterfaceLowerTerrain(Object[] args) 1438 private void InterfaceLowerTerrain(Object[] args)
1423 { 1439 {
1424 int x, y; 1440 int x, y;
1441 double val = (double)args[0];
1442 if (val < 0 || val > 655.35)
1443
1425 for (x = 0; x < m_channel.Width; x++) 1444 for (x = 0; x < m_channel.Width; x++)
1426 for (y = 0; y < m_channel.Height; y++) 1445 for (y = 0; y < m_channel.Height; y++)
1427 m_channel[x, y] -= (double) args[0]; 1446 m_channel[x, y] -= val;
1428 } 1447 }
1429 1448
1430 public void InterfaceFillTerrain(Object[] args) 1449 public void InterfaceFillTerrain(Object[] args)
1431 { 1450 {
1432 int x, y; 1451 int x, y;
1452 double val = (double)args[0];
1453 if (val < 0 || val > 655.35)
1454 {
1455 m_log.Error("height must be in range 0.0 to 655.0m");
1456 return;
1457 }
1433 1458
1434 for (x = 0; x < m_channel.Width; x++) 1459 for (x = 0; x < m_channel.Width; x++)
1435 for (y = 0; y < m_channel.Height; y++) 1460 for (y = 0; y < m_channel.Height; y++)
1436 m_channel[x, y] = (double) args[0]; 1461 m_channel[x, y] = val;
1437 } 1462 }
1438 1463
1439 private void InterfaceMinTerrain(Object[] args) 1464 private void InterfaceMinTerrain(Object[] args)
1440 { 1465 {
1441 int x, y; 1466 int x, y;
1467 double val = (double)args[0];
1468 if (val < 0 || val > 655.35)
1469 {
1470 m_log.Error("minimum must be in range 0.0 to 655.0m");
1471 return;
1472 }
1442 for (x = 0; x < m_channel.Width; x++) 1473 for (x = 0; x < m_channel.Width; x++)
1443 { 1474 {
1444 for (y = 0; y < m_channel.Height; y++) 1475 for (y = 0; y < m_channel.Height; y++)
1445 { 1476 {
1446 m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); 1477 m_channel[x, y] = Math.Max(val, m_channel[x, y]);
1447 } 1478 }
1448 } 1479 }
1449 } 1480 }
@@ -1451,11 +1482,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1451 private void InterfaceMaxTerrain(Object[] args) 1482 private void InterfaceMaxTerrain(Object[] args)
1452 { 1483 {
1453 int x, y; 1484 int x, y;
1485 double val = (double)args[0];
1486 if (val < 0 || val > 655.35)
1487 {
1488 m_log.Error("maximum must be in range 0.0 to 655.0m");
1489 return;
1490 }
1454 for (x = 0; x < m_channel.Width; x++) 1491 for (x = 0; x < m_channel.Width; x++)
1455 { 1492 {
1456 for (y = 0; y < m_channel.Height; y++) 1493 for (y = 0; y < m_channel.Height; y++)
1457 { 1494 {
1458 m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); 1495 m_channel[x, y] = Math.Min(val, m_channel[x, y]);
1459 } 1496 }
1460 } 1497 }
1461 } 1498 }
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
index 2dab246..75c3a3b 100644
--- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
+++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
@@ -157,7 +157,11 @@ namespace OpenSim.Region.Framework.Scenes
157 { 157 {
158 if (Double.IsNaN(value) || Double.IsInfinity(value)) 158 if (Double.IsNaN(value) || Double.IsInfinity(value))
159 return; 159 return;
160 160 if (value < 0)
161 value = 0;
162 else
163 if (value > 655.35)
164 value = 655.35;
161 m_terrainData[x, y] = (float)value; 165 m_terrainData[x, y] = (float)value;
162 } 166 }
163 } 167 }