diff --git a/OpenSim/Region/CoreModules/World/Terrain/Features/RectangleFeature.cs b/OpenSim/Region/CoreModules/World/Terrain/Features/RectangleFeature.cs deleted file mode 100644 index 33c3fbe35b..0000000000 --- a/OpenSim/Region/CoreModules/World/Terrain/Features/RectangleFeature.cs +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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. - */ - -using System; -using OpenSim.Region.CoreModules.World.Terrain; -using OpenSim.Region.Framework.Interfaces; - -namespace OpenSim.Region.CoreModules.World.Terrain.Features -{ - public class RectangleFeature : TerrainFeature - { - public RectangleFeature(ITerrainModule module) : base(module) - { - } - - public override string CreateFeature(ITerrainChannel map, string[] args) - { - string val; - string result; - if (args.Length < 7) - { - result = "Usage: " + GetUsage(); - } - else - { - result = String.Empty; - - float targetElevation; - val = base.parseFloat(args[3], out targetElevation); - if (val != String.Empty) - { - result = val; - } - - int xOrigin; - val = base.parseInt(args[4], out xOrigin); - if (val != String.Empty) - { - result = val; - } - else if (xOrigin < 0 || xOrigin >= map.Width) - { - result = "x-origin must be within the region"; - } - - int yOrigin; - val = base.parseInt(args[5], out yOrigin); - if (val != String.Empty) - { - result = val; - } - else if (yOrigin < 0 || yOrigin >= map.Height) - { - result = "y-origin must be within the region"; - } - - int xDelta; - val = base.parseInt(args[6], out xDelta); - if (val != String.Empty) - { - result = val; - } - else if (xDelta <= 0) - { - result = "x-size must be greater than zero"; - } - - int yDelta; - if (args.Length > 7) - { - val = base.parseInt(args[7], out yDelta); - if (val != String.Empty) - { - result = val; - } - else if (yDelta <= 0) - { - result = "y-size must be greater than zero"; - } - } - else - { - // no y-size.. make it square - yDelta = xDelta; - } - - // slightly more complex validation, if required. - if (result == String.Empty) - { - if (xOrigin + xDelta > map.Width) - { - result = "(x-origin + x-size) must be within the region size"; - } - else if (yOrigin + yDelta > map.Height) - { - result = "(y-origin + y-size) must be within the region size"; - } - } - - // if it's all good, then do the work - if (result == String.Empty) - { - int yPos = yOrigin + yDelta; - while(--yPos >= yOrigin) - { - int xPos = xOrigin + xDelta; - while(--xPos >= xOrigin) - { - map[xPos, yPos] = (double)targetElevation; - } - } - } - } - - return result; - } - - public override string GetUsage() - { - return "rectangle []"; - } - } - -} - diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainFeature.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs similarity index 56% rename from OpenSim/Region/CoreModules/World/Terrain/TerrainFeature.cs rename to OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs index 701a729d2e..0e0a0e4569 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainFeature.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs @@ -24,65 +24,53 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using System; -using System.Reflection; +using System; using OpenSim.Region.Framework.Interfaces; namespace OpenSim.Region.CoreModules.World.Terrain { - public abstract class TerrainFeature : ITerrainFeature + public interface ITerrainModifier { - protected ITerrainModule m_module; + /// + /// Creates the feature. + /// + /// + /// Empty string if successful, otherwise error message. + /// + /// + /// ITerrainChannel holding terrain data. + /// + /// + /// command-line arguments from console. + /// + string ModifyTerrain(ITerrainChannel map, string[] args); - protected TerrainFeature(ITerrainModule module) - { - m_module = module; - } - - public abstract string CreateFeature(ITerrainChannel map, string[] args); - - public abstract string GetUsage(); - - protected string parseFloat(String s, out float f) - { - string result; - double d; - if (Double.TryParse(s, out d)) - { - try - { - f = (float)d; - result = String.Empty; - } - catch(InvalidCastException) - { - result = String.Format("{0} is invalid", s); - f = -1.0f; - } - } - else - { - f = -1.0f; - result = String.Format("{0} is invalid", s); - } - return result; - } - - protected string parseInt(String s, out int i) - { - string result; - if (Int32.TryParse(s, out i)) - { - result = String.Empty; - } - else - { - result = String.Format("{0} is invalid", s); - } - return result; - } + /// + /// Gets a string describing the usage. + /// + /// + /// A string describing parameters for creating the feature. + /// Format is "feature-name ..." + /// + string GetUsage(); + /// + /// Apply the appropriate operation on the specified map, at (x, y). + /// + /// + /// Map. + /// + /// + /// Data. + /// + /// + /// X. + /// + /// + /// Y. + /// + double operate(double[,] map, TerrainModifierData data, int x, int y); } } diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs new file mode 100644 index 0000000000..0df7132417 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs @@ -0,0 +1,94 @@ +/* + * 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. + */ +using System; + +using OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class FillModifier : TerrainModifier + { + + public FillModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "fill [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nSets all points within the specified range to the specified value."; + return val; + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double factor = this.computeBevel(data, x, y); + double result = data.elevation - (data.elevation - data.bevelevation) * factor; + return result; + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs new file mode 100644 index 0000000000..3e4a457843 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs @@ -0,0 +1,93 @@ +/* + * 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. + */ +using System; +using OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class LowerModifier : TerrainModifier + { + public LowerModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "lower [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nLowers all points within the specified range by the specified amount."; + return val; + + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double factor = this.computeBevel(data, x, y); + double result = map[x, y] - (data.elevation - (data.elevation - data.bevelevation) * factor); + return result; + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs new file mode 100644 index 0000000000..02f185267c --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs @@ -0,0 +1,93 @@ +/* + * 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. + */ +using System; +using OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class MaxModifier : TerrainModifier + { + public MaxModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "max [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nEnsures that all points within the specified range are no higher than the specified value."; + return val; + + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double factor = this.computeBevel(data, x, y); + double result = Math.Min(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]); + return result; + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs new file mode 100644 index 0000000000..2db49c852c --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs @@ -0,0 +1,93 @@ +/* + * 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. + */ +using System; +using OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class MinModifier : TerrainModifier + { + public MinModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "min [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nEnsures that all points within the specified range are no lower than the specified value."; + return val; + + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double factor = this.computeBevel(data, x, y); + double result = Math.Max(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]); + return result; + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs new file mode 100644 index 0000000000..53a64dfc51 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs @@ -0,0 +1,109 @@ +/* + * 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. + */ +using System; +using OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class NoiseModifier : TerrainModifier + { + public NoiseModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.bevel == "taper") + { + if (data.bevelevation < 0.0 || data.bevelevation > 1.0) + { + result = String.Format("Taper must be 0.0 to 1.0: {0}", data.bevelevation); + } + } + else + { + data.bevelevation = 1.0f; + } + + if (data.elevation < 0.0 || data.elevation > 1.0) + { + result = String.Format("Noise strength must be 0.0 to 1.0: {0}", data.elevation); + } + + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "noise [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nAdds noise to all points within the specified range."; + return val; + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double factor = this.computeBevel(data, x, y); + double noise = TerrainUtil.PerlinNoise2D((double)x / map.GetLength(0), (double)y / map.GetLength(1), 8, 1.0); + return map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor) * (noise - .5); + } + + } + +} diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs new file mode 100644 index 0000000000..9ac1edd88c --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs @@ -0,0 +1,93 @@ +/* + * 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. + */ +using System; +using OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class RaiseModifier : TerrainModifier + { + public RaiseModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "raise [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nRaises all points within the specified range by the specified amount."; + return val; + + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double factor = this.computeBevel(data, x, y); + double result = map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor); + return result; + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs new file mode 100644 index 0000000000..72b172c5d1 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs @@ -0,0 +1,132 @@ +/* + * 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. + */ +using System; +using OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class SmoothModifier : TerrainModifier + { + public SmoothModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.bevel == "taper") + { + if (data.bevelevation < 0.01 || data.bevelevation > 0.99) + { + result = String.Format("Taper must be 0.01 to 0.99: {0}", data.bevelevation); + } + } + else + { + data.bevelevation = 2.0f / 3.0f; + } + + if (data.elevation < 0.0 || data.elevation > 1.0) + { + result = String.Format("Smoothing strength must be 0.0 to 1.0: {0}", data.elevation); + } + + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "smooth [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nSmooths all points within the specified range using a simple averaging algorithm."; + return val; + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double[] scale = new double[3]; + scale[0] = data.elevation; + scale[1] = ((1.0 - scale[0]) * data.bevelevation) / 8.0; + scale[2] = ((1.0 - scale[0]) * (1.0 - data.bevelevation)) / 16.0; + int xMax = map.GetLength(0); + int yMax = map.GetLength(1); + double result; + if ((x == 0) || (y == 0) || (x == (xMax - 1)) || (y == (yMax - 1))) + { + result = map[x, y]; + } + else + { + result = 0.0; + for(int yPos = (y - 2); yPos < (y + 3); yPos++) + { + int yVal = (yPos <= 0) ? 0 : ((yPos < yMax) ? yPos : yMax - 1); + for(int xPos = (x - 2); xPos < (x + 3); xPos++) + { + int xVal = (xPos <= 0) ? 0 : ((xPos < xMax) ? xPos : xMax - 1); + int dist = Math.Max(Math.Abs(x - xVal), Math.Abs(y - yVal)); + result += map[xVal, yVal] * scale[dist]; + } + } + } + return result; + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs new file mode 100644 index 0000000000..7ebd08e728 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs @@ -0,0 +1,378 @@ +/* + * 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. + */ +using System; +using System.Reflection; +using log4net; + +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain +{ + public abstract class TerrainModifier : ITerrainModifier + { + protected ITerrainModule m_module; + protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected TerrainModifier(ITerrainModule module) + { + m_module = module; + } + + public abstract string ModifyTerrain(ITerrainChannel map, string[] args); + + public abstract string GetUsage(); + + public abstract double operate(double[,] map, TerrainModifierData data, int x, int y); + + protected String parseParameters(string[] args, out TerrainModifierData data) + { + string val; + string arg; + string result; + data = new TerrainModifierData(); + data.shape = String.Empty; + data.bevel = String.Empty; + data.dx = 0; + data.dy = 0; + if (args.Length < 4) + { + result = "Usage: " + GetUsage(); + } + else + { + result = this.parseFloat(args[3], out data.elevation); + } + if (result == String.Empty) + { + int index = 3; + while(++index < args.Length && result == String.Empty) + { + arg = args[index]; + // check for shape + if (arg.StartsWith("-rec=") || arg.StartsWith("-ell=")) + { + if (data.shape != String.Empty) + { + result = "Only 1 '-rec' or '-ell' parameter is permitted."; + } + else + { + data.shape = arg.StartsWith("-ell=") ? "ellipse" : "rectangle"; + val = arg.Substring(arg.IndexOf("=") + 1); + string[] coords = val.Split(new char[] {','}); + if ((coords.Length < 3) || (coords.Length > 4)) + { + result = String.Format("Bad format for shape parameter {0}", arg); + } + else + { + result = this.parseInt(coords[0], out data.x0); + if (result == String.Empty) + { + result = this.parseInt(coords[1], out data.y0); + } + if (result == String.Empty) + { + result = this.parseInt(coords[2], out data.dx); + } + if (result == String.Empty) + { + if (coords.Length == 4) + { + result = this.parseInt(coords[3], out data.dy); + } + else + { + data.dy = data.dx; + } + } + if (result == String.Empty) + { + if ((data.dx <= 0) || (data.dy <= 0)) + { + result = "Shape sizes must be positive integers"; + } + } + else + { + result = String.Format("Bad value in shape parameters {0}", arg); + } + } + } + } + else if (arg.StartsWith("-taper=")) + { + if (data.bevel != String.Empty) + { + result = "Only 1 '-taper' parameter is permitted."; + } + else + { + data.bevel = "taper"; + val = arg.Substring(arg.IndexOf("=") + 1); + result = this.parseFloat(val, out data.bevelevation); + if (result != String.Empty) + { + result = String.Format("Bad format for taper parameter {0}", arg); + } + } + } + else + { + result = String.Format("Unrecognized parameter {0}", arg); + } + } + } + return result; + } + + protected string parseFloat(String s, out float f) + { + string result; + double d; + if (Double.TryParse(s, out d)) + { + try + { + f = (float)d; + result = String.Empty; + } + catch(InvalidCastException) + { + result = String.Format("{0} is invalid", s); + f = -1.0f; + } + } + else + { + f = -1.0f; + result = String.Format("{0} is invalid", s); + } + return result; + } + + protected string parseInt(String s, out int i) + { + string result; + if (Int32.TryParse(s, out i)) + { + result = String.Empty; + } + else + { + result = String.Format("{0} is invalid", s); + } + return result; + } + + protected void applyModification(ITerrainChannel map, TerrainModifierData data) + { + bool[,] mask; + int xMax; + int yMax; + int xMid; + int yMid; + if (data.shape == "ellipse") + { + mask = this.ellipticalMask(data.dx, data.dy); + xMax = mask.GetLength(0); + yMax = mask.GetLength(1); + xMid = xMax / 2 + xMax % 2; + yMid = yMax / 2 + yMax % 2; + } + else + { + mask = this.rectangularMask(data.dx, data.dy); + xMax = mask.GetLength(0); + yMax = mask.GetLength(1); + xMid = 0; + yMid = 0; + } +// m_log.DebugFormat("Apply {0} mask {1}x{2} @ {3},{4}", data.shape, xMax, yMax, xMid, yMid); + double[,] buffer = map.GetDoubles(); + int yDim = yMax; + while(--yDim >= 0) + { + int yPos = data.y0 + yDim - yMid; + if ((yPos >= 0) && (yPos < map.Height)) + { + int xDim = xMax; + while(--xDim >= 0) + { + int xPos = data.x0 + xDim - xMid; + if ((xPos >= 0) && (xPos < map.Width) && (mask[xDim, yDim])) + { + double endElevation = this.operate(buffer, data, xPos, yPos); + map[xPos, yPos] = endElevation; + } + } + } + } + } + + protected double computeBevel(TerrainModifierData data, int x, int y) + { + int deltaX; + int deltaY; + int xMax; + int yMax; + double factor; + if (data.bevel == "taper") + { + if (data.shape == "ellipse") + { + deltaX = x - data.x0; + deltaY = y - data.y0; + xMax = data.dx; + yMax = data.dy; + factor = (double)((deltaX * deltaX) + (deltaY * deltaY)); + factor /= ((xMax * xMax) + (yMax * yMax)); + } + else + { + // pyramid + xMax = data.dx / 2 + data.dx % 2; + yMax = data.dy / 2 + data.dy % 2; + deltaX = Math.Abs(data.x0 + xMax - x); + deltaY = Math.Abs(data.y0 + yMax - y); + factor = Math.Max(((double)(deltaY) / yMax), ((double)(deltaX) / xMax)); + } + } + else + { + factor = 0.0; + } + return factor; + } + + private bool[,] rectangularMask(int xSize, int ySize) + { + bool[,] mask = new bool[xSize, ySize]; + int yPos = ySize; + while(--yPos >= 0) + { + int xPos = xSize; + while(--xPos >= 0) + { + mask[xPos, yPos] = true; + } + } + return mask; + } + + /* + * Fast ellipse-based derivative of Bresenham algorithm. + * https://web.archive.org/web/20120225095359/http://homepage.smc.edu/kennedy_john/belipse.pdf + */ + private bool[,] ellipticalMask(int xRadius, int yRadius) + { + long twoASquared = 2L * xRadius * xRadius; + long twoBSquared = 2L * yRadius * yRadius; + + bool[,] mask = new bool[2 * xRadius + 1, 2 * yRadius + 1]; + + long ellipseError = 0L; + long stoppingX = twoBSquared * xRadius; + long stoppingY = 0L; + long xChange = yRadius * yRadius * (1L - 2L * xRadius); + long yChange = xRadius * xRadius; + + int xPos = xRadius; + int yPos = 0; + + // first set of points + while(stoppingX >= stoppingY) + { + int yUpper = yRadius + yPos; + int yLower = yRadius - yPos; + // fill in the mask + int xNow = xPos; + while(xNow >= 0) + { + mask[xRadius + xNow, yUpper] = true; + mask[xRadius - xNow, yUpper] = true; + mask[xRadius + xNow, yLower] = true; + mask[xRadius - xNow, yLower] = true; + --xNow; + } + yPos++; + stoppingY += twoASquared; + ellipseError += yChange; + yChange += twoASquared; + if ((2L * ellipseError + xChange) > 0L) + { + xPos--; + stoppingX -= twoBSquared; + ellipseError += xChange; + xChange += twoBSquared; + } + } + + // second set of points + xPos = 0; + yPos = yRadius; + xChange = yRadius * yRadius; + yChange = xRadius * xRadius * (1L - 2L * yRadius); + + ellipseError = 0L; + stoppingX = 0L; + stoppingY = twoASquared * yRadius; + + while(stoppingX <= stoppingY) + { + int xUpper = xRadius + xPos; + int xLower = xRadius - xPos; + // fill in the mask + int yNow = yPos; + while(yNow >= 0) + { + mask[xUpper, yRadius + yNow] = true; + mask[xUpper, yRadius - yNow] = true; + mask[xLower, yRadius + yNow] = true; + mask[xLower, yRadius - yNow] = true; + --yNow; + } + xPos++; + stoppingX += twoBSquared; + ellipseError += xChange; + xChange += twoBSquared; + if ((2L * ellipseError + yChange) > 0L) + { + yPos--; + stoppingY -= twoASquared; + ellipseError += yChange; + yChange += twoASquared; + } + } + return mask; + } + + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs new file mode 100644 index 0000000000..4e0f8d7141 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs @@ -0,0 +1,17 @@ +using System; + +namespace OpenSim.Region.CoreModules.World.Terrain +{ + public struct TerrainModifierData + { + public float elevation; + public string shape; + public int x0; + public int y0; + public int dx; + public int dy; + public string bevel; + public float bevelevation; + } +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 3bb804098c..05c5fca014 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -24,7 +24,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - using System; using System.Collections.Generic; using System.IO; @@ -42,7 +41,7 @@ using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Region.CoreModules.Framework.InterfaceCommander; using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; -using OpenSim.Region.CoreModules.World.Terrain.Features; +using OpenSim.Region.CoreModules.World.Terrain.Modifiers; using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes; using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; using OpenSim.Region.Framework.Interfaces; @@ -75,14 +74,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain #endregion - /// - /// Terrain Features - /// - public enum TerrainFeatures: byte - { - Rectangle = 1, - } - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); #pragma warning disable 414 @@ -90,26 +81,19 @@ namespace OpenSim.Region.CoreModules.World.Terrain #pragma warning restore 414 private readonly Commander m_commander = new Commander("terrain"); - private readonly Dictionary m_floodeffects = new Dictionary(); - private readonly Dictionary m_loaders = new Dictionary(); - private readonly Dictionary m_painteffects = new Dictionary(); - private Dictionary m_plugineffects; - - private Dictionary m_featureEffects = - new Dictionary(); - + private Dictionary m_modifyOperations = + new Dictionary(); private ITerrainChannel m_channel; private ITerrainChannel m_revert; private Scene m_scene; private volatile bool m_tainted; private readonly Stack m_undo = new Stack(5); - private String m_InitialTerrain = "pinhead-island"; // If true, send terrain patch updates to clients based on their view distance @@ -136,14 +120,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain { return (updateCount > 0); } + public void SetByXY(int x, int y, bool state) { this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state); } + public bool GetByPatch(int patchX, int patchY) { return updated[patchX, patchY]; } + public void SetByPatch(int patchX, int patchY, bool state) { bool prevState = updated[patchX, patchY]; @@ -153,11 +140,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain updateCount--; updated[patchX, patchY] = state; } + public void SetAll(bool state) { updateCount = 0; - for (int xx = 0; xx < updated.GetLength(0); xx++) - for (int yy = 0; yy < updated.GetLength(1); yy++) + for(int xx = 0; xx < updated.GetLength(0); xx++) + for(int yy = 0; yy < updated.GetLength(1); yy++) updated[xx, yy] = state; if (state) updateCount = updated.GetLength(0) * updated.GetLength(1); @@ -174,9 +162,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize) ); } - for (int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize) + for(int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize) { - for (int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize) + 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)) @@ -201,8 +189,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain #region ICommandableModule Members - public ICommander CommandInterface - { + public ICommander CommandInterface { get { return m_commander; } } @@ -230,7 +217,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_scene = scene; // Install terrain module in the simulator - lock (m_scene) + lock(m_scene) { if (m_scene.Heightmap == null) { @@ -262,7 +249,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain string supportedFilesSeparatorForTileSave = ""; m_supportFileExtensionsForTileSave = ""; - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { m_supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")"; supportedFilesSeparator = ", "; @@ -285,7 +272,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain public void RemoveRegion(Scene scene) { - lock (m_scene) + lock(m_scene) { // remove the commands m_scene.UnregisterModuleCommander(m_commander.Name); @@ -304,13 +291,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain { } - public Type ReplaceableInterface - { + public Type ReplaceableInterface { get { return null; } } - public string Name - { + public string Name { get { return "TerrainModule"; } } @@ -329,11 +314,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// Filename to terrain file. Type is determined by extension. public void LoadFromFile(string filename) { - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { if (filename.EndsWith(loader.Key)) { - lock (m_scene) + lock(m_scene) { try { @@ -349,20 +334,20 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_channel = channel; UpdateRevertMap(); } - catch (NotImplementedException) + catch(NotImplementedException) { m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + " parser does not support file loading. (May be save only)"); throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value)); } - catch (FileNotFoundException) + catch(FileNotFoundException) { m_log.Error( "[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)"); throw new TerrainException( String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename)); } - catch (ArgumentException e) + catch(ArgumentException e) { m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message); throw new TerrainException( @@ -386,7 +371,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain { try { - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { if (filename.EndsWith(loader.Key)) { @@ -396,7 +381,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain } } } - catch (IOException ioe) + catch(IOException ioe) { m_log.Error(String.Format("[TERRAIN]: Unable to save to {0}, {1}", filename, ioe.Message)); } @@ -429,11 +414,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain public void LoadFromStream(string filename, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement, Stream stream) { - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { if (filename.EndsWith(loader.Key)) { - lock (m_scene) + lock(m_scene) { try { @@ -441,7 +426,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement); UpdateRevertMap(); } - catch (NotImplementedException) + catch(NotImplementedException) { m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + " parser does not support file loading. (May be save only)"); @@ -501,7 +486,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain { try { - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { if (filename.EndsWith(loader.Key)) { @@ -510,7 +495,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain } } } - catch (NotImplementedException) + catch(NotImplementedException) { m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented."); throw new TerrainException(String.Format("Unable to save heightmap: saving of this file format not implemented")); @@ -519,12 +504,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients. // ITerrainModule.TaintTerrain() - public void TaintTerrain () + public void TaintTerrain() { - lock (m_perClientPatchUpdates) + lock(m_perClientPatchUpdates) { // Set the flags for all clients so the tainted patches will be sent out - foreach (PatchUpdates pups in m_perClientPatchUpdates.Values) + foreach(PatchUpdates pups in m_perClientPatchUpdates.Values) { pups.SetAll(m_scene.Heightmap.GetTerrainData()); } @@ -539,7 +524,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId); if (presence != null) { - lock (m_perClientPatchUpdates) + lock(m_perClientPatchUpdates) { PatchUpdates pups; if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups)) @@ -572,7 +557,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain return; string[] files = Directory.GetFiles(plugineffectsPath); - foreach (string file in files) + foreach(string file in files) { m_log.Info("Loading effects in " + file); try @@ -580,7 +565,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain Assembly library = Assembly.LoadFrom(file); LoadPlugins(library); } - catch (BadImageFormatException) + catch(BadImageFormatException) { } } @@ -588,7 +573,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void LoadPlugins(Assembly library) { - foreach (Type pluginType in library.GetTypes()) + foreach(Type pluginType in library.GetTypes()) { try { @@ -610,7 +595,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_log.Info("L ... " + typeName); } } - catch (AmbiguousMatchException) + catch(AmbiguousMatchException) { } } @@ -618,7 +603,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain public void InstallPlugin(string pluginName, ITerrainEffect effect) { - lock (m_plugineffects) + lock(m_plugineffects) { if (!m_plugineffects.ContainsKey(pluginName)) { @@ -661,8 +646,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea(); m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert); - // Terrain Feature effects - m_featureEffects["rectangle"] = new RectangleFeature(this); + // Terrain Modifier operations + m_modifyOperations["min"] = new MinModifier(this); + m_modifyOperations["max"] = new MaxModifier(this); + m_modifyOperations["raise"] = new RaiseModifier(this); + m_modifyOperations["lower"] = new LowerModifier(this); + m_modifyOperations["fill"] = new FillModifier(this); + m_modifyOperations["smooth"] = new SmoothModifier(this); + m_modifyOperations["noise"] = new NoiseModifier(this); // Filesystem load/save loaders m_loaders[".r32"] = new RAW32(); @@ -707,22 +698,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// Where to begin our slice public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY) { - int offsetX = (int) m_scene.RegionInfo.RegionLocX - fileStartX; - int offsetY = (int) m_scene.RegionInfo.RegionLocY - fileStartY; + int offsetX = (int)m_scene.RegionInfo.RegionLocX - fileStartX; + int offsetY = (int)m_scene.RegionInfo.RegionLocY - fileStartY; if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight) { // this region is included in the tile request - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { if (filename.EndsWith(loader.Key)) { - lock (m_scene) + lock(m_scene) { ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, fileWidth, fileHeight, - (int) m_scene.RegionInfo.RegionSizeX, - (int) m_scene.RegionInfo.RegionSizeY); + (int)m_scene.RegionInfo.RegionSizeX, + (int)m_scene.RegionInfo.RegionSizeY); m_scene.Heightmap = channel; m_channel = channel; UpdateRevertMap(); @@ -761,11 +752,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain } // this region is included in the tile request - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { if (filename.EndsWith(loader.Key) && loader.Value.SupportsTileSave()) { - lock (m_scene) + lock(m_scene) { loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, fileWidth, fileHeight, @@ -799,9 +790,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain TerrainData terrData = m_channel.GetTerrainData(); bool shouldTaint = false; - for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) + for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) { - for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) + for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) { if (terrData.IsTaintedAt(x, y)) { @@ -856,7 +847,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain string[] tmpArgs = new string[args.Length - 2]; int i; - for (i = 2; i < args.Length; i++) + for(i = 2; i < args.Length; i++) tmpArgs[i - 2] = args[i]; m_commander.ProcessConsoleCommand(args[1], tmpArgs); @@ -890,7 +881,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain; } - lock (m_perClientPatchUpdates) + lock(m_perClientPatchUpdates) m_perClientPatchUpdates.Remove(client); } @@ -904,12 +895,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain TerrainData terrData = m_channel.GetTerrainData(); bool wasLimited = false; - for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) + for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) { - for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) + for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) { if (terrData.IsTaintedAt(x, y, false /* clearOnTest */)) - { + { // 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. @@ -933,9 +924,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain // loop through the height map for this patch and compare it against // the revert map - for (int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) + for(int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) { - for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) + for(int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) { float requestedHeight = terrData[x, y]; float bakedHeight = (float)m_revert[x, y]; @@ -959,7 +950,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void client_OnLandUndo(IClientAPI client) { - lock (m_undo) + lock(m_undo) { if (m_undo.Count > 0) { @@ -981,19 +972,19 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (m_sendTerrainUpdatesByViewDistance) { // Add that this patch needs to be sent to the accounting for each client. - lock (m_perClientPatchUpdates) + lock(m_perClientPatchUpdates) { m_scene.ForEachScenePresence(presence => + { + PatchUpdates thisClientUpdates; + if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) { - PatchUpdates thisClientUpdates; - if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) - { - // There is a ScenePresence without a send patch map. Create one. - thisClientUpdates = new PatchUpdates(terrData, presence); - m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); - } - thisClientUpdates.SetByXY(x, y, true); + // There is a ScenePresence without a send patch map. Create one. + thisClientUpdates = new PatchUpdates(terrData, presence); + m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); } + thisClientUpdates.SetByXY(x, y, true); + } ); } } @@ -1005,11 +996,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain float[] heightMap = new float[10]; m_scene.ForEachClient( delegate(IClientAPI controller) - { - controller.SendLayerData(x / Constants.TerrainPatchSize, + { + controller.SendLayerData(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, heightMap); - } + } ); } } @@ -1019,12 +1010,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain public int PatchX; public int PatchY; public float Dist; + public PatchesToSend(int pX, int pY, float pDist) { PatchX = pX; PatchY = pY; Dist = pDist; } + public int CompareTo(PatchesToSend other) { return Dist.CompareTo(other.Dist); @@ -1036,9 +1029,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain // Loop through all the per-client info and send any patches necessary. private void CheckSendingPatchesToClients() { - lock (m_perClientPatchUpdates) + lock(m_perClientPatchUpdates) { - foreach (PatchUpdates pups in m_perClientPatchUpdates.Values) + foreach(PatchUpdates pups in m_perClientPatchUpdates.Values) { if (pups.HasUpdates()) { @@ -1062,7 +1055,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain int[] yPieces = new int[toSend.Count]; float[] patchPieces = new float[toSend.Count * 2]; int pieceIndex = 0; - foreach (PatchesToSend pts in toSend) + foreach(PatchesToSend pts in toSend) { patchPieces[pieceIndex++] = pts.PatchX; patchPieces[pieceIndex++] = pts.PatchY; @@ -1083,25 +1076,25 @@ namespace OpenSim.Region.CoreModules.World.Terrain return ret; // Compute the area of patches within our draw distance - int startX = (((int) (presence.AbsolutePosition.X - presence.DrawDistance))/Constants.TerrainPatchSize) - 2; + int startX = (((int)(presence.AbsolutePosition.X - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2; startX = Math.Max(startX, 0); - startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize); - int startY = (((int) (presence.AbsolutePosition.Y - presence.DrawDistance))/Constants.TerrainPatchSize) - 2; + startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize); + int startY = (((int)(presence.AbsolutePosition.Y - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2; startY = Math.Max(startY, 0); - startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize); - int endX = (((int) (presence.AbsolutePosition.X + presence.DrawDistance))/Constants.TerrainPatchSize) + 2; + startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize); + int endX = (((int)(presence.AbsolutePosition.X + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2; endX = Math.Max(endX, 0); - endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize); - int endY = (((int) (presence.AbsolutePosition.Y + presence.DrawDistance))/Constants.TerrainPatchSize) + 2; + endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize); + int endY = (((int)(presence.AbsolutePosition.Y + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2; endY = Math.Max(endY, 0); - endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize); + endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize); // m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, start=<{4},{5}>, end=<{6},{7}>", // LogHeader, m_scene.RegionInfo.RegionName, // presence.DrawDistance, presence.AbsolutePosition, // startX, startY, endX, endY); - for (int x = startX; x < endX; x++) + for(int x = startX; x < endX; x++) { - for (int y = startY; y < endY; y++) + for(int y = startY; y < endY; y++) { //Need to make sure we don't send the same ones over and over Vector3 presencePos = presence.AbsolutePosition; @@ -1133,28 +1126,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain bool allowed = false; if (north == south && east == west) { - if (m_painteffects.ContainsKey((StandardTerrainEffects) action)) + if (m_painteffects.ContainsKey((StandardTerrainEffects)action)) { - bool[,] allowMask = new bool[m_channel.Width,m_channel.Height]; + bool[,] allowMask = new bool[m_channel.Width, m_channel.Height]; allowMask.Initialize(); int n = size + 1; if (n > 2) n = 4; - int zx = (int) (west + 0.5); - int zy = (int) (north + 0.5); + int zx = (int)(west + 0.5); + int zy = (int)(north + 0.5); int dx; - for (dx=-n; dx<=n; dx++) + for(dx=-n; dx<=n; dx++) { int dy; - for (dy=-n; dy<=n; dy++) + for(dy=-n; dy<=n; dy++) { int x = zx + dx; int y = zy + dy; - if (x>=0 && y>=0 && x= 0 && y >= 0 && x < m_channel.Width && y < m_channel.Height) { - if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0))) + if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) { allowMask[x, y] = true; allowed = true; @@ -1165,7 +1158,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (allowed) { StoreUndoState(); - m_painteffects[(StandardTerrainEffects) action].PaintEffect( + m_painteffects[(StandardTerrainEffects)action].PaintEffect( m_channel, allowMask, west, south, height, size, seconds); //revert changes outside estate limits @@ -1180,22 +1173,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain } else { - if (m_floodeffects.ContainsKey((StandardTerrainEffects) action)) + if (m_floodeffects.ContainsKey((StandardTerrainEffects)action)) { - bool[,] fillArea = new bool[m_channel.Width,m_channel.Height]; + bool[,] fillArea = new bool[m_channel.Width, m_channel.Height]; fillArea.Initialize(); int x; - for (x = 0; x < m_channel.Width; x++) + for(x = 0; x < m_channel.Width; x++) { int y; - for (y = 0; y < m_channel.Height; y++) + for(y = 0; y < m_channel.Height; y++) { if (x < east && x > west) { if (y < north && y > south) { - if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0))) + if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) { fillArea[x, y] = true; allowed = true; @@ -1208,7 +1201,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (allowed) { StoreUndoState(); - m_floodeffects[(StandardTerrainEffects) action].FloodEffect(m_channel, fillArea, size); + m_floodeffects[(StandardTerrainEffects)action].FloodEffect(m_channel, fillArea, size); //revert changes outside estate limits if (!god) @@ -1243,7 +1236,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void StoreUndoState() { - lock (m_undo) + lock(m_undo) { if (m_undo.Count > 0) { @@ -1264,21 +1257,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceLoadFile(Object[] args) { - LoadFromFile((string) args[0]); + LoadFromFile((string)args[0]); } private void InterfaceLoadTileFile(Object[] args) { - LoadFromFile((string) args[0], - (int) args[1], - (int) args[2], - (int) args[3], - (int) args[4]); + LoadFromFile((string)args[0], + (int)args[1], + (int)args[2], + (int)args[3], + (int)args[4]); } private void InterfaceSaveFile(Object[] args) { - SaveToFile((string) args[0]); + SaveToFile((string)args[0]); } private void InterfaceSaveTileFile(Object[] args) @@ -1298,8 +1291,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceRevertTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) - for (y = 0; y < m_channel.Height; y++) + for(x = 0; x < m_channel.Width; x++) + for(y = 0; y < m_channel.Height; y++) m_channel[x, y] = m_revert[x, y]; } @@ -1310,9 +1303,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (direction.ToLower().StartsWith("y")) { - for (int x = 0; x < m_channel.Width; x++) + for(int x = 0; x < m_channel.Width; x++) { - for (int y = 0; y < m_channel.Height / 2; y++) + for(int y = 0; y < m_channel.Height / 2; y++) { double height = m_channel[x, y]; double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y]; @@ -1324,9 +1317,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain } else if (direction.ToLower().StartsWith("x")) { - for (int y = 0; y < m_channel.Height; y++) + for(int y = 0; y < m_channel.Height; y++) { - for (int x = 0; x < m_channel.Width / 2; x++) + for(int x = 0; x < m_channel.Width / 2; x++) { double height = m_channel[x, y]; double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y]; @@ -1365,9 +1358,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain int width = m_channel.Width; int height = m_channel.Height; - for (int x = 0; x < width; x++) + for(int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) + for(int y = 0; y < height; y++) { double currHeight = m_channel[x, y]; if (currHeight < currMin) @@ -1388,12 +1381,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain //m_log.InfoFormat("Scale = {0}", scale); // scale the heightmap accordingly - for (int x = 0; x < width; x++) + for(int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) + for(int y = 0; y < height; y++) { - double currHeight = m_channel[x, y] - currMin; - m_channel[x, y] = desiredMin + (currHeight * scale); + double currHeight = m_channel[x, y] - currMin; + m_channel[x, y] = desiredMin + (currHeight * scale); } } @@ -1404,42 +1397,42 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceElevateTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) - for (y = 0; y < m_channel.Height; y++) - m_channel[x, y] += (double) args[0]; + for(x = 0; x < m_channel.Width; x++) + for(y = 0; y < m_channel.Height; y++) + m_channel[x, y] += (double)args[0]; } private void InterfaceMultiplyTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) - for (y = 0; y < m_channel.Height; y++) - m_channel[x, y] *= (double) args[0]; + for(x = 0; x < m_channel.Width; x++) + for(y = 0; y < m_channel.Height; y++) + m_channel[x, y] *= (double)args[0]; } private void InterfaceLowerTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) - for (y = 0; y < m_channel.Height; y++) - m_channel[x, y] -= (double) args[0]; + for(x = 0; x < m_channel.Width; x++) + for(y = 0; y < m_channel.Height; y++) + m_channel[x, y] -= (double)args[0]; } public void InterfaceFillTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) - for (y = 0; y < m_channel.Height; y++) - m_channel[x, y] = (double) args[0]; + for(x = 0; x < m_channel.Width; x++) + for(y = 0; y < m_channel.Height; y++) + m_channel[x, y] = (double)args[0]; } private void InterfaceMinTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) + for(x = 0; x < m_channel.Width; x++) { - for (y = 0; y < m_channel.Height; y++) + for(y = 0; y < m_channel.Height; y++) { m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); } @@ -1449,9 +1442,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceMaxTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) + for(x = 0; x < m_channel.Width; x++) { - for (y = 0; y < m_channel.Height; y++) + for(y = 0; y < m_channel.Height; y++) { m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); } @@ -1480,10 +1473,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain double sum = 0; int x; - for (x = 0; x < m_channel.Width; x++) + for(x = 0; x < m_channel.Width; x++) { int y; - for (y = 0; y < m_channel.Height; y++) + for(y = 0; y < m_channel.Height; y++) { sum += m_channel[x, y]; if (max < m_channel[x, y]) @@ -1501,7 +1494,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceEnableExperimentalBrushes(Object[] args) { - if ((bool) args[0]) + if ((bool)args[0]) { m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere(); m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere(); @@ -1520,7 +1513,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (firstArg == "list") { MainConsole.Instance.Output("List of loaded plugins"); - foreach (KeyValuePair kvp in m_plugineffects) + foreach(KeyValuePair kvp in m_plugineffects) { MainConsole.Instance.Output(kvp.Key); } @@ -1665,46 +1658,56 @@ namespace OpenSim.Region.CoreModules.World.Terrain // Add this to our scene so scripts can call these functions m_scene.RegisterModuleCommander(m_commander); - // Add Feature command to Scene, since Command object requires fixed-length arglists - m_scene.AddCommand("Terrain", this, "terrain feature", - "terrain feature ", "Constructs a feature of the requested type.", FeatureCommand); + // Add Modify command to Scene, since Command object requires fixed-length arglists + m_scene.AddCommand("Terrain", this, "terrain modify", + "terrain modify [] []", + "Modifies the terrain as instructed." + + "\nEach operation can be limited to an area of effect:" + + "\n * -ell=x,y,rx[,ry] constrains the operation to an ellipse centred at x,y" + + "\n * -rec=x,y,dx[,dy] constrains the operation to a rectangle based at x,y" + + "\nEach operation can have its effect tapered based on distance from centre:" + + "\n * elliptical operations taper as cones" + + "\n * rectangular operations taper as pyramids" + , + ModifyCommand); } - public void FeatureCommand(string module, string[] cmd) + public void ModifyCommand(string module, string[] cmd) { string result; if (cmd.Length > 2) { - string featureType = cmd[2]; + string operationType = cmd[2]; - ITerrainFeature feature; - if (!m_featureEffects.TryGetValue(featureType, out feature)) + ITerrainModifier operation; + if (!m_modifyOperations.TryGetValue(operationType, out operation)) { - result = String.Format("Terrain Feature \"{0}\" not found.", featureType); + result = String.Format("Terrain Modify \"{0}\" not found.", operationType); } - else if ((cmd.Length > 3) && (cmd[3] == "usage")) + else if ((cmd.Length > 3) && (cmd[3] == "usage")) { - result = "Usage: " + feature.GetUsage(); + result = "Usage: " + operation.GetUsage(); } else { - result = feature.CreateFeature(m_channel, cmd); + result = operation.ModifyTerrain(m_channel, cmd); } - if(result == String.Empty) + if (result == String.Empty) { - result = "Created Feature"; - m_log.DebugFormat("Created terrain feature {0}", featureType); + result = "Modified terrain"; + m_log.DebugFormat("Performed terrain operation {0}", operationType); } } else { - result = "Usage: ..."; + result = "Usage: ..."; } MainConsole.Instance.Output(result); } - #endregion + +#endregion } }