From 9798b044fe92df6bd1b3f18c04937bd99a4d98cb Mon Sep 17 00:00:00 2001 From: Kevin Cozens Date: Wed, 26 Jan 2011 20:53:21 -0500 Subject: Added loading and saving of terrain files using Terragen format (Mantis #1564) Terrain files can now be loaded and saved using the Terragen (.ter) format. Selection of the terrain file loader to use is now based on the extension of the filename being loaded and the data is loaded using a memory stream instead of writing it to a file and then loading it from the file. --- .../World/Estate/EstateManagementModule.cs | 35 +-- .../World/Terrain/FileLoaders/Terragen.cs | 239 +++++++++++++++++++-- 2 files changed, 224 insertions(+), 50 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index b0563c5..01f04d9 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -555,37 +555,12 @@ namespace OpenSim.Region.CoreModules.World.Estate try { + MemoryStream terrainStream = new MemoryStream(terrainData); + terr.LoadFromStream(filename, terrainStream); + terrainStream.Close(); - string localfilename = "terrain.raw"; - - if (terrainData.Length == 851968) - { - localfilename = Path.Combine(Util.dataDir(),"terrain.raw"); // It's a .LLRAW - } - - if (terrainData.Length == 196662) // 24-bit 256x256 Bitmap - localfilename = Path.Combine(Util.dataDir(), "terrain.bmp"); - - if (terrainData.Length == 256 * 256 * 4) // It's a .R32 - localfilename = Path.Combine(Util.dataDir(), "terrain.r32"); - - if (terrainData.Length == 256 * 256 * 8) // It's a .R64 - localfilename = Path.Combine(Util.dataDir(), "terrain.r64"); - - if (File.Exists(localfilename)) - { - File.Delete(localfilename); - } - - FileStream input = new FileStream(localfilename, FileMode.CreateNew); - input.Write(terrainData, 0, terrainData.Length); - input.Close(); - - FileInfo x = new FileInfo(localfilename); - - terr.LoadFromFile(localfilename); - remoteClient.SendAlertMessage("Your terrain was loaded as a ." + x.Extension + " file. It may take a few moments to appear."); - + FileInfo x = new FileInfo(filename); + remoteClient.SendAlertMessage("Your terrain was loaded as a " + x.Extension + " file. It may take a few moments to appear."); } catch (IOException e) { diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs index 3ee20ae..2919897 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs @@ -30,6 +30,7 @@ using System.IO; using System.Text; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSim.Framework; namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders { @@ -53,17 +54,120 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders return retval; } + 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); + + bool eof = false; + + int fileXPoints = 0; + int fileYPoints = 0; + + // Terragen file + while (eof == false) + { + string tmp = Encoding.ASCII.GetString(bs.ReadBytes(4)); + switch (tmp) + { + case "SIZE": + fileXPoints = bs.ReadInt16() + 1; + fileYPoints = fileXPoints; + bs.ReadInt16(); + break; + case "XPTS": + fileXPoints = bs.ReadInt16(); + bs.ReadInt16(); + break; + case "YPTS": + fileYPoints = bs.ReadInt16(); + bs.ReadInt16(); + break; + case "ALTW": + eof = true; + Int16 heightScale = bs.ReadInt16(); + Int16 baseHeight = bs.ReadInt16(); + + int currFileYOffset = 0; + + // if our region isn't on the first X 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 * fileXPoints; + bs.ReadBytes(heightsToRead * 2); // because the shorts are 2 bytes in the file + currFileYOffset++; + } + + for (int y = 0; y < sectionHeight; y++) + { + int 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 * 2); // 2 bytes = short + currFileXOffset++; + } + + // got to our X offset, so write our regions X line + for (int x = 0; x < sectionWidth; x++) + { + // Read a strip and continue + retval[x, y] = baseHeight + bs.ReadInt16() * (double)heightScale / 65536.0; + } + // 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 * 2); // 2 bytes = short + currFileXOffset++; + } + //eat the last additional point + bs.ReadInt16(); + } + + + break; + default: + bs.ReadInt32(); + break; + } + } + + bs.Close(); + s.Close(); + + return retval; + } + public ITerrainChannel LoadStream(Stream s) { - TerrainChannel retval = new TerrainChannel(); + + int w = (int)Constants.RegionSize; + int h = (int)Constants.RegionSize; + + TerrainChannel retval = new TerrainChannel(w, h); BinaryReader bs = new BinaryReader(s); bool eof = false; if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ") { - int w = 256; - int h = 256; + + int fileWidth = w; + int fileHeight = h; + // Terragen file while (eof == false) @@ -73,30 +177,27 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders { case "SIZE": int sztmp = bs.ReadInt16() + 1; - w = sztmp; - h = sztmp; + fileWidth = sztmp; + fileHeight = sztmp; bs.ReadInt16(); break; case "XPTS": - w = bs.ReadInt16(); + fileWidth = bs.ReadInt16(); bs.ReadInt16(); break; case "YPTS": - h = bs.ReadInt16(); + fileHeight = bs.ReadInt16(); bs.ReadInt16(); break; case "ALTW": eof = true; Int16 heightScale = bs.ReadInt16(); Int16 baseHeight = bs.ReadInt16(); - retval = new TerrainChannel(w, h); - int x; - for (x = 0; x < w; x++) + for (int y = 0; y < h; y++) { - int y; - for (y = 0; y < h; y++) + for (int x = 0; x < w; x++) { - retval[x, y] = baseHeight + bs.ReadInt16() * (double) heightScale / 65536.0; + retval[x, y] = baseHeight + bs.ReadInt16() * (double)heightScale / 65536.0; } } break; @@ -114,12 +215,92 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders public void SaveFile(string filename, ITerrainChannel map) { - throw new NotImplementedException(); + FileInfo file = new FileInfo(filename); + FileStream s = file.Open(FileMode.Create, FileAccess.Write); + SaveStream(s, map); + + s.Close(); } public void SaveStream(Stream stream, ITerrainChannel map) { - throw new NotImplementedException(); + BinaryWriter bs = new BinaryWriter(stream); + + //find the max and min heights on the map + double heightMax = map[0,0]; + double heightMin = map[0,0]; + + for (int y = 0; y < map.Height; y++) + { + for (int x = 0; x < map.Width; x++) + { + double current = map[x,y]; + if (heightMax < current) + heightMax = current; + if (heightMin > current) + heightMin = current; + } + } + + double baseHeight = Math.Floor( (heightMax + heightMin) / 2d ); + + double horizontalScale = Math.Ceiling((heightMax - heightMin)); + + // if we are completely flat add 1cm range to avoid NaN divisions + if (horizontalScale < 0.01d) + horizontalScale = 0.01d; + + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + + bs.Write(enc.GetBytes("TERRAGENTERRAIN ")); + + bs.Write(enc.GetBytes("SIZE")); + bs.Write(Convert.ToInt16(Constants.RegionSize)); + bs.Write(Convert.ToInt16(0)); // necessary padding + + //The XPTS and YPTS chunks are not needed for square regions + //but L3DT won't load the terrain file properly without them. + bs.Write(enc.GetBytes("XPTS")); + bs.Write(Convert.ToInt16(Constants.RegionSize)); + bs.Write(Convert.ToInt16(0)); // necessary padding + + bs.Write(enc.GetBytes("YPTS")); + bs.Write(Convert.ToInt16(Constants.RegionSize)); + bs.Write(Convert.ToInt16(0)); // necessary padding + + bs.Write(enc.GetBytes("SCAL")); + bs.Write(ToLittleEndian(1f)); //we're going to say that 1 terrain unit is 1 metre + bs.Write(ToLittleEndian(1f)); + bs.Write(ToLittleEndian(1f)); + + // as we are square and not projected on a sphere then the other + // header blocks are not required + + // now write the elevation data + bs.Write(enc.GetBytes("ALTW")); + bs.Write(Convert.ToInt16(horizontalScale)); // range between max and min + bs.Write(Convert.ToInt16(baseHeight)); // base height or mid point + + for (int y = 0; y < map.Height; y++) + { + for (int x = 0; x < map.Width; x++) + { + float elevation = (float)((map[x,y] - baseHeight) * 65536 ) / (float)horizontalScale; // see LoadStream for inverse + + // clamp rounding issues + if (elevation > Int16.MaxValue) + elevation = Int16.MaxValue; + else if (elevation < Int16.MinValue) + elevation = Int16.MinValue; + + bs.Write(Convert.ToInt16(elevation)); + } + } + + //This is only necessary for older versions of Terragen. + bs.Write(enc.GetBytes("EOF ")); + + bs.Close(); } public string FileExtension @@ -127,16 +308,34 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders get { return ".ter"; } } - public ITerrainChannel LoadFile(string filename, int x, int y, int fileWidth, int fileHeight, int w, int h) - { - throw new NotImplementedException(); - } - #endregion public override string ToString() { return "Terragen"; } + + /// + /// terragen SCAL floats need to be written intel ordered regardless of + /// big or little endian system + /// + /// + /// + private byte[] ToLittleEndian( float number) + { + byte[] retVal = BitConverter.GetBytes(number); + if (BitConverter.IsLittleEndian == false) + { + byte[] tmp = new byte[4]; + for (int i = 0; i < 4; i++) + { + tmp[i] = retVal[3 - i]; + } + retVal = tmp; + + } + return retVal ; + } + } } -- cgit v1.1 From a0380af18ff7b383333f38d81a25a668154eb5c2 Mon Sep 17 00:00:00 2001 From: Kevin Cozens Date: Thu, 27 Jan 2011 22:57:08 -0500 Subject: Display supported file extensions/formats in "terrain load help" (Mantis #5349) --- OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 25d73c2..8a79d78 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -131,7 +131,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_scene.EventManager.OnNewClient += EventManager_OnNewClient; m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick; - InstallInterfaces(); } InstallDefaultEffects(); @@ -140,6 +139,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain public void RegionLoaded(Scene scene) { + //Do this here to give file loaders time to initialize and + //register their supported file extensions and file formats. + InstallInterfaces(); } public void RemoveRegion(Scene scene) @@ -1082,8 +1084,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain { // Load / Save string supportedFileExtensions = ""; + string supportedFilesSeparator = ""; foreach (KeyValuePair loader in m_loaders) - supportedFileExtensions += " " + loader.Key + " (" + loader.Value + ")"; + { + supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")"; + supportedFilesSeparator = ", "; + } Command loadFromFileCommand = new Command("load", CommandIntentions.COMMAND_HAZARDOUS, InterfaceLoadFile, "Loads a terrain from a specified file."); -- cgit v1.1 From ab1ec3c3cccf30ab61379b700129ca3284578274 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 28 Jan 2011 21:51:25 +0000 Subject: minor: remove a few mono compiler warnings --- .../Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs | 4 ++-- .../ServiceConnectorsOut/UserAccounts/UserAccountCache.cs | 7 ++++--- OpenSim/Region/CoreModules/World/Region/RestartModule.cs | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs index 542af25..4a42c93 100644 --- a/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs @@ -54,7 +54,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Scene m_scene; - private IAssetService m_assetService; +// private IAssetService m_assetService; private bool m_dumpAssetsToFile = false; #region IRegionModuleBase Members @@ -85,7 +85,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets public void RegionLoaded(Scene scene) { - m_assetService = m_scene.RequestModuleInterface(); +// m_assetService = m_scene.RequestModuleInterface(); m_scene.EventManager.OnRegisterCaps += RegisterCaps; } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs index 155335b..ddef75f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs @@ -38,9 +38,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { private const double CACHE_EXPIRATION_SECONDS = 120000.0; // 33 hours! - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = +// LogManager.GetLogger( +// MethodBase.GetCurrentMethod().DeclaringType); + private ExpiringCache m_UUIDCache; private ExpiringCache m_NameCache; diff --git a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs index c65aa6a..ab6a598 100644 --- a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs +++ b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs @@ -45,8 +45,8 @@ namespace OpenSim.Region.CoreModules.World.Region [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RestartModule")] public class RestartModule : INonSharedRegionModule, IRestartModule { - private static readonly ILog m_log = - LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = +// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected Scene m_Scene; protected Timer m_CountdownTimer = null; -- cgit v1.1 From 1fcb919798f8ff132353d447e6dfb81bedd3bc44 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 28 Jan 2011 22:46:29 +0000 Subject: If a non-globbed included file from config cannot be found then warn the user --- OpenSim/Region/Application/ConfigurationLoader.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs index 6e3d6af..d246181 100644 --- a/OpenSim/Region/Application/ConfigurationLoader.cs +++ b/OpenSim/Region/Application/ConfigurationLoader.cs @@ -180,6 +180,7 @@ namespace OpenSim { if (ReadConfig(sources[i])) iniFileExists = true; + AddIncludes(sources); } @@ -235,10 +236,19 @@ namespace OpenSim string path = Path.Combine(basepath, chunkWithoutWildcards); path = Path.GetFullPath(path) + chunkWithWildcards; string[] paths = Util.Glob(path); - foreach (string p in paths) + + // If the include path contains no wildcards, then warn the user that it wasn't found. + if (wildcardIndex == -1 && paths.Length == 0) { - if (!sources.Contains(p)) - sources.Add(p); + m_log.WarnFormat("[CONFIG]: Could not find include file {0}", path); + } + else + { + foreach (string p in paths) + { + if (!sources.Contains(p)) + sources.Add(p); + } } } } -- cgit v1.1 From a4acf485d7332ff6c22a2e0dffdbd1409e4b2dcb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 28 Jan 2011 22:50:49 +0000 Subject: minor: don't bother reparsing the sources for includes if ReadConfig() was unsuccessful --- OpenSim/Region/Application/ConfigurationLoader.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs index d246181..40ab765 100644 --- a/OpenSim/Region/Application/ConfigurationLoader.cs +++ b/OpenSim/Region/Application/ConfigurationLoader.cs @@ -179,9 +179,10 @@ namespace OpenSim for (int i = 0 ; i < sources.Count ; i++) { if (ReadConfig(sources[i])) + { iniFileExists = true; - - AddIncludes(sources); + AddIncludes(sources); + } } if (!iniFileExists) -- cgit v1.1 From 933f47e89df69200fd4cf03a9f48c465a0434e05 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 28 Jan 2011 22:59:07 +0000 Subject: Comment out unused call to GridService in TeleportAgent() --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index bca08fb..c0c790d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -702,7 +702,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // and convert the regionName to the target region if (regionName.Contains(".") && regionName.Contains(":")) { - List regions = World.GridService.GetRegionsByName(World.RegionInfo.ScopeID, regionName, 1); +// List regions = World.GridService.GetRegionsByName(World.RegionInfo.ScopeID, regionName, 1); string[] parts = regionName.Split(new char[] { ':' }); if (parts.Length > 2) regionName = parts[0] + ':' + parts[1] + "/ " + parts[2]; -- cgit v1.1