diff options
author | onefang | 2019-05-19 21:24:15 +1000 |
---|---|---|
committer | onefang | 2019-05-19 21:24:15 +1000 |
commit | 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb (patch) | |
tree | a9fbc62df9eb2d1d9ba2698d8552eae71eca20d8 /OpenSim/Region/Framework/Scenes/TerrainChannel.cs | |
parent | Add a build script. (diff) | |
download | opensim-SC-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.zip opensim-SC-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.gz opensim-SC-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.bz2 opensim-SC-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.xz |
Dump OpenSim 0.9.0.1 into it's own branch.
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/TerrainChannel.cs | 182 |
1 files changed, 166 insertions, 16 deletions
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs index 3d563a6..20bad94 100644 --- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs +++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs | |||
@@ -57,6 +57,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
57 | public int Height { get { return m_terrainData.SizeY; } } // Y dimension | 57 | public int Height { get { return m_terrainData.SizeY; } } // Y dimension |
58 | public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension | 58 | public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension |
59 | 59 | ||
60 | |||
60 | // Default, not-often-used builder | 61 | // Default, not-often-used builder |
61 | public TerrainChannel() | 62 | public TerrainChannel() |
62 | { | 63 | { |
@@ -195,13 +196,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
195 | // ITerrainChannel.LoadFromXmlString() | 196 | // ITerrainChannel.LoadFromXmlString() |
196 | public void LoadFromXmlString(string data) | 197 | public void LoadFromXmlString(string data) |
197 | { | 198 | { |
198 | StringReader sr = new StringReader(data); | 199 | using(StringReader sr = new StringReader(data)) |
199 | XmlTextReader reader = new XmlTextReader(sr); | 200 | { |
200 | reader.Read(); | 201 | using(XmlTextReader reader = new XmlTextReader(sr)) |
202 | { | ||
203 | reader.ProhibitDtd = true; | ||
201 | 204 | ||
202 | ReadXml(reader); | 205 | ReadXml(reader); |
203 | reader.Close(); | 206 | } |
204 | sr.Close(); | 207 | } |
205 | } | 208 | } |
206 | 209 | ||
207 | // ITerrainChannel.Merge | 210 | // ITerrainChannel.Merge |
@@ -278,6 +281,148 @@ namespace OpenSim.Region.Framework.Scenes | |||
278 | } | 281 | } |
279 | } | 282 | } |
280 | 283 | ||
284 | /// <summary> | ||
285 | /// A new version of terrain merge that processes the terrain in a specific order and corrects the problems with rotated terrains | ||
286 | /// having 'holes' in that need to be smoothed. The correct way to rotate something is to iterate over the target, taking data from | ||
287 | /// the source, not the other way around. This ensures that the target has no holes in it. | ||
288 | /// The processing order of an incoming terrain is: | ||
289 | /// 1. Apply rotation | ||
290 | /// 2. Apply bounding rectangle | ||
291 | /// 3. Apply displacement | ||
292 | /// rotationCenter is no longer needed and has been discarded. | ||
293 | /// </summary> | ||
294 | /// <param name="newTerrain"></param> | ||
295 | /// <param name="displacement"><x, y, z></param> | ||
296 | /// <param name="rotationDegrees"></param> | ||
297 | /// <param name="boundingOrigin"><x, y></param> | ||
298 | /// <param name="boundingSize"><x, y></param> | ||
299 | public void MergeWithBounding(ITerrainChannel newTerrain, Vector3 displacement, float rotationDegrees, Vector2 boundingOrigin, Vector2 boundingSize) | ||
300 | { | ||
301 | m_log.DebugFormat("{0} MergeWithBounding: inSize=<{1},{2}>, rot={3}, boundingOrigin={4}, boundingSize={5}, disp={6}, outSize=<{7},{8}>", | ||
302 | LogHeader, newTerrain.Width, newTerrain.Height, rotationDegrees, boundingOrigin.ToString(), | ||
303 | boundingSize.ToString(), displacement, m_terrainData.SizeX, m_terrainData.SizeY); | ||
304 | |||
305 | // get the size of the incoming terrain | ||
306 | int baseX = newTerrain.Width; | ||
307 | int baseY = newTerrain.Height; | ||
308 | |||
309 | // create an intermediate terrain map that is 25% bigger on each side that we can work with to handle rotation | ||
310 | int offsetX = baseX / 4; // the original origin will now be at these coordinates so now we can have imaginary negative coordinates ;) | ||
311 | int offsetY = baseY / 4; | ||
312 | int tmpX = baseX + baseX / 2; | ||
313 | int tmpY = baseY + baseY / 2; | ||
314 | int centreX = tmpX / 2; | ||
315 | int centreY = tmpY / 2; | ||
316 | TerrainData terrain_tmp = new HeightmapTerrainData(tmpX, tmpY, (int)Constants.RegionHeight); | ||
317 | for (int xx = 0; xx < tmpX; xx++) | ||
318 | for (int yy = 0; yy < tmpY; yy++) | ||
319 | terrain_tmp[xx, yy] = -65535f; //use this height like an 'alpha' mask channel | ||
320 | |||
321 | double radianRotation = Math.PI * rotationDegrees / 180f; | ||
322 | double cosR = Math.Cos(radianRotation); | ||
323 | double sinR = Math.Sin(radianRotation); | ||
324 | if (rotationDegrees < 0f) rotationDegrees += 360f; //-90=270 -180=180 -270=90 | ||
325 | |||
326 | // So first we apply the rotation to the incoming terrain, storing the result in terrain_tmp | ||
327 | // We special case orthogonal rotations for accuracy because even using double precision math, Math.Cos(90 degrees) is never fully 0 | ||
328 | // and we can never rotate around a centre 'pixel' because the 'bitmap' size is always even | ||
329 | |||
330 | int x, y, sx, sy; | ||
331 | for (y = 0; y <= tmpY; y++) | ||
332 | { | ||
333 | for (x = 0; x <= tmpX; x++) | ||
334 | { | ||
335 | if (rotationDegrees == 0f) | ||
336 | { | ||
337 | sx = x - offsetX; | ||
338 | sy = y - offsetY; | ||
339 | } | ||
340 | else if (rotationDegrees == 90f) | ||
341 | { | ||
342 | sx = y - offsetX; | ||
343 | sy = tmpY - 1 - x - offsetY; | ||
344 | } | ||
345 | else if (rotationDegrees == 180f) | ||
346 | { | ||
347 | sx = tmpX - 1 - x - offsetX; | ||
348 | sy = tmpY - 1 - y - offsetY; | ||
349 | } | ||
350 | else if (rotationDegrees == 270f) | ||
351 | { | ||
352 | sx = tmpX - 1 - y - offsetX; | ||
353 | sy = x - offsetY; | ||
354 | } | ||
355 | else | ||
356 | { | ||
357 | // arbitary rotation: hmmm should I be using (centreX - 0.5) and (centreY - 0.5) and round cosR and sinR to say only 5 decimal places? | ||
358 | sx = centreX + (int)Math.Round((((double)x - centreX) * cosR) + (((double)y - centreY) * sinR)) - offsetX; | ||
359 | sy = centreY + (int)Math.Round((((double)y - centreY) * cosR) - (((double)x - centreX) * sinR)) - offsetY; | ||
360 | } | ||
361 | |||
362 | if (sx >= 0 && sx < baseX && sy >= 0 && sy < baseY) | ||
363 | { | ||
364 | try | ||
365 | { | ||
366 | terrain_tmp[x, y] = (float)newTerrain[sx, sy]; | ||
367 | } | ||
368 | catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;) | ||
369 | { | ||
370 | m_log.DebugFormat("{0} MergeWithBounding - Rotate: Out of Bounds sx={1} sy={2} dx={3} dy={4}", sx, sy, x, y); | ||
371 | } | ||
372 | } | ||
373 | } | ||
374 | } | ||
375 | |||
376 | // We could also incorporate the next steps, bounding-rectangle and displacement in the loop above, but it's simpler to visualise if done separately | ||
377 | // and will also make it much easier when later I want the option for maybe a circular or oval bounding shape too ;). | ||
378 | |||
379 | int newX = m_terrainData.SizeX; | ||
380 | int newY = m_terrainData.SizeY; | ||
381 | // displacement is relative to <0,0> in the destination region and defines where the origin of the data selected by the bounding-rectangle is placed | ||
382 | int dispX = (int)Math.Floor(displacement.X); | ||
383 | int dispY = (int)Math.Floor(displacement.Y); | ||
384 | |||
385 | // startX/Y and endX/Y are coordinates in bitmap_tmp | ||
386 | int startX = (int)Math.Floor(boundingOrigin.X) + offsetX; | ||
387 | if (startX > tmpX) startX = tmpX; | ||
388 | if (startX < 0) startX = 0; | ||
389 | int startY = (int)Math.Floor(boundingOrigin.Y) + offsetY; | ||
390 | if (startY > tmpY) startY = tmpY; | ||
391 | if (startY < 0) startY = 0; | ||
392 | |||
393 | int endX = (int)Math.Floor(boundingOrigin.X + boundingSize.X) + offsetX; | ||
394 | if (endX > tmpX) endX = tmpX; | ||
395 | if (endX < 0) endX = 0; | ||
396 | int endY = (int)Math.Floor(boundingOrigin.Y + boundingSize.Y) + offsetY; | ||
397 | if (endY > tmpY) endY = tmpY; | ||
398 | if (endY < 0) endY = 0; | ||
399 | |||
400 | //m_log.DebugFormat("{0} MergeWithBounding: inSize=<{1},{2}>, disp=<{3},{4}> rot={5}, offset=<{6},{7}>, boundingStart=<{8},{9}>, boundingEnd=<{10},{11}>, cosR={12}, sinR={13}, outSize=<{14},{15}>", LogHeader, | ||
401 | // baseX, baseY, dispX, dispY, radianRotation, offsetX, offsetY, startX, startY, endX, endY, cosR, sinR, newX, newY); | ||
402 | |||
403 | int dx, dy; | ||
404 | for (y = startY; y < endY; y++) | ||
405 | { | ||
406 | for (x = startX; x < endX; x++) | ||
407 | { | ||
408 | dx = x - startX + dispX; | ||
409 | dy = y - startY + dispY; | ||
410 | if (dx >= 0 && dx < newX && dy >= 0 && dy < newY) | ||
411 | { | ||
412 | try | ||
413 | { | ||
414 | float newHeight = (float)terrain_tmp[x, y]; //use 'alpha' mask | ||
415 | if (newHeight != -65535f) m_terrainData[dx, dy] = newHeight + displacement.Z; | ||
416 | } | ||
417 | catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;) | ||
418 | { | ||
419 | m_log.DebugFormat("{0} MergeWithBounding - Bound & Displace: Out of Bounds sx={1} sy={2} dx={3} dy={4}", x, y, dx, dy); | ||
420 | } | ||
421 | } | ||
422 | } | ||
423 | } | ||
424 | } | ||
425 | |||
281 | #endregion | 426 | #endregion |
282 | 427 | ||
283 | public TerrainChannel Copy() | 428 | public TerrainChannel Copy() |
@@ -343,7 +488,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
343 | int index = 0; | 488 | int index = 0; |
344 | 489 | ||
345 | m_terrainData = new HeightmapTerrainData(Height, Width, (int)Constants.RegionHeight); | 490 | m_terrainData = new HeightmapTerrainData(Height, Width, (int)Constants.RegionHeight); |
346 | 491 | ||
347 | for (int y = 0; y < Height; y++) | 492 | for (int y = 0; y < Height; y++) |
348 | { | 493 | { |
349 | for (int x = 0; x < Width; x++) | 494 | for (int x = 0; x < Width; x++) |
@@ -363,8 +508,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
363 | public int SizeY; | 508 | public int SizeY; |
364 | public int SizeZ; | 509 | public int SizeZ; |
365 | public float CompressionFactor; | 510 | public float CompressionFactor; |
366 | public int[] Map; | 511 | public float[] Map; |
367 | public TerrainChannelXMLPackage(int pX, int pY, int pZ, float pCompressionFactor, int[] pMap) | 512 | public TerrainChannelXMLPackage(int pX, int pY, int pZ, float pCompressionFactor, float[] pMap) |
368 | { | 513 | { |
369 | Version = 1; | 514 | Version = 1; |
370 | SizeX = pX; | 515 | SizeX = pX; |
@@ -395,17 +540,22 @@ namespace OpenSim.Region.Framework.Scenes | |||
395 | // Fill the heightmap with the center bump terrain | 540 | // Fill the heightmap with the center bump terrain |
396 | private void PinHeadIsland() | 541 | private void PinHeadIsland() |
397 | { | 542 | { |
543 | float cx = m_terrainData.SizeX * 0.5f; | ||
544 | float cy = m_terrainData.SizeY * 0.5f; | ||
545 | float h; | ||
398 | for (int x = 0; x < Width; x++) | 546 | for (int x = 0; x < Width; x++) |
399 | { | 547 | { |
400 | for (int y = 0; y < Height; y++) | 548 | for (int y = 0; y < Height; y++) |
401 | { | 549 | { |
402 | m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; | 550 | // h = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; |
403 | float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d); | 551 | h = 1.0f; |
404 | float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d); | 552 | float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, cx, cy, 50) * 0.01d); |
405 | if (m_terrainData[x, y]< spherFacA) | 553 | float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, cx, cy, 100) * 0.001d); |
406 | m_terrainData[x, y]= spherFacA; | 554 | if (h < spherFacA) |
407 | if (m_terrainData[x, y]< spherFacB) | 555 | h = spherFacA; |
408 | m_terrainData[x, y] = spherFacB; | 556 | if (h < spherFacB) |
557 | h = spherFacB; | ||
558 | m_terrainData[x, y] = h; | ||
409 | } | 559 | } |
410 | } | 560 | } |
411 | } | 561 | } |