From 996309a6e1ee47d96d81c0bdfdd5bfc27db66efd Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Sun, 6 Apr 2008 13:48:28 +0000 Subject: * Various terrain engine fixes * Includes patch #894 fixes for terrain load-tile * Large number of other terrain fixes and new commands included. --- .../Modules/ModuleFramework/Commander.cs | 2 +- .../Modules/Terrain/FileLoaders/RAW32.cs | 51 ++++- .../Environment/Modules/Terrain/ITerrainEffect.cs | 2 +- .../Environment/Modules/Terrain/TerrainChannel.cs | 13 +- .../Environment/Modules/Terrain/TerrainModule.cs | 215 ++++++++++++++------- 5 files changed, 194 insertions(+), 89 deletions(-) (limited to 'OpenSim/Region/Environment/Modules') diff --git a/OpenSim/Region/Environment/Modules/ModuleFramework/Commander.cs b/OpenSim/Region/Environment/Modules/ModuleFramework/Commander.cs index 946a876..b6775b9 100644 --- a/OpenSim/Region/Environment/Modules/ModuleFramework/Commander.cs +++ b/OpenSim/Region/Environment/Modules/ModuleFramework/Commander.cs @@ -249,7 +249,7 @@ namespace OpenSim.Region.Environment.Modules.ModuleFramework { if (m_commands.ContainsKey(function)) { - if (args[0] == "help") + if (args.Length > 0 && args[0] == "help") { m_commands[function].ShowConsoleHelp(); } diff --git a/OpenSim/Region/Environment/Modules/Terrain/FileLoaders/RAW32.cs b/OpenSim/Region/Environment/Modules/Terrain/FileLoaders/RAW32.cs index fc81376..83ee341 100644 --- a/OpenSim/Region/Environment/Modules/Terrain/FileLoaders/RAW32.cs +++ b/OpenSim/Region/Environment/Modules/Terrain/FileLoaders/RAW32.cs @@ -62,30 +62,63 @@ namespace OpenSim.Region.Environment.Modules.Terrain.FileLoaders return "RAW32"; } - public ITerrainChannel LoadFile(string filename, int fileStartX, int fileStartY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight) + public ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight) { TerrainChannel retval = new TerrainChannel(sectionWidth, sectionHeight); FileInfo file = new FileInfo(filename); FileStream s = file.Open(FileMode.Open, FileAccess.Read); BinaryReader bs = new BinaryReader(s); + + int currFileXOffset = 0; + int currFileYOffset = 0; - // Advance to our section of the file - if (fileStartY * sectionHeight > 0) - bs.ReadBytes(fileStartY * sectionHeight); + // if our region isn't on the first Y section of the areas to be landscaped, then + // advance to our section of the file + while (currFileYOffset < offsetY) + { + // read a whole strip of regions + int heightsToRead = sectionHeight * (fileWidth * sectionWidth); + bs.ReadBytes( heightsToRead * 4); // because the floats are 4 bytes in the file + currFileYOffset++; + } + // got to the Y start offset within the file of our region + // so read the file bits associated with our region int x, y; - for (y = 0; y < retval.Height; y++) + // for each Y within our Y offset + for (y = 0; y < sectionHeight; y++) { - // Advance the stream if we aren't at the start of the section in the file - if (fileStartX * sectionWidth > 0) - bs.ReadBytes(fileStartX * sectionHeight); + currFileXOffset = 0; + + // if our region isn't the first X section of the areas to be landscaped, then + // advance the stream to the X start pos of our section in the file + // i.e. eat X upto where we start + while (currFileXOffset < offsetX) + { + bs.ReadBytes( sectionWidth * 4); // 4 bytes = single + currFileXOffset++; + } - for (x = 0; x < retval.Width; x++) + // got to our X offset, so write our regions X line + for (x = 0; x < sectionWidth; x++) { // Read a strip and continue retval[x, y] = bs.ReadSingle(); } + // record that we wrote it + currFileXOffset++; + + // if our region isn't the last X section of the areas to be landscaped, then + // advance the stream to the end of this Y column + while (currFileXOffset < fileWidth ) + { + // eat the next regions x line + bs.ReadBytes(sectionWidth * 4); // 4 bytes = single + currFileXOffset++; + } + + } bs.Close(); diff --git a/OpenSim/Region/Environment/Modules/Terrain/ITerrainEffect.cs b/OpenSim/Region/Environment/Modules/Terrain/ITerrainEffect.cs index 4d51324..5063e46 100644 --- a/OpenSim/Region/Environment/Modules/Terrain/ITerrainEffect.cs +++ b/OpenSim/Region/Environment/Modules/Terrain/ITerrainEffect.cs @@ -31,6 +31,6 @@ namespace OpenSim.Region.Environment.Modules.Terrain { public interface ITerrainEffect { - void RunEffect(ITerrainChannel map, double strength); + void RunEffect(ITerrainChannel map); } } diff --git a/OpenSim/Region/Environment/Modules/Terrain/TerrainChannel.cs b/OpenSim/Region/Environment/Modules/Terrain/TerrainChannel.cs index 6e1a5d6..01f6bdf 100644 --- a/OpenSim/Region/Environment/Modules/Terrain/TerrainChannel.cs +++ b/OpenSim/Region/Environment/Modules/Terrain/TerrainChannel.cs @@ -121,13 +121,12 @@ namespace OpenSim.Region.Environment.Modules.Terrain { for (y = 0; y < Constants.RegionSize; y++) { - //map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10; - // double spherFac = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize, Constants.RegionSize, 20); - // if (map[x, y] < spherFac) - // { - // map[x, y] = spherFac; - // } - map[x, y] = 26; + map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10; + double spherFac = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2, Constants.RegionSize / 2, 50) * 0.01; + if (map[x, y] < spherFac) + { + map[x, y] = spherFac; + } } } } diff --git a/OpenSim/Region/Environment/Modules/Terrain/TerrainModule.cs b/OpenSim/Region/Environment/Modules/Terrain/TerrainModule.cs index 88d7041..e9f1785 100644 --- a/OpenSim/Region/Environment/Modules/Terrain/TerrainModule.cs +++ b/OpenSim/Region/Environment/Modules/Terrain/TerrainModule.cs @@ -35,10 +35,9 @@ using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Scenes; using OpenSim.Region.Environment.Modules.ModuleFramework; - namespace OpenSim.Region.Environment.Modules.Terrain { - public class TerrainModule : IRegionModule , ITerrainTemp, ICommandableModule + public class TerrainModule : IRegionModule, ICommandableModule { public enum StandardTerrainEffects : byte { @@ -47,7 +46,12 @@ namespace OpenSim.Region.Environment.Modules.Terrain Lower = 2, Smooth = 3, Noise = 4, - Revert = 5 + Revert = 5, + + // Extended brushes + Erode = 255, + Weather = 254, + Olsen = 253 } private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); @@ -74,6 +78,9 @@ namespace OpenSim.Region.Environment.Modules.Terrain m_painteffects[StandardTerrainEffects.Noise] = new PaintBrushes.NoiseSphere(); m_painteffects[StandardTerrainEffects.Flatten] = new PaintBrushes.FlattenSphere(); m_painteffects[StandardTerrainEffects.Revert] = new PaintBrushes.RevertSphere(m_revert); + m_painteffects[StandardTerrainEffects.Erode] = new PaintBrushes.ErodeSphere(); + m_painteffects[StandardTerrainEffects.Weather] = new PaintBrushes.WeatherSphere(); + m_painteffects[StandardTerrainEffects.Olsen] = new PaintBrushes.OlsenSphere(); // Area of effect selection effects m_floodeffects[StandardTerrainEffects.Raise] = new FloodBrushes.RaiseArea(); @@ -90,6 +97,11 @@ namespace OpenSim.Region.Environment.Modules.Terrain m_loaders[".raw"] = new FileLoaders.LLRAW(); m_loaders[".jpg"] = new FileLoaders.JPEG(); m_loaders[".jpeg"] = m_loaders[".jpg"]; + m_loaders[".bmp"] = new FileLoaders.BMP(); + m_loaders[".png"] = new FileLoaders.PNG(); + m_loaders[".gif"] = new FileLoaders.GIF(); + m_loaders[".tif"] = new FileLoaders.TIFF(); + m_loaders[".tiff"] = m_loaders[".tif"]; } public void UpdateRevertMap() @@ -139,22 +151,26 @@ namespace OpenSim.Region.Environment.Modules.Terrain public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY) { - fileStartX -= (int)m_scene.RegionInfo.RegionLocX; - fileStartY -= (int)m_scene.RegionInfo.RegionLocY; + int offsetX = (int)m_scene.RegionInfo.RegionLocX - fileStartX; + int offsetY = (int)m_scene.RegionInfo.RegionLocY - fileStartY; - foreach (KeyValuePair loader in m_loaders) + if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight) { - if (filename.EndsWith(loader.Key)) + // this region is included in the tile request + foreach (KeyValuePair loader in m_loaders) { - lock (m_scene) + if (filename.EndsWith(loader.Key)) { - ITerrainChannel channel = loader.Value.LoadFile(filename, fileStartX, fileStartY, - fileWidth, fileHeight, (int)Constants.RegionSize, (int)Constants.RegionSize); - m_scene.Heightmap = channel; - m_channel = channel; - UpdateRevertMap(); + lock (m_scene) + { + ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, + fileWidth, fileHeight, (int)Constants.RegionSize, (int)Constants.RegionSize); + m_scene.Heightmap = channel; + m_channel = channel; + UpdateRevertMap(); + } + return; } - return; } } } @@ -181,7 +197,6 @@ namespace OpenSim.Region.Environment.Modules.Terrain public void Initialise(Scene scene, IConfigSource config) { m_scene = scene; - m_scene.RegisterModuleInterface(this); m_gConfig = config; // Install terrain module in the simulator @@ -222,7 +237,7 @@ namespace OpenSim.Region.Environment.Modules.Terrain private void InterfaceLoadFile(Object[] args) { LoadFromFile((string)args[0]); - SendUpdatedLayerData(); + CheckForTerrainUpdates(); } private void InterfaceLoadTileFile(Object[] args) @@ -232,7 +247,7 @@ namespace OpenSim.Region.Environment.Modules.Terrain (int)args[2], (int)args[3], (int)args[4]); - SendUpdatedLayerData(); + CheckForTerrainUpdates(); } private void InterfaceSaveFile(Object[] args) @@ -240,6 +255,48 @@ namespace OpenSim.Region.Environment.Modules.Terrain SaveToFile((string)args[0]); } + private void InterfaceBakeTerrain(Object[] args) + { + UpdateRevertMap(); + } + + private void InterfaceRevertTerrain(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] = m_revert[x, y]; + + CheckForTerrainUpdates(); + } + + 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]; + CheckForTerrainUpdates(); + } + + 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]; + CheckForTerrainUpdates(); + } + + 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]; + CheckForTerrainUpdates(); + } + private void InterfaceFillTerrain(Object[] args) { int x, y; @@ -247,7 +304,33 @@ namespace OpenSim.Region.Environment.Modules.Terrain for (x = 0; x < m_channel.Width; x++) for (y = 0; y < m_channel.Height; y++) m_channel[x, y] = (double)args[0]; - SendUpdatedLayerData(); + CheckForTerrainUpdates(); + } + + private void InterfaceShowDebugStats(Object[] args) + { + double max = Double.MinValue; + double min = double.MaxValue; + double avg = 0; + double sum = 0; + + int x, y; + for (x = 0; x < m_channel.Width; x++) + { + for (y = 0; y < m_channel.Height; y++) + { + sum += m_channel[x, y]; + if (max < m_channel[x, y]) + max = m_channel[x, y]; + if (min > m_channel[x, y]) + min = m_channel[x, y]; + } + } + + avg = sum / (m_channel.Height * m_channel.Width); + + m_log.Info("Channel " + m_channel.Width + "x" + m_channel.Height); + m_log.Info("max/min/avg/sum: " + max + "/" + min + "/" + avg + "/" + sum); } private void InterfaceEnableExperimentalBrushes(Object[] args) @@ -264,6 +347,12 @@ namespace OpenSim.Region.Environment.Modules.Terrain } } + private void InterfacePerformEffectTest(Object[] args) + { + Effects.CookieCutter cookie = new OpenSim.Region.Environment.Modules.Terrain.Effects.CookieCutter(); + cookie.RunEffect(m_channel); + } + private void InstallInterfaces() { // Load / Save @@ -288,15 +377,39 @@ namespace OpenSim.Region.Environment.Modules.Terrain Command fillRegionCommand = new Command("fill", InterfaceFillTerrain, "Fills the current heightmap with a specified value."); fillRegionCommand.AddArgument("value", "The numeric value of the height you wish to set your region to.", "Double"); - // Brushes + Command elevateCommand = new Command("elevate", InterfaceElevateTerrain, "Raises the current heightmap by the specified amount."); + elevateCommand.AddArgument("amount", "The amount of height to add to the terrain in meters.", "Double"); + + Command lowerCommand = new Command("lower", InterfaceLowerTerrain, "Lowers the current heightmap by the specified amount."); + lowerCommand.AddArgument("amount", "The amount of height to remove from the terrain in meters.", "Double"); + + Command multiplyCommand = new Command("multiply", InterfaceMultiplyTerrain, "Multiplies the heightmap by the value specified."); + multiplyCommand.AddArgument("value", "The value to multiply the heightmap by.", "Double"); + + Command bakeRegionCommand = new Command("bake", InterfaceBakeTerrain, "Saves the current terrain into the regions revert map."); + Command revertRegionCommand = new Command("revert", InterfaceRevertTerrain, "Loads the revert map terrain into the regions heightmap."); + + // Debug + Command showDebugStatsCommand = new Command("stats", InterfaceShowDebugStats, "Shows some information about the regions heightmap for debugging purposes."); + Command experimentalBrushesCommand = new Command("newbrushes", InterfaceEnableExperimentalBrushes, "Enables experimental brushes which replace the standard terrain brushes. WARNING: This is a debug setting and may be removed at any time."); experimentalBrushesCommand.AddArgument("Enabled?", "true / false - Enable new brushes", "Boolean"); + // Effects + Command effectsTestCommand = new Command("test", InterfacePerformEffectTest, "Performs an effects module test"); + m_commander.RegisterCommand("load", loadFromFileCommand); m_commander.RegisterCommand("load-tile", loadFromTileCommand); m_commander.RegisterCommand("save", saveToFileCommand); m_commander.RegisterCommand("fill", fillRegionCommand); + m_commander.RegisterCommand("elevate", elevateCommand); + m_commander.RegisterCommand("lower", lowerCommand); + m_commander.RegisterCommand("multiply", multiplyCommand); + m_commander.RegisterCommand("bake", bakeRegionCommand); + m_commander.RegisterCommand("revert", revertRegionCommand); m_commander.RegisterCommand("newbrushes", experimentalBrushesCommand); + m_commander.RegisterCommand("test", effectsTestCommand); + m_commander.RegisterCommand("stats", showDebugStatsCommand); // Add this to our scene so scripts can call these functions m_scene.RegisterModuleCommander("Terrain", m_commander); @@ -322,7 +435,7 @@ namespace OpenSim.Region.Environment.Modules.Terrain client.OnModifyTerrain += client_OnModifyTerrain; } - void SendUpdatedLayerData() + void CheckForTerrainUpdates() { bool shouldTaint = false; float[] serialised = m_channel.GetFloatsSerialised(); @@ -333,10 +446,7 @@ namespace OpenSim.Region.Environment.Modules.Terrain { if (m_channel.Tainted(x, y)) { - m_scene.ForEachClient(delegate(IClientAPI controller) - { - controller.SendLayerData(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, serialised); - }); + SendToClients(serialised, x, y); shouldTaint = true; } } @@ -347,6 +457,14 @@ namespace OpenSim.Region.Environment.Modules.Terrain } } + private void SendToClients(float[] serialised, int x, int y) + { + m_scene.ForEachClient(delegate(IClientAPI controller) + { + controller.SendLayerData(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, serialised); + }); + } + void client_OnModifyTerrain(float height, float seconds, byte size, byte action, float north, float west, float south, float east, IClientAPI remoteClient) { // Not a good permissions check, if in area mode, need to check the entire area. @@ -364,7 +482,7 @@ namespace OpenSim.Region.Environment.Modules.Terrain if (usingTerrainModule) { - SendUpdatedLayerData(); + CheckForTerrainUpdates(); } } else @@ -401,7 +519,7 @@ namespace OpenSim.Region.Environment.Modules.Terrain if (usingTerrainModule) { - SendUpdatedLayerData(); + CheckForTerrainUpdates(); } } else @@ -412,51 +530,6 @@ namespace OpenSim.Region.Environment.Modules.Terrain } } - public byte[] WriteJpegImage(string gradientmap) - { - byte[] imageData = null; - try - { - Bitmap bmp = TerrainToBitmap(gradientmap); - - imageData = OpenJPEGNet.OpenJPEG.EncodeFromImage(bmp, true); - - } - catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke - { - Console.WriteLine("Failed generating terrain map: " + e.ToString()); - } - - return imageData; - } - - private Bitmap TerrainToBitmap(string gradientmap) - { - Bitmap gradientmapLd = new Bitmap(gradientmap); - - int pallete = gradientmapLd.Height; - - Bitmap bmp = new Bitmap(m_channel.Width, m_channel.Height); - Color[] colours = new Color[pallete]; - - for (int i = 0; i < pallete; i++) - { - colours[i] = gradientmapLd.GetPixel(0, i); - } - - TerrainChannel copy =(TerrainChannel) m_channel.MakeCopy(); - for (int y = 0; y < copy.Height; y++) - { - for (int x = 0; x < copy.Width; x++) - { - // 512 is the largest possible height before colours clamp - int colorindex = (int)(Math.Max(Math.Min(1.0, copy[x, y] / 512.0), 0.0) * (pallete - 1)); - bmp.SetPixel(x, copy.Height - y - 1, colours[colorindex]); - } - } - return bmp; - } - public void PostInitialise() { InstallDefaultEffects(); -- cgit v1.1