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.
0.8.0.3
Robert Adams 2014-02-02 11:17:49 -08:00
parent a8e64cd59a
commit 9c97fb8e12
6 changed files with 129 additions and 54 deletions

View File

@ -121,7 +121,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
protected Vector3 m_displacement = Vector3.Zero; protected Vector3 m_displacement = Vector3.Zero;
/// <value> /// <value>
/// Rotation to apply to the objects as they are loaded. /// Rotation (in radians) to apply to the objects as they are loaded.
/// </value> /// </value>
protected float m_rotation = 0f; 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_displacement = options.ContainsKey("displacement") ? (Vector3)options["displacement"] : Vector3.Zero;
m_rotation = options.ContainsKey("rotation") ? (float)options["rotation"] : 0f; m_rotation = options.ContainsKey("rotation") ? (float)options["rotation"] : 0f;
m_rotationCenter = options.ContainsKey("rotationCenter") ? (Vector3)options["rotationCenter"] 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 // Zero can never be a valid user id
m_validUserUuids[UUID.Zero] = false; m_validUserUuids[UUID.Zero] = false;
@ -454,8 +454,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
// Reload serialized prims // Reload serialized prims
m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); 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, m_rotation);
OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, angle);
UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; 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 // Happily this does not do much to the object since it hasn't been added to the scene yet
if (sceneObject.AttachmentPoint == 0) if (sceneObject.AttachmentPoint == 0)
{ {
if (angle != 0f) if (m_displacement != Vector3.Zero || m_rotation != 0f)
{ {
sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation; Vector3 pos = sceneObject.AbsolutePosition;
Vector3 offset = sceneObject.AbsolutePosition - m_rotationCenter; if (m_rotation != 0f)
offset *= rot; {
sceneObject.AbsolutePosition = m_rotationCenter + offset; // Rotate the object
} sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation;
if (m_displacement != Vector3.Zero) // Get object position relative to rotation axis
{ Vector3 offset = pos - m_rotationCenter;
sceneObject.AbsolutePosition += m_displacement; // 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<ITerrainModule>(); ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>();
MemoryStream ms = new MemoryStream(data); 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); Vector2 rotationCenter = new Vector2(m_rotationCenter.X, m_rotationCenter.Y);
terrainModule.LoadFromStream(terrainPath, terrainDisplacement, ms); terrainModule.LoadFromStream(terrainPath, m_displacement, m_rotation, rotationCenter, ms);
} }
else else
{ {

View File

@ -120,19 +120,38 @@ namespace OpenSim.Region.CoreModules.World.Archiver
{ {
displacement = v == null ? Vector3.Zero : Vector3.Parse(v); displacement = v == null ? Vector3.Zero : Vector3.Parse(v);
} }
catch (Exception e) catch
{ {
m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing displacement"); 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) { options.Add("rotation=", delegate (string v) {
rotation = float.Parse(v); try
rotation = Util.Clamp<float>(rotation, -359f, 359f); {
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<float>(rotation, -359f, 359f) / 180f * (float)Math.PI;
}); });
options.Add("rotationcenter=", delegate (string v) { options.Add("rotationcenter=", delegate (string v) {
// RA 20130119: libomv's Vector2.Parse doesn't work. Need to use vector3 for the moment try
rotationCenter = Vector3.Parse(v); {
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 // Send a message to the region ready module

View File

@ -316,8 +316,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
public void LoadFromStream(string filename, Stream stream) public void LoadFromStream(string filename, Stream stream)
{ {
Vector2 defaultDisplacement = new Vector2(0f, 0f); LoadFromStream(filename, Vector3.Zero, 0f, Vector2.Zero, stream);
LoadFromStream(filename, defaultDisplacement, stream);
} }
/// <summary> /// <summary>
@ -325,7 +324,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
/// </summary> /// </summary>
/// <param name="filename">Filename to terrain file. Type is determined by extension.</param> /// <param name="filename">Filename to terrain file. Type is determined by extension.</param>
/// <param name="stream"></param> /// <param name="stream"></param>
public void LoadFromStream(string filename, Vector2 displacement, Stream stream) public void LoadFromStream(string filename, Vector3 displacement,
float radianRotation, Vector2 rotationDisplacement, Stream stream)
{ {
foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
{ {
@ -336,7 +336,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
try try
{ {
ITerrainChannel channel = loader.Value.LoadStream(stream); ITerrainChannel channel = loader.Value.LoadStream(stream);
MergeTerrainIntoExisting(channel, displacement); m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement);
UpdateRevertMap(); UpdateRevertMap();
} }
catch (NotImplementedException) 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)); 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) private static Stream URIFetch(Uri uri)
{ {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);

View File

@ -26,6 +26,7 @@
*/ */
using OpenSim.Framework; using OpenSim.Framework;
using OpenMetaverse;
namespace OpenSim.Region.Framework.Interfaces namespace OpenSim.Region.Framework.Interfaces
{ {
@ -56,5 +57,7 @@ namespace OpenSim.Region.Framework.Interfaces
ITerrainChannel MakeCopy(); ITerrainChannel MakeCopy();
string SaveToXmlString(); string SaveToXmlString();
void LoadFromXmlString(string data); void LoadFromXmlString(string data);
// Merge some terrain into this channel
void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement);
} }
} }

View File

@ -51,7 +51,7 @@ namespace OpenSim.Region.Framework.Interfaces
/// </param> /// </param>
/// <param name="stream"></param> /// <param name="stream"></param>
void LoadFromStream(string filename, Stream stream); 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); void LoadFromStream(string filename, System.Uri pathToTerrainHeightmap);
/// <summary> /// <summary>
/// Save a terrain to a stream. /// Save a terrain to a stream.

View File

@ -36,6 +36,8 @@ using OpenSim.Data;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenMetaverse;
using log4net; using log4net;
namespace OpenSim.Region.Framework.Scenes namespace OpenSim.Region.Framework.Scenes
@ -212,6 +214,76 @@ namespace OpenSim.Region.Framework.Scenes
sr.Close(); 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 #endregion
public TerrainChannel Copy() public TerrainChannel Copy()