From aafe424344a1f3c08055c97ae5676e6cfcb83902 Mon Sep 17 00:00:00 2001 From: Multfinite Date: Wed, 20 Sep 2023 01:21:49 +0300 Subject: [PATCH 1/7] Add new filter for images files - rename map file filter --- src/TSMapEditor/Constants.cs | 6 ++++-- src/TSMapEditor/UI/MainMenu.cs | 2 +- src/TSMapEditor/UI/TopBar/TopBarMenu.cs | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/TSMapEditor/Constants.cs b/src/TSMapEditor/Constants.cs index 19e4699fb..3db2e4148 100644 --- a/src/TSMapEditor/Constants.cs +++ b/src/TSMapEditor/Constants.cs @@ -20,9 +20,11 @@ public static class Constants public static string ExpectedClientExecutableName = "DTA.exe"; public static string GameRegistryInstallPath = "SOFTWARE\\DawnOfTheTiberiumAge"; - public static string OpenFileDialogFilter = "TS maps|*.map|All files|*.*"; public static bool EnableIniInclude = false; + public static string OpenFileMapDialogFilter = "TS maps|*.map|All files|*.*"; + public static string OpenImageFileDialogFilter = "Images|*.bmp;*.png;*.jpg;*.jpeg|All files|*.*"; + public static bool EnableIniInheritance = false; public static bool IntegerVariables = false; @@ -107,7 +109,7 @@ public static void Init() ExpectedClientExecutableName = constantsIni.GetStringValue(ConstantsSectionName, nameof(ExpectedClientExecutableName), ExpectedClientExecutableName); GameRegistryInstallPath = constantsIni.GetStringValue(ConstantsSectionName, nameof(GameRegistryInstallPath), GameRegistryInstallPath); - OpenFileDialogFilter = constantsIni.GetStringValue(ConstantsSectionName, nameof(OpenFileDialogFilter), OpenFileDialogFilter); + OpenFileMapDialogFilter = constantsIni.GetStringValue(ConstantsSectionName, nameof(OpenFileMapDialogFilter), OpenFileMapDialogFilter); EnableIniInclude = constantsIni.GetBooleanValue(ConstantsSectionName, nameof(EnableIniInclude), EnableIniInclude); EnableIniInheritance = constantsIni.GetBooleanValue(ConstantsSectionName, nameof(EnableIniInheritance), EnableIniInheritance); diff --git a/src/TSMapEditor/UI/MainMenu.cs b/src/TSMapEditor/UI/MainMenu.cs index b20a1802d..6f7446528 100644 --- a/src/TSMapEditor/UI/MainMenu.cs +++ b/src/TSMapEditor/UI/MainMenu.cs @@ -303,7 +303,7 @@ private void BtnBrowseMapPath_LeftClick(object sender, EventArgs e) using (OpenFileDialog openFileDialog = new OpenFileDialog()) { openFileDialog.InitialDirectory = tbMapPath.Text; - openFileDialog.Filter = Constants.OpenFileDialogFilter.Replace(':', ';'); + openFileDialog.Filter = Constants.OpenFileMapDialogFilter.Replace(':', ';'); openFileDialog.RestoreDirectory = true; if (openFileDialog.ShowDialog() == DialogResult.OK) diff --git a/src/TSMapEditor/UI/TopBar/TopBarMenu.cs b/src/TSMapEditor/UI/TopBar/TopBarMenu.cs index 9380ff755..0277598a7 100644 --- a/src/TSMapEditor/UI/TopBar/TopBarMenu.cs +++ b/src/TSMapEditor/UI/TopBar/TopBarMenu.cs @@ -265,7 +265,7 @@ private void Open() using (OpenFileDialog openFileDialog = new OpenFileDialog()) { openFileDialog.InitialDirectory = initialPath; - openFileDialog.Filter = Constants.OpenFileDialogFilter.Replace(':', ';'); + openFileDialog.Filter = Constants.OpenFileMapDialogFilter.Replace(':', ';'); openFileDialog.RestoreDirectory = true; if (openFileDialog.ShowDialog() == DialogResult.OK) @@ -287,7 +287,7 @@ private void SaveAs() { saveFileDialog.InitialDirectory = Path.GetDirectoryName(initialPath); saveFileDialog.FileName = Path.GetFileName(initialPath); - saveFileDialog.Filter = Constants.OpenFileDialogFilter.Replace(':', ';'); + saveFileDialog.Filter = Constants.OpenFileMapDialogFilter.Replace(':', ';'); saveFileDialog.RestoreDirectory = true; if (saveFileDialog.ShowDialog() == DialogResult.OK) From 06062827ac80b343be8947578395d6f0a093e003 Mon Sep 17 00:00:00 2001 From: Multfinite Date: Wed, 20 Sep 2023 15:33:41 +0300 Subject: [PATCH 2/7] FS extensions: OpenFile --- src/TSMapEditor/Misc/FileSystemExtensions.cs | 41 ++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/TSMapEditor/Misc/FileSystemExtensions.cs diff --git a/src/TSMapEditor/Misc/FileSystemExtensions.cs b/src/TSMapEditor/Misc/FileSystemExtensions.cs new file mode 100644 index 000000000..44b6a9f79 --- /dev/null +++ b/src/TSMapEditor/Misc/FileSystemExtensions.cs @@ -0,0 +1,41 @@ +using System; +using System.Windows.Forms; + +namespace TSMapEditor.Misc +{ + public static class FileSystemExtensions + { + public const string AllFilesFilter = "All files|*.*"; + + public static void OpenFile( + Action onOpened, + Action onAborted = null, + string filter = AllFilesFilter, + bool checkFileExist = true, + string initialDirectory = null + ) { +#if WINDOWS + using (OpenFileDialog openFileDialog = new OpenFileDialog()) + { + openFileDialog.InitialDirectory = string.IsNullOrEmpty(initialDirectory) ? Environment.CurrentDirectory : initialDirectory; + + openFileDialog.Filter = string.IsNullOrEmpty(filter) ? AllFilesFilter : filter; + openFileDialog.CheckFileExists = checkFileExist; + openFileDialog.RestoreDirectory = true; + + switch (openFileDialog.ShowDialog()) + { + case DialogResult.OK: + onOpened?.Invoke(openFileDialog.FileName); + break; + default: + onAborted?.Invoke(); + break; + } + } +#else + throw new NotImplementedException($"{nameof(FileSystemExtensions)}::{nameof(OpenFile)}"); +#endif + } + } +} From 47bcc3b447fc592c5e3e56c49a2c4f5d8d9b536d Mon Sep 17 00:00:00 2001 From: Multfinite Date: Wed, 20 Sep 2023 15:37:54 +0300 Subject: [PATCH 3/7] Terrain importer --- src/TSMapEditor/Config/Importer/Default.ini | 31 ++++ src/TSMapEditor/Constants.cs | 2 + src/TSMapEditor/Misc/TerrainImporter.cs | 143 ++++++++++++++++++ src/TSMapEditor/Models/Map.cs | 32 ++++ src/TSMapEditor/TSMapEditor.csproj | 4 + .../UI/Windows/MainMenuWindows/MapSetup.cs | 9 +- 6 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 src/TSMapEditor/Config/Importer/Default.ini create mode 100644 src/TSMapEditor/Misc/TerrainImporter.cs diff --git a/src/TSMapEditor/Config/Importer/Default.ini b/src/TSMapEditor/Config/Importer/Default.ini new file mode 100644 index 000000000..9b0c29942 --- /dev/null +++ b/src/TSMapEditor/Config/Importer/Default.ini @@ -0,0 +1,31 @@ +; Terrain image importer configuration +; DEFAULT +; Author: Multfinite + +[Tiles] +; Internal name for mapping = TileID +Default=0 ; LAT +Grass=0 +DarkGrass=131 +RoughGrass=418 +Pavement=534 +Sand=493 +Water=322 + +[Colors] +; R,G,B[,A] +Red=255,0,0 +Blue=0,0,255 +Green=0,255,0 +DarkGreen=0,191,0 +Yellow=255,255,0 +Gray=127,127,127 + +[Mapping] +; Color = Tile +Red=RoughGrass +Blue=Water +Green=Grass +DarkGreen=DarkGrass +Yellow=Sand +Gray=Pavement \ No newline at end of file diff --git a/src/TSMapEditor/Constants.cs b/src/TSMapEditor/Constants.cs index 3db2e4148..a57b9a1af 100644 --- a/src/TSMapEditor/Constants.cs +++ b/src/TSMapEditor/Constants.cs @@ -8,6 +8,7 @@ public static class Constants public static int CellSizeX = 48; public static int CellSizeY = 24; public static int CellHeight => CellSizeY / 2; + public static double CellWHRatio = CellSizeX / CellSizeY; public static int TileColorBufferSize = 576; public static int RenderPixelPadding = 50; @@ -26,6 +27,7 @@ public static class Constants public static string OpenImageFileDialogFilter = "Images|*.bmp;*.png;*.jpg;*.jpeg|All files|*.*"; public static bool EnableIniInheritance = false; + public static string OpenIniFileDialogFilter = "INI|*.ini|All files|*.*"; public static bool IntegerVariables = false; diff --git a/src/TSMapEditor/Misc/TerrainImporter.cs b/src/TSMapEditor/Misc/TerrainImporter.cs new file mode 100644 index 000000000..b964f6ecc --- /dev/null +++ b/src/TSMapEditor/Misc/TerrainImporter.cs @@ -0,0 +1,143 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Rampastring.Tools; +using System; +using System.Collections.Generic; +using TSMapEditor.Models; +using TSMapEditor.Rendering; + +namespace TSMapEditor.Misc +{ + public class TerrainImporter + { + public class Configuration + { + public Dictionary Mapping { get; set; } + public int Default { get; set; } + + public Configuration() {} + public Configuration(string fileName) + { + var tileTypes = new Dictionary(); + var colorTypes = new Dictionary(); + + var iniFile = new IniFile(fileName); + var sTileTypes = iniFile.GetSection("Tiles"); + var sColorTypes = iniFile.GetSection("Colors"); + var sMapping = iniFile.GetSection("Mapping"); + + foreach (var tileType in sTileTypes.Keys) + tileTypes.Add(tileType.Key, int.Parse(tileType.Value)); + foreach (var colorType in sColorTypes.Keys) + colorTypes.Add(colorType.Key, Helpers.ColorFromString(colorType.Value)); + + Mapping = new Dictionary(); + foreach (var mapping in sMapping.Keys) + Mapping.Add(colorTypes[mapping.Key], tileTypes[mapping.Value]); + + Default = tileTypes["Default"]; + } + + public Dictionary ReadTheater(ITheater theater) + { + Dictionary mapping = new Dictionary(); + foreach (var pair in Mapping) + mapping.Add(pair.Key, theater.GetTile(pair.Value)); + return mapping; + } + } + + public Configuration Current { get; set; } + + public TerrainImporter(Configuration configuration) + { + Current = configuration; + } + + public static Color GetPixel(Color[] colors, int x, int y, int width) + { + return colors[x + (y * width)]; + } + public static Color[] GetPixels(Texture2D texture) + { + Color[] colors1D = new Color[texture.Width * texture.Height]; + texture.GetData(colors1D); + return colors1D; + } + + public void Import(Map map, Texture2D terrainMap, Texture2D heightMap, byte basicLevel) + { + Dictionary mapping = Current.ReadTheater(map.TheaterInstance); + var defaultTileImg = map.TheaterInstance.GetTile(Current.Default); + + short w = (short) map.Size.X; + short h = (short) map.Size.Y; + var tiStepX = terrainMap == null ? -1 : Math.Round((double)terrainMap.Width / w); + var tiStepY = terrainMap == null ? -1 : Math.Round((double)terrainMap.Height / h); + var hmStepX = heightMap == null ? -1 : Math.Round((double)heightMap.Width / w); + var hmStepY = heightMap == null ? -1 : Math.Round((double)heightMap.Height / h); + var terrainData = terrainMap == null ? null : GetPixels(terrainMap); + var heightData = heightMap == null ? null : GetPixels(heightMap); + + var offX = 0; + var offY = ((w + h) / -2); + + List tiles = new List(); + var createTile = (int x, int y, int bx, int by, int otx, int oty) => + { + var tileImg = defaultTileImg; + var height = basicLevel; + if (terrainMap != null) + { + var tiX = (int)Math.Clamp(tiStepX * (x + bx), 0, terrainMap.Width - 1); + var tiY = (int)Math.Clamp(tiStepY * (y + by), 0, terrainMap.Height - 1); + var terrainColor = GetPixel(terrainData, tiX, tiY, terrainMap.Width); + tileImg = mapping.ContainsKey(terrainColor) ? mapping[terrainColor] : defaultTileImg; + } + if (heightMap != null) + { + var hmX = (int)Math.Clamp(hmStepX * (x + bx), 0, heightMap.Width - 1); + var hmY = (int)Math.Clamp(hmStepY * (y + by), 0, heightMap.Height - 1); + var heightColor = GetPixel(heightData, hmX, hmY, heightMap.Width); + height += (byte)(((short)heightColor.R + heightColor.G + heightColor.B) / 3); + } + + { + var tileX = 1 + x + y + offX; + var tileY = 1 + h + w - x + y + offY; + var tile = new MapTile(); + + tile.Level = height; + tile.ChangeTileIndex(tileImg.TileID, 0); + + tile.X = (short)Math.Round((double)tileX + otx); tile.Y = (short)Math.Round((double)tileY + oty); + tiles.Add(tile); + } + }; + + for (int y = 0; y < map.Size.Y; y++) + for (int x = 0; x < map.Size.X; x++) + { + // here there is a problem + // if create tile only for (x, y) then it became like chessboard: + // line (x+1, y) will be skipped. + // the easiest way just create tile line for (x+1, y) seperately. + // + // About offset. Some experiments + // *50x*61 <=> *5x*6 + // 100x122 <=> 11x11 + // 150x183 <=> 18x17 + // 200x244 <=> 23x22 + // The conclusion: + // otx = 0 - because the y component can be found in both formulas + // oty = h / 10 + var otx = 0; + var oty = -((h / 6)); + createTile(x, y, 0, 0, otx, oty); + createTile(x, y, 1, 0, 1 + otx, oty); + } + + map.SetTileData(tiles); + } + } +} diff --git a/src/TSMapEditor/Models/Map.cs b/src/TSMapEditor/Models/Map.cs index 37ba5db09..d48bcdfb2 100644 --- a/src/TSMapEditor/Models/Map.cs +++ b/src/TSMapEditor/Models/Map.cs @@ -1786,6 +1786,38 @@ private void CheckForAITriggerTeamWithMaxZeroIssue(AITriggerType aiTrigger, Team } } + public bool ApplyHeightDeltaOnWholeMap(int delta) + { + var theater = TheaterInstance; + + for (int y = 0; y < Size.Y; y++) + for (int x = 0; x < Size.X; x++) + { + var point = new Point2D(x, y); + var tile = GetTile(point); + if (tile == null) + { + PlaceTerrainTileAt(theater.GetTile(0), point); + tile = GetTile(point); + } + + short level = tile.Level; + var newLevel = level + delta; + if (newLevel > Constants.MaxMapHeightLevel || newLevel < 0) + return false; + } + + for (int y = 0; y < Size.Y; y++) + for (int x = 0; x < Size.X; x++) + { + var point = new Point2D(x, y); + var tile = GetTile(point); + tile.Level = (byte)(tile.Level + delta); + } + + return true; + } + public void Clear() { LoadedINI = null; diff --git a/src/TSMapEditor/TSMapEditor.csproj b/src/TSMapEditor/TSMapEditor.csproj index 26e0a8bd9..a699902cb 100644 --- a/src/TSMapEditor/TSMapEditor.csproj +++ b/src/TSMapEditor/TSMapEditor.csproj @@ -62,6 +62,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -390,6 +393,7 @@ + diff --git a/src/TSMapEditor/UI/Windows/MainMenuWindows/MapSetup.cs b/src/TSMapEditor/UI/Windows/MainMenuWindows/MapSetup.cs index 479f71bf4..a6eb41b44 100644 --- a/src/TSMapEditor/UI/Windows/MainMenuWindows/MapSetup.cs +++ b/src/TSMapEditor/UI/Windows/MainMenuWindows/MapSetup.cs @@ -1,13 +1,15 @@ +using Microsoft.Xna.Framework.Graphics; using Rampastring.Tools; using Rampastring.XNAUI; using System; using System.IO; using TSMapEditor.CCEngine; +using TSMapEditor.Extensions; using TSMapEditor.GameMath; using TSMapEditor.Initialization; +using TSMapEditor.Misc; using TSMapEditor.Models; using TSMapEditor.Rendering; -using TSMapEditor.Extensions; namespace TSMapEditor.UI.Windows.MainMenuWindows { @@ -82,6 +84,11 @@ public static string InitializeMap(string gameDirectory, bool createNew, string return null; } + public static void ImportTerrain(TerrainImporter importer, Texture2D terrainMap, Texture2D heightMap, byte basicLevel) + { + importer.Import(LoadedMap, terrainMap, heightMap, basicLevel); + } + /// /// Loads the theater graphics for the last-loaded map. /// From 2abe51e17c13d46a23a8cc345364e2dc4e109d2e Mon Sep 17 00:00:00 2001 From: Multfinite Date: Wed, 20 Sep 2023 15:38:39 +0300 Subject: [PATCH 4/7] Terrain importer UI --- .../Config/UI/Windows/CreateNewMapWindow.ini | 109 +++++++++++-- src/TSMapEditor/UI/MainMenu.cs | 18 ++- .../MainMenuWindows/CreateNewMapWindow.cs | 143 +++++++++++++++++- 3 files changed, 249 insertions(+), 21 deletions(-) diff --git a/src/TSMapEditor/Config/UI/Windows/CreateNewMapWindow.ini b/src/TSMapEditor/Config/UI/Windows/CreateNewMapWindow.ini index ba1d744c3..026b2f5eb 100644 --- a/src/TSMapEditor/Config/UI/Windows/CreateNewMapWindow.ini +++ b/src/TSMapEditor/Config/UI/Windows/CreateNewMapWindow.ini @@ -1,13 +1,25 @@ [CreateNewMapWindow] -Width=300 -$CC0=lblHeader:XNALabel -$CC1=ddTheater:XNADropDown -$CC2=lblTheater:XNALabel -$CC3=tbWidth:EditorNumberTextBox -$CC4=lblWidth:XNALabel -$CC5=tbHeight:EditorNumberTextBox -$CC6=lblHeight:XNALabel -$CC7=btnCreate:EditorButton +Width=500 +$CC00=lblHeader:XNALabel +$CC01=ddTheater:XNADropDown +$CC02=lblTheater:XNALabel +$CC03=tbWidth:EditorNumberTextBox +$CC04=lblWidth:XNALabel +$CC05=tbHeight:EditorNumberTextBox +$CC06=lblHeight:XNALabel +$CC07=tbBasicHeight:EditorNumberTextBox +$CC08=lblBasicHeight:XNALabel +$CC09=tbTerrainImage:EditorTextBox +$CC10=lblTerrainImage:XNALabel +$CC11=btnSelectTerrainImage:EditorButton +$CC12=tbHeightmap:EditorTextBox +$CC13=lblHeightmap:XNALabel +$CC14=btnSelectHeightmap:EditorButton +$CC15=tbImportConfig:EditorTextBox +$CC16=lblImportConfig:XNALabel +$CC17=btnSelectImportConfig:EditorButton +$CC18=btnCreate:EditorButton +$CC19=btnApplyTerrainImageRatio:EditorButton $Height=getBottom(btnCreate) + EMPTY_SPACE_BOTTOM @@ -43,7 +55,7 @@ Text=Width: [tbHeight] $X=getX(ddTheater) -$Width=getWidth(ddTheater) +$Width=getWidth(ddTheater) - 100 $Y=getBottom(tbWidth) + VERTICAL_SPACING Text=100 PreviousControl=tbWidth @@ -53,10 +65,81 @@ $X=getX(lblTheater) $Y=getY(tbHeight) + 1 Text=Height: +[tbBasicHeight] +$X=getX(ddTheater) +$Width=getWidth(ddTheater) +$Y=getBottom(tbHeight) + VERTICAL_SPACING +Text=0 +PreviousControl=tbHeight + +[lblBasicHeight] +$X=getX(lblTheater) +$Y=getY(tbBasicHeight) + 1 +Text=Base height: + +[tbTerrainImage] +$X=getX(ddTheater) +$Width=getWidth(ddTheater) - 100 +$Y=getBottom(tbBasicHeight) + VERTICAL_SPACING +PreviousControl=tbBasicHeight + +[lblTerrainImage] +$X=getX(lblTheater) +$Y=getY(tbTerrainImage) + 1 +Text=Terrain map to import: + +[btnSelectTerrainImage] +$Width=100 - HORIZONTAL_SPACING +$Height=getHeight(tbTerrainImage) +$Y=getY(tbTerrainImage) +$X=getX(tbTerrainImage) + getWidth(tbTerrainImage) + HORIZONTAL_SPACING +Text=Browse + +[tbHeightmap] +$X=getX(ddTheater) +$Width=getWidth(ddTheater) - 100 +$Y=getBottom(tbTerrainImage) + VERTICAL_SPACING +PreviousControl=tbTerrainImage + +[lblHeightmap] +$X=getX(lblTheater) +$Y=getY(tbHeightmap) + 1 +Text=Heightmap to import: + +[btnSelectHeightmap] +$Width=100 - HORIZONTAL_SPACING +$Height=getHeight(tbHeightmap) +$Y=getY(tbHeightmap) +$X=getX(tbHeightmap) + getWidth(tbHeightmap) + HORIZONTAL_SPACING +Text=Browse + +[tbImportConfig] +$X=getX(ddTheater) +$Width=getWidth(ddTheater) - 100 +$Y=getBottom(tbHeightmap) + VERTICAL_SPACING +PreviousControl=tbHeightmap + +[lblImportConfig] +$X=getX(lblTheater) +$Y=getY(tbImportConfig) + 1 +Text=Importer config: + +[btnSelectImportConfig] +$Width=100 - HORIZONTAL_SPACING +$Height=getHeight(tbImportConfig) +$Y=getY(tbImportConfig) +$X=getX(tbImportConfig) + getWidth(tbImportConfig) + HORIZONTAL_SPACING +Text=Browse + [btnCreate] $Width=100 -$Y=getBottom(tbHeight) + EMPTY_SPACE_TOP -$X=horizontalCenterOnParent() +$Y=getBottom(tbImportConfig) + EMPTY_SPACE_TOP +$X=EMPTY_SPACE_SIDES Text=Create - +[btnApplyTerrainImageRatio] +$Width=100 +$Height=getHeight(tbHeight) +$Y=getY(tbHeight) +$X=500 - getWidth(btnApplyTerrainImageRatio) - HORIZONTAL_SPACING +Text=Auto diff --git a/src/TSMapEditor/UI/MainMenu.cs b/src/TSMapEditor/UI/MainMenu.cs index 6f7446528..05cf6ba1f 100644 --- a/src/TSMapEditor/UI/MainMenu.cs +++ b/src/TSMapEditor/UI/MainMenu.cs @@ -10,6 +10,7 @@ using TSMapEditor.UI.Windows; using TSMapEditor.UI.Windows.MainMenuWindows; using MessageBoxButtons = TSMapEditor.UI.Windows.MessageBoxButtons; +using TSMapEditor.Misc; #if WINDOWS using System.Windows.Forms; @@ -23,9 +24,7 @@ public class MainMenu : EditorPanel private const string DirectoryPrefix = " "; private const int BrowseButtonWidth = 70; - public MainMenu(WindowManager windowManager) : base(windowManager) - { - } + public MainMenu(WindowManager windowManager) : base(windowManager) { } private string gameDirectory; @@ -199,7 +198,18 @@ private void CreateMapWindow_OnCreateNewMap(object sender, CreateNewMapEventArgs throw new InvalidOperationException("Failed to create new map! Returned error message: " + error); MapSetup.LoadTheaterGraphics(WindowManager, gameDirectory); - ((CreateNewMapWindow)sender).OnCreateNewMap -= CreateMapWindow_OnCreateNewMap; + + if(!(e.TerrainImage == null && e.Heightmap != null && e.BasicLevel > 0)) + { + var configuration = new TerrainImporter.Configuration(string.IsNullOrEmpty(e.ImportConfig) ? + Environment.CurrentDirectory + "/Config/Importer/Default.ini" : e.ImportConfig + ); + var importer = new TerrainImporter(configuration); + + MapSetup.ImportTerrain(importer, e.TerrainImage, e.Heightmap, e.BasicLevel); + } + + ((CreateNewMapWindow) sender).OnCreateNewMap -= CreateMapWindow_OnCreateNewMap; } private void ReadGameInstallDirectoryFromRegistry() diff --git a/src/TSMapEditor/UI/Windows/MainMenuWindows/CreateNewMapWindow.cs b/src/TSMapEditor/UI/Windows/MainMenuWindows/CreateNewMapWindow.cs index 1caca5a7a..7a53121ea 100644 --- a/src/TSMapEditor/UI/Windows/MainMenuWindows/CreateNewMapWindow.cs +++ b/src/TSMapEditor/UI/Windows/MainMenuWindows/CreateNewMapWindow.cs @@ -1,21 +1,34 @@ -using Rampastring.XNAUI; +using Microsoft.Xna.Framework.Graphics; +using Rampastring.XNAUI; using Rampastring.XNAUI.XNAControls; using System; +using System.IO; using TSMapEditor.GameMath; +using TSMapEditor.Misc; using TSMapEditor.UI.Controls; namespace TSMapEditor.UI.Windows.MainMenuWindows { public class CreateNewMapEventArgs : EventArgs { - public CreateNewMapEventArgs(string theater, Point2D mapSize) + public CreateNewMapEventArgs(string theater, Point2D mapSize, Texture2D terrainImage = null, Texture2D heightmap = null, byte basicLevel = 0, string importConfig = null) { Theater = theater; MapSize = mapSize; + BasicLevel = basicLevel; + TerrainImage = terrainImage; + Heightmap = heightmap; + ImportConfig = importConfig; } public string Theater { get; } public Point2D MapSize { get; } + + public byte BasicLevel { get; } + + public Texture2D TerrainImage { get; } + public Texture2D Heightmap { get; } + public string ImportConfig { get; } } public class CreateNewMapWindow : INItializableWindow @@ -35,7 +48,14 @@ public CreateNewMapWindow(WindowManager windowManager, bool canExit) : base(wind private XNADropDown ddTheater; private EditorNumberTextBox tbWidth; private EditorNumberTextBox tbHeight; - + private EditorNumberTextBox tbBasicHeight; + private EditorButton btnSelectTerrainImage; + private EditorTextBox tbTerrainImage; + private EditorButton btnSelectHeightmap; + private EditorTextBox tbHeightmap; + private EditorButton btnSelectImportConfig; + private EditorTextBox tbImportConfig; + private EditorButton btnApplyTerrainImageRatio; public override void Initialize() { @@ -47,11 +67,29 @@ public override void Initialize() ddTheater = FindChild(nameof(ddTheater)); tbWidth = FindChild(nameof(tbWidth)); tbHeight = FindChild(nameof(tbHeight)); + tbBasicHeight = FindChild(nameof(tbBasicHeight)); + + btnSelectTerrainImage = FindChild(nameof(btnSelectTerrainImage)); + tbTerrainImage = FindChild(nameof(tbTerrainImage)); + + btnSelectHeightmap = FindChild(nameof(btnSelectHeightmap)); + tbHeightmap = FindChild(nameof(tbHeightmap)); + + btnSelectImportConfig = FindChild(nameof(btnSelectImportConfig)); + tbImportConfig = FindChild(nameof(tbImportConfig)); + + btnApplyTerrainImageRatio = FindChild(nameof(btnApplyTerrainImageRatio)); FindChild("btnCreate").LeftClick += BtnCreate_LeftClick; + btnSelectTerrainImage.LeftClick += BtnBrowseTerrainImage_LeftClick; + btnSelectHeightmap.LeftClick += BtnBrowseHeightmap_LeftClick; + btnSelectTerrainImage.LeftClick += BtnBrowseImportConfig_LeftClick; + btnApplyTerrainImageRatio.LeftClick += BtnApplyTerrainImageRatio_LeftClick; ddTheater.SelectedIndex = 0; + tbTerrainImage.Text = "W:\\Games\\C&C\\Maps\\Oresund.png"; + CenterOnParent(); } @@ -92,8 +130,105 @@ private void BtnCreate_LeftClick(object sender, EventArgs e) return; } - OnCreateNewMap?.Invoke(this, new CreateNewMapEventArgs(ddTheater.SelectedItem.Text, new Point2D(tbWidth.Value, tbHeight.Value))); + var bmpTerrainImage = LoadTerrainImage(); + var bmpHeightmap = LoadHeightmap(); + + OnCreateNewMap?.Invoke(this, new CreateNewMapEventArgs( + ddTheater.SelectedItem.Text, + new Point2D(tbWidth.Value, tbHeight.Value), + bmpTerrainImage, bmpHeightmap, + (byte) tbBasicHeight.Value, + tbImportConfig.Text + )); WindowManager.RemoveControl(this); } + + private Texture2D LoadTerrainImage() + { + try + { + if (string.IsNullOrWhiteSpace(tbTerrainImage.Text)) + return null; + + Texture2D texture; + using (FileStream fileStream = new FileStream(tbTerrainImage.Text, FileMode.Open)) + { + texture = Texture2D.FromStream(GraphicsDevice, fileStream); + } + return texture; + } + catch (Exception ex) + { + EditorMessageBox.Show(WindowManager, "Import error", "File could not be open.", MessageBoxButtons.OK); + return null; + } + } + + private Texture2D LoadHeightmap() + { + try + { + if (string.IsNullOrWhiteSpace(tbHeightmap.Text)) + return null; + + Texture2D texture; + using (FileStream fileStream = new FileStream(tbHeightmap.Text, FileMode.Open)) + { + texture = Texture2D.FromStream(GraphicsDevice, fileStream); + } + return texture; + } + catch (Exception ex) + { + EditorMessageBox.Show(WindowManager, "Import error", "File could not be open.", MessageBoxButtons.OK); + return null; + } + } + + private void BtnBrowseTerrainImage_LeftClick(object sender, EventArgs e) + { + FileSystemExtensions.OpenFile( + onOpened: (fileName) => + { + tbTerrainImage.Text = fileName; + }, + filter: Constants.OpenImageFileDialogFilter + ); + } + private void BtnBrowseHeightmap_LeftClick(object sender, EventArgs e) + { + FileSystemExtensions.OpenFile( + onOpened: (fileName) => + { + tbHeightmap.Text = fileName; + }, + filter: Constants.OpenImageFileDialogFilter + ); + } + private void BtnBrowseImportConfig_LeftClick(object sender, EventArgs e) + { + FileSystemExtensions.OpenFile( + onOpened: (fileName) => + { + tbImportConfig.Text = fileName; + }, + filter: Constants.OpenIniFileDialogFilter + ); + } + + private void BtnApplyTerrainImageRatio_LeftClick(object sender, EventArgs e) + { + var img = LoadTerrainImage(); + if(img != null) + { + // w1 / h1 = w2 / h2 + // h1 / w1 = h2 / w2 + // w1 = w2 * (h1 / h2) + // h1 = h2 * (w1 / w2) + + tbHeight.Value = ((int)((float) img.Height * Constants.CellWHRatio * (tbWidth.Value) / (float) img.Width)); + //tbWidth.Value = ((int) ((float) bmpTerrainImage.Width * (float.Parse(tbHeight.Text) / (float) bmpTerrainImage.Height))); + } + } } } From 6bbebc07923d17b7b689b523164f38ef21371ffb Mon Sep 17 00:00:00 2001 From: Multfinite Date: Fri, 22 Sep 2023 21:21:49 +0300 Subject: [PATCH 5/7] UI Fix #1 --- .../Config/UI/Windows/CreateNewMapWindow.ini | 12 ++++++------ .../UI/Windows/MainMenuWindows/CreateNewMapWindow.cs | 2 -- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/TSMapEditor/Config/UI/Windows/CreateNewMapWindow.ini b/src/TSMapEditor/Config/UI/Windows/CreateNewMapWindow.ini index 026b2f5eb..e4766f7a6 100644 --- a/src/TSMapEditor/Config/UI/Windows/CreateNewMapWindow.ini +++ b/src/TSMapEditor/Config/UI/Windows/CreateNewMapWindow.ini @@ -86,14 +86,14 @@ PreviousControl=tbBasicHeight [lblTerrainImage] $X=getX(lblTheater) $Y=getY(tbTerrainImage) + 1 -Text=Terrain map to import: +Text=Terrain map: [btnSelectTerrainImage] $Width=100 - HORIZONTAL_SPACING $Height=getHeight(tbTerrainImage) $Y=getY(tbTerrainImage) $X=getX(tbTerrainImage) + getWidth(tbTerrainImage) + HORIZONTAL_SPACING -Text=Browse +Text=... [tbHeightmap] $X=getX(ddTheater) @@ -104,14 +104,14 @@ PreviousControl=tbTerrainImage [lblHeightmap] $X=getX(lblTheater) $Y=getY(tbHeightmap) + 1 -Text=Heightmap to import: +Text=Heightmap: [btnSelectHeightmap] $Width=100 - HORIZONTAL_SPACING $Height=getHeight(tbHeightmap) $Y=getY(tbHeightmap) $X=getX(tbHeightmap) + getWidth(tbHeightmap) + HORIZONTAL_SPACING -Text=Browse +Text=... [tbImportConfig] $X=getX(ddTheater) @@ -129,12 +129,12 @@ $Width=100 - HORIZONTAL_SPACING $Height=getHeight(tbImportConfig) $Y=getY(tbImportConfig) $X=getX(tbImportConfig) + getWidth(tbImportConfig) + HORIZONTAL_SPACING -Text=Browse +Text=... [btnCreate] $Width=100 $Y=getBottom(tbImportConfig) + EMPTY_SPACE_TOP -$X=EMPTY_SPACE_SIDES +$X=horizontalCenterOnParent() Text=Create [btnApplyTerrainImageRatio] diff --git a/src/TSMapEditor/UI/Windows/MainMenuWindows/CreateNewMapWindow.cs b/src/TSMapEditor/UI/Windows/MainMenuWindows/CreateNewMapWindow.cs index 7a53121ea..ba08cac7f 100644 --- a/src/TSMapEditor/UI/Windows/MainMenuWindows/CreateNewMapWindow.cs +++ b/src/TSMapEditor/UI/Windows/MainMenuWindows/CreateNewMapWindow.cs @@ -88,8 +88,6 @@ public override void Initialize() ddTheater.SelectedIndex = 0; - tbTerrainImage.Text = "W:\\Games\\C&C\\Maps\\Oresund.png"; - CenterOnParent(); } From 9ca8a003a63c4c6ad3b0692ffb0e4d98f05dfa90 Mon Sep 17 00:00:00 2001 From: ZivDero Date: Mon, 8 Jan 2024 01:48:59 +0300 Subject: [PATCH 6/7] Fix bad filter name --- src/TSMapEditor/Config/Constants.ini | 2 +- src/TSMapEditor/Constants.cs | 4 ++-- src/TSMapEditor/UI/MainMenu.cs | 2 +- src/TSMapEditor/UI/TopBar/TopBarMenu.cs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/TSMapEditor/Config/Constants.ini b/src/TSMapEditor/Config/Constants.ini index c2bc6f7b1..06b22d86c 100644 --- a/src/TSMapEditor/Config/Constants.ini +++ b/src/TSMapEditor/Config/Constants.ini @@ -48,7 +48,7 @@ GameRegistryInstallPath=SOFTWARE\DawnOfTheTiberiumAge ; Specifies the file filter string used in OpenFileDialog (Windows) ; For multiple file formats, list them with : (instead of ;) ; Example config with multiple file extensions: "YR maps|*.map:*.mpr:*.yrm|All files|*.*" -OpenFileDialogFilter=TS maps|*.map|All files|*.* +OpenMapFileDialogFilter=TS maps|*.map|All files|*.* ; Should the editor consider Ares [#include] or Phobos [$Include] section? EnableIniInclude=false diff --git a/src/TSMapEditor/Constants.cs b/src/TSMapEditor/Constants.cs index a57b9a1af..8089d2e4b 100644 --- a/src/TSMapEditor/Constants.cs +++ b/src/TSMapEditor/Constants.cs @@ -23,7 +23,7 @@ public static class Constants public static string GameRegistryInstallPath = "SOFTWARE\\DawnOfTheTiberiumAge"; public static bool EnableIniInclude = false; - public static string OpenFileMapDialogFilter = "TS maps|*.map|All files|*.*"; + public static string OpenMapFileDialogFilter = "TS maps|*.map|All files|*.*"; public static string OpenImageFileDialogFilter = "Images|*.bmp;*.png;*.jpg;*.jpeg|All files|*.*"; public static bool EnableIniInheritance = false; @@ -111,7 +111,7 @@ public static void Init() ExpectedClientExecutableName = constantsIni.GetStringValue(ConstantsSectionName, nameof(ExpectedClientExecutableName), ExpectedClientExecutableName); GameRegistryInstallPath = constantsIni.GetStringValue(ConstantsSectionName, nameof(GameRegistryInstallPath), GameRegistryInstallPath); - OpenFileMapDialogFilter = constantsIni.GetStringValue(ConstantsSectionName, nameof(OpenFileMapDialogFilter), OpenFileMapDialogFilter); + OpenMapFileDialogFilter = constantsIni.GetStringValue(ConstantsSectionName, nameof(OpenMapFileDialogFilter), OpenMapFileDialogFilter); EnableIniInclude = constantsIni.GetBooleanValue(ConstantsSectionName, nameof(EnableIniInclude), EnableIniInclude); EnableIniInheritance = constantsIni.GetBooleanValue(ConstantsSectionName, nameof(EnableIniInheritance), EnableIniInheritance); diff --git a/src/TSMapEditor/UI/MainMenu.cs b/src/TSMapEditor/UI/MainMenu.cs index 05cf6ba1f..f89565c4d 100644 --- a/src/TSMapEditor/UI/MainMenu.cs +++ b/src/TSMapEditor/UI/MainMenu.cs @@ -313,7 +313,7 @@ private void BtnBrowseMapPath_LeftClick(object sender, EventArgs e) using (OpenFileDialog openFileDialog = new OpenFileDialog()) { openFileDialog.InitialDirectory = tbMapPath.Text; - openFileDialog.Filter = Constants.OpenFileMapDialogFilter.Replace(':', ';'); + openFileDialog.Filter = Constants.OpenMapFileDialogFilter.Replace(':', ';'); openFileDialog.RestoreDirectory = true; if (openFileDialog.ShowDialog() == DialogResult.OK) diff --git a/src/TSMapEditor/UI/TopBar/TopBarMenu.cs b/src/TSMapEditor/UI/TopBar/TopBarMenu.cs index 0277598a7..2d4979735 100644 --- a/src/TSMapEditor/UI/TopBar/TopBarMenu.cs +++ b/src/TSMapEditor/UI/TopBar/TopBarMenu.cs @@ -265,7 +265,7 @@ private void Open() using (OpenFileDialog openFileDialog = new OpenFileDialog()) { openFileDialog.InitialDirectory = initialPath; - openFileDialog.Filter = Constants.OpenFileMapDialogFilter.Replace(':', ';'); + openFileDialog.Filter = Constants.OpenMapFileDialogFilter.Replace(':', ';'); openFileDialog.RestoreDirectory = true; if (openFileDialog.ShowDialog() == DialogResult.OK) @@ -287,7 +287,7 @@ private void SaveAs() { saveFileDialog.InitialDirectory = Path.GetDirectoryName(initialPath); saveFileDialog.FileName = Path.GetFileName(initialPath); - saveFileDialog.Filter = Constants.OpenFileMapDialogFilter.Replace(':', ';'); + saveFileDialog.Filter = Constants.OpenMapFileDialogFilter.Replace(':', ';'); saveFileDialog.RestoreDirectory = true; if (saveFileDialog.ShowDialog() == DialogResult.OK) From 89cc7f92120e7aed57ac9ca54f4fbf157dfb59d8 Mon Sep 17 00:00:00 2001 From: ZivDero Date: Mon, 8 Jan 2024 01:54:41 +0300 Subject: [PATCH 7/7] Changed config file header --- src/TSMapEditor/Config/Importer/Default.ini | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/TSMapEditor/Config/Importer/Default.ini b/src/TSMapEditor/Config/Importer/Default.ini index 9b0c29942..4cd6f6ce0 100644 --- a/src/TSMapEditor/Config/Importer/Default.ini +++ b/src/TSMapEditor/Config/Importer/Default.ini @@ -1,6 +1,7 @@ -; Terrain image importer configuration -; DEFAULT -; Author: Multfinite +; C&C World-Altering Editor (WAE) +; https://github.com/Rampastring/TSMapEditor + +; This file contains the configuration for the Terrain from image importer [Tiles] ; Internal name for mapping = TileID