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) {