aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/TerrainData.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/TerrainData.cs232
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
38namespace OpenSim.Framework 38namespace 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();