make main terrain taints also a bitarray

This commit is contained in:
UbitUmarov
2020-09-09 15:24:51 +01:00
parent 8b885a4c7f
commit 719e0d1c61
2 changed files with 158 additions and 57 deletions

View File

@@ -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);
}

View File

@@ -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
/// </summary>
/// <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="y">The patch corner to send</param>
private void SendToClients(TerrainData terrData, int x, int y)
/// <param name="px">x patch coords</param>
/// <param name="py">y patch coords</param>
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)
{