From 9c97fb8e127e91d48cf92eeed238cf80878e2286 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 2 Feb 2014 11:17:49 -0800 Subject: [PATCH] Implement terrain merging in TerrainChannel. Modify archiver to use terrain merging when loading oars. This makes displacement AND rotation properly work on terrain when loading oars. Especially useful when loading legacy region oars into large varregions. --- .../World/Archiver/ArchiveReadRequest.cs | 40 ++++++----- .../World/Archiver/ArchiverModule.cs | 31 ++++++-- .../World/Terrain/TerrainModule.cs | 35 ++------- .../Framework/Interfaces/ITerrainChannel.cs | 3 + .../Framework/Interfaces/ITerrainModule.cs | 2 +- .../Region/Framework/Scenes/TerrainChannel.cs | 72 +++++++++++++++++++ 6 files changed, 129 insertions(+), 54 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index f4807addbb..6f6896680b 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs @@ -121,7 +121,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver protected Vector3 m_displacement = Vector3.Zero; /// - /// Rotation to apply to the objects as they are loaded. + /// Rotation (in radians) to apply to the objects as they are loaded. /// protected float m_rotation = 0f; @@ -184,7 +184,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver m_displacement = options.ContainsKey("displacement") ? (Vector3)options["displacement"] : Vector3.Zero; m_rotation = options.ContainsKey("rotation") ? (float)options["rotation"] : 0f; m_rotationCenter = options.ContainsKey("rotationCenter") ? (Vector3)options["rotationCenter"] - : new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0f); + : new Vector3(scene.RegionInfo.RegionSizeX / 2f, scene.RegionInfo.RegionSizeY / 2f, 0f); // Zero can never be a valid user id m_validUserUuids[UUID.Zero] = false; @@ -454,8 +454,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Reload serialized prims m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); - float angle = (float)(m_rotation / 180.0 * Math.PI); - OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, angle); + OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, m_rotation); UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; @@ -483,16 +482,25 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Happily this does not do much to the object since it hasn't been added to the scene yet if (sceneObject.AttachmentPoint == 0) { - if (angle != 0f) + if (m_displacement != Vector3.Zero || m_rotation != 0f) { - sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation; - Vector3 offset = sceneObject.AbsolutePosition - m_rotationCenter; - offset *= rot; - sceneObject.AbsolutePosition = m_rotationCenter + offset; - } - if (m_displacement != Vector3.Zero) - { - sceneObject.AbsolutePosition += m_displacement; + Vector3 pos = sceneObject.AbsolutePosition; + if (m_rotation != 0f) + { + // Rotate the object + sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation; + // Get object position relative to rotation axis + Vector3 offset = pos - m_rotationCenter; + // Rotate the object position + offset *= rot; + // Restore the object position back to relative to the region + pos = m_rotationCenter + offset; + } + if (m_displacement != Vector3.Zero) + { + pos += m_displacement; + } + sceneObject.AbsolutePosition = pos; } } @@ -868,10 +876,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver ITerrainModule terrainModule = scene.RequestModuleInterface(); MemoryStream ms = new MemoryStream(data); - if (m_displacement != Vector3.Zero) + if (m_displacement != Vector3.Zero || m_rotation != 0f) { - Vector2 terrainDisplacement = new Vector2(m_displacement.X, m_displacement.Y); - terrainModule.LoadFromStream(terrainPath, terrainDisplacement, ms); + Vector2 rotationCenter = new Vector2(m_rotationCenter.X, m_rotationCenter.Y); + terrainModule.LoadFromStream(terrainPath, m_displacement, m_rotation, rotationCenter, ms); } else { diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs index 2a6f1eb23b..6fbac4c82a 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs @@ -120,19 +120,38 @@ namespace OpenSim.Region.CoreModules.World.Archiver { displacement = v == null ? Vector3.Zero : Vector3.Parse(v); } - catch (Exception e) + catch { m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing displacement"); - displacement = new Vector3(0f, 0f, 0f); + m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --displacement \"<128,128,0>\""); + return; } }); options.Add("rotation=", delegate (string v) { - rotation = float.Parse(v); - rotation = Util.Clamp(rotation, -359f, 359f); + try + { + rotation = v == null ? 0f : float.Parse(v); + } + catch + { + m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing rotation"); + m_log.ErrorFormat("[ARCHIVER MODULE] Must be an angle in degrees between -360 and +360: --rotation 45"); + return; + } + // Convert to radians for internals + rotation = Util.Clamp(rotation, -359f, 359f) / 180f * (float)Math.PI; }); options.Add("rotationcenter=", delegate (string v) { - // RA 20130119: libomv's Vector2.Parse doesn't work. Need to use vector3 for the moment - rotationCenter = Vector3.Parse(v); + try + { + rotationCenter = v == null ? Vector3.Zero : Vector3.Parse(v); + } + catch + { + m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing rotation displacement"); + m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --rotationcenter \"<128,128,0>\""); + return; + } }); // Send a message to the region ready module diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 7bc5e8845a..08891d98a8 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -316,8 +316,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain public void LoadFromStream(string filename, Stream stream) { - Vector2 defaultDisplacement = new Vector2(0f, 0f); - LoadFromStream(filename, defaultDisplacement, stream); + LoadFromStream(filename, Vector3.Zero, 0f, Vector2.Zero, stream); } /// @@ -325,7 +324,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// /// Filename to terrain file. Type is determined by extension. /// - public void LoadFromStream(string filename, Vector2 displacement, Stream stream) + public void LoadFromStream(string filename, Vector3 displacement, + float radianRotation, Vector2 rotationDisplacement, Stream stream) { foreach (KeyValuePair loader in m_loaders) { @@ -336,7 +336,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain try { ITerrainChannel channel = loader.Value.LoadStream(stream); - MergeTerrainIntoExisting(channel, displacement); + m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement); UpdateRevertMap(); } catch (NotImplementedException) @@ -356,33 +356,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain throw new TerrainException(String.Format("unable to load heightmap from file {0}: no loader available for that format", filename)); } - private void MergeTerrainIntoExisting(ITerrainChannel channel, Vector2 displacement) - { - if (displacement == Vector2.Zero) - { - // If there is no displacement, just use this channel as the new heightmap - m_scene.Heightmap = channel; - m_channel = channel; - } - else - { - // If there is a displacement, we copy the loaded heightmap into the overall region - for (int xx = 0; xx < channel.Width; xx++) - { - for (int yy = 0; yy < channel.Height; yy++) - { - int dispX = xx + (int)displacement.X; - int dispY = yy + (int)displacement.Y; - if (dispX >= 0 && dispX < m_channel.Width - && dispY >= 0 && dispY < m_channel.Height) - { - m_channel[dispX, dispY] = channel[xx, yy]; - } - } - } - } - } - private static Stream URIFetch(Uri uri) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs index 469bd31506..f660b8dbe0 100644 --- a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs +++ b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs @@ -26,6 +26,7 @@ */ using OpenSim.Framework; +using OpenMetaverse; namespace OpenSim.Region.Framework.Interfaces { @@ -56,5 +57,7 @@ namespace OpenSim.Region.Framework.Interfaces ITerrainChannel MakeCopy(); string SaveToXmlString(); void LoadFromXmlString(string data); + // Merge some terrain into this channel + void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement); } } diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs b/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs index 189a30accb..a6f5d9838e 100644 --- a/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs @@ -51,7 +51,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// void LoadFromStream(string filename, Stream stream); - void LoadFromStream(string filename, Vector2 displacement, Stream stream); + void LoadFromStream(string filename, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement, Stream stream); void LoadFromStream(string filename, System.Uri pathToTerrainHeightmap); /// /// Save a terrain to a stream. diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs index b4b1823de3..24709dcf74 100644 --- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs +++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs @@ -36,6 +36,8 @@ using OpenSim.Data; using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; +using OpenMetaverse; + using log4net; namespace OpenSim.Region.Framework.Scenes @@ -212,6 +214,76 @@ namespace OpenSim.Region.Framework.Scenes sr.Close(); } + // ITerrainChannel.Merge + public void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement) + { + for (int xx = 0; xx < newTerrain.Width; xx++) + { + for (int yy = 0; yy < newTerrain.Height; yy++) + { + int dispX = (int)displacement.X; + int dispY = (int)displacement.Y; + float newHeight = (float)newTerrain[xx, yy] + displacement.Z; + if (radianRotation == 0) + { + // If no rotation, place the new height in the specified location + dispX += xx; + dispY += yy; + if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY) + { + m_terrainData[dispX, dispY] = newHeight; + } + } + else + { + // If rotating, we have to smooth the result because the conversion + // to ints will mean heightmap entries will not get changed + // First compute the rotation location for the new height. + dispX += (int)(rotationDisplacement.X + + ((float)xx - rotationDisplacement.X) * Math.Cos(radianRotation) + - ((float)yy - rotationDisplacement.Y) * Math.Sin(radianRotation) ); + + dispY += (int)(rotationDisplacement.Y + + ((float)xx - rotationDisplacement.X) * Math.Sin(radianRotation) + + ((float)yy - rotationDisplacement.Y) * Math.Cos(radianRotation) ); + + if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY) + { + float oldHeight = m_terrainData[dispX, dispY]; + // Smooth the heights around this location if the old height is far from this one + for (int sxx = dispX - 2; sxx < dispX + 2; sxx++) + { + for (int syy = dispY - 2; syy < dispY + 2; syy++) + { + if (sxx >= 0 && sxx < m_terrainData.SizeX && syy >= 0 && syy < m_terrainData.SizeY) + { + if (sxx == dispX && syy == dispY) + { + // Set height for the exact rotated point + m_terrainData[dispX, dispY] = newHeight; + } + else + { + if (Math.Abs(m_terrainData[sxx, syy] - newHeight) > 1f) + { + // If the adjacent height is far off, force it to this height + m_terrainData[sxx, syy] = newHeight; + } + } + } + } + } + } + + if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY) + { + m_terrainData[dispX, dispY] = (float)newTerrain[xx, yy]; + } + } + } + } + } + #endregion public TerrainChannel Copy()