diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Framework/TerrainData.cs | 232 |
1 files changed, 105 insertions, 127 deletions
diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs index 5cec2b5..0e5e83e 100644 --- a/OpenSim/Framework/TerrainData.cs +++ b/OpenSim/Framework/TerrainData.cs | |||
@@ -37,52 +37,6 @@ using log4net; | |||
37 | 37 | ||
38 | namespace OpenSim.Framework | 38 | namespace OpenSim.Framework |
39 | { | 39 | { |
40 | public abstract class TerrainData | ||
41 | { | ||
42 | // Terrain always is a square | ||
43 | public int SizeX { get; protected set; } | ||
44 | public int SizeY { get; protected set; } | ||
45 | public int SizeZ { get; protected set; } | ||
46 | |||
47 | // A height used when the user doesn't specify anything | ||
48 | public const float DefaultTerrainHeight = 21f; | ||
49 | |||
50 | public abstract float this[int x, int y] { get; set; } | ||
51 | // Someday terrain will have caves | ||
52 | // at most holes :p | ||
53 | public abstract float this[int x, int y, int z] { get; set; } | ||
54 | |||
55 | public abstract bool IsTaintedAt(int xx, int yy); | ||
56 | public abstract bool IsTaintedAt(int xx, int yy, bool clearOnTest); | ||
57 | public abstract void TaintAllTerrain(); | ||
58 | public abstract void ClearTaint(); | ||
59 | |||
60 | public abstract void ClearLand(); | ||
61 | public abstract void ClearLand(float height); | ||
62 | |||
63 | // Return a representation of this terrain for storing as a blob in the database. | ||
64 | // Returns 'true' to say blob was stored in the 'out' locations. | ||
65 | public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob); | ||
66 | |||
67 | // Given a revision code and a blob from the database, create and return the right type of TerrainData. | ||
68 | // The sizes passed are the expected size of the region. The database info will be used to | ||
69 | // initialize the heightmap of that sized region with as much data is in the blob. | ||
70 | // Return created TerrainData or 'null' if unsuccessful. | ||
71 | public static TerrainData CreateFromDatabaseBlobFactory(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) | ||
72 | { | ||
73 | // For the moment, there is only one implementation class | ||
74 | return new HeightmapTerrainData(pSizeX, pSizeY, pSizeZ, pFormatCode, pBlob); | ||
75 | } | ||
76 | |||
77 | // return a special compressed representation of the heightmap in ushort | ||
78 | public abstract float[] GetCompressedMap(); | ||
79 | public abstract float CompressionFactor { get; } | ||
80 | |||
81 | public abstract float[] GetFloatsSerialized(); | ||
82 | public abstract double[,] GetDoubles(); | ||
83 | public abstract TerrainData Clone(); | ||
84 | } | ||
85 | |||
86 | // The terrain is stored in the database as a blob with a 'revision' field. | 40 | // The terrain is stored in the database as a blob with a 'revision' field. |
87 | // Some implementations of terrain storage would fill the revision field with | 41 | // Some implementations of terrain storage would fill the revision field with |
88 | // the time the terrain was stored. When real revisions were added and this | 42 | // the time the terrain was stored. When real revisions were added and this |
@@ -112,18 +66,37 @@ namespace OpenSim.Framework | |||
112 | RevisionHigh = 1234 | 66 | RevisionHigh = 1234 |
113 | } | 67 | } |
114 | 68 | ||
115 | // Version of terrain that is a heightmap. | 69 | public class TerrainData |
116 | // This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge | ||
117 | // of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer. | ||
118 | // The heighmap is kept as an array of ushorts. The ushort values are converted to | ||
119 | // and from floats by TerrainCompressionFactor. | ||
120 | public class HeightmapTerrainData : TerrainData | ||
121 | { | 70 | { |
122 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 71 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
123 | private static string LogHeader = "[HEIGHTMAP TERRAIN DATA]"; | 72 | private static string LogHeader = "[TERRAIN DATA]"; |
73 | |||
74 | private float[,] m_heightmap; | ||
75 | // Remember subregions of the heightmap that has changed. | ||
76 | private bool[,] m_taint; | ||
77 | |||
78 | // legacy CompressionFactor | ||
79 | public float CompressionFactor { get; private set; } | ||
80 | |||
81 | // Terrain always is a square | ||
82 | public int SizeX { get; protected set; } | ||
83 | public int SizeY { get; protected set; } | ||
84 | public int SizeZ { get; protected set; } | ||
85 | |||
86 | // A height used when the user doesn't specify anything | ||
87 | public const float DefaultTerrainHeight = 21f; | ||
88 | |||
89 | // Given a revision code and a blob from the database, create and return the right type of TerrainData. | ||
90 | // The sizes passed are the expected size of the region. The database info will be used to | ||
91 | // initialize the heightmap of that sized region with as much data is in the blob. | ||
92 | // Return created TerrainData or 'null' if unsuccessful. | ||
93 | public static TerrainData CreateFromDatabaseBlobFactory(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) | ||
94 | { | ||
95 | // For the moment, there is only one implementation class | ||
96 | return new TerrainData(pSizeX, pSizeY, pSizeZ, pFormatCode, pBlob); | ||
97 | } | ||
124 | 98 | ||
125 | // TerrainData.this[x, y] | 99 | public float this[int x, int y] |
126 | public override float this[int x, int y] | ||
127 | { | 100 | { |
128 | get { return m_heightmap[x, y]; } | 101 | get { return m_heightmap[x, y]; } |
129 | set | 102 | set |
@@ -136,21 +109,18 @@ namespace OpenSim.Framework | |||
136 | } | 109 | } |
137 | } | 110 | } |
138 | 111 | ||
139 | // TerrainData.this[x, y, z] | 112 | public float this[int x, int y, int z] |
140 | public override float this[int x, int y, int z] | ||
141 | { | 113 | { |
142 | get { return this[x, y]; } | 114 | get { return this[x, y]; } |
143 | set { this[x, y] = value; } | 115 | set { this[x, y] = value; } |
144 | } | 116 | } |
145 | 117 | ||
146 | // TerrainData.ClearTaint | 118 | public void ClearTaint() |
147 | public override void ClearTaint() | ||
148 | { | 119 | { |
149 | SetAllTaint(false); | 120 | SetAllTaint(false); |
150 | } | 121 | } |
151 | 122 | ||
152 | // TerrainData.TaintAllTerrain | 123 | public void TaintAllTerrain() |
153 | public override void TaintAllTerrain() | ||
154 | { | 124 | { |
155 | SetAllTaint(true); | 125 | SetAllTaint(true); |
156 | } | 126 | } |
@@ -162,13 +132,12 @@ namespace OpenSim.Framework | |||
162 | m_taint[ii, jj] = setting; | 132 | m_taint[ii, jj] = setting; |
163 | } | 133 | } |
164 | 134 | ||
165 | // TerrainData.ClearLand | 135 | public void ClearLand() |
166 | public override void ClearLand() | ||
167 | { | 136 | { |
168 | ClearLand(DefaultTerrainHeight); | 137 | ClearLand(DefaultTerrainHeight); |
169 | } | 138 | } |
170 | // TerrainData.ClearLand(float) | 139 | |
171 | public override void ClearLand(float pHeight) | 140 | public void ClearLand(float pHeight) |
172 | { | 141 | { |
173 | for (int xx = 0; xx < SizeX; xx++) | 142 | for (int xx = 0; xx < SizeX; xx++) |
174 | for (int yy = 0; yy < SizeY; yy++) | 143 | for (int yy = 0; yy < SizeY; yy++) |
@@ -178,7 +147,7 @@ namespace OpenSim.Framework | |||
178 | // Return 'true' of the patch that contains these region coordinates has been modified. | 147 | // Return 'true' of the patch that contains these region coordinates has been modified. |
179 | // Note that checking the taint clears it. | 148 | // Note that checking the taint clears it. |
180 | // There is existing code that relies on this feature. | 149 | // There is existing code that relies on this feature. |
181 | public override bool IsTaintedAt(int xx, int yy, bool clearOnTest) | 150 | public bool IsTaintedAt(int xx, int yy, bool clearOnTest) |
182 | { | 151 | { |
183 | int tx = xx / Constants.TerrainPatchSize; | 152 | int tx = xx / Constants.TerrainPatchSize; |
184 | int ty = yy / Constants.TerrainPatchSize; | 153 | int ty = yy / Constants.TerrainPatchSize; |
@@ -191,41 +160,22 @@ namespace OpenSim.Framework | |||
191 | // Old form that clears the taint flag when we check it. | 160 | // Old form that clears the taint flag when we check it. |
192 | // ubit: this dangerus naming should be only check without clear | 161 | // ubit: this dangerus naming should be only check without clear |
193 | // keeping for old modules outthere | 162 | // keeping for old modules outthere |
194 | public override bool IsTaintedAt(int xx, int yy) | 163 | public bool IsTaintedAt(int xx, int yy) |
195 | { | 164 | { |
196 | return IsTaintedAt(xx, yy, true /* clearOnTest */); | 165 | return IsTaintedAt(xx, yy, true /* clearOnTest */); |
197 | } | 166 | } |
198 | 167 | ||
199 | // TerrainData.GetDatabaseBlob | 168 | // TerrainData.GetDatabaseBlob |
200 | // The user wants something to store in the database. | 169 | // The user wants something to store in the database. |
201 | public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob) | 170 | public bool GetDatabaseBlob(out int DBRevisionCode, out Array blob) |
202 | { | 171 | { |
203 | bool ret = false; | 172 | DBRevisionCode = (int)DBTerrainRevision.Variable2DGzip; |
204 | /* save all as Variable2DGzip | 173 | blob = ToCompressedTerrainSerializationV2DGzip(); |
205 | if (SizeX == Constants.RegionSize && SizeY == Constants.RegionSize) | 174 | return true; |
206 | { | ||
207 | DBRevisionCode = (int)DBTerrainRevision.Legacy256; | ||
208 | blob = ToLegacyTerrainSerialization(); | ||
209 | ret = true; | ||
210 | } | ||
211 | else | ||
212 | { | ||
213 | */ | ||
214 | DBRevisionCode = (int)DBTerrainRevision.Variable2DGzip; | ||
215 | // DBRevisionCode = (int)DBTerrainRevision.Variable2D; | ||
216 | blob = ToCompressedTerrainSerializationV2DGzip(); | ||
217 | // blob = ToCompressedTerrainSerializationV2D(); | ||
218 | ret = true; | ||
219 | // } | ||
220 | return ret; | ||
221 | } | 175 | } |
222 | 176 | ||
223 | // TerrainData.CompressionFactor | ||
224 | private float m_compressionFactor = 100.0f; | ||
225 | public override float CompressionFactor { get { return m_compressionFactor; } } | ||
226 | |||
227 | // TerrainData.GetCompressedMap | 177 | // TerrainData.GetCompressedMap |
228 | public override float[] GetCompressedMap() | 178 | public float[] GetCompressedMap() |
229 | { | 179 | { |
230 | float[] newMap = new float[SizeX * SizeY]; | 180 | float[] newMap = new float[SizeX * SizeY]; |
231 | 181 | ||
@@ -235,21 +185,16 @@ namespace OpenSim.Framework | |||
235 | newMap[ind++] = m_heightmap[xx, yy]; | 185 | newMap[ind++] = m_heightmap[xx, yy]; |
236 | 186 | ||
237 | return newMap; | 187 | return newMap; |
238 | |||
239 | } | 188 | } |
240 | // TerrainData.Clone | 189 | |
241 | public override TerrainData Clone() | 190 | public TerrainData Clone() |
242 | { | 191 | { |
243 | HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ); | 192 | TerrainData ret = new TerrainData(SizeX, SizeY, SizeZ); |
244 | ret.m_heightmap = (float[,])this.m_heightmap.Clone(); | 193 | ret.m_heightmap = (float[,])this.m_heightmap.Clone(); |
245 | return ret; | 194 | return ret; |
246 | } | 195 | } |
247 | 196 | ||
248 | // TerrainData.GetFloatsSerialized | 197 | public float[] GetFloatsSerialized() |
249 | // This one dimensional version is ordered so height = map[y*sizeX+x]; | ||
250 | // DEPRECATED: don't use this function as it does not retain the dimensions of the terrain | ||
251 | // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256. | ||
252 | public override float[] GetFloatsSerialized() | ||
253 | { | 198 | { |
254 | int points = SizeX * SizeY; | 199 | int points = SizeX * SizeY; |
255 | float[] heights = new float[points]; | 200 | float[] heights = new float[points]; |
@@ -264,8 +209,7 @@ namespace OpenSim.Framework | |||
264 | return heights; | 209 | return heights; |
265 | } | 210 | } |
266 | 211 | ||
267 | // TerrainData.GetDoubles | 212 | public double[,] GetDoubles() |
268 | public override double[,] GetDoubles() | ||
269 | { | 213 | { |
270 | double[,] ret = new double[SizeX, SizeY]; | 214 | double[,] ret = new double[SizeX, SizeY]; |
271 | for (int xx = 0; xx < SizeX; xx++) | 215 | for (int xx = 0; xx < SizeX; xx++) |
@@ -275,14 +219,53 @@ namespace OpenSim.Framework | |||
275 | return ret; | 219 | return ret; |
276 | } | 220 | } |
277 | 221 | ||
222 | public unsafe void GetPatchMinMax(int px, int py, out float zmin, out float zmax) | ||
223 | { | ||
224 | zmax = float.MinValue; | ||
225 | zmin = float.MaxValue; | ||
278 | 226 | ||
279 | // ============================================================= | 227 | int stride = m_heightmap.GetLength(1); |
280 | 228 | ||
281 | private float[,] m_heightmap; | 229 | int startx = px * 16 * stride; |
282 | // Remember subregions of the heightmap that has changed. | 230 | int endx = (px + 1) * 16 * stride; |
283 | private bool[,] m_taint; | 231 | int starty = py * 16; |
232 | fixed (float* map = m_heightmap) | ||
233 | { | ||
234 | for (int i = startx; i < endx; i += stride) | ||
235 | { | ||
236 | float* p = &map[i]; | ||
237 | for (int j = starty; j < starty + 16; j++) | ||
238 | { | ||
239 | float val = p[j]; | ||
240 | if (val > zmax) zmax = val; | ||
241 | if (val < zmin) zmin = val; | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | public unsafe void GetPatchBlock(float[] _block, int px, int py, float sub, float premult) | ||
248 | { | ||
249 | int k = 0; | ||
250 | int stride = m_heightmap.GetLength(1); | ||
284 | 251 | ||
285 | // that is coded as the float height times the compression factor (usually '100' | 252 | int startX = px * 16 * stride; |
253 | int endX = (px + 1) * 16 * stride; | ||
254 | int startY = py * 16; | ||
255 | fixed(float* block = _block, map = m_heightmap) | ||
256 | { | ||
257 | for (int y = startY; y < startY + 16; y++) | ||
258 | { | ||
259 | for (int x = startX; x < endX; x += stride) | ||
260 | { | ||
261 | block[k++] = (map[x + y] - sub) * premult; | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | // that is coded as the float height times the compression factor (usually '100' | ||
286 | // to make for two decimal points). | 269 | // to make for two decimal points). |
287 | public short ToCompressedHeightshort(float pHeight) | 270 | public short ToCompressedHeightshort(float pHeight) |
288 | { | 271 | { |
@@ -305,6 +288,7 @@ namespace OpenSim.Framework | |||
305 | return ushort.MaxValue; | 288 | return ushort.MaxValue; |
306 | return (ushort)pHeight; | 289 | return (ushort)pHeight; |
307 | } | 290 | } |
291 | */ | ||
308 | 292 | ||
309 | public float FromCompressedHeight(short pHeight) | 293 | public float FromCompressedHeight(short pHeight) |
310 | { | 294 | { |
@@ -318,12 +302,12 @@ namespace OpenSim.Framework | |||
318 | 302 | ||
319 | // To keep with the legacy theme, create an instance of this class based on the | 303 | // To keep with the legacy theme, create an instance of this class based on the |
320 | // way terrain used to be passed around. | 304 | // way terrain used to be passed around. |
321 | public HeightmapTerrainData(double[,] pTerrain) | 305 | public TerrainData(double[,] pTerrain) |
322 | { | 306 | { |
323 | SizeX = pTerrain.GetLength(0); | 307 | SizeX = pTerrain.GetLength(0); |
324 | SizeY = pTerrain.GetLength(1); | 308 | SizeY = pTerrain.GetLength(1); |
325 | SizeZ = (int)Constants.RegionHeight; | 309 | SizeZ = (int)Constants.RegionHeight; |
326 | m_compressionFactor = 100.0f; | 310 | CompressionFactor = 100.0f; |
327 | 311 | ||
328 | m_heightmap = new float[SizeX, SizeY]; | 312 | m_heightmap = new float[SizeX, SizeY]; |
329 | for (int ii = 0; ii < SizeX; ii++) | 313 | for (int ii = 0; ii < SizeX; ii++) |
@@ -341,12 +325,12 @@ namespace OpenSim.Framework | |||
341 | } | 325 | } |
342 | 326 | ||
343 | // Create underlying structures but don't initialize the heightmap assuming the caller will immediately do that | 327 | // Create underlying structures but don't initialize the heightmap assuming the caller will immediately do that |
344 | public HeightmapTerrainData(int pX, int pY, int pZ) | 328 | public TerrainData(int pX, int pY, int pZ) |
345 | { | 329 | { |
346 | SizeX = pX; | 330 | SizeX = pX; |
347 | SizeY = pY; | 331 | SizeY = pY; |
348 | SizeZ = pZ; | 332 | SizeZ = pZ; |
349 | m_compressionFactor = 100.0f; | 333 | CompressionFactor = 100.0f; |
350 | m_heightmap = new float[SizeX, SizeY]; | 334 | m_heightmap = new float[SizeX, SizeY]; |
351 | m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize]; | 335 | m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize]; |
352 | // m_log.DebugFormat("{0} new by dimensions. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ); | 336 | // m_log.DebugFormat("{0} new by dimensions. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ); |
@@ -354,10 +338,10 @@ namespace OpenSim.Framework | |||
354 | ClearLand(0f); | 338 | ClearLand(0f); |
355 | } | 339 | } |
356 | 340 | ||
357 | public HeightmapTerrainData(float[] cmap, float pCompressionFactor, int pX, int pY, int pZ) | 341 | public TerrainData(float[] cmap, float pCompressionFactor, int pX, int pY, int pZ) |
358 | : this(pX, pY, pZ) | 342 | : this(pX, pY, pZ) |
359 | { | 343 | { |
360 | m_compressionFactor = pCompressionFactor; | 344 | CompressionFactor = pCompressionFactor; |
361 | int ind = 0; | 345 | int ind = 0; |
362 | for (int xx = 0; xx < SizeX; xx++) | 346 | for (int xx = 0; xx < SizeX; xx++) |
363 | for (int yy = 0; yy < SizeY; yy++) | 347 | for (int yy = 0; yy < SizeY; yy++) |
@@ -366,7 +350,7 @@ namespace OpenSim.Framework | |||
366 | } | 350 | } |
367 | 351 | ||
368 | // Create a heighmap from a database blob | 352 | // Create a heighmap from a database blob |
369 | public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) | 353 | public TerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) |
370 | : this(pSizeX, pSizeY, pSizeZ) | 354 | : this(pSizeX, pSizeY, pSizeZ) |
371 | { | 355 | { |
372 | switch ((DBTerrainRevision)pFormatCode) | 356 | switch ((DBTerrainRevision)pFormatCode) |
@@ -476,13 +460,9 @@ namespace OpenSim.Framework | |||
476 | ret = str.ToArray(); | 460 | ret = str.ToArray(); |
477 | } | 461 | } |
478 | } | 462 | } |
479 | catch | 463 | catch {} |
480 | { | ||
481 | |||
482 | } | ||
483 | 464 | ||
484 | m_log.DebugFormat("{0} V2D {1} bytes", | 465 | m_log.DebugFormat("{0} V2D {1} bytes", LogHeader, ret.Length); |
485 | LogHeader, ret.Length); | ||
486 | 466 | ||
487 | return ret; | 467 | return ret; |
488 | } | 468 | } |
@@ -502,7 +482,8 @@ namespace OpenSim.Framework | |||
502 | for (int yy = 0; yy < SizeY; yy++) | 482 | for (int yy = 0; yy < SizeY; yy++) |
503 | for (int xx = 0; xx < SizeX; xx++) | 483 | for (int xx = 0; xx < SizeX; xx++) |
504 | { | 484 | { |
505 | bw.Write((float)m_heightmap[xx, yy]); | 485 | //bw.Write((float)m_heightmap[xx, yy]); |
486 | bw.Write((float)Math.Round(m_heightmap[xx, yy], 3, MidpointRounding.AwayFromZero)); | ||
506 | } | 487 | } |
507 | 488 | ||
508 | bw.Flush(); | 489 | bw.Flush(); |
@@ -520,12 +501,9 @@ namespace OpenSim.Framework | |||
520 | } | 501 | } |
521 | } | 502 | } |
522 | } | 503 | } |
523 | catch | 504 | catch {} |
524 | { | ||
525 | 505 | ||
526 | } | 506 | m_log.DebugFormat("{0} V2DGzip {1} bytes", LogHeader, ret.Length); |
527 | m_log.DebugFormat("{0} V2DGzip {1} bytes", | ||
528 | LogHeader, ret.Length); | ||
529 | return ret; | 507 | return ret; |
530 | } | 508 | } |
531 | 509 | ||
@@ -548,7 +526,7 @@ namespace OpenSim.Framework | |||
548 | hmSizeY = br.ReadInt32(); | 526 | hmSizeY = br.ReadInt32(); |
549 | hmCompressionFactor = br.ReadInt32(); | 527 | hmCompressionFactor = br.ReadInt32(); |
550 | 528 | ||
551 | m_compressionFactor = hmCompressionFactor; | 529 | CompressionFactor = hmCompressionFactor; |
552 | 530 | ||
553 | // In case database info doesn't match real terrain size, initialize the whole terrain. | 531 | // In case database info doesn't match real terrain size, initialize the whole terrain. |
554 | ClearLand(); | 532 | ClearLand(); |