mirror of
https://github.com/opensim/opensim.git
synced 2026-08-11 20:05:33 +08:00
Merge branch 'mbworkvar2' into ubitvar
This commit is contained in:
@@ -2221,14 +2221,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
itemID = UUID.Zero;
|
||||
if (grp != null)
|
||||
{
|
||||
Vector3 inventoryStoredPosition = new Vector3
|
||||
(((grp.AbsolutePosition.X > (int)Constants.RegionSize)
|
||||
? 250
|
||||
: grp.AbsolutePosition.X)
|
||||
,
|
||||
(grp.AbsolutePosition.X > (int)Constants.RegionSize)
|
||||
? 250
|
||||
: grp.AbsolutePosition.X,
|
||||
Vector3 inventoryStoredPosition = new Vector3(
|
||||
Math.Min(grp.AbsolutePosition.X, RegionInfo.RegionSizeX - 6),
|
||||
Math.Min(grp.AbsolutePosition.Y, RegionInfo.RegionSizeY - 6),
|
||||
grp.AbsolutePosition.Z);
|
||||
|
||||
Vector3 originalPosition = grp.AbsolutePosition;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyrightD
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
@@ -103,7 +103,29 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// <summary>
|
||||
/// If false then physical objects are disabled, though collisions will continue as normal.
|
||||
/// </summary>
|
||||
public bool PhysicsEnabled { get; set; }
|
||||
public bool PhysicsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_physicsEnabled;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
m_physicsEnabled = value;
|
||||
|
||||
if (PhysicsScene != null)
|
||||
{
|
||||
IPhysicsParameters physScene = PhysicsScene as IPhysicsParameters;
|
||||
|
||||
if (physScene != null)
|
||||
physScene.SetPhysicsParameter(
|
||||
"Active", m_physicsEnabled.ToString(), PhysParameterEntry.APPLY_TO_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool m_physicsEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// If false then scripts are not enabled on the smiulator
|
||||
@@ -160,11 +182,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// </summary>
|
||||
public SimStatsReporter StatsReporter { get; private set; }
|
||||
|
||||
public List<Border> NorthBorders = new List<Border>();
|
||||
public List<Border> EastBorders = new List<Border>();
|
||||
public List<Border> SouthBorders = new List<Border>();
|
||||
public List<Border> WestBorders = new List<Border>();
|
||||
|
||||
/// <summary>
|
||||
/// Controls whether physics can be applied to prims. Even if false, prims still have entries in a
|
||||
/// PhysicsScene in order to perform collision detection
|
||||
@@ -204,15 +221,16 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// </summary>
|
||||
public int m_linksetCapacity = 0;
|
||||
|
||||
public bool m_clampPrimSize;
|
||||
public bool m_trustBinaries;
|
||||
public bool m_allowScriptCrossings = true;
|
||||
|
||||
/// <summary>
|
||||
/// Max prims an Physical object will hold
|
||||
/// </summary>
|
||||
///
|
||||
public int m_linksetPhysCapacity = 0;
|
||||
|
||||
public bool m_clampPrimSize;
|
||||
public bool m_trustBinaries;
|
||||
public bool m_allowScriptCrossings;
|
||||
public bool m_useFlySlow;
|
||||
public bool m_useTrashOnDelete = true;
|
||||
|
||||
@@ -364,7 +382,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
// TODO: Possibly stop other classes being able to manipulate this directly.
|
||||
private SceneGraph m_sceneGraph;
|
||||
private volatile int m_bordersLocked;
|
||||
private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
|
||||
private volatile bool m_backingup;
|
||||
private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
|
||||
@@ -446,18 +463,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
set { m_splitRegionID = value; }
|
||||
}
|
||||
|
||||
public bool BordersLocked
|
||||
{
|
||||
get { return m_bordersLocked == 1; }
|
||||
set
|
||||
{
|
||||
if (value == true)
|
||||
m_bordersLocked = 1;
|
||||
else
|
||||
m_bordersLocked = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public new float TimeDilation
|
||||
{
|
||||
get { return m_sceneGraph.PhysicsScene.TimeDilation; }
|
||||
@@ -1075,28 +1080,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
PeriodicBackup = true;
|
||||
UseBackup = true;
|
||||
|
||||
BordersLocked = true;
|
||||
Border northBorder = new Border();
|
||||
northBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, RegionInfo.RegionSizeY); //<---
|
||||
northBorder.CrossDirection = Cardinals.N;
|
||||
NorthBorders.Add(northBorder);
|
||||
|
||||
Border southBorder = new Border();
|
||||
southBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,0); //--->
|
||||
southBorder.CrossDirection = Cardinals.S;
|
||||
SouthBorders.Add(southBorder);
|
||||
|
||||
Border eastBorder = new Border();
|
||||
eastBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, RegionInfo.RegionSizeX); //<---
|
||||
eastBorder.CrossDirection = Cardinals.E;
|
||||
EastBorders.Add(eastBorder);
|
||||
|
||||
Border westBorder = new Border();
|
||||
westBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,0); //--->
|
||||
westBorder.CrossDirection = Cardinals.W;
|
||||
WestBorders.Add(westBorder);
|
||||
BordersLocked = false;
|
||||
|
||||
m_eventManager = new EventManager();
|
||||
|
||||
m_permissions = new ScenePermissions(this);
|
||||
@@ -1975,7 +1958,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
try
|
||||
{
|
||||
double[,] map = SimulationDataService.LoadTerrain(RegionInfo.RegionID);
|
||||
TerrainData map = SimulationDataService.LoadTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
|
||||
if (map == null)
|
||||
{
|
||||
// This should be in the Terrain module, but it isn't because
|
||||
@@ -1986,7 +1969,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
|
||||
|
||||
m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
|
||||
Heightmap = new TerrainChannel(m_InitialTerrain);
|
||||
Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
|
||||
|
||||
SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
|
||||
}
|
||||
@@ -2611,185 +2594,35 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
EntityTransferModule.Cross(grp, attemptedPosition, silent);
|
||||
}
|
||||
|
||||
public Border GetCrossedBorder(Vector3 position, Cardinals gridline)
|
||||
// Simple test to see if a position is in the current region.
|
||||
// This test is mostly used to see if a region crossing is necessary.
|
||||
// Assuming the position is relative to the region so anything outside its bounds.
|
||||
// Return 'true' if position inside region.
|
||||
public bool PositionIsInCurrentRegion(Vector3 pos)
|
||||
{
|
||||
if (BordersLocked)
|
||||
bool ret = false;
|
||||
int xx = (int)Math.Floor(pos.X);
|
||||
int yy = (int)Math.Floor(pos.Y);
|
||||
if (xx < 0 || yy < 0)
|
||||
return false;
|
||||
|
||||
IRegionCombinerModule regionCombinerModule = RequestModuleInterface<IRegionCombinerModule>();
|
||||
if (regionCombinerModule == null)
|
||||
{
|
||||
switch (gridline)
|
||||
{
|
||||
case Cardinals.N:
|
||||
lock (NorthBorders)
|
||||
{
|
||||
foreach (Border b in NorthBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return b;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Cardinals.S:
|
||||
lock (SouthBorders)
|
||||
{
|
||||
foreach (Border b in SouthBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case Cardinals.E:
|
||||
lock (EastBorders)
|
||||
{
|
||||
foreach (Border b in EastBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case Cardinals.W:
|
||||
|
||||
lock (WestBorders)
|
||||
{
|
||||
foreach (Border b in WestBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return b;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
// Regular region. Just check for region size
|
||||
if (xx < RegionInfo.RegionSizeX && yy < RegionInfo.RegionSizeY )
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (gridline)
|
||||
{
|
||||
case Cardinals.N:
|
||||
foreach (Border b in NorthBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return b;
|
||||
}
|
||||
|
||||
break;
|
||||
case Cardinals.S:
|
||||
foreach (Border b in SouthBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return b;
|
||||
}
|
||||
break;
|
||||
case Cardinals.E:
|
||||
foreach (Border b in EastBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return b;
|
||||
}
|
||||
|
||||
break;
|
||||
case Cardinals.W:
|
||||
foreach (Border b in WestBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return b;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
// We're in a mega-region so see if we are still in that larger region
|
||||
ret = regionCombinerModule.PositionIsInMegaregion(this.RegionInfo.RegionID, xx, yy);
|
||||
}
|
||||
|
||||
return null;
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
public bool TestBorderCross(Vector3 position, Cardinals border)
|
||||
{
|
||||
if (BordersLocked)
|
||||
{
|
||||
switch (border)
|
||||
{
|
||||
case Cardinals.N:
|
||||
lock (NorthBorders)
|
||||
{
|
||||
foreach (Border b in NorthBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Cardinals.E:
|
||||
lock (EastBorders)
|
||||
{
|
||||
foreach (Border b in EastBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Cardinals.S:
|
||||
lock (SouthBorders)
|
||||
{
|
||||
foreach (Border b in SouthBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Cardinals.W:
|
||||
lock (WestBorders)
|
||||
{
|
||||
foreach (Border b in WestBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (border)
|
||||
{
|
||||
case Cardinals.N:
|
||||
foreach (Border b in NorthBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Cardinals.E:
|
||||
foreach (Border b in EastBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Cardinals.S:
|
||||
foreach (Border b in SouthBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Cardinals.W:
|
||||
foreach (Border b in WestBorders)
|
||||
{
|
||||
if (b.TestCross(position))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Called when objects or attachments cross the border, or teleport, between regions.
|
||||
/// </summary>
|
||||
@@ -4116,60 +3949,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
// CleanDroppedAttachments();
|
||||
|
||||
if (TestBorderCross(acd.startpos, Cardinals.E))
|
||||
{
|
||||
Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E);
|
||||
acd.startpos.X = crossedBorder.BorderLine.Z - 1;
|
||||
}
|
||||
|
||||
if (TestBorderCross(acd.startpos, Cardinals.N))
|
||||
{
|
||||
Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.N);
|
||||
acd.startpos.Y = crossedBorder.BorderLine.Z - 1;
|
||||
}
|
||||
|
||||
//Mitigate http://opensimulator.org/mantis/view.php?id=3522
|
||||
// Check if start position is outside of region
|
||||
// If it is, check the Z start position also.. if not, leave it alone.
|
||||
if (BordersLocked)
|
||||
{
|
||||
lock (EastBorders)
|
||||
{
|
||||
if (acd.startpos.X > EastBorders[0].BorderLine.Z)
|
||||
{
|
||||
m_log.Warn("FIX AGENT POSITION");
|
||||
acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
|
||||
if (acd.startpos.Z > 720)
|
||||
acd.startpos.Z = 720;
|
||||
}
|
||||
}
|
||||
lock (NorthBorders)
|
||||
{
|
||||
if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
|
||||
{
|
||||
m_log.Warn("FIX Agent POSITION");
|
||||
acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
|
||||
if (acd.startpos.Z > 720)
|
||||
acd.startpos.Z = 720;
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (acd.startpos.X > EastBorders[0].BorderLine.Z)
|
||||
{
|
||||
m_log.Warn("FIX AGENT POSITION");
|
||||
acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
|
||||
if (acd.startpos.Z > 720)
|
||||
acd.startpos.Z = 720;
|
||||
}
|
||||
if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
|
||||
{
|
||||
m_log.Warn("FIX Agent POSITION");
|
||||
acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
|
||||
if (acd.startpos.Z > 720)
|
||||
acd.startpos.Z = 720;
|
||||
}
|
||||
}
|
||||
// Make sure avatar position is in the region (why it wouldn't be is a mystery but do sanity checking)
|
||||
if (acd.startpos.X < 0) acd.startpos.X = 1f;
|
||||
if (acd.startpos.X >= RegionInfo.RegionSizeX) acd.startpos.X = RegionInfo.RegionSizeX - 1f;
|
||||
if (acd.startpos.Y < 0) acd.startpos.Y = 1f;
|
||||
if (acd.startpos.Y >= RegionInfo.RegionSizeY) acd.startpos.Y = RegionInfo.RegionSizeY - 1f;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}",
|
||||
@@ -4883,44 +4667,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
ScenePresence sp = GetScenePresence(remoteClient.AgentId);
|
||||
if (sp != null)
|
||||
{
|
||||
uint regionX = RegionInfo.RegionLocX;
|
||||
uint regionY = RegionInfo.RegionLocY;
|
||||
|
||||
Utils.LongToUInts(regionHandle, out regionX, out regionY);
|
||||
|
||||
int shiftx = (int) regionX - (int) RegionInfo.RegionLocX * (int)Constants.RegionSize;
|
||||
int shifty = (int) regionY - (int) RegionInfo.RegionLocY * (int)Constants.RegionSize;
|
||||
|
||||
position.X += shiftx;
|
||||
position.Y += shifty;
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (TestBorderCross(position,Cardinals.N))
|
||||
result = true;
|
||||
|
||||
if (TestBorderCross(position, Cardinals.S))
|
||||
result = true;
|
||||
|
||||
if (TestBorderCross(position, Cardinals.E))
|
||||
result = true;
|
||||
|
||||
if (TestBorderCross(position, Cardinals.W))
|
||||
result = true;
|
||||
|
||||
// bordercross if position is outside of region
|
||||
|
||||
if (!result)
|
||||
{
|
||||
regionHandle = RegionInfo.RegionHandle;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not in this region, undo the shift!
|
||||
position.X -= shiftx;
|
||||
position.Y -= shifty;
|
||||
}
|
||||
|
||||
if (EntityTransferModule != null)
|
||||
{
|
||||
EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags);
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
public class SceneCommunicationService //one instance per region
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static string LogHeader = "[SCENE COMMUNICATION SERVICE]";
|
||||
|
||||
protected RegionInfo m_regionInfo;
|
||||
protected Scene m_scene;
|
||||
@@ -100,7 +101,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[SCENE COMMUNICATION SERVICE]: Region {0} failed to inform neighbour at {1}-{2} that it is up.",
|
||||
m_scene.Name, x / Constants.RegionSize, y / Constants.RegionSize);
|
||||
m_scene.Name, Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +167,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
// we only want to send one update to each simulator; the simulator will
|
||||
// hand it off to the regions where a child agent exists, this does assume
|
||||
// that the region position is cached or performance will degrade
|
||||
Utils.LongToUInts(regionHandle, out x, out y);
|
||||
Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
|
||||
GridRegion dest = m_scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y);
|
||||
if (dest == null)
|
||||
continue;
|
||||
@@ -206,7 +207,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
//m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
|
||||
uint x = 0, y = 0;
|
||||
Utils.LongToUInts(regionHandle, out x, out y);
|
||||
Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
|
||||
|
||||
GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y);
|
||||
|
||||
@@ -226,6 +227,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
foreach (ulong handle in regionslst)
|
||||
{
|
||||
// We must take a copy here since handle acts like a reference when used in an iterator.
|
||||
// This leads to race conditions if directly passed to SendCloseChildAgent with more than one neighbour region.
|
||||
ulong handleCopy = handle;
|
||||
Util.FireAndForget((o) => { SendCloseChildAgent(agentID, handleCopy, auth_code); });
|
||||
}
|
||||
|
||||
@@ -412,7 +412,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
get
|
||||
{
|
||||
Vector3 minScale = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionSize);
|
||||
Vector3 minScale = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, Constants.MaximumRegionSize);
|
||||
Vector3 maxScale = Vector3.Zero;
|
||||
Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
|
||||
|
||||
@@ -529,12 +529,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
set
|
||||
{
|
||||
Vector3 val = value;
|
||||
if (Scene != null && !IsAttachmentCheckFull()
|
||||
&& !Scene.LoadingPrims &&
|
||||
(Scene.TestBorderCross(val, Cardinals.E) ||
|
||||
Scene.TestBorderCross(val, Cardinals.W) ||
|
||||
Scene.TestBorderCross(val, Cardinals.N) ||
|
||||
Scene.TestBorderCross(val, Cardinals.S))
|
||||
if (Scene != null
|
||||
&& Scene.PositionIsInCurrentRegion(val)
|
||||
&& !IsAttachmentCheckFull()
|
||||
&& !Scene.LoadingPrims
|
||||
)
|
||||
{
|
||||
if (!inTransit)
|
||||
|
||||
@@ -2979,10 +2979,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
Vector3 newpos = new Vector3(pa.Position.GetBytes(), 0);
|
||||
|
||||
if (ParentGroup.Scene.TestBorderCross(newpos, Cardinals.N)
|
||||
|| ParentGroup.Scene.TestBorderCross(newpos, Cardinals.S)
|
||||
|| ParentGroup.Scene.TestBorderCross(newpos, Cardinals.E)
|
||||
|| ParentGroup.Scene.TestBorderCross(newpos, Cardinals.W))
|
||||
if (!ParentGroup.Scene.PositionIsInCurrentRegion(newpos))
|
||||
{
|
||||
ParentGroup.AbsolutePosition = newpos;
|
||||
return;
|
||||
|
||||
@@ -842,9 +842,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
foreach (ulong handle in seeds.Keys)
|
||||
{
|
||||
uint x, y;
|
||||
Utils.LongToUInts(handle, out x, out y);
|
||||
x = x / Constants.RegionSize;
|
||||
y = y / Constants.RegionSize;
|
||||
Util.RegionHandleToRegionLoc(handle, out x, out y);
|
||||
|
||||
if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY))
|
||||
{
|
||||
old.Add(handle);
|
||||
@@ -866,9 +865,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
foreach (KeyValuePair<ulong, string> kvp in KnownRegions)
|
||||
{
|
||||
uint x, y;
|
||||
Utils.LongToUInts(kvp.Key, out x, out y);
|
||||
x = x / Constants.RegionSize;
|
||||
y = y / Constants.RegionSize;
|
||||
Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
|
||||
m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
|
||||
}
|
||||
}
|
||||
@@ -1170,18 +1167,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
if (ParentID == 0)
|
||||
{
|
||||
if (m_scene.TestBorderCross(pos, Cardinals.E))
|
||||
{
|
||||
Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E);
|
||||
pos.X = crossedBorder.BorderLine.Z - 1;
|
||||
}
|
||||
|
||||
if (m_scene.TestBorderCross(pos, Cardinals.N))
|
||||
{
|
||||
Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N);
|
||||
pos.Y = crossedBorder.BorderLine.Z - 1;
|
||||
}
|
||||
|
||||
CheckAndAdjustLandingPoint(ref pos);
|
||||
|
||||
if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
|
||||
@@ -1201,7 +1186,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
float posZLimit = 0;
|
||||
|
||||
if (pos.X < Constants.RegionSize && pos.Y < Constants.RegionSize)
|
||||
if (pos.X < m_scene.RegionInfo.RegionSizeX && pos.Y < m_scene.RegionInfo.RegionSizeY)
|
||||
posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y];
|
||||
|
||||
float newPosZ = posZLimit + localAVHeight / 2;
|
||||
@@ -2612,7 +2597,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if (regionCombinerModule != null)
|
||||
regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
|
||||
else
|
||||
regionSize = new Vector2(Constants.RegionSize);
|
||||
regionSize = new Vector2(m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY);
|
||||
|
||||
if (pos.X < 0 || pos.X >= regionSize.X
|
||||
|| pos.Y < 0 || pos.Y >= regionSize.Y
|
||||
@@ -2630,8 +2615,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
// }
|
||||
|
||||
// Get terrain height for sub-region in a megaregion if necessary
|
||||
int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X);
|
||||
int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y);
|
||||
int X = (int)((m_scene.RegionInfo.WorldLocX) + pos.X);
|
||||
int Y = (int)((m_scene.RegionInfo.WorldLocY) + pos.Y);
|
||||
GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y);
|
||||
// If X and Y is NaN, target_region will be null
|
||||
if (target_region == null)
|
||||
@@ -2642,7 +2627,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene))
|
||||
targetScene = m_scene;
|
||||
|
||||
float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % Constants.RegionSize), (int)(pos.Y % Constants.RegionSize)];
|
||||
float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % regionSize.X), (int)(pos.Y % regionSize.Y)];
|
||||
// dont try to land underground
|
||||
terrainHeight += Appearance.AvatarHeight / 2;
|
||||
pos.Z = Math.Max(terrainHeight, pos.Z);
|
||||
@@ -3872,32 +3857,28 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}",
|
||||
// pos2, Name, Scene.Name);
|
||||
|
||||
if( Scene.TestBorderCross(pos2, Cardinals.E) ||
|
||||
Scene.TestBorderCross(pos2, Cardinals.W) ||
|
||||
Scene.TestBorderCross(pos2, Cardinals.N) ||
|
||||
Scene.TestBorderCross(pos2, Cardinals.S)
|
||||
)
|
||||
|
||||
if (Scene.PositionIsInCurrentRegion(pos2))
|
||||
return;
|
||||
|
||||
if (!CrossToNewRegion() && m_requestedSitTargetUUID == UUID.Zero)
|
||||
{
|
||||
if (!CrossToNewRegion() && m_requestedSitTargetUUID == UUID.Zero)
|
||||
{
|
||||
// we don't have entity transfer module
|
||||
Vector3 pos = AbsolutePosition;
|
||||
float px = pos.X;
|
||||
if (px < 0)
|
||||
pos.X += Velocity.X * 2;
|
||||
else if (px > m_scene.RegionInfo.RegionSizeX)
|
||||
pos.X -= Velocity.X * 2;
|
||||
// we don't have entity transfer module
|
||||
Vector3 pos = AbsolutePosition;
|
||||
float px = pos.X;
|
||||
if (px < 0)
|
||||
pos.X += Velocity.X * 2;
|
||||
else if (px > m_scene.RegionInfo.RegionSizeX)
|
||||
pos.X -= Velocity.X * 2;
|
||||
|
||||
float py = pos.Y;
|
||||
if (py < 0)
|
||||
pos.Y += Velocity.Y * 2;
|
||||
else if (py > m_scene.RegionInfo.RegionSizeY)
|
||||
pos.Y -= Velocity.Y * 2;
|
||||
float py = pos.Y;
|
||||
if (py < 0)
|
||||
pos.Y += Velocity.Y * 2;
|
||||
else if (py > m_scene.RegionInfo.RegionSizeY)
|
||||
pos.Y -= Velocity.Y * 2;
|
||||
|
||||
Velocity = Vector3.Zero;
|
||||
AbsolutePosition = pos;
|
||||
}
|
||||
Velocity = Vector3.Zero;
|
||||
AbsolutePosition = pos;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3962,7 +3943,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
// Put the child agent back at the center
|
||||
AbsolutePosition
|
||||
= new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 70);
|
||||
= new Vector3(((float)m_scene.RegionInfo.RegionSizeX * 0.5f), ((float)m_scene.RegionInfo.RegionSizeY * 0.5f), 70);
|
||||
|
||||
Animator.ResetAnimations();
|
||||
}
|
||||
@@ -3989,9 +3970,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if (handle != Scene.RegionInfo.RegionHandle)
|
||||
{
|
||||
uint x, y;
|
||||
Utils.LongToUInts(handle, out x, out y);
|
||||
x = x / Constants.RegionSize;
|
||||
y = y / Constants.RegionSize;
|
||||
Util.RegionHandleToRegionLoc(handle, out x, out y);
|
||||
|
||||
// m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX)));
|
||||
// m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY)));
|
||||
|
||||
@@ -25,13 +25,20 @@
|
||||
* 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.Region.Framework.Interfaces;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using OpenMetaverse;
|
||||
|
||||
using log4net;
|
||||
|
||||
namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
@@ -40,140 +47,136 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// </summary>
|
||||
public class TerrainChannel : ITerrainChannel
|
||||
{
|
||||
private readonly bool[,] taint;
|
||||
private double[,] map;
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static string LogHeader = "[TERRAIN CHANNEL]";
|
||||
|
||||
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
|
||||
public int Height { get { return m_terrainData.SizeY; } } // Y dimension
|
||||
public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension
|
||||
|
||||
// Default, not-often-used builder
|
||||
public TerrainChannel()
|
||||
{
|
||||
map = new double[Constants.RegionSize, Constants.RegionSize];
|
||||
taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16];
|
||||
|
||||
PinHeadIsland();
|
||||
m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
|
||||
FlatLand();
|
||||
// PinHeadIsland();
|
||||
}
|
||||
|
||||
public TerrainChannel(String type)
|
||||
// Create terrain of given size
|
||||
public TerrainChannel(int pX, int pY)
|
||||
{
|
||||
map = new double[Constants.RegionSize, Constants.RegionSize];
|
||||
taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16];
|
||||
m_terrainData = new HeightmapTerrainData(pX, pY, (int)Constants.RegionHeight);
|
||||
}
|
||||
|
||||
// Create terrain of specified size and initialize with specified terrain.
|
||||
// TODO: join this with the terrain initializers.
|
||||
public TerrainChannel(String type, int pX, int pY, int pZ)
|
||||
{
|
||||
m_terrainData = new HeightmapTerrainData(pX, pY, pZ);
|
||||
if (type.Equals("flat"))
|
||||
FlatLand();
|
||||
else
|
||||
PinHeadIsland();
|
||||
}
|
||||
|
||||
public TerrainChannel(double[,] import)
|
||||
// Create channel passed a heightmap and expected dimensions of the region.
|
||||
// The heightmap might not fit the passed size so accomodations must be made.
|
||||
public TerrainChannel(double[,] pM, int pSizeX, int pSizeY, int pAltitude)
|
||||
{
|
||||
map = import;
|
||||
taint = new bool[import.GetLength(0),import.GetLength(1)];
|
||||
int hmSizeX = pM.GetLength(0);
|
||||
int hmSizeY = pM.GetLength(1);
|
||||
|
||||
m_terrainData = new HeightmapTerrainData(pSizeX, pSizeY, pAltitude);
|
||||
|
||||
for (int xx = 0; xx < pSizeX; xx++)
|
||||
for (int yy = 0; yy < pSizeY; yy++)
|
||||
if (xx > hmSizeX || yy > hmSizeY)
|
||||
m_terrainData[xx, yy] = TerrainData.DefaultTerrainHeight;
|
||||
else
|
||||
m_terrainData[xx, yy] = (float)pM[xx, yy];
|
||||
}
|
||||
|
||||
public TerrainChannel(bool createMap)
|
||||
public TerrainChannel(TerrainData pTerrData)
|
||||
{
|
||||
if (createMap)
|
||||
{
|
||||
map = new double[Constants.RegionSize,Constants.RegionSize];
|
||||
taint = new bool[Constants.RegionSize / 16,Constants.RegionSize / 16];
|
||||
}
|
||||
}
|
||||
|
||||
public TerrainChannel(int w, int h)
|
||||
{
|
||||
map = new double[w,h];
|
||||
taint = new bool[w / 16,h / 16];
|
||||
m_terrainData = pTerrData;
|
||||
}
|
||||
|
||||
#region ITerrainChannel Members
|
||||
|
||||
public int Width
|
||||
{
|
||||
get { return map.GetLength(0); }
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get { return map.GetLength(1); }
|
||||
}
|
||||
|
||||
// ITerrainChannel.MakeCopy()
|
||||
public ITerrainChannel MakeCopy()
|
||||
{
|
||||
TerrainChannel copy = new TerrainChannel(false);
|
||||
copy.map = (double[,]) map.Clone();
|
||||
|
||||
return copy;
|
||||
return this.Copy();
|
||||
}
|
||||
|
||||
// ITerrainChannel.GetTerrainData()
|
||||
public TerrainData GetTerrainData()
|
||||
{
|
||||
return m_terrainData;
|
||||
}
|
||||
|
||||
// ITerrainChannel.GetFloatsSerialized()
|
||||
// This one dimensional version is ordered so height = map[y*sizeX+x];
|
||||
// DEPRECATED: don't use this function as it does not retain the dimensions of the terrain
|
||||
// and the caller will probably do the wrong thing if the terrain is not the legacy 256x256.
|
||||
public float[] GetFloatsSerialised()
|
||||
{
|
||||
// Move the member variables into local variables, calling
|
||||
// member variables 256*256 times gets expensive
|
||||
int w = Width;
|
||||
int h = Height;
|
||||
float[] heights = new float[w * h];
|
||||
return m_terrainData.GetFloatsSerialized();
|
||||
}
|
||||
|
||||
// ITerrainChannel.GetDoubles()
|
||||
public double[,] GetDoubles()
|
||||
{
|
||||
double[,] heights = new double[Width, Height];
|
||||
|
||||
int i, j; // map coordinates
|
||||
int idx = 0; // index into serialized array
|
||||
for (i = 0; i < h; i++)
|
||||
for (int ii = 0; ii < Width; ii++)
|
||||
{
|
||||
for (j = 0; j < w; j++)
|
||||
for (int jj = 0; jj < Height; jj++)
|
||||
{
|
||||
heights[idx++] = (float)map[j, i];
|
||||
heights[ii, jj] = (double)m_terrainData[ii, jj];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
return heights;
|
||||
}
|
||||
|
||||
public double[,] GetDoubles()
|
||||
{
|
||||
return map;
|
||||
}
|
||||
|
||||
// ITerrainChannel.this[x,y]
|
||||
public double this[int x, int y]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (x < 0) x = 0;
|
||||
if (y < 0) y = 0;
|
||||
if (x >= (int)Constants.RegionSize) x = (int)Constants.RegionSize - 1;
|
||||
if (y >= (int)Constants.RegionSize) y = (int)Constants.RegionSize - 1;
|
||||
|
||||
return map[x, y];
|
||||
get {
|
||||
if (x < 0 || x >= Width || y < 0 || y >= Height)
|
||||
return 0;
|
||||
return (double)m_terrainData[x, y];
|
||||
}
|
||||
set
|
||||
{
|
||||
// Will "fix" terrain hole problems. Although not fantastically.
|
||||
if (Double.IsNaN(value) || Double.IsInfinity(value))
|
||||
return;
|
||||
|
||||
if (map[x, y] != value)
|
||||
{
|
||||
taint[x / 16, y / 16] = true;
|
||||
map[x, y] = value;
|
||||
}
|
||||
m_terrainData[x, y] = (float)value;
|
||||
}
|
||||
}
|
||||
|
||||
// ITerrainChannel.GetHieghtAtXYZ(x, y, z)
|
||||
public float GetHeightAtXYZ(float x, float y, float z)
|
||||
{
|
||||
if (x < 0 || x >= Width || y < 0 || y >= Height)
|
||||
return 0;
|
||||
return m_terrainData[(int)x, (int)y];
|
||||
}
|
||||
|
||||
// ITerrainChannel.Tainted()
|
||||
public bool Tainted(int x, int y)
|
||||
{
|
||||
if (taint[x / 16, y / 16])
|
||||
{
|
||||
taint[x / 16, y / 16] = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public TerrainChannel Copy()
|
||||
{
|
||||
TerrainChannel copy = new TerrainChannel(false);
|
||||
copy.map = (double[,]) map.Clone();
|
||||
|
||||
return copy;
|
||||
return m_terrainData.IsTaintedAt(x, y);
|
||||
}
|
||||
|
||||
// ITerrainChannel.SaveToXmlString()
|
||||
public string SaveToXmlString()
|
||||
{
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
@@ -189,13 +192,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteXml(XmlWriter writer)
|
||||
{
|
||||
writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
|
||||
ToXml(writer);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
// ITerrainChannel.LoadFromXmlString()
|
||||
public void LoadFromXmlString(string data)
|
||||
{
|
||||
StringReader sr = new StringReader(data);
|
||||
@@ -207,12 +204,124 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
sr.Close();
|
||||
}
|
||||
|
||||
private void ReadXml(XmlReader reader)
|
||||
// ITerrainChannel.Merge
|
||||
public void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement)
|
||||
{
|
||||
reader.ReadStartElement("TerrainMap");
|
||||
FromXml(reader);
|
||||
m_log.DebugFormat("{0} Merge. inSize=<{1},{2}>, disp={3}, rot={4}, rotDisp={5}, outSize=<{6},{7}>", LogHeader,
|
||||
newTerrain.Width, newTerrain.Height,
|
||||
displacement, radianRotation, rotationDisplacement,
|
||||
m_terrainData.SizeX, m_terrainData.SizeY);
|
||||
for (int xx = 0; xx < newTerrain.Width; xx++)
|
||||
{
|
||||
for (int yy = 0; yy < newTerrain.Height; yy++)
|
||||
{
|
||||
int dispX = (int)displacement.X;
|
||||
int dispY = (int)displacement.Y;
|
||||
float newHeight = (float)newTerrain[xx, yy] + displacement.Z;
|
||||
if (radianRotation == 0)
|
||||
{
|
||||
// If no rotation, place the new height in the specified location
|
||||
dispX += xx;
|
||||
dispY += yy;
|
||||
if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
|
||||
{
|
||||
m_terrainData[dispX, dispY] = newHeight;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If rotating, we have to smooth the result because the conversion
|
||||
// to ints will mean heightmap entries will not get changed
|
||||
// First compute the rotation location for the new height.
|
||||
dispX += (int)(rotationDisplacement.X
|
||||
+ ((float)xx - rotationDisplacement.X) * Math.Cos(radianRotation)
|
||||
- ((float)yy - rotationDisplacement.Y) * Math.Sin(radianRotation) );
|
||||
|
||||
dispY += (int)(rotationDisplacement.Y
|
||||
+ ((float)xx - rotationDisplacement.X) * Math.Sin(radianRotation)
|
||||
+ ((float)yy - rotationDisplacement.Y) * Math.Cos(radianRotation) );
|
||||
|
||||
if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
|
||||
{
|
||||
float oldHeight = m_terrainData[dispX, dispY];
|
||||
// Smooth the heights around this location if the old height is far from this one
|
||||
for (int sxx = dispX - 2; sxx < dispX + 2; sxx++)
|
||||
{
|
||||
for (int syy = dispY - 2; syy < dispY + 2; syy++)
|
||||
{
|
||||
if (sxx >= 0 && sxx < m_terrainData.SizeX && syy >= 0 && syy < m_terrainData.SizeY)
|
||||
{
|
||||
if (sxx == dispX && syy == dispY)
|
||||
{
|
||||
// Set height for the exact rotated point
|
||||
m_terrainData[dispX, dispY] = newHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Math.Abs(m_terrainData[sxx, syy] - newHeight) > 1f)
|
||||
{
|
||||
// If the adjacent height is far off, force it to this height
|
||||
m_terrainData[sxx, syy] = newHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
|
||||
{
|
||||
m_terrainData[dispX, dispY] = (float)newTerrain[xx, yy];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public TerrainChannel Copy()
|
||||
{
|
||||
TerrainChannel copy = new TerrainChannel();
|
||||
copy.m_terrainData = m_terrainData.Clone();
|
||||
return copy;
|
||||
}
|
||||
|
||||
private void WriteXml(XmlWriter writer)
|
||||
{
|
||||
if (Width == Constants.RegionSize && Height == Constants.RegionSize)
|
||||
{
|
||||
// Downward compatibility for legacy region terrain maps.
|
||||
// If region is exactly legacy size, return the old format XML.
|
||||
writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
|
||||
ToXml(writer);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
// New format XML that includes width and length.
|
||||
writer.WriteStartElement(String.Empty, "TerrainMap2", String.Empty);
|
||||
ToXml2(writer);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadXml(XmlReader reader)
|
||||
{
|
||||
// Check the first element. If legacy element, use the legacy reader.
|
||||
if (reader.IsStartElement("TerrainMap"))
|
||||
{
|
||||
reader.ReadStartElement("TerrainMap");
|
||||
FromXml(reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.ReadStartElement("TerrainMap2");
|
||||
FromXml2(reader);
|
||||
}
|
||||
}
|
||||
|
||||
// Write legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
|
||||
private void ToXml(XmlWriter xmlWriter)
|
||||
{
|
||||
float[] mapData = GetFloatsSerialised();
|
||||
@@ -226,12 +335,15 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
serializer.Serialize(xmlWriter, buffer);
|
||||
}
|
||||
|
||||
// Read legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
|
||||
private void FromXml(XmlReader xmlReader)
|
||||
{
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(byte[]));
|
||||
byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
|
||||
int index = 0;
|
||||
|
||||
m_terrainData = new HeightmapTerrainData(Height, Width, (int)Constants.RegionHeight);
|
||||
|
||||
for (int y = 0; y < Height; y++)
|
||||
{
|
||||
for (int x = 0; x < Width; x++)
|
||||
@@ -244,35 +356,63 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
private class TerrainChannelXMLPackage
|
||||
{
|
||||
public int Version;
|
||||
public int SizeX;
|
||||
public int SizeY;
|
||||
public int SizeZ;
|
||||
public float CompressionFactor;
|
||||
public int[] Map;
|
||||
public TerrainChannelXMLPackage(int pX, int pY, int pZ, float pCompressionFactor, int[] pMap)
|
||||
{
|
||||
Version = 1;
|
||||
SizeX = pX;
|
||||
SizeY = pY;
|
||||
SizeZ = pZ;
|
||||
CompressionFactor = pCompressionFactor;
|
||||
Map = pMap;
|
||||
}
|
||||
}
|
||||
|
||||
// New terrain serialization format that includes the width and length.
|
||||
private void ToXml2(XmlWriter xmlWriter)
|
||||
{
|
||||
TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_terrainData.CompressionFactor,
|
||||
m_terrainData.GetCompressedMap());
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
|
||||
serializer.Serialize(xmlWriter, package);
|
||||
}
|
||||
|
||||
// New terrain serialization format that includes the width and length.
|
||||
private void FromXml2(XmlReader xmlReader)
|
||||
{
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
|
||||
TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader);
|
||||
m_terrainData = new HeightmapTerrainData(package.Map, package.CompressionFactor, package.SizeX, package.SizeY, package.SizeZ);
|
||||
}
|
||||
|
||||
// Fill the heightmap with the center bump terrain
|
||||
private void PinHeadIsland()
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < Constants.RegionSize; x++)
|
||||
for (int x = 0; x < Width; x++)
|
||||
{
|
||||
int y;
|
||||
for (y = 0; y < Constants.RegionSize; y++)
|
||||
for (int y = 0; y < Height; y++)
|
||||
{
|
||||
map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10;
|
||||
double spherFacA = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01;
|
||||
double spherFacB = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001;
|
||||
if (map[x, y] < spherFacA)
|
||||
map[x, y] = spherFacA;
|
||||
if (map[x, y] < spherFacB)
|
||||
map[x, y] = spherFacB;
|
||||
m_terrainData[x, y] = (float)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);
|
||||
float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d);
|
||||
if (m_terrainData[x, y]< spherFacA)
|
||||
m_terrainData[x, y]= spherFacA;
|
||||
if (m_terrainData[x, y]< spherFacB)
|
||||
m_terrainData[x, y] = spherFacB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FlatLand()
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < Constants.RegionSize; x++)
|
||||
{
|
||||
int y;
|
||||
for (y = 0; y < Constants.RegionSize; y++)
|
||||
map[x, y] = 21;
|
||||
}
|
||||
m_terrainData.ClearLand();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
948
OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
Normal file
948
OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
Normal file
@@ -0,0 +1,948 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Freely adapted from the Aurora version of the terrain compressor.
|
||||
* Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
using log4net;
|
||||
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Packets;
|
||||
|
||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
public static class OpenSimTerrainCompressor
|
||||
{
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
#pragma warning disable 414
|
||||
private static string LogHeader = "[TERRAIN COMPRESSOR]";
|
||||
#pragma warning restore 414
|
||||
|
||||
public const int END_OF_PATCHES = 97;
|
||||
|
||||
private const float OO_SQRT2 = 0.7071067811865475244008443621049f;
|
||||
private const int STRIDE = 264;
|
||||
|
||||
private const int ZERO_CODE = 0x0;
|
||||
private const int ZERO_EOB = 0x2;
|
||||
private const int POSITIVE_VALUE = 0x6;
|
||||
private const int NEGATIVE_VALUE = 0x7;
|
||||
|
||||
private static readonly float[] DequantizeTable16 =
|
||||
new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
|
||||
private static readonly float[] DequantizeTable32 =
|
||||
new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
|
||||
private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
//private static readonly float[] CosineTable32 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize];
|
||||
private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
private static readonly int[] CopyMatrix32 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
|
||||
private static readonly float[] QuantizeTable16 =
|
||||
new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
|
||||
static OpenSimTerrainCompressor()
|
||||
{
|
||||
// Initialize the decompression tables
|
||||
BuildDequantizeTable16();
|
||||
SetupCosines16();
|
||||
BuildCopyMatrix16();
|
||||
BuildQuantizeTable16();
|
||||
}
|
||||
|
||||
// Used to send cloud and wind patches
|
||||
public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, byte type, int pRegionSizeX,
|
||||
int pRegionSizeY)
|
||||
{
|
||||
LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
|
||||
|
||||
TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
|
||||
{Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
|
||||
|
||||
// Should be enough to fit even the most poorly packed data
|
||||
byte[] data = new byte[patches.Length*Constants.TerrainPatchSize*Constants.TerrainPatchSize*2];
|
||||
BitPack bitpack = new BitPack(data, 0);
|
||||
bitpack.PackBits(header.Stride, 16);
|
||||
bitpack.PackBits(header.PatchSize, 8);
|
||||
bitpack.PackBits(type, 8);
|
||||
|
||||
foreach (TerrainPatch t in patches)
|
||||
CreatePatch(bitpack, t.Data, t.X, t.Y, pRegionSizeX, pRegionSizeY);
|
||||
|
||||
bitpack.PackBits(END_OF_PATCHES, 8);
|
||||
|
||||
layer.LayerData.Data = new byte[bitpack.BytePos + 1];
|
||||
Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
// Create a land packet for a single patch.
|
||||
public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY)
|
||||
{
|
||||
int[] xPieces = new int[1];
|
||||
int[] yPieces = new int[1];
|
||||
xPieces[0] = patchX; // patch X dimension
|
||||
yPieces[0] = patchY;
|
||||
|
||||
return CreateLandPacket(terrData, xPieces, yPieces);
|
||||
}
|
||||
|
||||
public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] xPieces, int[] yPieces)
|
||||
{
|
||||
byte landPacketType = (byte)TerrainPatch.LayerType.Land;
|
||||
if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
|
||||
{
|
||||
landPacketType = (byte)TerrainPatch.LayerType.LandExtended;
|
||||
}
|
||||
|
||||
return CreateLandPacket(terrData, xPieces, yPieces, landPacketType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a LayerData packet for compressed land data given a full
|
||||
/// simulator heightmap and an array of indices of patches to compress
|
||||
/// </summary>
|
||||
/// <param name="terrData">
|
||||
/// Terrain data that can result in a meter square heightmap.
|
||||
/// </param>
|
||||
/// <param name="x">
|
||||
/// Array of indexes in the grid of patches
|
||||
/// for this simulator.
|
||||
/// If creating a packet for multiple patches, there will be entries in
|
||||
/// both the X and Y arrays for each of the patches.
|
||||
/// For example if patches 1 and 17 are to be sent,
|
||||
/// x[] = {1,1} and y[] = {0,1} which specifies the patches at
|
||||
/// indexes <1,0> and <1,1> (presuming the terrain size is 16x16 patches).
|
||||
/// </param>
|
||||
/// <param name="y">
|
||||
/// Array of indexes in the grid of patches.
|
||||
/// </param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type)
|
||||
{
|
||||
LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
|
||||
|
||||
TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
|
||||
{Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
|
||||
|
||||
byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2];
|
||||
BitPack bitpack = new BitPack(data, 0);
|
||||
bitpack.PackBits(header.Stride, 16);
|
||||
bitpack.PackBits(header.PatchSize, 8);
|
||||
bitpack.PackBits(type, 8);
|
||||
|
||||
for (int i = 0; i < x.Length; i++)
|
||||
CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]);
|
||||
|
||||
bitpack.PackBits(END_OF_PATCHES, 8);
|
||||
|
||||
layer.LayerData.Data = new byte[bitpack.BytePos + 1];
|
||||
Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
// Unused: left for historical reference.
|
||||
public static void CreatePatch(BitPack output, float[] patchData, int x, int y, int pRegionSizeX, int pRegionSizeY)
|
||||
{
|
||||
TerrainPatch.Header header = PrescanPatch(patchData);
|
||||
header.QuantWBits = 136;
|
||||
if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
|
||||
{
|
||||
header.PatchIDs = (y & 0xFFFF);
|
||||
header.PatchIDs += (x << 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
header.PatchIDs = (y & 0x1F);
|
||||
header.PatchIDs += (x << 5);
|
||||
}
|
||||
|
||||
// NOTE: No idea what prequant and postquant should be or what they do
|
||||
|
||||
int wbits;
|
||||
int[] patch = CompressPatch(patchData, header, 10, out wbits);
|
||||
wbits = EncodePatchHeader(output, header, patch, Constants.RegionSize, Constants.RegionSize, wbits);
|
||||
EncodePatch(output, patch, 0, wbits);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a patch of terrain to a BitPacker
|
||||
/// </summary>
|
||||
/// <param name="output">BitPacker to write the patch to</param>
|
||||
/// <param name="heightmap">
|
||||
/// Heightmap of the simulator. Presumed to be an sizeX*sizeY array.
|
||||
/// </param>
|
||||
/// <param name="patchX">
|
||||
/// X offset of the patch to create.
|
||||
/// </param>
|
||||
/// <param name="patchY">
|
||||
/// Y offset of the patch to create.
|
||||
/// </param>
|
||||
/// <param name="pRegionSizeX"></param>
|
||||
/// <param name="pRegionSizeY"></param>
|
||||
public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY)
|
||||
{
|
||||
TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY);
|
||||
header.QuantWBits = 136;
|
||||
|
||||
// If larger than legacy region size, pack patch X and Y info differently.
|
||||
if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
|
||||
{
|
||||
header.PatchIDs = (patchY & 0xFFFF);
|
||||
header.PatchIDs += (patchX << 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
header.PatchIDs = (patchY & 0x1F);
|
||||
header.PatchIDs += (patchX << 5);
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("{0} CreatePatchFromHeightmap. patchX={1}, patchY={2}, DCOffset={3}, range={4}",
|
||||
// LogHeader, patchX, patchY, header.DCOffset, header.Range);
|
||||
|
||||
// NOTE: No idea what prequant and postquant should be or what they do
|
||||
int wbits;
|
||||
int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits);
|
||||
wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits);
|
||||
EncodePatch(output, patch, 0, wbits);
|
||||
}
|
||||
|
||||
private static TerrainPatch.Header PrescanPatch(float[] patch)
|
||||
{
|
||||
TerrainPatch.Header header = new TerrainPatch.Header();
|
||||
float zmax = -99999999.0f;
|
||||
float zmin = 99999999.0f;
|
||||
|
||||
for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
|
||||
{
|
||||
float val = patch[i];
|
||||
if (val > zmax) zmax = val;
|
||||
if (val < zmin) zmin = val;
|
||||
}
|
||||
|
||||
header.DCOffset = zmin;
|
||||
header.Range = (int) ((zmax - zmin) + 1.0f);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
// Scan the height info we're returning and return a patch packet header for this patch.
|
||||
private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY)
|
||||
{
|
||||
TerrainPatch.Header header = new TerrainPatch.Header();
|
||||
float zmax = -99999999.0f;
|
||||
float zmin = 99999999.0f;
|
||||
|
||||
for (int j = patchY*Constants.TerrainPatchSize; j < (patchY + 1)*Constants.TerrainPatchSize; j++)
|
||||
{
|
||||
for (int i = patchX*Constants.TerrainPatchSize; i < (patchX + 1)*Constants.TerrainPatchSize; i++)
|
||||
{
|
||||
float val = terrData[i, j];
|
||||
if (val > zmax) zmax = val;
|
||||
if (val < zmin) zmin = val;
|
||||
}
|
||||
}
|
||||
|
||||
header.DCOffset = zmin;
|
||||
header.Range = (int)((zmax - zmin) + 1.0f);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack)
|
||||
{
|
||||
TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)};
|
||||
|
||||
// Quantized word bits
|
||||
if (header.QuantWBits == END_OF_PATCHES)
|
||||
return header;
|
||||
|
||||
// DC offset
|
||||
header.DCOffset = bitpack.UnpackFloat();
|
||||
|
||||
// Range
|
||||
header.Range = bitpack.UnpackBits(16);
|
||||
|
||||
// Patch IDs (10 bits)
|
||||
header.PatchIDs = bitpack.UnpackBits(10);
|
||||
|
||||
// Word bits
|
||||
header.WordBits = (uint) ((header.QuantWBits & 0x0f) + 2);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, uint pRegionSizeX,
|
||||
uint pRegionSizeY, int wbits)
|
||||
{
|
||||
/*
|
||||
int temp;
|
||||
int wbits = (header.QuantWBits & 0x0f) + 2;
|
||||
uint maxWbits = (uint)wbits + 5;
|
||||
uint minWbits = ((uint)wbits >> 1);
|
||||
int wbitsMaxValue;
|
||||
*/
|
||||
// goal is to determ minimum number of bits to use so all data fits
|
||||
/*
|
||||
wbits = (int)minWbits;
|
||||
wbitsMaxValue = (1 << wbits);
|
||||
|
||||
for (int i = 0; i < patch.Length; i++)
|
||||
{
|
||||
temp = patch[i];
|
||||
if (temp != 0)
|
||||
{
|
||||
// Get the absolute value
|
||||
if (temp < 0) temp *= -1;
|
||||
|
||||
no coments..
|
||||
|
||||
for (int j = (int)maxWbits; j > (int)minWbits; j--)
|
||||
{
|
||||
if ((temp & (1 << j)) != 0)
|
||||
{
|
||||
if (j > wbits) wbits = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (temp > wbitsMaxValue)
|
||||
{
|
||||
wbits++;
|
||||
if (wbits == maxWbits)
|
||||
goto Done;
|
||||
wbitsMaxValue = 1 << wbits;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Done:
|
||||
|
||||
// wbits += 1;
|
||||
*/
|
||||
// better check
|
||||
if (wbits > 17)
|
||||
wbits = 16;
|
||||
else if (wbits < 3)
|
||||
wbits = 3;
|
||||
|
||||
header.QuantWBits &= 0xf0;
|
||||
|
||||
header.QuantWBits |= (wbits - 2);
|
||||
|
||||
output.PackBits(header.QuantWBits, 8);
|
||||
output.PackFloat(header.DCOffset);
|
||||
output.PackBits(header.Range, 16);
|
||||
if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
|
||||
output.PackBits(header.PatchIDs, 32);
|
||||
else
|
||||
output.PackBits(header.PatchIDs, 10);
|
||||
|
||||
return wbits;
|
||||
}
|
||||
|
||||
private static void IDCTColumn16(float[] linein, float[] lineout, int column)
|
||||
{
|
||||
for (int n = 0; n < Constants.TerrainPatchSize; n++)
|
||||
{
|
||||
float total = OO_SQRT2*linein[column];
|
||||
|
||||
for (int u = 1; u < Constants.TerrainPatchSize; u++)
|
||||
{
|
||||
int usize = u*Constants.TerrainPatchSize;
|
||||
total += linein[usize + column]*CosineTable16[usize + n];
|
||||
}
|
||||
|
||||
lineout[Constants.TerrainPatchSize*n + column] = total;
|
||||
}
|
||||
}
|
||||
|
||||
private static void IDCTLine16(float[] linein, float[] lineout, int line)
|
||||
{
|
||||
const float oosob = 2.0f/Constants.TerrainPatchSize;
|
||||
int lineSize = line*Constants.TerrainPatchSize;
|
||||
|
||||
for (int n = 0; n < Constants.TerrainPatchSize; n++)
|
||||
{
|
||||
float total = OO_SQRT2*linein[lineSize];
|
||||
|
||||
for (int u = 1; u < Constants.TerrainPatchSize; u++)
|
||||
{
|
||||
total += linein[lineSize + u]*CosineTable16[u*Constants.TerrainPatchSize + n];
|
||||
}
|
||||
|
||||
lineout[lineSize + n] = total*oosob;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
private static void DCTLine16(float[] linein, float[] lineout, int line)
|
||||
{
|
||||
float total = 0.0f;
|
||||
int lineSize = line * Constants.TerrainPatchSize;
|
||||
|
||||
for (int n = 0; n < Constants.TerrainPatchSize; n++)
|
||||
{
|
||||
total += linein[lineSize + n];
|
||||
}
|
||||
|
||||
lineout[lineSize] = OO_SQRT2 * total;
|
||||
|
||||
int uptr = 0;
|
||||
for (int u = 1; u < Constants.TerrainPatchSize; u++)
|
||||
{
|
||||
total = 0.0f;
|
||||
uptr += Constants.TerrainPatchSize;
|
||||
|
||||
for (int n = 0; n < Constants.TerrainPatchSize; n++)
|
||||
{
|
||||
total += linein[lineSize + n] * CosineTable16[uptr + n];
|
||||
}
|
||||
|
||||
lineout[lineSize + u] = total;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private static void DCTLine16(float[] linein, float[] lineout, int line)
|
||||
{
|
||||
// outputs transpose data (lines exchanged with coluns )
|
||||
// so to save a bit of cpu when doing coluns
|
||||
float total = 0.0f;
|
||||
int lineSize = line*Constants.TerrainPatchSize;
|
||||
|
||||
for (int n = 0; n < Constants.TerrainPatchSize; n++)
|
||||
{
|
||||
total += linein[lineSize + n];
|
||||
}
|
||||
|
||||
lineout[line] = OO_SQRT2*total;
|
||||
|
||||
for (int u = Constants.TerrainPatchSize;
|
||||
u < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
|
||||
u += Constants.TerrainPatchSize)
|
||||
{
|
||||
total = 0.0f;
|
||||
for (int ptrn = lineSize, ptru = u; ptrn < lineSize + Constants.TerrainPatchSize; ptrn++,ptru++)
|
||||
{
|
||||
total += linein[ptrn]*CosineTable16[ptru];
|
||||
}
|
||||
|
||||
lineout[line + u] = total;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
private static void DCTColumn16(float[] linein, int[] lineout, int column)
|
||||
{
|
||||
float total = 0.0f;
|
||||
// const float oosob = 2.0f / Constants.TerrainPatchSize;
|
||||
|
||||
for (int n = 0; n < Constants.TerrainPatchSize; n++)
|
||||
{
|
||||
total += linein[Constants.TerrainPatchSize * n + column];
|
||||
}
|
||||
|
||||
// lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
|
||||
lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * QuantizeTable16[column]);
|
||||
|
||||
for (int uptr = Constants.TerrainPatchSize; uptr < Constants.TerrainPatchSize * Constants.TerrainPatchSize; uptr += Constants.TerrainPatchSize)
|
||||
{
|
||||
total = 0.0f;
|
||||
|
||||
for (int n = 0; n < Constants.TerrainPatchSize; n++)
|
||||
{
|
||||
total += linein[Constants.TerrainPatchSize * n + column] * CosineTable16[uptr + n];
|
||||
}
|
||||
|
||||
// lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
|
||||
lineout[CopyMatrix16[uptr + column]] = (int)(total * QuantizeTable16[uptr + column]);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DCTColumn16(float[] linein, int[] lineout, int column)
|
||||
{
|
||||
// input columns are in fact stored in lines now
|
||||
|
||||
float total = 0.0f;
|
||||
// const float oosob = 2.0f / Constants.TerrainPatchSize;
|
||||
int inlinesptr = Constants.TerrainPatchSize*column;
|
||||
|
||||
for (int n = 0; n < Constants.TerrainPatchSize; n++)
|
||||
{
|
||||
total += linein[inlinesptr + n];
|
||||
}
|
||||
|
||||
// lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
|
||||
lineout[CopyMatrix16[column]] = (int) (OO_SQRT2*total*QuantizeTable16[column]);
|
||||
|
||||
for (int uptr = Constants.TerrainPatchSize;
|
||||
uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
|
||||
uptr += Constants.TerrainPatchSize)
|
||||
{
|
||||
total = 0.0f;
|
||||
|
||||
for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
|
||||
{
|
||||
total += linein[n]*CosineTable16[ptru];
|
||||
}
|
||||
|
||||
// lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
|
||||
lineout[CopyMatrix16[uptr + column]] = (int) (total*QuantizeTable16[uptr + column]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private static int DCTColumn16Wbits(float[] linein, int[] lineout, int column, int wbits, int maxwbits)
|
||||
{
|
||||
// input columns are in fact stored in lines now
|
||||
|
||||
bool dowbits = wbits != maxwbits;
|
||||
int wbitsMaxValue = 1 << wbits;
|
||||
|
||||
float total = 0.0f;
|
||||
// const float oosob = 2.0f / Constants.TerrainPatchSize;
|
||||
int inlinesptr = Constants.TerrainPatchSize*column;
|
||||
|
||||
for (int n = 0; n < Constants.TerrainPatchSize; n++)
|
||||
{
|
||||
total += linein[inlinesptr + n];
|
||||
}
|
||||
|
||||
// lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
|
||||
int tmp = (int) (OO_SQRT2*total*QuantizeTable16[column]);
|
||||
lineout[CopyMatrix16[column]] = tmp;
|
||||
|
||||
if (dowbits)
|
||||
{
|
||||
if (tmp < 0) tmp *= -1;
|
||||
while (tmp > wbitsMaxValue)
|
||||
{
|
||||
wbits++;
|
||||
wbitsMaxValue = 1 << wbits;
|
||||
if (wbits == maxwbits)
|
||||
{
|
||||
dowbits = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int uptr = Constants.TerrainPatchSize;
|
||||
uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
|
||||
uptr += Constants.TerrainPatchSize)
|
||||
{
|
||||
total = 0.0f;
|
||||
|
||||
for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
|
||||
{
|
||||
total += linein[n]*CosineTable16[ptru];
|
||||
}
|
||||
|
||||
tmp = (int) (total*QuantizeTable16[uptr + column]);
|
||||
lineout[CopyMatrix16[uptr + column]] = tmp;
|
||||
|
||||
if (dowbits)
|
||||
{
|
||||
if (tmp < 0) tmp *= -1;
|
||||
while (tmp > wbitsMaxValue)
|
||||
{
|
||||
wbits++;
|
||||
wbitsMaxValue = 1 << wbits;
|
||||
if (wbits == maxwbits)
|
||||
{
|
||||
dowbits = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return wbits;
|
||||
}
|
||||
|
||||
public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size)
|
||||
{
|
||||
for (int n = 0; n < size*size; n++)
|
||||
{
|
||||
// ?
|
||||
int temp = bitpack.UnpackBits(1);
|
||||
if (temp != 0)
|
||||
{
|
||||
// Value or EOB
|
||||
temp = bitpack.UnpackBits(1);
|
||||
if (temp != 0)
|
||||
{
|
||||
// Value
|
||||
temp = bitpack.UnpackBits(1);
|
||||
if (temp != 0)
|
||||
{
|
||||
// Negative
|
||||
temp = bitpack.UnpackBits((int) header.WordBits);
|
||||
patches[n] = temp*-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Positive
|
||||
temp = bitpack.UnpackBits((int) header.WordBits);
|
||||
patches[n] = temp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the rest to zero
|
||||
// TODO: This might not be necessary
|
||||
for (int o = n; o < size*size; o++)
|
||||
{
|
||||
patches[o] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
patches[n] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits)
|
||||
{
|
||||
int maxwbitssize = (1 << wbits) - 1;
|
||||
|
||||
if (postquant > Constants.TerrainPatchSize*Constants.TerrainPatchSize || postquant < 0)
|
||||
{
|
||||
Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (postquant != 0) patch[Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant] = 0;
|
||||
|
||||
for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
|
||||
{
|
||||
int temp = patch[i];
|
||||
|
||||
if (temp == 0)
|
||||
{
|
||||
bool eob = true;
|
||||
|
||||
for (int j = i; j < Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant; j++)
|
||||
{
|
||||
if (patch[j] != 0)
|
||||
{
|
||||
eob = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (eob)
|
||||
{
|
||||
output.PackBits(ZERO_EOB, 2);
|
||||
return;
|
||||
}
|
||||
output.PackBits(ZERO_CODE, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (temp < 0)
|
||||
{
|
||||
temp *= -1;
|
||||
|
||||
if (temp > maxwbitssize) temp = maxwbitssize;
|
||||
|
||||
output.PackBits(NEGATIVE_VALUE, 3);
|
||||
output.PackBits(temp, wbits);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (temp > maxwbitssize) temp = maxwbitssize;
|
||||
|
||||
output.PackBits(POSITIVE_VALUE, 3);
|
||||
output.PackBits(temp, wbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group)
|
||||
{
|
||||
float[] block = new float[group.PatchSize*group.PatchSize];
|
||||
float[] output = new float[group.PatchSize*group.PatchSize];
|
||||
int prequant = (header.QuantWBits >> 4) + 2;
|
||||
int quantize = 1 << prequant;
|
||||
float ooq = 1.0f/quantize;
|
||||
float mult = ooq*header.Range;
|
||||
float addval = mult*(1 << (prequant - 1)) + header.DCOffset;
|
||||
|
||||
if (group.PatchSize == Constants.TerrainPatchSize)
|
||||
{
|
||||
for (int n = 0; n < Constants.TerrainPatchSize*Constants.TerrainPatchSize; n++)
|
||||
{
|
||||
block[n] = patches[CopyMatrix16[n]]*DequantizeTable16[n];
|
||||
}
|
||||
|
||||
float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
|
||||
for (int o = 0; o < Constants.TerrainPatchSize; o++)
|
||||
IDCTColumn16(block, ftemp, o);
|
||||
for (int o = 0; o < Constants.TerrainPatchSize; o++)
|
||||
IDCTLine16(ftemp, block, o);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int n = 0; n < Constants.TerrainPatchSize*2*Constants.TerrainPatchSize*2; n++)
|
||||
{
|
||||
block[n] = patches[CopyMatrix32[n]]*DequantizeTable32[n];
|
||||
}
|
||||
|
||||
Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error);
|
||||
}
|
||||
|
||||
for (int j = 0; j < block.Length; j++)
|
||||
{
|
||||
output[j] = block[j]*mult + addval;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits)
|
||||
{
|
||||
float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
int wordsize = (prequant - 2) & 0x0f;
|
||||
float oozrange = 1.0f/header.Range;
|
||||
float range = (1 << prequant);
|
||||
float premult = oozrange*range;
|
||||
float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
|
||||
|
||||
header.QuantWBits = wordsize;
|
||||
header.QuantWBits |= wordsize << 4;
|
||||
|
||||
int k = 0;
|
||||
for (int j = 0; j < Constants.TerrainPatchSize; j++)
|
||||
{
|
||||
for (int i = 0; i < Constants.TerrainPatchSize; i++)
|
||||
block[k++] = patchData[j*Constants.TerrainPatchSize + i]*premult - sub;
|
||||
}
|
||||
|
||||
float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
|
||||
|
||||
int maxWbits = prequant + 5;
|
||||
wbits = (prequant >> 1);
|
||||
|
||||
for (int o = 0; o < Constants.TerrainPatchSize; o++)
|
||||
DCTLine16(block, ftemp, o);
|
||||
for (int o = 0; o < Constants.TerrainPatchSize; o++)
|
||||
wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
|
||||
|
||||
return itemp;
|
||||
}
|
||||
|
||||
private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant, out int wbits)
|
||||
{
|
||||
float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
float oozrange = 1.0f/header.Range;
|
||||
float range = (1 << prequant);
|
||||
float premult = oozrange*range;
|
||||
float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
|
||||
int wordsize = (prequant - 2) & 0x0f;
|
||||
|
||||
header.QuantWBits = wordsize;
|
||||
header.QuantWBits |= wordsize << 4;
|
||||
|
||||
int k = 0;
|
||||
for (int j = 0; j < Constants.TerrainPatchSize; j++)
|
||||
{
|
||||
for (int i = 0; i < Constants.TerrainPatchSize; i++)
|
||||
block[k++] = patchData[j, i]*premult - sub;
|
||||
}
|
||||
|
||||
float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
|
||||
int maxWbits = prequant + 5;
|
||||
wbits = (prequant >> 1);
|
||||
|
||||
for (int o = 0; o < Constants.TerrainPatchSize; o++)
|
||||
DCTLine16(block, ftemp, o);
|
||||
for (int o = 0; o < Constants.TerrainPatchSize; o++)
|
||||
wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
|
||||
|
||||
return itemp;
|
||||
}
|
||||
|
||||
private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header,
|
||||
int prequant, out int wbits)
|
||||
{
|
||||
float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
int wordsize = prequant;
|
||||
float oozrange = 1.0f/header.Range;
|
||||
float range = (1 << prequant);
|
||||
float premult = oozrange*range;
|
||||
float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
|
||||
|
||||
header.QuantWBits = wordsize - 2;
|
||||
header.QuantWBits |= (prequant - 2) << 4;
|
||||
|
||||
int k = 0;
|
||||
|
||||
int yPatchLimit = patchY >= (terrData.SizeY / Constants.TerrainPatchSize) ?
|
||||
(terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchY;
|
||||
yPatchLimit = (yPatchLimit + 1) * Constants.TerrainPatchSize;
|
||||
|
||||
int xPatchLimit = patchX >= (terrData.SizeX / Constants.TerrainPatchSize) ?
|
||||
(terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchX;
|
||||
xPatchLimit = (xPatchLimit + 1) * Constants.TerrainPatchSize;
|
||||
|
||||
for (int yy = patchY * Constants.TerrainPatchSize; yy < yPatchLimit; yy++)
|
||||
{
|
||||
for (int xx = patchX * Constants.TerrainPatchSize; xx < xPatchLimit; xx++)
|
||||
{
|
||||
block[k++] = terrData[xx, yy] * premult - sub;
|
||||
}
|
||||
}
|
||||
|
||||
float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
|
||||
|
||||
int maxWbits = prequant + 5;
|
||||
wbits = (prequant >> 1);
|
||||
|
||||
for (int o = 0; o < Constants.TerrainPatchSize; o++)
|
||||
DCTLine16(block, ftemp, o);
|
||||
for (int o = 0; o < Constants.TerrainPatchSize; o++)
|
||||
wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
|
||||
|
||||
return itemp;
|
||||
}
|
||||
|
||||
#region Initialization
|
||||
|
||||
private static void BuildDequantizeTable16()
|
||||
{
|
||||
for (int j = 0; j < Constants.TerrainPatchSize; j++)
|
||||
{
|
||||
for (int i = 0; i < Constants.TerrainPatchSize; i++)
|
||||
{
|
||||
DequantizeTable16[j*Constants.TerrainPatchSize + i] = 1.0f + 2.0f*(i + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void BuildQuantizeTable16()
|
||||
{
|
||||
const float oosob = 2.0f/Constants.TerrainPatchSize;
|
||||
for (int j = 0; j < Constants.TerrainPatchSize; j++)
|
||||
{
|
||||
for (int i = 0; i < Constants.TerrainPatchSize; i++)
|
||||
{
|
||||
// QuantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j));
|
||||
QuantizeTable16[j*Constants.TerrainPatchSize + i] = oosob/(1.0f + 2.0f*(i + (float) j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetupCosines16()
|
||||
{
|
||||
const float hposz = (float) Math.PI*0.5f/Constants.TerrainPatchSize;
|
||||
|
||||
for (int u = 0; u < Constants.TerrainPatchSize; u++)
|
||||
{
|
||||
for (int n = 0; n < Constants.TerrainPatchSize; n++)
|
||||
{
|
||||
CosineTable16[u*Constants.TerrainPatchSize + n] = (float) Math.Cos((2.0f*n + 1.0f)*u*hposz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void BuildCopyMatrix16()
|
||||
{
|
||||
bool diag = false;
|
||||
bool right = true;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int count = 0;
|
||||
|
||||
while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize)
|
||||
{
|
||||
CopyMatrix16[j*Constants.TerrainPatchSize + i] = count++;
|
||||
|
||||
if (!diag)
|
||||
{
|
||||
if (right)
|
||||
{
|
||||
if (i < Constants.TerrainPatchSize - 1) i++;
|
||||
else j++;
|
||||
|
||||
right = false;
|
||||
diag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j < Constants.TerrainPatchSize - 1) j++;
|
||||
else i++;
|
||||
|
||||
right = true;
|
||||
diag = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (right)
|
||||
{
|
||||
i++;
|
||||
j--;
|
||||
if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
i--;
|
||||
j++;
|
||||
if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Initialization
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user