diff options
Diffstat (limited to 'OpenSim/Region/Framework')
5 files changed, 284 insertions, 110 deletions
diff --git a/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs b/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs index 3e97a7a..13358cb 100644 --- a/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs +++ b/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs | |||
@@ -68,13 +68,22 @@ namespace OpenSim.Region.Framework.Interfaces | |||
68 | /// </summary> | 68 | /// </summary> |
69 | /// <param name="ter">HeightField data</param> | 69 | /// <param name="ter">HeightField data</param> |
70 | /// <param name="regionID">region UUID</param> | 70 | /// <param name="regionID">region UUID</param> |
71 | void StoreTerrain(TerrainData terrain, UUID regionID); | ||
72 | |||
73 | // Legacy version kept for downward compabibility | ||
71 | void StoreTerrain(double[,] terrain, UUID regionID); | 74 | void StoreTerrain(double[,] terrain, UUID regionID); |
72 | 75 | ||
73 | /// <summary> | 76 | /// <summary> |
74 | /// Load the latest terrain revision from region storage | 77 | /// Load the latest terrain revision from region storage |
75 | /// </summary> | 78 | /// </summary> |
76 | /// <param name="regionID">the region UUID</param> | 79 | /// <param name="regionID">the region UUID</param> |
80 | /// <param name="sizeX">the X dimension of the region being filled</param> | ||
81 | /// <param name="sizeY">the Y dimension of the region being filled</param> | ||
82 | /// <param name="sizeZ">the Z dimension of the region being filled</param> | ||
77 | /// <returns>Heightfield data</returns> | 83 | /// <returns>Heightfield data</returns> |
84 | TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ); | ||
85 | |||
86 | // Legacy version kept for downward compabibility | ||
78 | double[,] LoadTerrain(UUID regionID); | 87 | double[,] LoadTerrain(UUID regionID); |
79 | 88 | ||
80 | void StoreLandObject(ILandObject Parcel); | 89 | void StoreLandObject(ILandObject Parcel); |
diff --git a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs index 17bd48b..e09f775 100644 --- a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs +++ b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs | |||
@@ -79,13 +79,22 @@ namespace OpenSim.Region.Framework.Interfaces | |||
79 | /// </summary> | 79 | /// </summary> |
80 | /// <param name="ter">HeightField data</param> | 80 | /// <param name="ter">HeightField data</param> |
81 | /// <param name="regionID">region UUID</param> | 81 | /// <param name="regionID">region UUID</param> |
82 | void StoreTerrain(TerrainData terrain, UUID regionID); | ||
83 | |||
84 | // Legacy version kept for downward compabibility | ||
82 | void StoreTerrain(double[,] terrain, UUID regionID); | 85 | void StoreTerrain(double[,] terrain, UUID regionID); |
83 | 86 | ||
84 | /// <summary> | 87 | /// <summary> |
85 | /// Load the latest terrain revision from region storage | 88 | /// Load the latest terrain revision from region storage |
86 | /// </summary> | 89 | /// </summary> |
87 | /// <param name="regionID">the region UUID</param> | 90 | /// <param name="regionID">the region UUID</param> |
91 | /// <param name="pSizeX">the X dimension of the terrain being filled</param> | ||
92 | /// <param name="pSizeY">the Y dimension of the terrain being filled</param> | ||
93 | /// <param name="pSizeZ">the Z dimension of the terrain being filled</param> | ||
88 | /// <returns>Heightfield data</returns> | 94 | /// <returns>Heightfield data</returns> |
95 | TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ); | ||
96 | |||
97 | // Legacy version kept for downward compabibility | ||
89 | double[,] LoadTerrain(UUID regionID); | 98 | double[,] LoadTerrain(UUID regionID); |
90 | 99 | ||
91 | void StoreLandObject(ILandObject Parcel); | 100 | void StoreLandObject(ILandObject Parcel); |
@@ -136,4 +145,5 @@ namespace OpenSim.Region.Framework.Interfaces | |||
136 | 145 | ||
137 | void Shutdown(); | 146 | void Shutdown(); |
138 | } | 147 | } |
148 | |||
139 | } | 149 | } |
diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs index e467701..f660b8d 100644 --- a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs +++ b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs | |||
@@ -25,13 +25,23 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using OpenSim.Framework; | ||
29 | using OpenMetaverse; | ||
30 | |||
28 | namespace OpenSim.Region.Framework.Interfaces | 31 | namespace OpenSim.Region.Framework.Interfaces |
29 | { | 32 | { |
30 | public interface ITerrainChannel | 33 | public interface ITerrainChannel |
31 | { | 34 | { |
32 | int Height { get; } | 35 | int Width { get;} // X dimension |
36 | int Height { get;} // Y dimension | ||
37 | int Altitude { get;} // Z dimension | ||
38 | |||
33 | double this[int x, int y] { get; set; } | 39 | double this[int x, int y] { get; set; } |
34 | int Width { get; } | 40 | |
41 | float GetHeightAtXYZ(float x, float y, float z); | ||
42 | |||
43 | // Return the packaged terrain data for passing into lower levels of communication | ||
44 | TerrainData GetTerrainData(); | ||
35 | 45 | ||
36 | /// <summary> | 46 | /// <summary> |
37 | /// Squash the entire heightmap into a single dimensioned array | 47 | /// Squash the entire heightmap into a single dimensioned array |
@@ -40,9 +50,14 @@ namespace OpenSim.Region.Framework.Interfaces | |||
40 | float[] GetFloatsSerialised(); | 50 | float[] GetFloatsSerialised(); |
41 | 51 | ||
42 | double[,] GetDoubles(); | 52 | double[,] GetDoubles(); |
53 | |||
54 | // Check if a location has been updated. Clears the taint flag as a side effect. | ||
43 | bool Tainted(int x, int y); | 55 | bool Tainted(int x, int y); |
56 | |||
44 | ITerrainChannel MakeCopy(); | 57 | ITerrainChannel MakeCopy(); |
45 | string SaveToXmlString(); | 58 | string SaveToXmlString(); |
46 | void LoadFromXmlString(string data); | 59 | void LoadFromXmlString(string data); |
60 | // Merge some terrain into this channel | ||
61 | void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement); | ||
47 | } | 62 | } |
48 | } | 63 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 03270d7..f5458c1 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -1935,7 +1935,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1935 | { | 1935 | { |
1936 | try | 1936 | try |
1937 | { | 1937 | { |
1938 | double[,] map = SimulationDataService.LoadTerrain(RegionInfo.RegionID); | 1938 | TerrainData map = SimulationDataService.LoadTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ); |
1939 | if (map == null) | 1939 | if (map == null) |
1940 | { | 1940 | { |
1941 | // This should be in the Terrain module, but it isn't because | 1941 | // This should be in the Terrain module, but it isn't because |
@@ -1946,7 +1946,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1946 | m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); | 1946 | m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); |
1947 | 1947 | ||
1948 | m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); | 1948 | m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); |
1949 | Heightmap = new TerrainChannel(m_InitialTerrain); | 1949 | Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ); |
1950 | 1950 | ||
1951 | SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); | 1951 | SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); |
1952 | } | 1952 | } |
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs index b6e0a97..3d563a6 100644 --- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs +++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs | |||
@@ -25,14 +25,21 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using OpenSim.Framework; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | using System; | 28 | using System; |
29 | using System.IO; | ||
31 | using System.Text; | 30 | using System.Text; |
31 | using System.Reflection; | ||
32 | using System.Xml; | 32 | using System.Xml; |
33 | using System.IO; | ||
34 | using System.Xml.Serialization; | 33 | using System.Xml.Serialization; |
35 | 34 | ||
35 | using OpenSim.Data; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | |||
41 | using log4net; | ||
42 | |||
36 | namespace OpenSim.Region.Framework.Scenes | 43 | namespace OpenSim.Region.Framework.Scenes |
37 | { | 44 | { |
38 | /// <summary> | 45 | /// <summary> |
@@ -40,140 +47,136 @@ namespace OpenSim.Region.Framework.Scenes | |||
40 | /// </summary> | 47 | /// </summary> |
41 | public class TerrainChannel : ITerrainChannel | 48 | public class TerrainChannel : ITerrainChannel |
42 | { | 49 | { |
43 | private readonly bool[,] taint; | 50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
44 | private double[,] map; | 51 | private static string LogHeader = "[TERRAIN CHANNEL]"; |
45 | 52 | ||
53 | protected TerrainData m_terrainData; | ||
54 | |||
55 | public int Width { get { return m_terrainData.SizeX; } } // X dimension | ||
56 | // Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y | ||
57 | public int Height { get { return m_terrainData.SizeY; } } // Y dimension | ||
58 | public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension | ||
59 | |||
60 | // Default, not-often-used builder | ||
46 | public TerrainChannel() | 61 | public TerrainChannel() |
47 | { | 62 | { |
48 | map = new double[Constants.RegionSize, Constants.RegionSize]; | 63 | m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight); |
49 | taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; | 64 | FlatLand(); |
50 | 65 | // PinHeadIsland(); | |
51 | PinHeadIsland(); | ||
52 | } | 66 | } |
53 | 67 | ||
54 | public TerrainChannel(String type) | 68 | // Create terrain of given size |
69 | public TerrainChannel(int pX, int pY) | ||
55 | { | 70 | { |
56 | map = new double[Constants.RegionSize, Constants.RegionSize]; | 71 | m_terrainData = new HeightmapTerrainData(pX, pY, (int)Constants.RegionHeight); |
57 | taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; | 72 | } |
58 | 73 | ||
74 | // Create terrain of specified size and initialize with specified terrain. | ||
75 | // TODO: join this with the terrain initializers. | ||
76 | public TerrainChannel(String type, int pX, int pY, int pZ) | ||
77 | { | ||
78 | m_terrainData = new HeightmapTerrainData(pX, pY, pZ); | ||
59 | if (type.Equals("flat")) | 79 | if (type.Equals("flat")) |
60 | FlatLand(); | 80 | FlatLand(); |
61 | else | 81 | else |
62 | PinHeadIsland(); | 82 | PinHeadIsland(); |
63 | } | 83 | } |
64 | 84 | ||
65 | public TerrainChannel(double[,] import) | 85 | // Create channel passed a heightmap and expected dimensions of the region. |
86 | // The heightmap might not fit the passed size so accomodations must be made. | ||
87 | public TerrainChannel(double[,] pM, int pSizeX, int pSizeY, int pAltitude) | ||
66 | { | 88 | { |
67 | map = import; | 89 | int hmSizeX = pM.GetLength(0); |
68 | taint = new bool[import.GetLength(0),import.GetLength(1)]; | 90 | int hmSizeY = pM.GetLength(1); |
69 | } | ||
70 | 91 | ||
71 | public TerrainChannel(bool createMap) | 92 | m_terrainData = new HeightmapTerrainData(pSizeX, pSizeY, pAltitude); |
72 | { | 93 | |
73 | if (createMap) | 94 | for (int xx = 0; xx < pSizeX; xx++) |
74 | { | 95 | for (int yy = 0; yy < pSizeY; yy++) |
75 | map = new double[Constants.RegionSize,Constants.RegionSize]; | 96 | if (xx > hmSizeX || yy > hmSizeY) |
76 | taint = new bool[Constants.RegionSize / 16,Constants.RegionSize / 16]; | 97 | m_terrainData[xx, yy] = TerrainData.DefaultTerrainHeight; |
77 | } | 98 | else |
99 | m_terrainData[xx, yy] = (float)pM[xx, yy]; | ||
78 | } | 100 | } |
79 | 101 | ||
80 | public TerrainChannel(int w, int h) | 102 | public TerrainChannel(TerrainData pTerrData) |
81 | { | 103 | { |
82 | map = new double[w,h]; | 104 | m_terrainData = pTerrData; |
83 | taint = new bool[w / 16,h / 16]; | ||
84 | } | 105 | } |
85 | 106 | ||
86 | #region ITerrainChannel Members | 107 | #region ITerrainChannel Members |
87 | 108 | ||
88 | public int Width | 109 | // ITerrainChannel.MakeCopy() |
110 | public ITerrainChannel MakeCopy() | ||
89 | { | 111 | { |
90 | get { return map.GetLength(0); } | 112 | return this.Copy(); |
91 | } | 113 | } |
92 | 114 | ||
93 | public int Height | 115 | // ITerrainChannel.GetTerrainData() |
116 | public TerrainData GetTerrainData() | ||
94 | { | 117 | { |
95 | get { return map.GetLength(1); } | 118 | return m_terrainData; |
96 | } | 119 | } |
97 | 120 | ||
98 | public ITerrainChannel MakeCopy() | 121 | // ITerrainChannel.GetFloatsSerialized() |
122 | // This one dimensional version is ordered so height = map[y*sizeX+x]; | ||
123 | // DEPRECATED: don't use this function as it does not retain the dimensions of the terrain | ||
124 | // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256. | ||
125 | public float[] GetFloatsSerialised() | ||
99 | { | 126 | { |
100 | TerrainChannel copy = new TerrainChannel(false); | 127 | return m_terrainData.GetFloatsSerialized(); |
101 | copy.map = (double[,]) map.Clone(); | ||
102 | |||
103 | return copy; | ||
104 | } | 128 | } |
105 | 129 | ||
106 | public float[] GetFloatsSerialised() | 130 | // ITerrainChannel.GetDoubles() |
131 | public double[,] GetDoubles() | ||
107 | { | 132 | { |
108 | // Move the member variables into local variables, calling | 133 | double[,] heights = new double[Width, Height]; |
109 | // member variables 256*256 times gets expensive | ||
110 | int w = Width; | ||
111 | int h = Height; | ||
112 | float[] heights = new float[w * h]; | ||
113 | 134 | ||
114 | int i, j; // map coordinates | ||
115 | int idx = 0; // index into serialized array | 135 | int idx = 0; // index into serialized array |
116 | for (i = 0; i < h; i++) | 136 | for (int ii = 0; ii < Width; ii++) |
117 | { | 137 | { |
118 | for (j = 0; j < w; j++) | 138 | for (int jj = 0; jj < Height; jj++) |
119 | { | 139 | { |
120 | heights[idx++] = (float)map[j, i]; | 140 | heights[ii, jj] = (double)m_terrainData[ii, jj]; |
141 | idx++; | ||
121 | } | 142 | } |
122 | } | 143 | } |
123 | 144 | ||
124 | return heights; | 145 | return heights; |
125 | } | 146 | } |
126 | 147 | ||
127 | public double[,] GetDoubles() | 148 | // ITerrainChannel.this[x,y] |
128 | { | ||
129 | return map; | ||
130 | } | ||
131 | |||
132 | public double this[int x, int y] | 149 | public double this[int x, int y] |
133 | { | 150 | { |
134 | get | 151 | get { |
135 | { | 152 | if (x < 0 || x >= Width || y < 0 || y >= Height) |
136 | if (x < 0) x = 0; | 153 | return 0; |
137 | if (y < 0) y = 0; | 154 | return (double)m_terrainData[x, y]; |
138 | if (x >= (int)Constants.RegionSize) x = (int)Constants.RegionSize - 1; | ||
139 | if (y >= (int)Constants.RegionSize) y = (int)Constants.RegionSize - 1; | ||
140 | |||
141 | return map[x, y]; | ||
142 | } | 155 | } |
143 | set | 156 | set |
144 | { | 157 | { |
145 | // Will "fix" terrain hole problems. Although not fantastically. | ||
146 | if (Double.IsNaN(value) || Double.IsInfinity(value)) | 158 | if (Double.IsNaN(value) || Double.IsInfinity(value)) |
147 | return; | 159 | return; |
148 | 160 | ||
149 | if (map[x, y] != value) | 161 | m_terrainData[x, y] = (float)value; |
150 | { | ||
151 | taint[x / 16, y / 16] = true; | ||
152 | map[x, y] = value; | ||
153 | } | ||
154 | } | 162 | } |
155 | } | 163 | } |
156 | 164 | ||
157 | public bool Tainted(int x, int y) | 165 | // ITerrainChannel.GetHieghtAtXYZ(x, y, z) |
166 | public float GetHeightAtXYZ(float x, float y, float z) | ||
158 | { | 167 | { |
159 | if (taint[x / 16, y / 16]) | 168 | if (x < 0 || x >= Width || y < 0 || y >= Height) |
160 | { | 169 | return 0; |
161 | taint[x / 16, y / 16] = false; | 170 | return m_terrainData[(int)x, (int)y]; |
162 | return true; | ||
163 | } | ||
164 | return false; | ||
165 | } | 171 | } |
166 | 172 | ||
167 | #endregion | 173 | // ITerrainChannel.Tainted() |
168 | 174 | public bool Tainted(int x, int y) | |
169 | public TerrainChannel Copy() | ||
170 | { | 175 | { |
171 | TerrainChannel copy = new TerrainChannel(false); | 176 | return m_terrainData.IsTaintedAt(x, y); |
172 | copy.map = (double[,]) map.Clone(); | ||
173 | |||
174 | return copy; | ||
175 | } | 177 | } |
176 | 178 | ||
179 | // ITerrainChannel.SaveToXmlString() | ||
177 | public string SaveToXmlString() | 180 | public string SaveToXmlString() |
178 | { | 181 | { |
179 | XmlWriterSettings settings = new XmlWriterSettings(); | 182 | XmlWriterSettings settings = new XmlWriterSettings(); |
@@ -189,13 +192,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
189 | } | 192 | } |
190 | } | 193 | } |
191 | 194 | ||
192 | private void WriteXml(XmlWriter writer) | 195 | // ITerrainChannel.LoadFromXmlString() |
193 | { | ||
194 | writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty); | ||
195 | ToXml(writer); | ||
196 | writer.WriteEndElement(); | ||
197 | } | ||
198 | |||
199 | public void LoadFromXmlString(string data) | 196 | public void LoadFromXmlString(string data) |
200 | { | 197 | { |
201 | StringReader sr = new StringReader(data); | 198 | StringReader sr = new StringReader(data); |
@@ -207,12 +204,124 @@ namespace OpenSim.Region.Framework.Scenes | |||
207 | sr.Close(); | 204 | sr.Close(); |
208 | } | 205 | } |
209 | 206 | ||
207 | // ITerrainChannel.Merge | ||
208 | public void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement) | ||
209 | { | ||
210 | m_log.DebugFormat("{0} Merge. inSize=<{1},{2}>, disp={3}, rot={4}, rotDisp={5}, outSize=<{6},{7}>", LogHeader, | ||
211 | newTerrain.Width, newTerrain.Height, | ||
212 | displacement, radianRotation, rotationDisplacement, | ||
213 | m_terrainData.SizeX, m_terrainData.SizeY); | ||
214 | for (int xx = 0; xx < newTerrain.Width; xx++) | ||
215 | { | ||
216 | for (int yy = 0; yy < newTerrain.Height; yy++) | ||
217 | { | ||
218 | int dispX = (int)displacement.X; | ||
219 | int dispY = (int)displacement.Y; | ||
220 | float newHeight = (float)newTerrain[xx, yy] + displacement.Z; | ||
221 | if (radianRotation == 0) | ||
222 | { | ||
223 | // If no rotation, place the new height in the specified location | ||
224 | dispX += xx; | ||
225 | dispY += yy; | ||
226 | if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY) | ||
227 | { | ||
228 | m_terrainData[dispX, dispY] = newHeight; | ||
229 | } | ||
230 | } | ||
231 | else | ||
232 | { | ||
233 | // If rotating, we have to smooth the result because the conversion | ||
234 | // to ints will mean heightmap entries will not get changed | ||
235 | // First compute the rotation location for the new height. | ||
236 | dispX += (int)(rotationDisplacement.X | ||
237 | + ((float)xx - rotationDisplacement.X) * Math.Cos(radianRotation) | ||
238 | - ((float)yy - rotationDisplacement.Y) * Math.Sin(radianRotation) ); | ||
239 | |||
240 | dispY += (int)(rotationDisplacement.Y | ||
241 | + ((float)xx - rotationDisplacement.X) * Math.Sin(radianRotation) | ||
242 | + ((float)yy - rotationDisplacement.Y) * Math.Cos(radianRotation) ); | ||
243 | |||
244 | if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY) | ||
245 | { | ||
246 | float oldHeight = m_terrainData[dispX, dispY]; | ||
247 | // Smooth the heights around this location if the old height is far from this one | ||
248 | for (int sxx = dispX - 2; sxx < dispX + 2; sxx++) | ||
249 | { | ||
250 | for (int syy = dispY - 2; syy < dispY + 2; syy++) | ||
251 | { | ||
252 | if (sxx >= 0 && sxx < m_terrainData.SizeX && syy >= 0 && syy < m_terrainData.SizeY) | ||
253 | { | ||
254 | if (sxx == dispX && syy == dispY) | ||
255 | { | ||
256 | // Set height for the exact rotated point | ||
257 | m_terrainData[dispX, dispY] = newHeight; | ||
258 | } | ||
259 | else | ||
260 | { | ||
261 | if (Math.Abs(m_terrainData[sxx, syy] - newHeight) > 1f) | ||
262 | { | ||
263 | // If the adjacent height is far off, force it to this height | ||
264 | m_terrainData[sxx, syy] = newHeight; | ||
265 | } | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY) | ||
273 | { | ||
274 | m_terrainData[dispX, dispY] = (float)newTerrain[xx, yy]; | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | #endregion | ||
282 | |||
283 | public TerrainChannel Copy() | ||
284 | { | ||
285 | TerrainChannel copy = new TerrainChannel(); | ||
286 | copy.m_terrainData = m_terrainData.Clone(); | ||
287 | return copy; | ||
288 | } | ||
289 | |||
290 | private void WriteXml(XmlWriter writer) | ||
291 | { | ||
292 | if (Width == Constants.RegionSize && Height == Constants.RegionSize) | ||
293 | { | ||
294 | // Downward compatibility for legacy region terrain maps. | ||
295 | // If region is exactly legacy size, return the old format XML. | ||
296 | writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty); | ||
297 | ToXml(writer); | ||
298 | writer.WriteEndElement(); | ||
299 | } | ||
300 | else | ||
301 | { | ||
302 | // New format XML that includes width and length. | ||
303 | writer.WriteStartElement(String.Empty, "TerrainMap2", String.Empty); | ||
304 | ToXml2(writer); | ||
305 | writer.WriteEndElement(); | ||
306 | } | ||
307 | } | ||
308 | |||
210 | private void ReadXml(XmlReader reader) | 309 | private void ReadXml(XmlReader reader) |
211 | { | 310 | { |
212 | reader.ReadStartElement("TerrainMap"); | 311 | // Check the first element. If legacy element, use the legacy reader. |
213 | FromXml(reader); | 312 | if (reader.IsStartElement("TerrainMap")) |
313 | { | ||
314 | reader.ReadStartElement("TerrainMap"); | ||
315 | FromXml(reader); | ||
316 | } | ||
317 | else | ||
318 | { | ||
319 | reader.ReadStartElement("TerrainMap2"); | ||
320 | FromXml2(reader); | ||
321 | } | ||
214 | } | 322 | } |
215 | 323 | ||
324 | // Write legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array. | ||
216 | private void ToXml(XmlWriter xmlWriter) | 325 | private void ToXml(XmlWriter xmlWriter) |
217 | { | 326 | { |
218 | float[] mapData = GetFloatsSerialised(); | 327 | float[] mapData = GetFloatsSerialised(); |
@@ -226,12 +335,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
226 | serializer.Serialize(xmlWriter, buffer); | 335 | serializer.Serialize(xmlWriter, buffer); |
227 | } | 336 | } |
228 | 337 | ||
338 | // Read legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array. | ||
229 | private void FromXml(XmlReader xmlReader) | 339 | private void FromXml(XmlReader xmlReader) |
230 | { | 340 | { |
231 | XmlSerializer serializer = new XmlSerializer(typeof(byte[])); | 341 | XmlSerializer serializer = new XmlSerializer(typeof(byte[])); |
232 | byte[] dataArray = (byte[])serializer.Deserialize(xmlReader); | 342 | byte[] dataArray = (byte[])serializer.Deserialize(xmlReader); |
233 | int index = 0; | 343 | int index = 0; |
234 | 344 | ||
345 | m_terrainData = new HeightmapTerrainData(Height, Width, (int)Constants.RegionHeight); | ||
346 | |||
235 | for (int y = 0; y < Height; y++) | 347 | for (int y = 0; y < Height; y++) |
236 | { | 348 | { |
237 | for (int x = 0; x < Width; x++) | 349 | for (int x = 0; x < Width; x++) |
@@ -244,35 +356,63 @@ namespace OpenSim.Region.Framework.Scenes | |||
244 | } | 356 | } |
245 | } | 357 | } |
246 | 358 | ||
359 | private class TerrainChannelXMLPackage | ||
360 | { | ||
361 | public int Version; | ||
362 | public int SizeX; | ||
363 | public int SizeY; | ||
364 | public int SizeZ; | ||
365 | public float CompressionFactor; | ||
366 | public int[] Map; | ||
367 | public TerrainChannelXMLPackage(int pX, int pY, int pZ, float pCompressionFactor, int[] pMap) | ||
368 | { | ||
369 | Version = 1; | ||
370 | SizeX = pX; | ||
371 | SizeY = pY; | ||
372 | SizeZ = pZ; | ||
373 | CompressionFactor = pCompressionFactor; | ||
374 | Map = pMap; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | // New terrain serialization format that includes the width and length. | ||
379 | private void ToXml2(XmlWriter xmlWriter) | ||
380 | { | ||
381 | TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_terrainData.CompressionFactor, | ||
382 | m_terrainData.GetCompressedMap()); | ||
383 | XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage)); | ||
384 | serializer.Serialize(xmlWriter, package); | ||
385 | } | ||
386 | |||
387 | // New terrain serialization format that includes the width and length. | ||
388 | private void FromXml2(XmlReader xmlReader) | ||
389 | { | ||
390 | XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage)); | ||
391 | TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader); | ||
392 | m_terrainData = new HeightmapTerrainData(package.Map, package.CompressionFactor, package.SizeX, package.SizeY, package.SizeZ); | ||
393 | } | ||
394 | |||
395 | // Fill the heightmap with the center bump terrain | ||
247 | private void PinHeadIsland() | 396 | private void PinHeadIsland() |
248 | { | 397 | { |
249 | int x; | 398 | for (int x = 0; x < Width; x++) |
250 | for (x = 0; x < Constants.RegionSize; x++) | ||
251 | { | 399 | { |
252 | int y; | 400 | for (int y = 0; y < Height; y++) |
253 | for (y = 0; y < Constants.RegionSize; y++) | ||
254 | { | 401 | { |
255 | map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; | 402 | m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; |
256 | double spherFacA = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01; | 403 | float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d); |
257 | double spherFacB = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001; | 404 | float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d); |
258 | if (map[x, y] < spherFacA) | 405 | if (m_terrainData[x, y]< spherFacA) |
259 | map[x, y] = spherFacA; | 406 | m_terrainData[x, y]= spherFacA; |
260 | if (map[x, y] < spherFacB) | 407 | if (m_terrainData[x, y]< spherFacB) |
261 | map[x, y] = spherFacB; | 408 | m_terrainData[x, y] = spherFacB; |
262 | } | 409 | } |
263 | } | 410 | } |
264 | } | 411 | } |
265 | 412 | ||
266 | private void FlatLand() | 413 | private void FlatLand() |
267 | { | 414 | { |
268 | int x; | 415 | m_terrainData.ClearLand(); |
269 | for (x = 0; x < Constants.RegionSize; x++) | ||
270 | { | ||
271 | int y; | ||
272 | for (y = 0; y < Constants.RegionSize; y++) | ||
273 | map[x, y] = 21; | ||
274 | } | ||
275 | } | 416 | } |
276 | |||
277 | } | 417 | } |
278 | } | 418 | } |