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
OpenSim
Data
Framework
Region
ClientStack/Linden/UDP
CoreModules/World/Terrain
Framework
Services/Interfaces
|
@ -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