varregion: plug in TerrainData class and modify TerrainModule and LLClientView to use same. This passes a terrain info class around rather than passing a one dimensional array thus allowing variable regions. Update the database storage for variable region sizes. This should be downward compatible (same format for 256x256 regions).
parent
25ae59b9eb
commit
7416809077
|
@ -49,6 +49,7 @@ namespace OpenSim.Data.MSSQL
|
||||||
|
|
||||||
// private static FileSystemDataStore Instance = new FileSystemDataStore();
|
// private static FileSystemDataStore Instance = new FileSystemDataStore();
|
||||||
private static readonly ILog _Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog _Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
private static string LogHeader = "[REGION DB MSSQL]";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The database manager
|
/// The database manager
|
||||||
|
@ -569,15 +570,19 @@ ELSE
|
||||||
return terrain;
|
return terrain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Legacy entry point for when terrain was always a 256x256 hieghtmap
|
||||||
|
public void StoreTerrain(double[,] ter, UUID regionID)
|
||||||
|
{
|
||||||
|
StoreTerrain(new HeightmapTerrainData(ter), regionID);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores the terrain map to DB.
|
/// Stores the terrain map to DB.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="terrain">terrain map data.</param>
|
/// <param name="terrain">terrain map data.</param>
|
||||||
/// <param name="regionID">regionID.</param>
|
/// <param name="regionID">regionID.</param>
|
||||||
public void StoreTerrain(double[,] terrain, UUID regionID)
|
public void StoreTerrain(TerrainData terrData, UUID regionID)
|
||||||
{
|
{
|
||||||
int revision = (int)DBTerrainRevision.Legacy256;
|
|
||||||
|
|
||||||
//Delete old terrain map
|
//Delete old terrain map
|
||||||
string sql = "delete from terrain where RegionUUID=@RegionUUID";
|
string sql = "delete from terrain where RegionUUID=@RegionUUID";
|
||||||
using (SqlConnection conn = new SqlConnection(m_connectionString))
|
using (SqlConnection conn = new SqlConnection(m_connectionString))
|
||||||
|
@ -590,17 +595,21 @@ ELSE
|
||||||
|
|
||||||
sql = "insert into terrain(RegionUUID, Revision, Heightfield) values(@RegionUUID, @Revision, @Heightfield)";
|
sql = "insert into terrain(RegionUUID, Revision, Heightfield) values(@RegionUUID, @Revision, @Heightfield)";
|
||||||
|
|
||||||
|
int terrainDBRevision;
|
||||||
|
Array terrainDBblob;
|
||||||
|
terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
|
||||||
|
|
||||||
using (SqlConnection conn = new SqlConnection(m_connectionString))
|
using (SqlConnection conn = new SqlConnection(m_connectionString))
|
||||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||||
{
|
{
|
||||||
cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
|
cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
|
||||||
cmd.Parameters.Add(_Database.CreateParameter("@Revision", revision));
|
cmd.Parameters.Add(_Database.CreateParameter("@Revision", terrainDBRevision));
|
||||||
cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", serializeTerrain(terrain)));
|
cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", terrainDBblob));
|
||||||
conn.Open();
|
conn.Open();
|
||||||
cmd.ExecuteNonQuery();
|
cmd.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
_Log.Info("[REGION DB]: Stored terrain revision r " + revision);
|
_Log.InfoFormat("{0} Stored terrain revision r={1}", LogHeader, terrainDBRevision);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1344,30 +1353,6 @@ VALUES
|
||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Serializes the terrain data for storage in DB.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="val">terrain data</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static Array serializeTerrain(double[,] val)
|
|
||||||
{
|
|
||||||
MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) * sizeof(double));
|
|
||||||
BinaryWriter bw = new BinaryWriter(str);
|
|
||||||
|
|
||||||
// TODO: COMPATIBILITY - Add byte-order conversions
|
|
||||||
for (int x = 0; x < (int)Constants.RegionSize; x++)
|
|
||||||
for (int y = 0; y < (int)Constants.RegionSize; y++)
|
|
||||||
{
|
|
||||||
double height = val[x, y];
|
|
||||||
if (height == 0.0)
|
|
||||||
height = double.Epsilon;
|
|
||||||
|
|
||||||
bw.Write(height);
|
|
||||||
}
|
|
||||||
|
|
||||||
return str.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores new regionsettings.
|
/// Stores new regionsettings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -48,6 +48,7 @@ namespace OpenSim.Data.MySQL
|
||||||
public class MySQLSimulationData : ISimulationDataStore
|
public class MySQLSimulationData : ISimulationDataStore
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
private static string LogHeader = "[REGION DB MYSQL]";
|
||||||
|
|
||||||
private string m_connectionString;
|
private string m_connectionString;
|
||||||
private object m_dbLock = new object();
|
private object m_dbLock = new object();
|
||||||
|
@ -91,7 +92,7 @@ namespace OpenSim.Data.MySQL
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
m_log.Error("[REGION DB]: MySQL error in ExecuteReader: " + e.Message);
|
m_log.ErrorFormat("{0} MySQL error in ExecuteReader: {1}", LogHeader, e);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,11 +573,14 @@ namespace OpenSim.Data.MySQL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Legacy entry point for when terrain was always a 256x256 hieghtmap
|
||||||
public void StoreTerrain(double[,] ter, UUID regionID)
|
public void StoreTerrain(double[,] ter, UUID regionID)
|
||||||
{
|
{
|
||||||
m_log.Info("[REGION DB]: Storing terrain");
|
StoreTerrain(new HeightmapTerrainData(ter), regionID);
|
||||||
int revision = (int)DBTerrainRevision.Legacy256;
|
}
|
||||||
|
|
||||||
|
public void StoreTerrain(TerrainData terrData, UUID regionID)
|
||||||
|
{
|
||||||
lock (m_dbLock)
|
lock (m_dbLock)
|
||||||
{
|
{
|
||||||
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||||
|
@ -590,11 +594,18 @@ namespace OpenSim.Data.MySQL
|
||||||
|
|
||||||
ExecuteNonQuery(cmd);
|
ExecuteNonQuery(cmd);
|
||||||
|
|
||||||
|
int terrainDBRevision;
|
||||||
|
Array terrainDBblob;
|
||||||
|
terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
|
||||||
|
|
||||||
|
m_log.InfoFormat("{0} Storing terrain. X={1}, Y={2}, rev={3}",
|
||||||
|
LogHeader, terrData.SizeX, terrData.SizeY, terrainDBRevision);
|
||||||
|
|
||||||
cmd.CommandText = "insert into terrain (RegionUUID, Revision, Heightfield)"
|
cmd.CommandText = "insert into terrain (RegionUUID, Revision, Heightfield)"
|
||||||
+ "values (?RegionUUID, ?Revision, ?Heightfield)";
|
+ "values (?RegionUUID, ?Revision, ?Heightfield)";
|
||||||
|
|
||||||
cmd.Parameters.AddWithValue("Revision", revision);
|
cmd.Parameters.AddWithValue("Revision", terrainDBRevision);
|
||||||
cmd.Parameters.AddWithValue("Heightfield", SerializeTerrain(ter));
|
cmd.Parameters.AddWithValue("Heightfield", terrainDBblob);
|
||||||
|
|
||||||
ExecuteNonQuery(cmd);
|
ExecuteNonQuery(cmd);
|
||||||
}
|
}
|
||||||
|
@ -1525,30 +1536,6 @@ namespace OpenSim.Data.MySQL
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="val"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static Array SerializeTerrain(double[,] val)
|
|
||||||
{
|
|
||||||
MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) *sizeof (double));
|
|
||||||
BinaryWriter bw = new BinaryWriter(str);
|
|
||||||
|
|
||||||
// TODO: COMPATIBILITY - Add byte-order conversions
|
|
||||||
for (int x = 0; x < (int)Constants.RegionSize; x++)
|
|
||||||
for (int y = 0; y < (int)Constants.RegionSize; y++)
|
|
||||||
{
|
|
||||||
double height = val[x, y];
|
|
||||||
if (height == 0.0)
|
|
||||||
height = double.Epsilon;
|
|
||||||
|
|
||||||
bw.Write(height);
|
|
||||||
}
|
|
||||||
|
|
||||||
return str.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fill the prim command with prim values
|
/// Fill the prim command with prim values
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -51,6 +51,7 @@ namespace OpenSim.Data.SQLite
|
||||||
public class SQLiteSimulationData : ISimulationDataStore
|
public class SQLiteSimulationData : ISimulationDataStore
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
private static readonly string LogHeader = "[REGION DB SQLLITE]";
|
||||||
|
|
||||||
private const string primSelect = "select * from prims";
|
private const string primSelect = "select * from prims";
|
||||||
private const string shapeSelect = "select * from primshapes";
|
private const string shapeSelect = "select * from primshapes";
|
||||||
|
@ -819,17 +820,21 @@ namespace OpenSim.Data.SQLite
|
||||||
prim.Inventory.RestoreInventoryItems(inventory);
|
prim.Inventory.RestoreInventoryItems(inventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Legacy entry point for when terrain was always a 256x256 hieghtmap
|
||||||
|
public void StoreTerrain(double[,] ter, UUID regionID)
|
||||||
|
{
|
||||||
|
StoreTerrain(new HeightmapTerrainData(ter), regionID);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Store a terrain revision in region storage
|
/// Store a terrain revision in region storage
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ter">terrain heightfield</param>
|
/// <param name="ter">terrain heightfield</param>
|
||||||
/// <param name="regionID">region UUID</param>
|
/// <param name="regionID">region UUID</param>
|
||||||
public void StoreTerrain(double[,] ter, UUID regionID)
|
public void StoreTerrain(TerrainData terrData, UUID regionID)
|
||||||
{
|
{
|
||||||
lock (ds)
|
lock (ds)
|
||||||
{
|
{
|
||||||
int revision = (int)DBTerrainRevision.Legacy256;
|
|
||||||
|
|
||||||
using (
|
using (
|
||||||
SqliteCommand cmd = new SqliteCommand("delete from terrain where RegionUUID=:RegionUUID", m_conn))
|
SqliteCommand cmd = new SqliteCommand("delete from terrain where RegionUUID=:RegionUUID", m_conn))
|
||||||
{
|
{
|
||||||
|
@ -839,15 +844,20 @@ namespace OpenSim.Data.SQLite
|
||||||
|
|
||||||
// the following is an work around for .NET. The perf
|
// the following is an work around for .NET. The perf
|
||||||
// issues associated with it aren't as bad as you think.
|
// issues associated with it aren't as bad as you think.
|
||||||
m_log.Debug("[SQLITE REGION DB]: Storing terrain revision r" + revision.ToString());
|
|
||||||
String sql = "insert into terrain(RegionUUID, Revision, Heightfield)" +
|
String sql = "insert into terrain(RegionUUID, Revision, Heightfield)" +
|
||||||
" values(:RegionUUID, :Revision, :Heightfield)";
|
" values(:RegionUUID, :Revision, :Heightfield)";
|
||||||
|
|
||||||
|
int terrainDBRevision;
|
||||||
|
Array terrainDBblob;
|
||||||
|
terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
|
||||||
|
|
||||||
|
m_log.DebugFormat("{0} Storing terrain revision r {1}", LogHeader, terrainDBRevision);
|
||||||
|
|
||||||
using (SqliteCommand cmd = new SqliteCommand(sql, m_conn))
|
using (SqliteCommand cmd = new SqliteCommand(sql, m_conn))
|
||||||
{
|
{
|
||||||
cmd.Parameters.Add(new SqliteParameter(":RegionUUID", regionID.ToString()));
|
cmd.Parameters.Add(new SqliteParameter(":RegionUUID", regionID.ToString()));
|
||||||
cmd.Parameters.Add(new SqliteParameter(":Revision", revision));
|
cmd.Parameters.Add(new SqliteParameter(":Revision", terrainDBRevision));
|
||||||
cmd.Parameters.Add(new SqliteParameter(":Heightfield", serializeTerrain(ter)));
|
cmd.Parameters.Add(new SqliteParameter(":Heightfield", terrainDBblob));
|
||||||
cmd.ExecuteNonQuery();
|
cmd.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2006,24 +2016,6 @@ namespace OpenSim.Data.SQLite
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="val"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static Array serializeTerrain(double[,] val)
|
|
||||||
{
|
|
||||||
MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) * sizeof(double));
|
|
||||||
BinaryWriter bw = new BinaryWriter(str);
|
|
||||||
|
|
||||||
// TODO: COMPATIBILITY - Add byte-order conversions
|
|
||||||
for (int x = 0; x < (int)Constants.RegionSize; x++)
|
|
||||||
for (int y = 0; y < (int)Constants.RegionSize; y++)
|
|
||||||
bw.Write(val[x, y]);
|
|
||||||
|
|
||||||
return str.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
// private void fillTerrainRow(DataRow row, UUID regionUUID, int rev, double[,] val)
|
// private void fillTerrainRow(DataRow row, UUID regionUUID, int rev, double[,] val)
|
||||||
// {
|
// {
|
||||||
// row["RegionUUID"] = regionUUID;
|
// row["RegionUUID"] = regionUUID;
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace OpenSim.Framework
|
||||||
public const float TerrainCompression = 100.0f;
|
public const float TerrainCompression = 100.0f;
|
||||||
// Since terrain is stored in 16x16 heights, regions must be a multiple of this number and that is the minimum
|
// Since terrain is stored in 16x16 heights, regions must be a multiple of this number and that is the minimum
|
||||||
public const int MinRegionSize = 16;
|
public const int MinRegionSize = 16;
|
||||||
public const byte TerrainPatchSize = 16;
|
public const int TerrainPatchSize = 16;
|
||||||
|
|
||||||
public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f";
|
public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f";
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,19 @@ namespace OpenSim.Framework
|
||||||
// Someday terrain will have caves
|
// Someday terrain will have caves
|
||||||
public abstract float this[int x, int y, int z] { get; set; }
|
public abstract float this[int x, int y, int z] { get; set; }
|
||||||
|
|
||||||
|
public bool IsTainted { get; protected set; }
|
||||||
|
public abstract bool IsTaintedAt(int xx, int yy);
|
||||||
|
public abstract void ClearTaint();
|
||||||
|
|
||||||
// Return a representation of this terrain for storing as a blob in the database.
|
// Return a representation of this terrain for storing as a blob in the database.
|
||||||
// Returns 'true' to say blob was stored in the 'out' locations.
|
// Returns 'true' to say blob was stored in the 'out' locations.
|
||||||
public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob);
|
public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob);
|
||||||
|
|
||||||
|
// return a special compressed representation of the heightmap in shorts
|
||||||
|
public abstract short[] GetCompressedMap();
|
||||||
|
public abstract void SetCompressedMap(short[] cmap);
|
||||||
|
|
||||||
|
public abstract TerrainData Clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The terrain is stored as a blob in the database with a 'revision' field.
|
// The terrain is stored as a blob in the database with a 'revision' field.
|
||||||
|
@ -72,13 +82,23 @@ namespace OpenSim.Framework
|
||||||
// Version of terrain that is a heightmap.
|
// Version of terrain that is a heightmap.
|
||||||
// This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge
|
// This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge
|
||||||
// of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer.
|
// of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer.
|
||||||
|
// The heighmap is kept as an array of short integers. The integer values are converted to
|
||||||
|
// and from floats by TerrainCompressionFactor.
|
||||||
public class HeightmapTerrainData : TerrainData
|
public class HeightmapTerrainData : TerrainData
|
||||||
{
|
{
|
||||||
// TerrainData.this[x, y]
|
// TerrainData.this[x, y]
|
||||||
public override float this[int x, int y]
|
public override float this[int x, int y]
|
||||||
{
|
{
|
||||||
get { return m_heightmap[x * SizeX + y]; }
|
get { return FromCompressedHeight(m_heightmap[x, y]); }
|
||||||
set { m_heightmap[x * SizeX + y] = value; }
|
set {
|
||||||
|
short newVal = ToCompressedHeight(value);
|
||||||
|
if (m_heightmap[x, y] != newVal)
|
||||||
|
{
|
||||||
|
m_heightmap[x, y] = newVal;
|
||||||
|
m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TerrainData.this[x, y, z]
|
// TerrainData.this[x, y, z]
|
||||||
|
@ -88,6 +108,20 @@ namespace OpenSim.Framework
|
||||||
set { this[x, y] = value; }
|
set { this[x, y] = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TerrainData.ClearTaint
|
||||||
|
public override void ClearTaint()
|
||||||
|
{
|
||||||
|
IsTainted = false;
|
||||||
|
for (int ii = 0; ii < m_taint.GetLength(0); ii++)
|
||||||
|
for (int jj = 0; jj < m_taint.GetLength(1); jj++)
|
||||||
|
m_taint[ii, jj] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsTaintedAt(int xx, int yy)
|
||||||
|
{
|
||||||
|
return m_taint[xx / Constants.TerrainPatchSize, yy / Constants.TerrainPatchSize];
|
||||||
|
}
|
||||||
|
|
||||||
// TerrainData.GetDatabaseBlob
|
// TerrainData.GetDatabaseBlob
|
||||||
// The user wants something to store in the database.
|
// The user wants something to store in the database.
|
||||||
public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob)
|
public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob)
|
||||||
|
@ -96,7 +130,53 @@ namespace OpenSim.Framework
|
||||||
blob = LegacyTerrainSerialization();
|
blob = LegacyTerrainSerialization();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
private float[] m_heightmap;
|
|
||||||
|
public override short[] GetCompressedMap()
|
||||||
|
{
|
||||||
|
short[] newMap = new short[SizeX * SizeY];
|
||||||
|
|
||||||
|
int ind = 0;
|
||||||
|
for (int xx = 0; xx < SizeX; xx++)
|
||||||
|
for (int yy = 0; yy < SizeY; yy++)
|
||||||
|
newMap[ind++] = m_heightmap[xx, yy];
|
||||||
|
|
||||||
|
return newMap;
|
||||||
|
|
||||||
|
}
|
||||||
|
public override void SetCompressedMap(short[] cmap)
|
||||||
|
{
|
||||||
|
int ind = 0;
|
||||||
|
for (int xx = 0; xx < SizeX; xx++)
|
||||||
|
for (int yy = 0; yy < SizeY; yy++)
|
||||||
|
m_heightmap[xx, yy] = cmap[ind++];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TerrainData.Clone
|
||||||
|
public override TerrainData Clone()
|
||||||
|
{
|
||||||
|
HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ);
|
||||||
|
ret.m_heightmap = (short[,])this.m_heightmap.Clone();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================
|
||||||
|
|
||||||
|
private short[,] m_heightmap;
|
||||||
|
// Remember subregions of the heightmap that has changed.
|
||||||
|
private bool[,] m_taint;
|
||||||
|
|
||||||
|
// To save space (especially for large regions), keep the height as a short integer
|
||||||
|
// that is coded as the float height times the compression factor (usually '100'
|
||||||
|
// to make for two decimal points).
|
||||||
|
public static short ToCompressedHeight(double pHeight)
|
||||||
|
{
|
||||||
|
return (short)(pHeight * Constants.TerrainCompression);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float FromCompressedHeight(short pHeight)
|
||||||
|
{
|
||||||
|
return ((float)pHeight) / Constants.TerrainCompression;
|
||||||
|
}
|
||||||
|
|
||||||
// To keep with the legacy theme, this can be created with the way terrain
|
// To keep with the legacy theme, this can be created with the way terrain
|
||||||
// used to passed around as.
|
// used to passed around as.
|
||||||
|
@ -106,26 +186,37 @@ namespace OpenSim.Framework
|
||||||
SizeY = pTerrain.GetLength(1);
|
SizeY = pTerrain.GetLength(1);
|
||||||
SizeZ = (int)Constants.RegionHeight;
|
SizeZ = (int)Constants.RegionHeight;
|
||||||
|
|
||||||
int idx = 0;
|
m_heightmap = new short[SizeX, SizeY];
|
||||||
m_heightmap = new float[SizeX * SizeY];
|
|
||||||
for (int ii = 0; ii < SizeX; ii++)
|
for (int ii = 0; ii < SizeX; ii++)
|
||||||
{
|
{
|
||||||
for (int jj = 0; jj < SizeY; jj++)
|
for (int jj = 0; jj < SizeY; jj++)
|
||||||
{
|
{
|
||||||
m_heightmap[idx++] = (float)pTerrain[ii, jj];
|
m_heightmap[ii, jj] = ToCompressedHeight(pTerrain[ii, jj]);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
|
||||||
|
ClearTaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
public HeightmapTerrainData(float[] pHeightmap, int pX, int pY, int pZ)
|
// Create underlying structures but don't initialize the heightmap assuming the caller will immediately do that
|
||||||
|
public HeightmapTerrainData(int pX, int pY, int pZ)
|
||||||
{
|
{
|
||||||
m_heightmap = pHeightmap;
|
|
||||||
SizeX = pX;
|
SizeX = pX;
|
||||||
SizeY = pY;
|
SizeY = pY;
|
||||||
SizeZ = pZ;
|
SizeZ = pZ;
|
||||||
|
m_heightmap = new short[SizeX, SizeY];
|
||||||
|
m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
|
||||||
|
ClearTaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HeightmapTerrainData(short[] cmap, int pX, int pY, int pZ) : this(pX, pY, pZ)
|
||||||
|
{
|
||||||
|
SetCompressedMap(cmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Just create an array of doubles. Presumes the caller implicitly knows the size.
|
// Just create an array of doubles. Presumes the caller implicitly knows the size.
|
||||||
public Array LegacyTerrainSerialization()
|
public Array LegacyTerrainSerialization()
|
||||||
{
|
{
|
||||||
|
@ -135,12 +226,12 @@ namespace OpenSim.Framework
|
||||||
using (BinaryWriter bw = new BinaryWriter(str))
|
using (BinaryWriter bw = new BinaryWriter(str))
|
||||||
{
|
{
|
||||||
// TODO: COMPATIBILITY - Add byte-order conversions
|
// TODO: COMPATIBILITY - Add byte-order conversions
|
||||||
for (int ii = 0; ii < m_heightmap.Length; ii++)
|
for (int ii = 0; ii < SizeX; ii++)
|
||||||
|
for (int jj = 0; jj < SizeY; jj++)
|
||||||
{
|
{
|
||||||
double height = (double)m_heightmap[ii];
|
double height = this[ii, jj];
|
||||||
if (height == 0.0)
|
if (height == 0.0)
|
||||||
height = double.Epsilon;
|
height = double.Epsilon;
|
||||||
|
|
||||||
bw.Write(height);
|
bw.Write(height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,11 +34,13 @@ using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
|
||||||
using log4net;
|
using log4net;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenMetaverse.Packets;
|
using OpenMetaverse.Packets;
|
||||||
using OpenMetaverse.Messages.Linden;
|
using OpenMetaverse.Messages.Linden;
|
||||||
using OpenMetaverse.StructuredData;
|
using OpenMetaverse.StructuredData;
|
||||||
|
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Framework.Client;
|
using OpenSim.Framework.Client;
|
||||||
using OpenSim.Framework.Monitoring;
|
using OpenSim.Framework.Monitoring;
|
||||||
|
@ -48,7 +50,6 @@ using OpenSim.Services.Interfaces;
|
||||||
using Timer = System.Timers.Timer;
|
using Timer = System.Timers.Timer;
|
||||||
using AssetLandmark = OpenSim.Framework.AssetLandmark;
|
using AssetLandmark = OpenSim.Framework.AssetLandmark;
|
||||||
using RegionFlags = OpenMetaverse.RegionFlags;
|
using RegionFlags = OpenMetaverse.RegionFlags;
|
||||||
using Nini.Config;
|
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using PermissionMask = OpenSim.Framework.PermissionMask;
|
using PermissionMask = OpenSim.Framework.PermissionMask;
|
||||||
|
@ -307,6 +308,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
|
private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
|
||||||
|
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
private static string LogHeader = "[LLCLIENTVIEW]";
|
||||||
protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
|
protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -447,7 +449,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
// ~LLClientView()
|
// ~LLClientView()
|
||||||
// {
|
// {
|
||||||
// m_log.DebugFormat("[LLCLIENTVIEW]: Destructor called for {0}, circuit code {1}", Name, CircuitCode);
|
// m_log.DebugFormat("{0} Destructor called for {1}, circuit code {2}", LogHeader, Name, CircuitCode);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -513,9 +515,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
// there is some unidentified connection problem, not where we have issues due to deadlock
|
// there is some unidentified connection problem, not where we have issues due to deadlock
|
||||||
if (!IsActive && !force)
|
if (!IsActive && !force)
|
||||||
{
|
{
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat( "{0} Not attempting to close inactive client {1} in {2} since force flag is not set",
|
||||||
"[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set",
|
LogHeader, Name, m_scene.Name);
|
||||||
Name, m_scene.Name);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1162,10 +1163,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// <param name="o"></param>
|
/// <param name="o"></param>
|
||||||
private void DoSendLayerData(object o)
|
private void DoSendLayerData(object o)
|
||||||
{
|
{
|
||||||
float[] map = LLHeightFieldMoronize((float[])o);
|
float[] map = (float[])o;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Send LayerData in typerwriter pattern
|
||||||
//for (int y = 0; y < 16; y++)
|
//for (int y = 0; y < 16; y++)
|
||||||
//{
|
//{
|
||||||
// for (int x = 0; x < 16; x++)
|
// for (int x = 0; x < 16; x++)
|
||||||
|
@ -1230,7 +1232,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a specified patch to a client
|
/// Sends a terrain packet for the point specified.
|
||||||
|
/// This is a legacy call that has refarbed the terrain into a flat map of floats.
|
||||||
|
/// We just use the terrain from the region we know about.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="px">Patch coordinate (x) 0..15</param>
|
/// <param name="px">Patch coordinate (x) 0..15</param>
|
||||||
/// <param name="py">Patch coordinate (y) 0..15</param>
|
/// <param name="py">Patch coordinate (y) 0..15</param>
|
||||||
|
@ -1239,10 +1243,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int[] patches = new int[] { py * 16 + px };
|
// For unknown reasons, after this point, patch numbers are swapped X for y.
|
||||||
float[] heightmap = (map.Length == 65536) ? map : LLHeightFieldMoronize(map);
|
// That means, that for <patchNumX, patchNumY, the array location is computed as map[patchNumY * 16 + patchNumX].
|
||||||
|
// TODO: someday straighten the below implementation to keep the X row order for patch numbers.
|
||||||
LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
|
// Since this is passing only one patch, we just swap the patch numbers.
|
||||||
|
LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(m_scene.Heightmap.GetTerrainData(), px, py);
|
||||||
|
|
||||||
// When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience.
|
// When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience.
|
||||||
// To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain.
|
// To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain.
|
||||||
|
@ -1260,14 +1265,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
if (m_justEditedTerrain)
|
if (m_justEditedTerrain)
|
||||||
{
|
{
|
||||||
layerpack.Header.Reliable = false;
|
layerpack.Header.Reliable = false;
|
||||||
OutPacket(layerpack,
|
OutPacket(layerpack, ThrottleOutPacketType.Unknown );
|
||||||
ThrottleOutPacketType.Unknown );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
layerpack.Header.Reliable = true;
|
layerpack.Header.Reliable = true;
|
||||||
OutPacket(layerpack,
|
OutPacket(layerpack, ThrottleOutPacketType.Land);
|
||||||
ThrottleOutPacketType.Land);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -1276,38 +1279,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Munges heightfield into the LLUDP backed in restricted heightfield.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="map">float array in the base; Constants.RegionSize</param>
|
|
||||||
/// <returns>float array in the base 256</returns>
|
|
||||||
internal float[] LLHeightFieldMoronize(float[] map)
|
|
||||||
{
|
|
||||||
if (map.Length == 65536)
|
|
||||||
return map;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float[] returnmap = new float[65536];
|
|
||||||
|
|
||||||
if (map.Length < 65535)
|
|
||||||
{
|
|
||||||
// rebase the vector stride to 256
|
|
||||||
for (int i = 0; i < Constants.RegionSize; i++)
|
|
||||||
Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, (int)Constants.RegionSize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 256; i++)
|
|
||||||
Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Array.Copy(map,0,returnmap,0,(map.Length < 65536)? map.Length : 65536);
|
|
||||||
|
|
||||||
return returnmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send the wind matrix to the client
|
/// Send the wind matrix to the client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2780,8 +2751,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
if (req.AssetInf.Data == null)
|
if (req.AssetInf.Data == null)
|
||||||
{
|
{
|
||||||
m_log.ErrorFormat("Cannot send asset {0} ({1}), asset data is null",
|
m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset data is null",
|
||||||
req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
|
LogHeader, req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,14 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
using log4net;
|
using log4net;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
|
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using Mono.Addins;
|
using Mono.Addins;
|
||||||
|
|
||||||
|
using OpenSim.Data;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
|
using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
|
||||||
using OpenSim.Region.CoreModules.World.Terrain.FileLoaders;
|
using OpenSim.Region.CoreModules.World.Terrain.FileLoaders;
|
||||||
|
@ -130,8 +134,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||||
{
|
{
|
||||||
if (m_scene.Heightmap == null)
|
if (m_scene.Heightmap == null)
|
||||||
{
|
{
|
||||||
m_channel = new TerrainChannel(m_InitialTerrain,
|
m_channel = new TerrainChannel(m_InitialTerrain, (int)m_scene.RegionInfo.RegionSizeX,
|
||||||
m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY, m_scene.RegionInfo.RegionSizeZ);
|
(int)m_scene.RegionInfo.RegionSizeY,
|
||||||
|
(int)m_scene.RegionInfo.RegionSizeZ);
|
||||||
m_scene.Heightmap = m_channel;
|
m_scene.Heightmap = m_channel;
|
||||||
UpdateRevertMap();
|
UpdateRevertMap();
|
||||||
}
|
}
|
||||||
|
@ -707,7 +712,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||||
private void CheckForTerrainUpdates(bool respectEstateSettings)
|
private void CheckForTerrainUpdates(bool respectEstateSettings)
|
||||||
{
|
{
|
||||||
bool shouldTaint = false;
|
bool shouldTaint = false;
|
||||||
float[] serialised = m_channel.GetFloatsSerialised();
|
float[] terrData = m_channel.GetFloatsSerialised();
|
||||||
int x;
|
int x;
|
||||||
for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize)
|
for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize)
|
||||||
{
|
{
|
||||||
|
@ -716,16 +721,16 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||||
{
|
{
|
||||||
if (m_channel.Tainted(x, y))
|
if (m_channel.Tainted(x, y))
|
||||||
{
|
{
|
||||||
// if we should respect the estate settings then
|
// If we should respect the estate settings then
|
||||||
// fixup and height deltas that don't respect them
|
// fixup and height deltas that don't respect them.
|
||||||
|
// Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values.
|
||||||
if (respectEstateSettings && LimitChannelChanges(x, y))
|
if (respectEstateSettings && LimitChannelChanges(x, y))
|
||||||
{
|
{
|
||||||
// this has been vetoed, so update
|
// Terrain heights were modified. Refetch the terrain info.
|
||||||
// what we are going to send to the client
|
terrData = m_channel.GetFloatsSerialised();
|
||||||
serialised = m_channel.GetFloatsSerialised();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SendToClients(serialised, x, y);
|
SendToClients(terrData, x, y);
|
||||||
shouldTaint = true;
|
shouldTaint = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -794,13 +799,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||||
/// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param>
|
/// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param>
|
||||||
/// <param name="x">The patch corner to send</param>
|
/// <param name="x">The patch corner to send</param>
|
||||||
/// <param name="y">The patch corner to send</param>
|
/// <param name="y">The patch corner to send</param>
|
||||||
private void SendToClients(float[] serialised, int x, int y)
|
private void SendToClients(float[] heightMap, int x, int y)
|
||||||
{
|
{
|
||||||
m_scene.ForEachClient(
|
m_scene.ForEachClient(
|
||||||
delegate(IClientAPI controller)
|
delegate(IClientAPI controller)
|
||||||
{ controller.SendLayerData(
|
{ controller.SendLayerData( x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, heightMap); }
|
||||||
x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, serialised);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,24 +136,4 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The terrain is stored as a blob in the database with a 'revision' field.
|
|
||||||
// Some implementations of terrain storage would fill the revision field with
|
|
||||||
// the time the terrain was stored. When real revisions were added and this
|
|
||||||
// feature removed, that left some old entries with the time in the revision
|
|
||||||
// field.
|
|
||||||
// Thus, if revision is greater than 'RevisionHigh' then terrain db entry is
|
|
||||||
// left over and it is presumed to be 'Legacy256'.
|
|
||||||
// Numbers are arbitrary and are chosen to to reduce possible mis-interpretation.
|
|
||||||
// If a revision does not match any of these, it is assumed to be Legacy256.
|
|
||||||
public enum DBTerrainRevision
|
|
||||||
{
|
|
||||||
// Terrain is 'double[256,256]'
|
|
||||||
Legacy256 = 11,
|
|
||||||
// Terrain is 'int32, int32, float[,]' where the shorts are X and Y dimensions
|
|
||||||
// The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
|
|
||||||
Variable2D = 22,
|
|
||||||
// A revision that is not listed above or any revision greater than this value is 'Legacy256'.
|
|
||||||
RevisionHigh = 1234
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using OpenSim.Framework;
|
||||||
|
|
||||||
namespace OpenSim.Region.Framework.Interfaces
|
namespace OpenSim.Region.Framework.Interfaces
|
||||||
{
|
{
|
||||||
public interface ITerrainChannel
|
public interface ITerrainChannel
|
||||||
|
@ -35,18 +37,20 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||||
|
|
||||||
double this[int x, int y] { get; set; }
|
double this[int x, int y] { get; set; }
|
||||||
|
|
||||||
|
// Return the packaged terrain data for passing into lower levels of communication
|
||||||
|
TerrainData GetTerrainData();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Squash the entire heightmap into a single dimensioned array
|
/// Squash the entire heightmap into a single dimensioned array
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
float[] GetFloatsSerialised();
|
float[] GetFloatsSerialised();
|
||||||
// Get version of map as a single dimensioned array and each value compressed
|
|
||||||
// into an int (compressedHeight = (int)(floatHeight * Constants.TerrainCompression);)
|
|
||||||
// This is done to make the map smaller as it can get pretty larger for variable sized regions.
|
|
||||||
short[] GetCompressedMap();
|
|
||||||
|
|
||||||
double[,] GetDoubles();
|
double[,] GetDoubles();
|
||||||
|
|
||||||
|
// Check if a location has been updated. Clears the taint flag as a side effect.
|
||||||
bool Tainted(int x, int y);
|
bool Tainted(int x, int y);
|
||||||
|
|
||||||
ITerrainChannel MakeCopy();
|
ITerrainChannel MakeCopy();
|
||||||
string SaveToXmlString();
|
string SaveToXmlString();
|
||||||
void LoadFromXmlString(string data);
|
void LoadFromXmlString(string data);
|
||||||
|
|
|
@ -1905,7 +1905,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
|
m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
|
||||||
|
|
||||||
m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
|
m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
|
||||||
Heightmap = new TerrainChannel(m_InitialTerrain, RegionInfo.RegionSizeX, RegionInfo.RegionSizeY, RegionInfo.RegionSizeZ);
|
Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
|
||||||
|
|
||||||
SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
|
SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,18 @@
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
using OpenSim.Data;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
using System;
|
|
||||||
using System.Text;
|
using log4net;
|
||||||
using System.Xml;
|
|
||||||
using System.IO;
|
|
||||||
using System.Xml.Serialization;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.Framework.Scenes
|
namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
|
@ -40,18 +45,20 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TerrainChannel : ITerrainChannel
|
public class TerrainChannel : ITerrainChannel
|
||||||
{
|
{
|
||||||
protected bool[,] m_taint;
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
protected short[] m_map;
|
private static string LogHeader = "[TERRAIN CHANNEL]";
|
||||||
|
|
||||||
public int Width { get; private set; } // X dimension
|
protected TerrainData m_terrainData;
|
||||||
|
|
||||||
|
public int Width { get { return m_terrainData.SizeX; } } // X dimension
|
||||||
// Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y
|
// Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y
|
||||||
public int Height { get; private set; } // Y dimension
|
public int Height { get { return m_terrainData.SizeY; } } // Y dimension
|
||||||
public int Altitude { get; private set; } // Y dimension
|
public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension
|
||||||
|
|
||||||
// Default, not-often-used builder
|
// Default, not-often-used builder
|
||||||
public TerrainChannel()
|
public TerrainChannel()
|
||||||
{
|
{
|
||||||
InitializeStructures(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight, false);
|
m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
|
||||||
FlatLand();
|
FlatLand();
|
||||||
// PinHeadIsland();
|
// PinHeadIsland();
|
||||||
}
|
}
|
||||||
|
@ -59,27 +66,23 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// Create terrain of given size
|
// Create terrain of given size
|
||||||
public TerrainChannel(int pX, int pY)
|
public TerrainChannel(int pX, int pY)
|
||||||
{
|
{
|
||||||
InitializeStructures((uint)pX, (uint)pY, Constants.RegionHeight, true);
|
m_terrainData = new HeightmapTerrainData(pX, pY, (int)Constants.RegionHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create terrain of specified size and initialize with specified terrain.
|
// Create terrain of specified size and initialize with specified terrain.
|
||||||
// TODO: join this with the terrain initializers.
|
// TODO: join this with the terrain initializers.
|
||||||
public TerrainChannel(String type, uint pX, uint pY, uint pZ)
|
public TerrainChannel(String type, int pX, int pY, int pZ)
|
||||||
{
|
{
|
||||||
InitializeStructures(pX, pY, pZ, false);
|
m_terrainData = new HeightmapTerrainData(pX, pY, pZ);
|
||||||
if (type.Equals("flat"))
|
if (type.Equals("flat"))
|
||||||
FlatLand();
|
FlatLand();
|
||||||
else
|
else
|
||||||
PinHeadIsland();
|
PinHeadIsland();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TerrainChannel(double[,] pM, uint pH)
|
public TerrainChannel(double[,] pM, uint pAltitude)
|
||||||
{
|
{
|
||||||
InitializeStructures((uint)pM.GetLength(0), (uint)pM.GetLength(1), pH, false);
|
m_terrainData = new HeightmapTerrainData(pM);
|
||||||
int idx = 0;
|
|
||||||
for (int ii = 0; ii < Height; ii++)
|
|
||||||
for (int jj = 0; jj < Width; jj++)
|
|
||||||
m_map[idx++] = ToCompressedHeight(pM[ii, jj]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region ITerrainChannel Members
|
#region ITerrainChannel Members
|
||||||
|
@ -90,20 +93,23 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
return this.Copy();
|
return this.Copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ITerrainChannel.GetCompressedMap()
|
// ITerrainChannel.GetTerrainData()
|
||||||
public short[] GetCompressedMap()
|
public TerrainData GetTerrainData()
|
||||||
{
|
{
|
||||||
return m_map;
|
return m_terrainData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ITerrainChannel.GetFloatsSerialized()
|
// ITerrainChannel.GetFloatsSerialized()
|
||||||
|
// NOTICE that the one dimensional form is ordered by Y!!
|
||||||
public float[] GetFloatsSerialised()
|
public float[] GetFloatsSerialised()
|
||||||
{
|
{
|
||||||
int points = Width * Height;
|
int points = Width * Height;
|
||||||
float[] heights = new float[points];
|
float[] heights = new float[points];
|
||||||
|
|
||||||
for (int ii = 0; ii < points; ii++)
|
int idx = 0;
|
||||||
heights[ii] = FromCompressedHeight(m_map[ii]);
|
for (int ii = 0; ii < Height; ii++)
|
||||||
|
for (int jj = 0; jj < Width; jj++)
|
||||||
|
heights[idx++] = m_terrainData[jj, ii];
|
||||||
|
|
||||||
return heights;
|
return heights;
|
||||||
}
|
}
|
||||||
|
@ -116,11 +122,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
double[,] heights = new double[w, l];
|
double[,] heights = new double[w, l];
|
||||||
|
|
||||||
int idx = 0; // index into serialized array
|
int idx = 0; // index into serialized array
|
||||||
for (int ii = 0; ii < l; ii++)
|
for (int ii = 0; ii < w; ii++)
|
||||||
{
|
{
|
||||||
for (int jj = 0; jj < w; jj++)
|
for (int jj = 0; jj < l; jj++)
|
||||||
{
|
{
|
||||||
heights[ii, jj] = (double)FromCompressedHeight(m_map[idx]);
|
heights[ii, jj] = (double)m_terrainData[ii, jj];
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,31 +137,20 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// ITerrainChannel.this[x,y]
|
// ITerrainChannel.this[x,y]
|
||||||
public double this[int x, int y]
|
public double this[int x, int y]
|
||||||
{
|
{
|
||||||
get { return m_map[x * Width + y]; }
|
get { return (double)m_terrainData[x, y]; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
// Will "fix" terrain hole problems. Although not fantastically.
|
|
||||||
if (Double.IsNaN(value) || Double.IsInfinity(value))
|
if (Double.IsNaN(value) || Double.IsInfinity(value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int idx = x * Width + y;
|
m_terrainData[x, y] = (float)value;
|
||||||
if (m_map[idx] != value)
|
|
||||||
{
|
|
||||||
m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true;
|
|
||||||
m_map[idx] = ToCompressedHeight(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ITerrainChannel.Tainted()
|
// ITerrainChannel.Tainted()
|
||||||
public bool Tainted(int x, int y)
|
public bool Tainted(int x, int y)
|
||||||
{
|
{
|
||||||
if (m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize])
|
return m_terrainData.IsTaintedAt(x, y);
|
||||||
{
|
|
||||||
m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ITerrainChannel.SaveToXmlString()
|
// ITerrainChannel.SaveToXmlString()
|
||||||
|
@ -188,49 +183,25 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private void InitializeStructures(uint pX, uint pY, uint pZ, bool shouldInitializeHeightmap)
|
/*
|
||||||
{
|
|
||||||
Width = (int)pX;
|
|
||||||
Height = (int)pY;
|
|
||||||
Altitude = (int)pZ;
|
|
||||||
m_map = new short[Width * Height];
|
|
||||||
m_taint = new bool[Width / Constants.TerrainPatchSize, Height / Constants.TerrainPatchSize];
|
|
||||||
ClearTaint();
|
|
||||||
if (shouldInitializeHeightmap)
|
|
||||||
{
|
|
||||||
FlatLand();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearTaint()
|
|
||||||
{
|
|
||||||
for (int ii = 0; ii < Width / Constants.TerrainPatchSize; ii++)
|
|
||||||
for (int jj = 0; jj < Height / Constants.TerrainPatchSize; jj++)
|
|
||||||
m_taint[ii, jj] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// To save space (especially for large regions), keep the height as a short integer
|
// To save space (especially for large regions), keep the height as a short integer
|
||||||
// that is coded as the float height times the compression factor (usually '100'
|
// that is coded as the float height times the compression factor (usually '100'
|
||||||
// to make for two decimal points).
|
// to make for two decimal points).
|
||||||
public short ToCompressedHeight(double pHeight)
|
public static short ToCompressedHeight(double pHeight)
|
||||||
{
|
{
|
||||||
return (short)(pHeight * Constants.TerrainCompression);
|
return (short)(pHeight * Constants.TerrainCompression);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float FromCompressedHeight(short pHeight)
|
public static float FromCompressedHeight(short pHeight)
|
||||||
{
|
{
|
||||||
return ((float)pHeight) / Constants.TerrainCompression;
|
return ((float)pHeight) / Constants.TerrainCompression;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public TerrainChannel Copy()
|
public TerrainChannel Copy()
|
||||||
{
|
{
|
||||||
TerrainChannel copy = new TerrainChannel();
|
TerrainChannel copy = new TerrainChannel();
|
||||||
copy.m_map = (short[])m_map.Clone();
|
copy.m_terrainData = m_terrainData.Clone();
|
||||||
copy.m_taint = (bool[,])m_taint.Clone();
|
|
||||||
copy.Width = Width;
|
|
||||||
copy.Height = Height;
|
|
||||||
copy.Altitude = Altitude;
|
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +260,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
|
byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
|
m_terrainData = new HeightmapTerrainData(Width, Height, Altitude);
|
||||||
|
|
||||||
for (int y = 0; y < Height; y++)
|
for (int y = 0; y < Height; y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < Width; x++)
|
for (int x = 0; x < Width; x++)
|
||||||
|
@ -321,7 +294,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// New terrain serialization format that includes the width and length.
|
// New terrain serialization format that includes the width and length.
|
||||||
private void ToXml2(XmlWriter xmlWriter)
|
private void ToXml2(XmlWriter xmlWriter)
|
||||||
{
|
{
|
||||||
TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_map);
|
TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_terrainData.GetCompressedMap());
|
||||||
XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
|
XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
|
||||||
serializer.Serialize(xmlWriter, package);
|
serializer.Serialize(xmlWriter, package);
|
||||||
}
|
}
|
||||||
|
@ -331,38 +304,32 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
|
XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
|
||||||
TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader);
|
TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader);
|
||||||
Width = package.SizeX;
|
m_terrainData = new HeightmapTerrainData(package.Map, package.SizeX, package.SizeY, package.SizeZ);
|
||||||
Height = package.SizeY;
|
|
||||||
Altitude = package.SizeZ;
|
|
||||||
m_map = package.Map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill the heightmap with the center bump terrain
|
// Fill the heightmap with the center bump terrain
|
||||||
private void PinHeadIsland()
|
private void PinHeadIsland()
|
||||||
{
|
{
|
||||||
int x;
|
for (int x = 0; x < Width; x++)
|
||||||
for (x = 0; x < Width; x++)
|
|
||||||
{
|
{
|
||||||
int y;
|
for (int y = 0; y < Height; y++)
|
||||||
for (y = 0; y < Height; y++)
|
|
||||||
{
|
{
|
||||||
int idx = x * (int)Width + y;
|
m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10;
|
||||||
m_map[idx] = ToCompressedHeight(TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10);
|
float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d);
|
||||||
short spherFacA = ToCompressedHeight(TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01);
|
float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d);
|
||||||
short spherFacB = ToCompressedHeight(TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001);
|
if (m_terrainData[x, y]< spherFacA)
|
||||||
if (m_map[idx] < spherFacA)
|
m_terrainData[x, y]= spherFacA;
|
||||||
m_map[idx] = spherFacA;
|
if (m_terrainData[x, y]< spherFacB)
|
||||||
if (m_map[idx] < spherFacB)
|
m_terrainData[x, y] = spherFacB;
|
||||||
m_map[idx] = spherFacB;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FlatLand()
|
private void FlatLand()
|
||||||
{
|
{
|
||||||
short flatHeight = ToCompressedHeight(21);
|
for (int xx = 0; xx < Width; xx++)
|
||||||
for (int ii = 0; ii < m_map.Length; ii++)
|
for (int yy = 0; yy < Height; yy++)
|
||||||
m_map[ii] = flatHeight;
|
m_terrainData[xx, yy] = 21;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,22 +113,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
// routines (like IClientAPI) only pass the float array of heights around. This entry
|
// routines (like IClientAPI) only pass the float array of heights around. This entry
|
||||||
// converts that legacy representation into the more compact represenation used in
|
// converts that legacy representation into the more compact represenation used in
|
||||||
// TerrainChannel. Someday fix the plumbing between here and the scene.
|
// TerrainChannel. Someday fix the plumbing between here and the scene.
|
||||||
public static LayerDataPacket CreateLandPacket(float[] heightmap, int patchX, int patchY, uint sizeX, uint sizeY)
|
public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY)
|
||||||
{
|
{
|
||||||
int[] xPieces = new int[1];
|
int[] xPieces = new int[1];
|
||||||
int[] yPieces = new int[1];
|
int[] yPieces = new int[1];
|
||||||
|
|
||||||
short[] newmap = new short[heightmap.Length];
|
|
||||||
for (int ii = 0; ii < heightmap.Length; ii++)
|
|
||||||
newmap[ii] = TerrainChannel.ToCompressedHeight(heightmap[ii]);
|
|
||||||
|
|
||||||
xPieces[0] = patchX; // patch X dimension
|
xPieces[0] = patchX; // patch X dimension
|
||||||
yPieces[0] = patchY;
|
yPieces[0] = patchY;
|
||||||
|
|
||||||
m_log.DebugFormat("{0} CreateLandPacket. patchX={1}, patchY={2}, sizeX={3}, sizeY={4}",
|
m_log.DebugFormat("{0} CreateLandPacket. patchX={1}, patchY={2}, sizeX={3}, sizeY={4}",
|
||||||
LogHeader, patchX, patchY, sizeX, sizeY);
|
LogHeader, patchX, patchY, terrData.SizeX, terrData.SizeY);
|
||||||
|
|
||||||
return CreateLandPacket(newmap, xPieces, yPieces, (int)TerrainPatch.LayerType.Land, sizeX, sizeY);
|
return CreateLandPacket(terrData, xPieces, yPieces, (int)TerrainPatch.LayerType.Land);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -153,8 +148,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// <param name="pRegionSizeX"></param>
|
/// <param name="pRegionSizeX"></param>
|
||||||
/// <param name="pRegionSizeY"></param>
|
/// <param name="pRegionSizeY"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static LayerDataPacket CreateLandPacket(short[] heightmap, int[] x, int[] y, byte type,
|
public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type)
|
||||||
uint pRegionSizeX, uint pRegionSizeY)
|
|
||||||
{
|
{
|
||||||
LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
|
LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
|
||||||
|
|
||||||
|
@ -168,7 +162,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
bitpack.PackBits(type, 8);
|
bitpack.PackBits(type, 8);
|
||||||
|
|
||||||
for (int i = 0; i < x.Length; i++)
|
for (int i = 0; i < x.Length; i++)
|
||||||
CreatePatchFromHeightmap(bitpack, heightmap, x[i], y[i], pRegionSizeX, pRegionSizeY);
|
CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]);
|
||||||
|
|
||||||
bitpack.PackBits(END_OF_PATCHES, 8);
|
bitpack.PackBits(END_OF_PATCHES, 8);
|
||||||
|
|
||||||
|
@ -217,14 +211,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="pRegionSizeX"></param>
|
/// <param name="pRegionSizeX"></param>
|
||||||
/// <param name="pRegionSizeY"></param>
|
/// <param name="pRegionSizeY"></param>
|
||||||
public static void CreatePatchFromHeightmap(BitPack output, short[] heightmap, int patchX, int patchY,
|
public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY)
|
||||||
uint pRegionSizeX, uint pRegionSizeY)
|
|
||||||
{
|
{
|
||||||
TerrainPatch.Header header = PrescanPatch(heightmap, patchX, patchY, pRegionSizeX, pRegionSizeY);
|
TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY);
|
||||||
header.QuantWBits = 136;
|
header.QuantWBits = 136;
|
||||||
|
|
||||||
// If larger than legacy region size, pack patch X and Y info differently.
|
// If larger than legacy region size, pack patch X and Y info differently.
|
||||||
if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
|
if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
|
||||||
{
|
{
|
||||||
header.PatchIDs = (patchY & 0xFFFF);
|
header.PatchIDs = (patchY & 0xFFFF);
|
||||||
header.PatchIDs += (patchX << 16);
|
header.PatchIDs += (patchX << 16);
|
||||||
|
@ -237,8 +230,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
// NOTE: No idea what prequant and postquant should be or what they do
|
// NOTE: No idea what prequant and postquant should be or what they do
|
||||||
int wbits;
|
int wbits;
|
||||||
int[] patch = CompressPatch(heightmap, patchX, patchY, header, 10, pRegionSizeX, pRegionSizeY, out wbits);
|
int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits);
|
||||||
wbits = EncodePatchHeader(output, header, patch, pRegionSizeX, pRegionSizeY, wbits);
|
wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits);
|
||||||
EncodePatch(output, patch, 0, wbits);
|
EncodePatch(output, patch, 0, wbits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,19 +255,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan the height info we're returning and return a patch packet header for this patch.
|
// Scan the height info we're returning and return a patch packet header for this patch.
|
||||||
// TODO. Why are patches ordered Y,X rather than X,Y?
|
private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY)
|
||||||
private static TerrainPatch.Header PrescanPatch(short[] heightmap, int patchX, int patchY,
|
|
||||||
uint pRegionSizeX, uint pRegionSizeY)
|
|
||||||
{
|
{
|
||||||
TerrainPatch.Header header = new TerrainPatch.Header();
|
TerrainPatch.Header header = new TerrainPatch.Header();
|
||||||
short zmax = -32767;
|
float zmax = -99999999.0f;
|
||||||
short zmin = 32767;
|
float zmin = 99999999.0f;
|
||||||
|
|
||||||
for (int j = patchY*16; j < (patchY + 1)*16; j++)
|
for (int j = patchY*16; j < (patchY + 1)*16; j++)
|
||||||
{
|
{
|
||||||
for (int i = patchX*16; i < (patchX + 1)*16; i++)
|
for (int i = patchX*16; i < (patchX + 1)*16; i++)
|
||||||
{
|
{
|
||||||
short val = heightmap[j*pRegionSizeX + i];
|
// short val = heightmap[j*pRegionSizeX + i];
|
||||||
|
float val = terrData[j, i];
|
||||||
if (val > zmax) zmax = val;
|
if (val > zmax) zmax = val;
|
||||||
if (val < zmin) zmin = val;
|
if (val < zmin) zmin = val;
|
||||||
}
|
}
|
||||||
|
@ -282,8 +274,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
// Since the the min and max values are the shorts, rescale to be real values.
|
// Since the the min and max values are the shorts, rescale to be real values.
|
||||||
// TODO: all this logic should go into the class wrapping the short values.
|
// TODO: all this logic should go into the class wrapping the short values.
|
||||||
header.DCOffset = TerrainChannel.FromCompressedHeight(zmin);
|
header.DCOffset = zmin;
|
||||||
header.Range = (int)(TerrainChannel.FromCompressedHeight(zmax) - TerrainChannel.FromCompressedHeight(zmin) + 1.0f);
|
header.Range = (int)(zmax - zmin + 1.0f);
|
||||||
|
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
@ -812,8 +804,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
return itemp;
|
return itemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int[] CompressPatch(short[] heightmap, int patchX, int patchY, TerrainPatch.Header header,
|
private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header,
|
||||||
int prequant, uint pRegionSizeX, uint pRegionSizeY, out int wbits)
|
int prequant, out int wbits)
|
||||||
{
|
{
|
||||||
float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||||
int wordsize = prequant;
|
int wordsize = prequant;
|
||||||
|
@ -827,19 +819,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
int k = 0;
|
int k = 0;
|
||||||
|
|
||||||
premult /= Constants.TerrainCompression; // put here short to float factor
|
|
||||||
|
|
||||||
int jPatchLimit = patchY;
|
int jPatchLimit = patchY;
|
||||||
if (patchY >= (pRegionSizeY / Constants.TerrainPatchSize))
|
if (patchY >= (terrData.SizeY / Constants.TerrainPatchSize))
|
||||||
{
|
{
|
||||||
jPatchLimit = (int)(pRegionSizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize;
|
jPatchLimit = (int)(terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize;
|
||||||
}
|
}
|
||||||
jPatchLimit = (jPatchLimit + 1) * Constants.TerrainPatchSize;
|
jPatchLimit = (jPatchLimit + 1) * Constants.TerrainPatchSize;
|
||||||
|
|
||||||
int iPatchLimit = patchX;
|
int iPatchLimit = patchX;
|
||||||
if (patchX >= (pRegionSizeX / Constants.TerrainPatchSize))
|
if (patchX >= (terrData.SizeX / Constants.TerrainPatchSize))
|
||||||
{
|
{
|
||||||
iPatchLimit = (int)(pRegionSizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize;
|
iPatchLimit = (int)(terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize;
|
||||||
}
|
}
|
||||||
iPatchLimit = (iPatchLimit + 1) * Constants.TerrainPatchSize;
|
iPatchLimit = (iPatchLimit + 1) * Constants.TerrainPatchSize;
|
||||||
|
|
||||||
|
@ -847,7 +837,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
for (int i = patchX * Constants.TerrainPatchSize; i < iPatchLimit; i++)
|
for (int i = patchX * Constants.TerrainPatchSize; i < iPatchLimit; i++)
|
||||||
{
|
{
|
||||||
block[k++] = (heightmap[j*pRegionSizeX + i])*premult - sub;
|
// block[k++] = (heightmap[j*pRegionSizeX + i])*premult - sub;
|
||||||
|
block[k++] = terrData[j, i] - sub;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -246,8 +246,8 @@ namespace OpenSim.Services.Interfaces
|
||||||
public GridRegion(RegionInfo ConvertFrom)
|
public GridRegion(RegionInfo ConvertFrom)
|
||||||
{
|
{
|
||||||
m_regionName = ConvertFrom.RegionName;
|
m_regionName = ConvertFrom.RegionName;
|
||||||
m_regionLocX = (int)(ConvertFrom.LegacyRegionLocX * Constants.RegionSize);
|
m_regionLocX = (int)(ConvertFrom.RegionWorldLocX);
|
||||||
m_regionLocY = (int)(ConvertFrom.LegacyRegionLocY * Constants.RegionSize);
|
m_regionLocY = (int)(ConvertFrom.RegionWorldLocY);
|
||||||
m_internalEndPoint = ConvertFrom.InternalEndPoint;
|
m_internalEndPoint = ConvertFrom.InternalEndPoint;
|
||||||
m_externalHostName = ConvertFrom.ExternalHostName;
|
m_externalHostName = ConvertFrom.ExternalHostName;
|
||||||
m_httpPort = ConvertFrom.HttpPort;
|
m_httpPort = ConvertFrom.HttpPort;
|
||||||
|
|
Loading…
Reference in New Issue