diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs
index 7242ca6f12..d08b98722f 100644
--- a/OpenSim/Framework/TerrainData.cs
+++ b/OpenSim/Framework/TerrainData.cs
@@ -26,7 +26,7 @@
*/
using System;
-using System.Collections.Generic;
+using System.Collections;
using System.IO;
using System.IO.Compression;
using System.Reflection;
@@ -73,12 +73,15 @@ namespace OpenSim.Framework
private float[,] m_heightmap;
// Remember subregions of the heightmap that has changed.
- private bool[,] m_taint;
+
+ private BitArray m_taint;
+ private int m_taintSizeX;
+ private int m_taintStrideForY; // stride when Y is in meters
+ private int m_taintSizeY;
// legacy CompressionFactor
public float CompressionFactor { get; private set; }
- // Terrain always is a square
public int SizeX { get; protected set; }
public int SizeY { get; protected set; }
public int SizeZ { get; protected set; }
@@ -104,7 +107,7 @@ namespace OpenSim.Framework
if (m_heightmap[x, y] != value)
{
m_heightmap[x, y] = value;
- m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true;
+ m_taint[x / Constants.TerrainPatchSize + y * m_taintStrideForY] = true;
}
}
}
@@ -117,19 +120,17 @@ namespace OpenSim.Framework
public void ClearTaint()
{
- SetAllTaint(false);
+ m_taint.SetAll(false);
}
public void TaintAllTerrain()
{
- SetAllTaint(true);
+ m_taint.SetAll(true);
}
private void SetAllTaint(bool setting)
{
- for (int ii = 0; ii < m_taint.GetLength(0); ii++)
- for (int jj = 0; jj < m_taint.GetLength(1); jj++)
- m_taint[ii, jj] = setting;
+ m_taint.SetAll(setting);
}
public void ClearLand()
@@ -147,24 +148,63 @@ namespace OpenSim.Framework
// Return 'true' of the patch that contains these region coordinates has been modified.
// Note that checking the taint clears it.
// There is existing code that relies on this feature.
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public bool IsTaintedAt(int xx, int yy, bool clearOnTest)
{
- int tx = xx / Constants.TerrainPatchSize;
- int ty = yy / Constants.TerrainPatchSize;
- bool ret = m_taint[tx, ty];
+ int indx = xx / Constants.TerrainPatchSize + yy * m_taintStrideForY;
+ bool ret = m_taint[indx];
if (ret && clearOnTest)
- m_taint[tx, ty] = false;
+ m_taint[indx] = false;
return ret;
}
- // Old form that clears the taint flag when we check it.
- // ubit: this dangerus naming should be only check without clear
- // keeping for old modules outthere
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public bool IsTaintedAt(int xx, int yy)
{
- return IsTaintedAt(xx, yy, true /* clearOnTest */);
+ return m_taint[xx / Constants.TerrainPatchSize + yy * m_taintStrideForY];
}
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
+ public bool IsTaintedAtPatch(int xx, int yy, bool clearOnTest)
+ {
+ int indx = xx + yy * m_taintSizeX;
+ bool ret = m_taint[indx];
+ if (ret && clearOnTest)
+ m_taint[indx] = false;
+ return ret;
+ }
+
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
+ public bool IsTaintedAtPatch(int xx, int yy)
+ {
+ return m_taint[xx + yy * m_taintSizeX];
+ }
+
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
+ public bool IsTaintedAtPatch(int indx, bool clearOnTest)
+ {
+ bool ret = m_taint[indx];
+ if (ret && clearOnTest)
+ m_taint[indx] = false;
+ return ret;
+ }
+
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
+ public bool IsTaintedAtPatchWithClear(int indx)
+ {
+ if(m_taint[indx])
+ {
+ m_taint[indx] = false;
+ return true;
+ }
+ return false;
+ }
+
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
+ public bool IsTaintedAtPatch(int indx)
+ {
+ return m_taint[indx];
+ }
// TerrainData.GetDatabaseBlob
// The user wants something to store in the database.
public bool GetDatabaseBlob(out int DBRevisionCode, out Array blob)
@@ -306,6 +346,10 @@ namespace OpenSim.Framework
{
SizeX = pTerrain.GetLength(0);
SizeY = pTerrain.GetLength(1);
+ m_taintSizeX = SizeX / Constants.TerrainPatchSize;
+ m_taintStrideForY = m_taintSizeX / Constants.TerrainPatchSize;
+ m_taintSizeY = SizeY / Constants.TerrainPatchSize;
+
SizeZ = (int)Constants.RegionHeight;
CompressionFactor = 100.0f;
@@ -320,8 +364,7 @@ namespace OpenSim.Framework
}
// m_log.DebugFormat("{0} new by doubles. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
- m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
- ClearTaint();
+ m_taint = new BitArray(m_taintSizeX * m_taintSizeY, false);
}
// Create underlying structures but don't initialize the heightmap assuming the caller will immediately do that
@@ -330,11 +373,14 @@ namespace OpenSim.Framework
SizeX = pX;
SizeY = pY;
SizeZ = pZ;
+ m_taintSizeX = SizeX / Constants.TerrainPatchSize;
+ m_taintStrideForY = m_taintSizeX / Constants.TerrainPatchSize;
+ m_taintSizeY = SizeY / Constants.TerrainPatchSize;
CompressionFactor = 100.0f;
m_heightmap = new float[SizeX, SizeY];
- m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
+ m_taint = new BitArray(m_taintSizeX * m_taintSizeY, false);
+
// m_log.DebugFormat("{0} new by dimensions. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
- ClearTaint();
ClearLand(0f);
}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index 603d32165e..27ba809015 100755
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -121,6 +121,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain
sendAllcurrentY = 0;
}
+ public PatchUpdates(TerrainData terrData, ScenePresence pPresence, bool defaultState)
+ {
+ xsize = terrData.SizeX / Constants.TerrainPatchSize;
+ ysize = terrData.SizeY / Constants.TerrainPatchSize;
+ updated = new BitArray(xsize * ysize, true);
+ updateCount = defaultState ? xsize * ysize : 0;
+ Presence = pPresence;
+ sendAll = defaultState;
+ sendAllcurrentX = 0;
+ sendAllcurrentY = 0;
+ }
+
// Returns 'true' if there are any patches marked for sending
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public bool HasUpdates()
@@ -140,17 +152,23 @@ namespace OpenSim.Region.CoreModules.World.Terrain
return updated[patchX + xsize * patchY];
}
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
+ public bool GetByPatch(int indx)
+ {
+ return updated[indx];
+ }
+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public bool GetByPatchAndClear(int patchX, int patchY)
{
int indx = patchX + xsize * patchY;
- bool ret = updated[indx];
- if(ret)
+ if(updated[indx])
{
updated[indx] = false;
--updateCount;
+ return true;
}
- return ret;
+ return false;
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
@@ -162,12 +180,54 @@ namespace OpenSim.Region.CoreModules.World.Terrain
if (state)
{
if (!prevState)
- updateCount++;
+ ++updateCount;
}
else
{
if (prevState)
- updateCount--;
+ --updateCount;
+ }
+ }
+
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
+ public void SetTrueByPatch(int patchX, int patchY)
+ {
+ int indx = patchX + xsize * patchY;
+ if (!updated[indx])
+ {
+ updated[indx] = true;
+ ++updateCount;
+ }
+ }
+
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
+ public void SetTrueByPatch(int indx)
+ {
+ if (!updated[indx])
+ {
+ updated[indx] = true;
+ ++updateCount;
+ }
+ }
+
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
+ public void SetFalseByPatch(int patchX, int patchY)
+ {
+ int indx = patchX + xsize * patchY;
+ if (updated[indx])
+ {
+ updated[indx] = false;
+ --updateCount;
+ }
+ }
+
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
+ public void SetFalseByPatch(int indx)
+ {
+ if (updated[indx])
+ {
+ updated[indx] = false;
+ --updateCount;
}
}
@@ -199,16 +259,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
);
}
- for (int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize)
+ for (int indx = 0; indx < updated.Length; ++indx)
{
- for (int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize)
- {
- // Only set tainted. The patch bit may be set if the patch was to be sent later.
- if (terrData.IsTaintedAt(xx, yy, false))
- {
- SetByXY(xx, yy, true);
- }
- }
+ if (terrData.IsTaintedAtPatch(indx))
+ SetTrueByPatch(indx);
}
}
}
@@ -638,7 +692,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence);
m_perClientPatchUpdates.Add(presence.UUID, pups);
}
- pups.SetAll(true);
+ else
+ pups.SetAll(true);
}
}
}
@@ -896,15 +951,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain
// dont overlap execution
if(Monitor.TryEnter(TerrainCheckUpdatesLock))
{
- // this needs fixing
TerrainData terrData = m_channel.GetTerrainData();
-
bool shouldTaint = false;
- for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
+
+ int sx = terrData.SizeX / Constants.TerrainPatchSize;
+ for (int y = 0, py = 0; y < terrData.SizeY / Constants.TerrainPatchSize; y++, py += sx)
{
- for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
+ for (int x = 0; x < sx; x++)
{
- if (terrData.IsTaintedAt(x, y,true))
+ if (terrData.IsTaintedAtPatchWithClear(x + py))
{
// Found a patch that was modified. Push this flag into the clients.
SendToClients(terrData, x, y);
@@ -1010,8 +1065,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{
for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
{
- if (terrData.IsTaintedAt(x, y, false /* clearOnTest */))
- {
+ if (terrData.IsTaintedAt(x, y))
+ {
// If we should respect the estate settings then
// fixup and height deltas that don't respect them.
// Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values.
@@ -1031,8 +1086,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{
for (int y = startX; y <= endY; y += Constants.TerrainPatchSize)
{
- if (terrData.IsTaintedAt(x, y, false /* clearOnTest */))
- {
+ if (terrData.IsTaintedAt(x, y))
+ {
// If we should respect the estate settings then
// fixup and height deltas that don't respect them.
// Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values.
@@ -1088,9 +1143,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
/// Sends a copy of the current terrain to the scenes clients
///
/// A copy of the terrain as a 1D float array of size w*h
- /// The patch corner to send
- /// The patch corner to send
- private void SendToClients(TerrainData terrData, int x, int y)
+ /// x patch coords
+ /// y patch coords
+ private void SendToClients(TerrainData terrData, int px, int py)
{
if (m_sendTerrainUpdatesByViewDistance)
{
@@ -1099,14 +1154,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{
m_scene.ForEachScenePresence(presence =>
{
- PatchUpdates thisClientUpdates;
- if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates))
+ if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out PatchUpdates thisClientUpdates))
{
- // There is a ScenePresence without a send patch map. Create one.
- thisClientUpdates = new PatchUpdates(terrData, presence);
+ // There is a ScenePresence without a send patch map. Create one. should not happen
+ thisClientUpdates = new PatchUpdates(terrData, presence, false);
m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates);
}
- thisClientUpdates.SetByXY(x, y, true);
+ thisClientUpdates.SetTrueByPatch(px, py);
}
);
}
@@ -1116,7 +1170,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
// Legacy update sending where the update is sent out as soon as noticed
// We know the actual terrain data that is passed is ignored so this passes a dummy heightmap.
//float[] heightMap = terrData.GetFloatsSerialized();
- int[] map = new int[]{ x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize };
+ int[] map = new int[]{px, py};
m_scene.ForEachClient(
delegate (IClientAPI controller)
{
@@ -1319,20 +1373,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain
DrawDistance *= DrawDistance;
- for (int y = startY; y < endY; y++)
+ for (int y = startY, py = startY * limitX; y < endY; y++, py += limitX)
{
distysq = y - testposY;
distysq *= distysq;
distlimitsq = DrawDistance - distysq;
for (int x = startX; x < endX; x++)
{
- if (pups.GetByPatch(x, y))
+ int indx = x + py;
+ if (pups.GetByPatch(indx))
{
distxsq = x - testposX;
distxsq *= distxsq;
if (distxsq < distlimitsq)
{
- pups.SetByPatch(x, y, false);
+ pups.SetFalseByPatch(x + py);
ret.Add(new PatchesToSend(x, y, distxsq + distysq));
if (npatchs++ > 1024)
{