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()