diff options
author | Robert Adams | 2013-09-25 17:21:20 -0700 |
---|---|---|
committer | Robert Adams | 2013-09-28 07:33:56 -0700 |
commit | 8c1d80fdfd104b94cb7a4fd247b3baa2a9988ea1 (patch) | |
tree | 0423a4cd16f354f21d12162eaa351d9e13ba52fd | |
parent | Remove time based terrain storage in SQLite so revision number can be used (diff) | |
download | opensim-SC_OLD-8c1d80fdfd104b94cb7a4fd247b3baa2a9988ea1.zip opensim-SC_OLD-8c1d80fdfd104b94cb7a4fd247b3baa2a9988ea1.tar.gz opensim-SC_OLD-8c1d80fdfd104b94cb7a4fd247b3baa2a9988ea1.tar.bz2 opensim-SC_OLD-8c1d80fdfd104b94cb7a4fd247b3baa2a9988ea1.tar.xz |
varregion: serious rework of TerrainChannel:
-- addition of varaible region size in X and Y
-- internal storage of heightmap changed from double[] to short[]
-- helper routines for handling internal structure while keeping existing API
-- to and from XML that adds region size information (for downward compatibility,
output in the legacy XML format if X and Y are 256)
Updated and commented Constants.RegionSize but didn't change the name for compatibility.
9 files changed, 247 insertions, 135 deletions
diff --git a/OpenSim/Framework/Constants.cs b/OpenSim/Framework/Constants.cs index a2eb5ee..7979132 100644 --- a/OpenSim/Framework/Constants.cs +++ b/OpenSim/Framework/Constants.cs | |||
@@ -30,9 +30,18 @@ namespace OpenSim.Framework | |||
30 | { | 30 | { |
31 | public class Constants | 31 | public class Constants |
32 | { | 32 | { |
33 | // 'RegionSize' captures the legacy region size. | ||
34 | // DO NOT USE THIS FOR ANY NEW CODE. Use Scene.RegionSize[XYZ] as a region might not | ||
35 | // be the legacy region size. | ||
33 | public const uint RegionSize = 256; | 36 | public const uint RegionSize = 256; |
34 | public const uint RegionHeight = 4096; | 37 | public const uint RegionHeight = 4096; |
38 | |||
39 | // Terrain heightmap is kept as shorts that are the float value times this compression factor | ||
40 | public const float TerrainCompression = 100.0f; | ||
41 | // Since terrain is stored in 16x16 heights, regions must be a multiple of this number and that is the minimum | ||
42 | public const int MinRegionSize = 16; | ||
35 | public const byte TerrainPatchSize = 16; | 43 | public const byte TerrainPatchSize = 16; |
44 | |||
36 | public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f"; | 45 | public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f"; |
37 | 46 | ||
38 | public enum EstateAccessCodex : uint | 47 | public enum EstateAccessCodex : uint |
diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index 2d3c9ea..882fe33 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs | |||
@@ -472,7 +472,7 @@ namespace OpenSim.Framework | |||
472 | /// The x co-ordinate of this region in map tiles (e.g. 1000). | 472 | /// The x co-ordinate of this region in map tiles (e.g. 1000). |
473 | /// Coordinate is scaled as world coordinates divided by the legacy region size | 473 | /// Coordinate is scaled as world coordinates divided by the legacy region size |
474 | /// and is thus is the number of legacy regions. | 474 | /// and is thus is the number of legacy regions. |
475 | /// This entrypoint exists for downward compatability for external modules. | 475 | /// DO NOT USE FOR NEW CODE! This entrypoint exists for downward compatability with external modules. |
476 | /// </summary> | 476 | /// </summary> |
477 | public uint RegionLocX | 477 | public uint RegionLocX |
478 | { | 478 | { |
@@ -480,22 +480,11 @@ namespace OpenSim.Framework | |||
480 | set { LegacyRegionLocX = value; } | 480 | set { LegacyRegionLocX = value; } |
481 | } | 481 | } |
482 | 482 | ||
483 | public void SetDefaultRegionSize() | ||
484 | { | ||
485 | RegionWorldLocX = 0; | ||
486 | RegionWorldLocY = 0; | ||
487 | RegionWorldLocZ = 0; | ||
488 | RegionSizeX = Constants.RegionSize; | ||
489 | RegionSizeY = Constants.RegionSize; | ||
490 | RegionSizeZ = Constants.RegionHeight; | ||
491 | } | ||
492 | |||
493 | |||
494 | /// <summary> | 483 | /// <summary> |
495 | /// The y co-ordinate of this region in map tiles (e.g. 1000). | 484 | /// The y co-ordinate of this region in map tiles (e.g. 1000). |
496 | /// Coordinate is scaled as world coordinates divided by the legacy region size | 485 | /// Coordinate is scaled as world coordinates divided by the legacy region size |
497 | /// and is thus is the number of legacy regions. | 486 | /// and is thus is the number of legacy regions. |
498 | /// This entrypoint exists for downward compatability for external modules. | 487 | /// DO NOT USE FOR NEW CODE! This entrypoint exists for downward compatability with external modules. |
499 | /// </summary> | 488 | /// </summary> |
500 | public uint RegionLocY | 489 | public uint RegionLocY |
501 | { | 490 | { |
@@ -503,6 +492,16 @@ namespace OpenSim.Framework | |||
503 | set { LegacyRegionLocY = value; } | 492 | set { LegacyRegionLocY = value; } |
504 | } | 493 | } |
505 | 494 | ||
495 | public void SetDefaultRegionSize() | ||
496 | { | ||
497 | RegionWorldLocX = 0; | ||
498 | RegionWorldLocY = 0; | ||
499 | RegionWorldLocZ = 0; | ||
500 | RegionSizeX = Constants.RegionSize; | ||
501 | RegionSizeY = Constants.RegionSize; | ||
502 | RegionSizeZ = Constants.RegionHeight; | ||
503 | } | ||
504 | |||
506 | // A unique region handle is created from the region's world coordinates. | 505 | // A unique region handle is created from the region's world coordinates. |
507 | // This cannot be changed because some code expects to receive the region handle and then | 506 | // This cannot be changed because some code expects to receive the region handle and then |
508 | // compute the region coordinates from it. | 507 | // compute the region coordinates from it. |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 22bff9f..fea9ddf 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -1240,9 +1240,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1240 | try | 1240 | try |
1241 | { | 1241 | { |
1242 | int[] patches = new int[] { py * 16 + px }; | 1242 | int[] patches = new int[] { py * 16 + px }; |
1243 | float[] heightmap = (map.Length == 65536) ? | 1243 | float[] heightmap = (map.Length == 65536) ? map : LLHeightFieldMoronize(map); |
1244 | map : | ||
1245 | LLHeightFieldMoronize(map); | ||
1246 | 1244 | ||
1247 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); | 1245 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); |
1248 | 1246 | ||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs index d78ade5..d5c77ec 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs | |||
@@ -67,7 +67,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
67 | { | 67 | { |
68 | using (Bitmap bitmap = new Bitmap(filename)) | 68 | using (Bitmap bitmap = new Bitmap(filename)) |
69 | { | 69 | { |
70 | ITerrainChannel retval = new TerrainChannel(true); | 70 | ITerrainChannel retval = new TerrainChannel(w, h); |
71 | 71 | ||
72 | for (int x = 0; x < retval.Width; x++) | 72 | for (int x = 0; x < retval.Width; x++) |
73 | { | 73 | { |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index c1ffd22..2fff4c1 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs | |||
@@ -130,15 +130,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
130 | { | 130 | { |
131 | if (m_scene.Heightmap == null) | 131 | if (m_scene.Heightmap == null) |
132 | { | 132 | { |
133 | m_channel = new TerrainChannel(m_InitialTerrain); | 133 | m_channel = new TerrainChannel(m_InitialTerrain, |
134 | m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY, m_scene.RegionInfo.RegionSizeZ); | ||
134 | m_scene.Heightmap = m_channel; | 135 | m_scene.Heightmap = m_channel; |
135 | m_revert = new TerrainChannel(); | ||
136 | UpdateRevertMap(); | 136 | UpdateRevertMap(); |
137 | } | 137 | } |
138 | else | 138 | else |
139 | { | 139 | { |
140 | m_channel = m_scene.Heightmap; | 140 | m_channel = m_scene.Heightmap; |
141 | m_revert = new TerrainChannel(); | ||
142 | UpdateRevertMap(); | 141 | UpdateRevertMap(); |
143 | } | 142 | } |
144 | 143 | ||
@@ -532,6 +531,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
532 | /// </summary> | 531 | /// </summary> |
533 | public void UpdateRevertMap() | 532 | public void UpdateRevertMap() |
534 | { | 533 | { |
534 | /* | ||
535 | int x; | 535 | int x; |
536 | for (x = 0; x < m_channel.Width; x++) | 536 | for (x = 0; x < m_channel.Width; x++) |
537 | { | 537 | { |
@@ -541,6 +541,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
541 | m_revert[x, y] = m_channel[x, y]; | 541 | m_revert[x, y] = m_channel[x, y]; |
542 | } | 542 | } |
543 | } | 543 | } |
544 | */ | ||
545 | m_revert = m_channel.MakeCopy(); | ||
544 | } | 546 | } |
545 | 547 | ||
546 | /// <summary> | 548 | /// <summary> |
diff --git a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs index c936a84..847d245 100644 --- a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs +++ b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs | |||
@@ -134,26 +134,26 @@ namespace OpenSim.Region.Framework.Interfaces | |||
134 | Dictionary<string, string> GetExtra(UUID regionID); | 134 | Dictionary<string, string> GetExtra(UUID regionID); |
135 | 135 | ||
136 | void Shutdown(); | 136 | void Shutdown(); |
137 | } | 137 | } |
138 | 138 | ||
139 | // The terrain is stored as a blob in the database with a 'revision' field. | 139 | // The terrain is stored as a blob in the database with a 'revision' field. |
140 | // Some implementations of terrain storage would fill the revision field with | 140 | // Some implementations of terrain storage would fill the revision field with |
141 | // the time the terrain was stored. When real revisions were added and this | 141 | // the time the terrain was stored. When real revisions were added and this |
142 | // feature removed, that left some old entries with the time in the revision | 142 | // feature removed, that left some old entries with the time in the revision |
143 | // field. | 143 | // field. |
144 | // Thus, if revision is greater than 'RevisionHigh' then terrain db entry is | 144 | // Thus, if revision is greater than 'RevisionHigh' then terrain db entry is |
145 | // left over and it is presumed to be 'Legacy256'. | 145 | // left over and it is presumed to be 'Legacy256'. |
146 | // Numbers are arbitrary and are chosen to to reduce possible mis-interpretation. | 146 | // Numbers are arbitrary and are chosen to to reduce possible mis-interpretation. |
147 | // If a revision does not match any of these, it is assumed to be Legacy256. | 147 | // If a revision does not match any of these, it is assumed to be Legacy256. |
148 | public enum DBTerrainRevision | 148 | public enum DBTerrainRevision |
149 | { | 149 | { |
150 | // Terrain is 'double[256,256]' | 150 | // Terrain is 'double[256,256]' |
151 | Legacy256 = 11, | 151 | Legacy256 = 11, |
152 | // Terrain is 'int32, int32, float[,]' where the shorts are X and Y dimensions | 152 | // Terrain is 'int32, int32, float[,]' where the shorts are X and Y dimensions |
153 | // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256. | 153 | // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256. |
154 | Variable2D = 22, | 154 | Variable2D = 22, |
155 | // A revision that is not listed above or any revision greater than this value is 'Legacy256'. | 155 | // A revision that is not listed above or any revision greater than this value is 'Legacy256'. |
156 | RevisionHigh = 1234 | 156 | RevisionHigh = 1234 |
157 | } | 157 | } |
158 | 158 | ||
159 | } | 159 | } |
diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs index e467701..3c060a4 100644 --- a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs +++ b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs | |||
@@ -29,15 +29,21 @@ namespace OpenSim.Region.Framework.Interfaces | |||
29 | { | 29 | { |
30 | public interface ITerrainChannel | 30 | public interface ITerrainChannel |
31 | { | 31 | { |
32 | int Height { get; } | 32 | int Width { get;} // X dimension |
33 | int Height { get;} // Y dimension | ||
34 | int Altitude { get;} // Z dimension | ||
35 | |||
33 | double this[int x, int y] { get; set; } | 36 | double this[int x, int y] { get; set; } |
34 | int Width { get; } | ||
35 | 37 | ||
36 | /// <summary> | 38 | /// <summary> |
37 | /// Squash the entire heightmap into a single dimensioned array | 39 | /// Squash the entire heightmap into a single dimensioned array |
38 | /// </summary> | 40 | /// </summary> |
39 | /// <returns></returns> | 41 | /// <returns></returns> |
40 | float[] GetFloatsSerialised(); | 42 | float[] GetFloatsSerialised(); |
43 | // Get version of map as a single dimensioned array and each value compressed | ||
44 | // into an int (compressedHeight = (int)(floatHeight * Constants.TerrainCompression);) | ||
45 | // This is done to make the map smaller as it can get pretty larger for variable sized regions. | ||
46 | short[] GetCompressedMap(); | ||
41 | 47 | ||
42 | double[,] GetDoubles(); | 48 | double[,] GetDoubles(); |
43 | bool Tainted(int x, int y); | 49 | bool Tainted(int x, int y); |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 26e7d7d..49e32c6 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -1905,13 +1905,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1905 | m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); | 1905 | m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); |
1906 | 1906 | ||
1907 | m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); | 1907 | m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); |
1908 | Heightmap = new TerrainChannel(m_InitialTerrain); | 1908 | Heightmap = new TerrainChannel(m_InitialTerrain, RegionInfo.RegionSizeX, RegionInfo.RegionSizeY, RegionInfo.RegionSizeZ); |
1909 | 1909 | ||
1910 | SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); | 1910 | SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); |
1911 | } | 1911 | } |
1912 | else | 1912 | else |
1913 | { | 1913 | { |
1914 | Heightmap = new TerrainChannel(map); | 1914 | Heightmap = new TerrainChannel(map, RegionInfo.RegionSizeZ); |
1915 | } | 1915 | } |
1916 | } | 1916 | } |
1917 | catch (IOException e) | 1917 | catch (IOException e) |
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs index c0ca48e..fef93bf 100644 --- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs +++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs | |||
@@ -40,132 +40,125 @@ namespace OpenSim.Region.Framework.Scenes | |||
40 | /// </summary> | 40 | /// </summary> |
41 | public class TerrainChannel : ITerrainChannel | 41 | public class TerrainChannel : ITerrainChannel |
42 | { | 42 | { |
43 | private readonly bool[,] taint; | 43 | protected bool[,] m_taint; |
44 | private double[,] map; | 44 | protected short[] m_map; |
45 | 45 | ||
46 | public int Width { get; private set; } // X dimension | ||
47 | // Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y | ||
48 | public int Height { get; private set; } // Y dimension | ||
49 | public int Altitude { get; private set; } // Y dimension | ||
50 | |||
51 | // Default, not-often-used builder | ||
46 | public TerrainChannel() | 52 | public TerrainChannel() |
47 | { | 53 | { |
48 | map = new double[Constants.RegionSize, Constants.RegionSize]; | 54 | InitializeStructures(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight, false); |
49 | taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; | 55 | FlatLand(); |
50 | 56 | // PinHeadIsland(); | |
51 | PinHeadIsland(); | ||
52 | } | 57 | } |
53 | 58 | ||
54 | public TerrainChannel(String type) | 59 | // Create terrain of given size |
60 | public TerrainChannel(int pX, int pY) | ||
55 | { | 61 | { |
56 | map = new double[Constants.RegionSize, Constants.RegionSize]; | 62 | InitializeStructures((uint)pX, (uint)pY, Constants.RegionHeight, true); |
57 | taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; | 63 | } |
58 | 64 | ||
65 | // Create terrain of specified size and initialize with specified terrain. | ||
66 | // TODO: join this with the terrain initializers. | ||
67 | public TerrainChannel(String type, uint pX, uint pY, uint pZ) | ||
68 | { | ||
69 | InitializeStructures(pX, pY, pZ, false); | ||
59 | if (type.Equals("flat")) | 70 | if (type.Equals("flat")) |
60 | FlatLand(); | 71 | FlatLand(); |
61 | else | 72 | else |
62 | PinHeadIsland(); | 73 | PinHeadIsland(); |
63 | } | 74 | } |
64 | 75 | ||
65 | public TerrainChannel(double[,] import) | 76 | public TerrainChannel(double[,] pM, uint pH) |
66 | { | ||
67 | map = import; | ||
68 | taint = new bool[import.GetLength(0),import.GetLength(1)]; | ||
69 | } | ||
70 | |||
71 | public TerrainChannel(bool createMap) | ||
72 | { | ||
73 | if (createMap) | ||
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 | { | 77 | { |
82 | map = new double[w,h]; | 78 | InitializeStructures((uint)pM.GetLength(0), (uint)pM.GetLength(1), pH, false); |
83 | taint = new bool[w / 16,h / 16]; | 79 | int idx = 0; |
80 | for (int ii = 0; ii < Height; ii++) | ||
81 | for (int jj = 0; jj < Width; jj++) | ||
82 | m_map[idx++] = ToCompressedHeight(pM[ii, jj]); | ||
84 | } | 83 | } |
85 | 84 | ||
86 | #region ITerrainChannel Members | 85 | #region ITerrainChannel Members |
87 | 86 | ||
88 | public int Width | 87 | // ITerrainChannel.MakeCopy() |
88 | public ITerrainChannel MakeCopy() | ||
89 | { | 89 | { |
90 | get { return map.GetLength(0); } | 90 | return this.Copy(); |
91 | } | 91 | } |
92 | 92 | ||
93 | public int Height | 93 | // ITerrainChannel.GetCompressedMap() |
94 | public short[] GetCompressedMap() | ||
94 | { | 95 | { |
95 | get { return map.GetLength(1); } | 96 | return m_map; |
96 | } | 97 | } |
97 | 98 | ||
98 | public ITerrainChannel MakeCopy() | 99 | // ITerrainChannel.GetFloatsSerialized() |
100 | public float[] GetFloatsSerialised() | ||
99 | { | 101 | { |
100 | TerrainChannel copy = new TerrainChannel(false); | 102 | int points = Width * Height; |
101 | copy.map = (double[,]) map.Clone(); | 103 | float[] heights = new float[points]; |
102 | 104 | ||
103 | return copy; | 105 | for (int ii = 0; ii < points; ii++) |
106 | heights[ii] = FromCompressedHeight(m_map[ii]); | ||
107 | |||
108 | return heights; | ||
104 | } | 109 | } |
105 | 110 | ||
106 | public float[] GetFloatsSerialised() | 111 | // ITerrainChannel.GetDoubles() |
112 | public double[,] GetDoubles() | ||
107 | { | 113 | { |
108 | // Move the member variables into local variables, calling | ||
109 | // member variables 256*256 times gets expensive | ||
110 | int w = Width; | 114 | int w = Width; |
111 | int h = Height; | 115 | int l = Height; |
112 | float[] heights = new float[w * h]; | 116 | double[,] heights = new double[w, l]; |
113 | 117 | ||
114 | int i, j; // map coordinates | ||
115 | int idx = 0; // index into serialized array | 118 | int idx = 0; // index into serialized array |
116 | for (i = 0; i < h; i++) | 119 | for (int ii = 0; ii < l; ii++) |
117 | { | 120 | { |
118 | for (j = 0; j < w; j++) | 121 | for (int jj = 0; jj < w; jj++) |
119 | { | 122 | { |
120 | heights[idx++] = (float)map[j, i]; | 123 | heights[ii, jj] = (double)FromCompressedHeight(m_map[idx]); |
124 | idx++; | ||
121 | } | 125 | } |
122 | } | 126 | } |
123 | 127 | ||
124 | return heights; | 128 | return heights; |
125 | } | 129 | } |
126 | 130 | ||
127 | public double[,] GetDoubles() | 131 | // ITerrainChannel.this[x,y] |
128 | { | ||
129 | return map; | ||
130 | } | ||
131 | |||
132 | public double this[int x, int y] | 132 | public double this[int x, int y] |
133 | { | 133 | { |
134 | get { return map[x, y]; } | 134 | get { return m_map[x * Width + y]; } |
135 | set | 135 | set |
136 | { | 136 | { |
137 | // Will "fix" terrain hole problems. Although not fantastically. | 137 | // Will "fix" terrain hole problems. Although not fantastically. |
138 | if (Double.IsNaN(value) || Double.IsInfinity(value)) | 138 | if (Double.IsNaN(value) || Double.IsInfinity(value)) |
139 | return; | 139 | return; |
140 | 140 | ||
141 | if (map[x, y] != value) | 141 | int idx = x * Width + y; |
142 | if (m_map[idx] != value) | ||
142 | { | 143 | { |
143 | taint[x / 16, y / 16] = true; | 144 | m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true; |
144 | map[x, y] = value; | 145 | m_map[idx] = ToCompressedHeight(value); |
145 | } | 146 | } |
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 | if (m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize]) |
152 | { | 154 | { |
153 | taint[x / 16, y / 16] = false; | 155 | m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = false; |
154 | return true; | 156 | return true; |
155 | } | 157 | } |
156 | return false; | 158 | return false; |
157 | } | 159 | } |
158 | 160 | ||
159 | #endregion | 161 | // ITerrainChannel.SaveToXmlString() |
160 | |||
161 | public TerrainChannel Copy() | ||
162 | { | ||
163 | TerrainChannel copy = new TerrainChannel(false); | ||
164 | copy.map = (double[,]) map.Clone(); | ||
165 | |||
166 | return copy; | ||
167 | } | ||
168 | |||
169 | public string SaveToXmlString() | 162 | public string SaveToXmlString() |
170 | { | 163 | { |
171 | XmlWriterSettings settings = new XmlWriterSettings(); | 164 | XmlWriterSettings settings = new XmlWriterSettings(); |
@@ -181,13 +174,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
181 | } | 174 | } |
182 | } | 175 | } |
183 | 176 | ||
184 | private void WriteXml(XmlWriter writer) | 177 | // 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) | 178 | public void LoadFromXmlString(string data) |
192 | { | 179 | { |
193 | StringReader sr = new StringReader(data); | 180 | StringReader sr = new StringReader(data); |
@@ -199,12 +186,89 @@ namespace OpenSim.Region.Framework.Scenes | |||
199 | sr.Close(); | 186 | sr.Close(); |
200 | } | 187 | } |
201 | 188 | ||
189 | #endregion | ||
190 | |||
191 | private void InitializeStructures(uint pX, uint pY, uint pZ, bool shouldInitializeHeightmap) | ||
192 | { | ||
193 | Width = (int)pX; | ||
194 | Height = (int)pY; | ||
195 | Altitude = (int)pZ; | ||
196 | m_map = new short[Width * Height]; | ||
197 | m_taint = new bool[Width / Constants.TerrainPatchSize, Height / Constants.TerrainPatchSize]; | ||
198 | ClearTaint(); | ||
199 | if (shouldInitializeHeightmap) | ||
200 | { | ||
201 | FlatLand(); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | public void ClearTaint() | ||
206 | { | ||
207 | for (int ii = 0; ii < Width / Constants.TerrainPatchSize; ii++) | ||
208 | for (int jj = 0; jj < Height / Constants.TerrainPatchSize; jj++) | ||
209 | m_taint[ii, jj] = false; | ||
210 | } | ||
211 | |||
212 | // To save space (especially for large regions), keep the height as a short integer | ||
213 | // that is coded as the float height times the compression factor (usually '100' | ||
214 | // to make for two decimal points). | ||
215 | public short ToCompressedHeight(double pHeight) | ||
216 | { | ||
217 | return (short)(pHeight * Constants.TerrainCompression); | ||
218 | } | ||
219 | |||
220 | public float FromCompressedHeight(short pHeight) | ||
221 | { | ||
222 | return ((float)pHeight) / Constants.TerrainCompression; | ||
223 | } | ||
224 | |||
225 | public TerrainChannel Copy() | ||
226 | { | ||
227 | TerrainChannel copy = new TerrainChannel(); | ||
228 | copy.m_map = (short[])m_map.Clone(); | ||
229 | copy.m_taint = (bool[,])m_taint.Clone(); | ||
230 | copy.Width = Width; | ||
231 | copy.Height = Height; | ||
232 | copy.Altitude = Altitude; | ||
233 | |||
234 | return copy; | ||
235 | } | ||
236 | |||
237 | private void WriteXml(XmlWriter writer) | ||
238 | { | ||
239 | if (Width == Constants.RegionSize && Height == Constants.RegionSize) | ||
240 | { | ||
241 | // Downward compatibility for legacy region terrain maps. | ||
242 | // If region is exactly legacy size, return the old format XML. | ||
243 | writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty); | ||
244 | ToXml(writer); | ||
245 | writer.WriteEndElement(); | ||
246 | } | ||
247 | else | ||
248 | { | ||
249 | // New format XML that includes width and length. | ||
250 | writer.WriteStartElement(String.Empty, "TerrainMap2", String.Empty); | ||
251 | ToXml2(writer); | ||
252 | writer.WriteEndElement(); | ||
253 | } | ||
254 | } | ||
255 | |||
202 | private void ReadXml(XmlReader reader) | 256 | private void ReadXml(XmlReader reader) |
203 | { | 257 | { |
204 | reader.ReadStartElement("TerrainMap"); | 258 | // Check the first element. If legacy element, use the legacy reader. |
205 | FromXml(reader); | 259 | if (reader.IsStartElement("TerrainMap")) |
260 | { | ||
261 | reader.ReadStartElement("TerrainMap"); | ||
262 | FromXml(reader); | ||
263 | } | ||
264 | else | ||
265 | { | ||
266 | reader.ReadStartElement("TerrainMap2"); | ||
267 | FromXml2(reader); | ||
268 | } | ||
206 | } | 269 | } |
207 | 270 | ||
271 | // Write legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array. | ||
208 | private void ToXml(XmlWriter xmlWriter) | 272 | private void ToXml(XmlWriter xmlWriter) |
209 | { | 273 | { |
210 | float[] mapData = GetFloatsSerialised(); | 274 | float[] mapData = GetFloatsSerialised(); |
@@ -218,6 +282,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
218 | serializer.Serialize(xmlWriter, buffer); | 282 | serializer.Serialize(xmlWriter, buffer); |
219 | } | 283 | } |
220 | 284 | ||
285 | // Read legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array. | ||
221 | private void FromXml(XmlReader xmlReader) | 286 | private void FromXml(XmlReader xmlReader) |
222 | { | 287 | { |
223 | XmlSerializer serializer = new XmlSerializer(typeof(byte[])); | 288 | XmlSerializer serializer = new XmlSerializer(typeof(byte[])); |
@@ -236,35 +301,68 @@ namespace OpenSim.Region.Framework.Scenes | |||
236 | } | 301 | } |
237 | } | 302 | } |
238 | 303 | ||
304 | private class TerrainChannelXMLPackage | ||
305 | { | ||
306 | public int Version; | ||
307 | public int SizeX; | ||
308 | public int SizeY; | ||
309 | public int SizeZ; | ||
310 | public short[] Map; | ||
311 | public TerrainChannelXMLPackage(int pX, int pY, int pZ, short[] pMap) | ||
312 | { | ||
313 | Version = 1; | ||
314 | SizeX = pX; | ||
315 | SizeY = pY; | ||
316 | SizeZ = pZ; | ||
317 | Map = pMap; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | // New terrain serialization format that includes the width and length. | ||
322 | private void ToXml2(XmlWriter xmlWriter) | ||
323 | { | ||
324 | TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_map); | ||
325 | XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage)); | ||
326 | serializer.Serialize(xmlWriter, package); | ||
327 | } | ||
328 | |||
329 | // New terrain serialization format that includes the width and length. | ||
330 | private void FromXml2(XmlReader xmlReader) | ||
331 | { | ||
332 | XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage)); | ||
333 | TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader); | ||
334 | Width = package.SizeX; | ||
335 | Height = package.SizeY; | ||
336 | Altitude = package.SizeZ; | ||
337 | m_map = package.Map; | ||
338 | } | ||
339 | |||
340 | // Fill the heightmap with the center bump terrain | ||
239 | private void PinHeadIsland() | 341 | private void PinHeadIsland() |
240 | { | 342 | { |
241 | int x; | 343 | int x; |
242 | for (x = 0; x < Constants.RegionSize; x++) | 344 | for (x = 0; x < Width; x++) |
243 | { | 345 | { |
244 | int y; | 346 | int y; |
245 | for (y = 0; y < Constants.RegionSize; y++) | 347 | for (y = 0; y < Height; y++) |
246 | { | 348 | { |
247 | map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; | 349 | int idx = x * (int)Width + y; |
248 | double spherFacA = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01; | 350 | m_map[idx] = ToCompressedHeight(TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10); |
249 | double spherFacB = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001; | 351 | short spherFacA = ToCompressedHeight(TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01); |
250 | if (map[x, y] < spherFacA) | 352 | short spherFacB = ToCompressedHeight(TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001); |
251 | map[x, y] = spherFacA; | 353 | if (m_map[idx] < spherFacA) |
252 | if (map[x, y] < spherFacB) | 354 | m_map[idx] = spherFacA; |
253 | map[x, y] = spherFacB; | 355 | if (m_map[idx] < spherFacB) |
356 | m_map[idx] = spherFacB; | ||
254 | } | 357 | } |
255 | } | 358 | } |
256 | } | 359 | } |
257 | 360 | ||
258 | private void FlatLand() | 361 | private void FlatLand() |
259 | { | 362 | { |
260 | int x; | 363 | short flatHeight = ToCompressedHeight(21); |
261 | for (x = 0; x < Constants.RegionSize; x++) | 364 | for (int ii = 0; ii < m_map.Length; ii++) |
262 | { | 365 | m_map[ii] = flatHeight; |
263 | int y; | ||
264 | for (y = 0; y < Constants.RegionSize; y++) | ||
265 | map[x, y] = 21; | ||
266 | } | ||
267 | } | 366 | } |
268 | |||
269 | } | 367 | } |
270 | } | 368 | } |