From 586c19d4f43487165de0e51546d1251e8bbdc460 Mon Sep 17 00:00:00 2001 From: Zurphing <72351816+Zurphing@users.noreply.github.com> Date: Mon, 29 Jul 2024 18:08:20 -0400 Subject: [PATCH 1/4] Add files via upload --- OpenKh.Tools.Common.CustomImGui/ImGuiEx.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/OpenKh.Tools.Common.CustomImGui/ImGuiEx.cs b/OpenKh.Tools.Common.CustomImGui/ImGuiEx.cs index 28944ac85..7a6817c82 100644 --- a/OpenKh.Tools.Common.CustomImGui/ImGuiEx.cs +++ b/OpenKh.Tools.Common.CustomImGui/ImGuiEx.cs @@ -309,6 +309,23 @@ public static void ForCombo(string name, string[] items, Func getter, Actio var value = getter(); if (ImGui.Combo(name, ref value, items, items.Length)) setter(value); + } + + //Used for custom color/opacity in kh2mapstudio/eventactivators + public static void ForEdit5(string name, Func getter, Action setter, float speed = 0.01f) + { + var value = getter(); + if (ImGui.DragFloat(name, ref value, speed)) + setter(value); + } + + public static bool ForEdit(string label, Func get, Action set) + { + var value = get(); + var modified = ImGui.InputFloat3(label, ref value); + if (modified) + set(value); + return modified; } } } From 99b33f84458dd1d14056468d6b2dc641dfeff995 Mon Sep 17 00:00:00 2001 From: Zurphing <72351816+Zurphing@users.noreply.github.com> Date: Mon, 29 Jul 2024 18:08:41 -0400 Subject: [PATCH 2/4] Upload files. --- OpenKh.Tools.Kh2MapStudio/App.cs | 159 +++++--- OpenKh.Tools.Kh2MapStudio/EditorSettings.cs | 122 +++++++ OpenKh.Tools.Kh2MapStudio/MapRenderer.cs | 104 +++--- .../ObjEntryController.cs | 129 ++++--- OpenKh.Tools.Kh2MapStudio/Program.cs | 6 +- .../Settings.Designer.cs | 153 +++++++- OpenKh.Tools.Kh2MapStudio/Settings.settings | 33 ++ .../Windows/BobDescriptorWindow.cs | 185 +++++----- .../Windows/CameraWindow.cs | 11 + .../Windows/CollisionWindow.cs | 98 ++++- .../Windows/MeshGroupWindow.cs | 9 +- .../Windows/SpawnPointWindow.cs | 341 ++++++++++++++++-- 12 files changed, 1066 insertions(+), 284 deletions(-) diff --git a/OpenKh.Tools.Kh2MapStudio/App.cs b/OpenKh.Tools.Kh2MapStudio/App.cs index 078ccb160..74bf4b69b 100644 --- a/OpenKh.Tools.Kh2MapStudio/App.cs +++ b/OpenKh.Tools.Kh2MapStudio/App.cs @@ -4,12 +4,14 @@ using OpenKh.Engine; using OpenKh.Kh2; using OpenKh.Tools.Common.CustomImGui; +using OpenKh.Tools.Kh2MapStudio.Models; using OpenKh.Tools.Kh2MapStudio.Windows; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Numerics; +using System.Reflection; using System.Windows; using Xe.Tools.Wpf.Dialogs; using static OpenKh.Tools.Common.CustomImGui.ImGuiEx; @@ -86,30 +88,36 @@ public string Title var mapName = _mapName != null ? $"{_mapName}@" : string.Empty; return $"{mapName}{_gamePath ?? "unloaded"} | {MonoGameImGuiBootstrap.ApplicationName}"; } + } + + private string GamePath + { + get => _gamePath; + set + { + _gamePath = value; + UpdateTitle(); + EnumerateMapList(); + + _objEntryController?.Dispose(); + + // Determine the objentry file to use + var objEntryFileName = Path.Combine(_gamePath, "mapstudio", "00objentry.bin"); + if (!File.Exists(objEntryFileName)) + { + objEntryFileName = Path.Combine(_gamePath, "00objentry.bin"); + } + + _objEntryController = new ObjEntryController( + _bootstrap.GraphicsDevice, + _objPath, + objEntryFileName); + _mapRenderer.ObjEntryController = _objEntryController; + + Settings.Default.GamePath = value; + Settings.Default.Save(); + } } - - private string GamePath - { - get => _gamePath; - set - { - _gamePath = value; - UpdateTitle(); - EnumerateMapList(); - - _objEntryController?.Dispose(); - _objEntryController = new ObjEntryController( - _bootstrap.GraphicsDevice, - _objPath, - Path.Combine(_gamePath, "00objentry.bin")); - _mapRenderer.ObjEntryController = _objEntryController; - - Settings.Default.GamePath = value; - Settings.Default.Save(); - - } - } - private string MapName { get => _mapName; @@ -179,8 +187,9 @@ public bool MainLoop() ImGui.Text($"AreaSettings {x} -1"); } } - } + } + if (EditorSettings.ViewCamera) CameraWindow.Run(_mapRenderer.Camera); if (EditorSettings.ViewLayerControl) @@ -188,7 +197,9 @@ public bool MainLoop() if (EditorSettings.ViewSpawnPoint) SpawnPointWindow.Run(_mapRenderer); if (EditorSettings.ViewMeshGroup) - MeshGroupWindow.Run(_mapRenderer.MapMeshGroups); + MeshGroupWindow.Run(_mapRenderer.MapMeshGroups); + if (EditorSettings.ViewCollision && _mapRenderer.MapCollision != null) + CollisionWindow.Run(_mapRenderer.MapCollision.Coct); if (EditorSettings.ViewBobDescriptor) BobDescriptorWindow.Run(_mapRenderer.BobDescriptors, _mapRenderer.BobMeshGroups.Count); if (EditorSettings.ViewSpawnScriptMap) @@ -196,7 +207,8 @@ public bool MainLoop() if (EditorSettings.ViewSpawnScriptBattle) SpawnScriptWindow.Run("btl", _mapRenderer.SpawnScriptBattle); if (EditorSettings.ViewSpawnScriptEvent) - SpawnScriptWindow.Run("evt", _mapRenderer.SpawnScriptEvent); + SpawnScriptWindow.Run("evt", _mapRenderer.SpawnScriptEvent); + if (EditorSettings.ViewEventScript && _mapRenderer.EventScripts != null) { @@ -205,7 +217,13 @@ public bool MainLoop() EventScriptWindow.Run(eventScript.Name, eventScript); } } - }); + }); + + //Add separate Camera Window if setting is toggled on. + if (EditorSettings.SeparateCamera) + { + SeparateWindow.Run(_mapRenderer.Camera); + }; SelectArdFilesPopup(); @@ -289,10 +307,11 @@ private void MainWindow() ForControl(() => { var nextPos = ImGui.GetCursorPos(); - var ret = ImGui.Begin("MapList", - ImGuiWindowFlags.NoDecoration | - ImGuiWindowFlags.NoCollapse | - ImGuiWindowFlags.NoMove); + var ret = ImGui.Begin("Map List", //List of all the maps, the left-side bar. + //ImGuiWindowFlags.NoDecoration | //Removes the scroll-bar + ImGuiWindowFlags.NoCollapse | //Prevents it from being collapsible + ImGuiWindowFlags.AlwaysAutoResize | //NEW: Resizes the window to accomodate the "Please select a map" text. + ImGuiWindowFlags.NoMove); //Prevents it from being moved around ImGui.SetWindowPos(nextPos); ImGui.SetWindowSize(new Vector2(64, 0)); return ret; @@ -324,11 +343,11 @@ private void MainWindow() } } })); - ImGui.SameLine(); + //ImGui.SameLine(); if (!IsMapOpen) { - ImGui.Text("Please select a map to edit."); + //ImGui.Text("Select a map to edit."); //Text. Appears at the bottom of the list, commented out. return; } @@ -356,30 +375,58 @@ void MainMenu() ForMenuItem("Camera Collision", ExportCameraCollision, _mapRenderer.ShowCameraCollision.HasValue); ForMenuItem("Light Collision", ExportLightCollision, _mapRenderer.ShowLightCollision.HasValue); }); - ImGui.Separator(); - ForMenu("Preferences", () => - { - ForEdit("Movement speed", () => EditorSettings.MoveSpeed, x => EditorSettings.MoveSpeed = x); - ForEdit("Movement speed (shift)", () => EditorSettings.MoveSpeedShift, x => EditorSettings.MoveSpeedShift = x); - }); - ImGui.Separator(); + ImGui.Separator(); ForMenuItem("Exit", MenuFileExit); }); ForMenu("View", () => { - ForMenuCheck("Camera", () => EditorSettings.ViewCamera, x => EditorSettings.ViewCamera = x); + ForMenuCheck("Camera", () => EditorSettings.ViewCamera, x => EditorSettings.ViewCamera = x); + ForMenuCheck("Separate Camera Window", () => EditorSettings.SeparateCamera, x => EditorSettings.SeparateCamera = x); ForMenuCheck("Layer control", () => EditorSettings.ViewLayerControl, x => EditorSettings.ViewLayerControl = x); ForMenuCheck("Spawn points", () => EditorSettings.ViewSpawnPoint, x => EditorSettings.ViewSpawnPoint = x); ForMenuCheck("BOB descriptors", () => EditorSettings.ViewBobDescriptor, x => EditorSettings.ViewBobDescriptor = x); - ForMenuCheck("Mesh group", () => EditorSettings.ViewMeshGroup, x => EditorSettings.ViewMeshGroup = x); + ForMenuCheck("Mesh group", () => EditorSettings.ViewMeshGroup, x => EditorSettings.ViewMeshGroup = x); + ForMenuCheck("Collision (Experimental)", () => EditorSettings.ViewCollision, x => EditorSettings.ViewCollision = x); ForMenuCheck("Spawn script MAP", () => EditorSettings.ViewSpawnScriptMap, x => EditorSettings.ViewSpawnScriptMap = x); ForMenuCheck("Spawn script BTL", () => EditorSettings.ViewSpawnScriptBattle, x => EditorSettings.ViewSpawnScriptBattle = x); ForMenuCheck("Spawn script EVT", () => EditorSettings.ViewSpawnScriptEvent, x => EditorSettings.ViewSpawnScriptEvent = x); ForMenuCheck("Event script", () => EditorSettings.ViewEventScript, x => EditorSettings.ViewEventScript = x); }); + + ForMenu("Preferences", () => + { + ForMenu("Movement Speed", () => + { + ForEdit("Default Speed", () => EditorSettings.MoveSpeed, x => EditorSettings.MoveSpeed = x); + ForEdit("Accelerated Speed (hold shift)", () => EditorSettings.MoveSpeedShift, x => EditorSettings.MoveSpeedShift = x); + }); + ForMenu("Event Activator Colors & Opacity", () => + { + ForEdit5("Opacity", () => EditorSettings.OpacityLevel, x => EditorSettings.OpacityLevel = x); + ForEdit5("Red", () => EditorSettings.RedValue, x => EditorSettings.RedValue = x); + ForEdit5("Green", () => EditorSettings.GreenValue, x => EditorSettings.GreenValue = x); + ForEdit5("Blue", () => EditorSettings.BlueValue, x => EditorSettings.BlueValue = x); + }); + ForMenu("Event Activator Entrance Colors & Opacity", () => + { + ForEdit5("Opacity", () => EditorSettings.OpacityEntranceLevel, x => EditorSettings.OpacityEntranceLevel = x); + ForEdit5("Red", () => EditorSettings.RedValueEntrance, x => EditorSettings.RedValueEntrance = x); + ForEdit5("Green", () => EditorSettings.GreenValueEntrance, x => EditorSettings.GreenValueEntrance = x); + ForEdit5("Blue", () => EditorSettings.BlueValueEntrance, x => EditorSettings.BlueValueEntrance = x); + }); + ForMenu("Default Window Size", () => + { + ForEdit("Window Width", () => EditorSettings.InitialWindowWidth, x => EditorSettings.InitialWindowWidth = x); + ForEdit("Window Height", () => EditorSettings.InitialWindowHeight, x => EditorSettings.InitialWindowHeight = x); + + }); + }); + ForMenu("Help", () => { ForMenuItem("About", ShowAboutDialog); + ForMenuItem("Preference Info", ShowPrefDialog); + ForMenuItem("Controls", ShowControlsDialog); }); }); } @@ -527,7 +574,6 @@ private void ProcessKeyboardInput(KeyboardState keyboard, float deltaTime) camera.CameraPosition += new Vector3(0, 1 * moveSpeed * 5, 0); if (keyboard.IsKeyDown(Keys.LeftControl)) camera.CameraPosition += new Vector3(0, -1 * moveSpeed * 5, 0); - if (keyboard.IsKeyDown(Keys.Up)) camera.CameraRotationYawPitchRoll += new Vector3(0, 0, 1 * speed); if (keyboard.IsKeyDown(Keys.Down)) @@ -577,7 +623,30 @@ private static void ExportScene(string fileName, Scene scene) public static void ShowError(string message, string title = "Error") => MessageBox.Show(message, title, MessageBoxButton.OK, MessageBoxImage.Error); - private void ShowAboutDialog() => - MessageBox.Show("OpenKH is amazing."); + private void ShowAboutDialog() => + //MessageBox.Show("OpenKH is amazing."); + MessageBox.Show("Welcome to OpenKH MapStudio." + + "\n\nThis tool allows you to view .map files along with their associated .ard files." + + "\n\nThe .map and .ard files are loaded using the extracted game data. " + + "\n\nEntities are loaded from the extracted 00objentry.bin & obj folder. New maps and entities can be added into the extracted game data to have them usable in MapStudio." + + "\n\nAlternatively, you can create a folder named mapstudio in your extracted game folder. Placing a modified 00objentry.bin as well as any MDLXs inside that folder will cause MapStudio to prioritize loading from that folder instead." + + "\n\nA .map file contains the geometry and collision of the map." + + "\n\nAn .ard file controls what spawns inside of a map." + + "\n\nSpawn points, where you can encounter enemies, cutscenes, cutscene triggers, chest locations, etc. are all handled by .ard files." + + "\n\nView documentation on openkh.dev to learn more about the file." + ); + + private void ShowPrefDialog() => + MessageBox.Show("Movement speed will alter how fast you can move through the map." + + "\n\nEvent Activator Opacity & Red, Green, and Blue Values all control how the triggers that send you to different areas & spawn enemies will look." + + "\n\nEntrance Marker will mark the entrances of warp points with that color, so that you can properly orient the entrance in the map." + + "\n\nValues for RGBA are floats. For the most accurate representation of warps the values should be set between 0 and 1, though values below 0 and above 1 will work." + + "\n\nValues for Opacity are floats between 0 and 1."); + + private void ShowControlsDialog() => + MessageBox.Show("W/A/S/D/E/Q: Moves in any direction, influenced by the camera's rotation." + + "\n\nLeft Control/Space: Move directly down/up, regardless of camera's rotation." + + "\n\nShift: Increase movement speed (can be changed under Preferences)." + + "\n\nLeft Click/Arrow Keys: Rotate Camera"); } } diff --git a/OpenKh.Tools.Kh2MapStudio/EditorSettings.cs b/OpenKh.Tools.Kh2MapStudio/EditorSettings.cs index 2ec51ec6d..661f09d00 100644 --- a/OpenKh.Tools.Kh2MapStudio/EditorSettings.cs +++ b/OpenKh.Tools.Kh2MapStudio/EditorSettings.cs @@ -60,6 +60,16 @@ public static bool ViewMeshGroup Settings.Default.ViewMeshGroup = value; Settings.Default.Save(); } + } + + public static bool ViewCollision + { + get => Settings.Default.ViewCollision; + set + { + Settings.Default.ViewCollision = value; + Settings.Default.Save(); + } } public static bool ViewBobDescriptor @@ -110,6 +120,118 @@ public static bool ViewEventScript Settings.Default.ViewEventScript = value; Settings.Default.Save(); } + } + + public static bool SeparateCamera + { + get => Settings.Default.SeparateCamera; + set + { + Settings.Default.SeparateCamera = value; + Settings.Default.Save(); + } + } + public static float OpacityLevel + { + get => Settings.Default.OpacityLevel; + set + { + Settings.Default.OpacityLevel = value; + Settings.Default.Save(); + } } + + public static float RedValue + { + get => Settings.Default.RedValue; + set + { + Settings.Default.RedValue = value; + Settings.Default.Save(); + } + } + + public static float GreenValue + { + get => Settings.Default.GreenValue; + set + { + Settings.Default.GreenValue = value; + Settings.Default.Save(); + } + } + + public static float BlueValue + { + get => Settings.Default.BlueValue; + set + { + Settings.Default.BlueValue = value; + Settings.Default.Save(); + } + } + + public static float OpacityEntranceLevel + { + get => Settings.Default.OpacityEntranceLevel; + set + { + Settings.Default.OpacityEntranceLevel = value; + Settings.Default.Save(); + } + } + + public static float RedValueEntrance + { + get => Settings.Default.RedValueEntrance; + set + { + Settings.Default.RedValueEntrance = value; + Settings.Default.Save(); + } + } + + public static float GreenValueEntrance + { + get => Settings.Default.GreenValueEntrance; + set + { + Settings.Default.GreenValueEntrance = value; + Settings.Default.Save(); + } + } + + public static float BlueValueEntrance + { + get => Settings.Default.BlueValueEntrance; + set + { + Settings.Default.BlueValueEntrance = value; + Settings.Default.Save(); + } + } + + public static int InitialWindowWidth + { + get => Settings.Default.InitialWindowWidth; + set + { + Settings.Default.InitialWindowWidth = value; + Settings.Default.Save(); + + } + } + + public static int InitialWindowHeight + { + get => Settings.Default.InitialWindowHeight; + set + { + Settings.Default.InitialWindowHeight = value; + Settings.Default.Save(); + + } + } + } } diff --git a/OpenKh.Tools.Kh2MapStudio/MapRenderer.cs b/OpenKh.Tools.Kh2MapStudio/MapRenderer.cs index f8c6aecca..a34c578a7 100644 --- a/OpenKh.Tools.Kh2MapStudio/MapRenderer.cs +++ b/OpenKh.Tools.Kh2MapStudio/MapRenderer.cs @@ -338,58 +338,70 @@ public void Draw() } } - if (CurrentSpawnPoint != null) - { - foreach (var spawnPoint in CurrentSpawnPoint.SpawnPoints) - { - foreach (var entity in spawnPoint.Entities) - { - _shader.SetModelView(Matrix4x4.CreateRotationX(entity.RotationX) * - Matrix4x4.CreateRotationY(entity.RotationY) * - Matrix4x4.CreateRotationZ(entity.RotationZ) * - Matrix4x4.CreateTranslation(entity.PositionX, -entity.PositionY, -entity.PositionZ)); - RenderMeshNew(pass, CurrentSpawnPoint.ObjEntryCtrl[entity.ObjectId], true); - } - - _graphics.RasterizerState = new RasterizerState() - { - CullMode = CullMode.None - }; - _shader.SetRenderTexture(pass, _whiteTexture); - foreach (var item in spawnPoint.EventActivators) - { - _shader.SetModelView(Matrix4x4.CreateRotationX(item.RotationX) * - Matrix4x4.CreateRotationY(item.RotationY) * - Matrix4x4.CreateRotationZ(item.RotationZ) * - Matrix4x4.CreateScale(item.ScaleX, item.ScaleY, item.ScaleZ) * - Matrix4x4.CreateTranslation(item.PositionX, -item.PositionY, -item.PositionZ)); - pass.Apply(); - - var color = new xna.Color(1f, 0f, 0f, .5f); - float opacity = 0.3f; - var vertices = new PositionColoredTextured[] - { - new PositionColoredTextured(-1, -1, -1, 0, 0, 1f, 0f, 0f, opacity), - new PositionColoredTextured(+1, -1, -1, 0, 0, 1f, 0f, 0f, opacity), - new PositionColoredTextured(+1, +1, -1, 0, 0, 1f, 0f, 0f, opacity), - new PositionColoredTextured(-1, +1, -1, 0, 0, 1f, 0f, 0f, opacity), - new PositionColoredTextured(-1, -1, +1, 0, 0, 1f, 0f, 0f, opacity), - new PositionColoredTextured(+1, -1, +1, 0, 0, 1f, 0f, 0f, opacity), - new PositionColoredTextured(+1, +1, +1, 0, 0, 1f, 0f, 0f, opacity), - new PositionColoredTextured(-1, +1, +1, 0, 0, 1f, 0f, 0f, opacity), - }; - var indices = new int[] - { + if (CurrentSpawnPoint != null) + if (CurrentSpawnPoint != null) + { + foreach (var spawnPoint in CurrentSpawnPoint.SpawnPoints) + { + foreach (var entity in spawnPoint.Entities) + { + _shader.SetModelView(Matrix4x4.CreateRotationX(entity.RotationX) * + Matrix4x4.CreateRotationY(entity.RotationY) * + Matrix4x4.CreateRotationZ(entity.RotationZ) * + Matrix4x4.CreateTranslation(entity.PositionX, -entity.PositionY, -entity.PositionZ)); + RenderMeshNew(pass, CurrentSpawnPoint.ObjEntryCtrl[entity.ObjectId], true); + } + + _graphics.RasterizerState = new RasterizerState() + { + CullMode = CullMode.None + }; + _shader.SetRenderTexture(pass, _whiteTexture); + foreach (var item in spawnPoint.EventActivators) + { + _shader.SetModelView(Matrix4x4.CreateRotationX(item.RotationX) * + Matrix4x4.CreateRotationY(item.RotationY) * + Matrix4x4.CreateRotationZ(item.RotationZ) * + Matrix4x4.CreateScale(item.ScaleX, item.ScaleY, item.ScaleZ) * + Matrix4x4.CreateTranslation(item.PositionX, -item.PositionY, -item.PositionZ)); + pass.Apply(); + + var color = new xna.Color(1f, 0f, 0f, .5f); + //float opacity = 0.3f; + var opacity = (float)(EditorSettings.OpacityLevel); + var RedValue = (float)(EditorSettings.RedValue); + var GreenValue = (float)(EditorSettings.GreenValue); + var BlueValue = (float)(EditorSettings.BlueValue); + var opacityEntrance = (float)(EditorSettings.OpacityEntranceLevel); + var RedValueEntrance = (float)(EditorSettings.RedValueEntrance); + var GreenValueEntrance = (float)(EditorSettings.GreenValueEntrance); + var BlueValueEntrance = (float)(EditorSettings.BlueValueEntrance); + var vertices = new PositionColoredTextured[] + { + //Order of constructing vertices matters. It's currently constructed "Side to side", lets see if we can construct it "Front to back" + new PositionColoredTextured(-1, -1, -1, 0, 0, RedValue, GreenValue, BlueValue, opacity), //Vertex 1 (1-4 are the right-side vertices) + new PositionColoredTextured(+1, -1, -1, 0, 0, RedValueEntrance, GreenValueEntrance, BlueValueEntrance, opacityEntrance), //Vertex 2 (Good with Vertex 7) + new PositionColoredTextured(+1, +1, -1, 0, 0, RedValueEntrance, GreenValueEntrance, BlueValueEntrance, opacityEntrance), //Vertex 3 (Good with Vertex 7) + //(3-6 represent the bottom-left & top-right vertices, connecting.) + new PositionColoredTextured(-1, +1, -1, 0, 0, RedValue, GreenValue, BlueValue, opacity), //Vertex 4 + new PositionColoredTextured(-1, -1, +1, 0, 0, RedValue, GreenValue, BlueValue, opacity), //Vertex 5 (5-8 are the left-side vertices) + new PositionColoredTextured(+1, -1, +1, 0, 0, RedValueEntrance, GreenValueEntrance, BlueValueEntrance, opacityEntrance), //Vertex 6 Good with Vertex 7... + new PositionColoredTextured(+1, +1, +1, 0, 0, RedValueEntrance, GreenValueEntrance, BlueValueEntrance, opacityEntrance), //Vertex 7 + new PositionColoredTextured(-1, +1, +1, 0, 0, RedValue, GreenValue, BlueValue, opacity), //Vertex 8 + + }; + var indices = new int[] + { 0, 1, 3, 3, 1, 2, 1, 5, 2, 2, 5, 6, 5, 4, 6, 6, 4, 7, 4, 0, 7, 7, 0, 3, 3, 2, 7, 7, 2, 6, - 4, 5, 0, 0, 5, 1 - }; - _graphics.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, 8, indices, 0, 12, MeshLoader.PositionColoredTexturedVertexDeclaration); + 4, 5, 0, 0, 5, 1 + }; + _graphics.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, 8, indices, 0, 12, MeshLoader.PositionColoredTexturedVertexDeclaration); + } } - } } }); } diff --git a/OpenKh.Tools.Kh2MapStudio/ObjEntryController.cs b/OpenKh.Tools.Kh2MapStudio/ObjEntryController.cs index e4705fb80..14f72fb5e 100644 --- a/OpenKh.Tools.Kh2MapStudio/ObjEntryController.cs +++ b/OpenKh.Tools.Kh2MapStudio/ObjEntryController.cs @@ -49,52 +49,91 @@ public void Dispose() foreach (var texture in meshGroup.Value.Textures) texture.Dispose(); _meshGroups.Clear(); - } - - public string GetName(int objectId) => _objEntryLookupReversed[objectId]; - - public MeshGroup this[int objId] - { - get - { - if (_meshGroups.TryGetValue(objId, out var meshGroup)) - return meshGroup; - - var objEntryName = _objEntryLookupReversed[objId]; + } + + //Below: First tries to get the name from the specified index. + //If that fails, fall back to warning the user with the name. + public string GetName(int objectId) + { + if (_objEntryLookupReversed.TryGetValue(objectId, out var objEntryName)) + { + return objEntryName; + } + return "ENTITY ID NOT PRESENT IN OBJENTRY"; + } + + public MeshGroup this[int objId] + { + get + { + if (_meshGroups.TryGetValue(objId, out var meshGroup)) + return meshGroup; + + // Fix OBJIds being out of range by falling back onto a value of 1. + if (!_objEntryLookupReversed.ContainsKey(objId)) + { + objId = 1; // Default to 1 if out of range + } + + var objEntryName = _objEntryLookupReversed[objId]; + var baseModelPath = Path.Combine(_objPath, objEntryName); + var moddedFolderPath = Path.Combine(_objPath, "..", "mapstudio"); // Move up one level and then to 'mapstudio' + var moddedModelPath = Path.Combine(moddedFolderPath, objEntryName); + var baseModelFileName = baseModelPath + ".mdlx"; + var moddedModelFileName = moddedModelPath + ".mdlx"; + + // Determine the correct file path to load from, prioritizing modded path + var modelFileName = File.Exists(moddedModelFileName) ? moddedModelFileName : baseModelFileName; + + MeshGroup LoadMeshGroup(string fileName) + { + if (!File.Exists(fileName)) + return EmptyMeshGroup; + + var mdlxEntries = File.OpenRead(fileName).Using(Bar.Read); + var modelEntry = mdlxEntries.FirstOrDefault(x => x.Type == Bar.EntryType.Model); + if (modelEntry == null) + return EmptyMeshGroup; + + var model = Mdlx.Read(modelEntry.Stream); + ModelTexture textures = null; + + var textureEntry = mdlxEntries.FirstOrDefault(x => x.Type == Bar.EntryType.ModelTexture); + if (textureEntry != null) + textures = ModelTexture.Read(textureEntry.Stream); + + var modelMotion = MeshLoader.FromKH2(model); + modelMotion.ApplyMotion(modelMotion.InitialPose); + return new MeshGroup + { + MeshDescriptors = modelMotion.MeshDescriptors, + Textures = textures == null ? new IKingdomTexture[0] : textures.LoadTextures(_graphics).ToArray() + }; + } + + meshGroup = LoadMeshGroup(modelFileName); + + // Check if model or texture is missing and load from fallback if necessary. Loads a simple pyramid model. + if (meshGroup == EmptyMeshGroup || meshGroup.Textures.Length == 0) + { + var fallbackModelFileName = Path.Combine(_objPath, "F_HB700.mdlx"); + var fallbackMeshGroup = LoadMeshGroup(fallbackModelFileName); + + if (meshGroup == EmptyMeshGroup) + { + meshGroup = fallbackMeshGroup; + } + else if (meshGroup.Textures.Length == 0) + { + meshGroup.Textures = fallbackMeshGroup.Textures; + } + } + + _meshGroups[objId] = meshGroup; + return meshGroup; + } + } - var modelPath = Path.Combine(_objPath, objEntryName); - var modelFileName = modelPath + ".mdlx"; - if (File.Exists(modelFileName)) - { - var mdlxEntries = File.OpenRead(modelFileName).Using(Bar.Read); - var modelEntry = mdlxEntries.FirstOrDefault(x => x.Type == Bar.EntryType.Model); - if (modelEntry != null) - { - var model = Mdlx.Read(modelEntry.Stream); - ModelTexture textures = null; - - var textureEntry = mdlxEntries.FirstOrDefault(x => x.Type == Bar.EntryType.ModelTexture); - if (textureEntry != null) - textures = ModelTexture.Read(textureEntry.Stream); - - var modelMotion = MeshLoader.FromKH2(model); - modelMotion.ApplyMotion(modelMotion.InitialPose); - meshGroup = new MeshGroup - { - MeshDescriptors = modelMotion.MeshDescriptors, - Textures = textures == null ? new IKingdomTexture[0] : textures.LoadTextures(_graphics).ToArray() - }; - } - else - meshGroup = EmptyMeshGroup; - } - else - meshGroup = EmptyMeshGroup; - - _meshGroups[objId] = meshGroup; - return meshGroup; - } - } public MeshGroup this[string objName] => this[_objEntryLookup[objName]]; } diff --git a/OpenKh.Tools.Kh2MapStudio/Program.cs b/OpenKh.Tools.Kh2MapStudio/Program.cs index 4c5d975ea..836b9e68b 100644 --- a/OpenKh.Tools.Kh2MapStudio/Program.cs +++ b/OpenKh.Tools.Kh2MapStudio/Program.cs @@ -29,8 +29,10 @@ private static string GetVersion() public string GamePath { get; } #endregion - const int InitialWindowWidth = 1000; - const int InitialWindowHeight = 800; + //New variables for being able to change the default Window Height & Width + readonly int InitialWindowWidth = (int)(EditorSettings.InitialWindowWidth); + readonly int InitialWindowHeight = (int)(EditorSettings.InitialWindowHeight); + // private readonly MonoGameImGuiBootstrap _bootstrap; private App _app; diff --git a/OpenKh.Tools.Kh2MapStudio/Settings.Designer.cs b/OpenKh.Tools.Kh2MapStudio/Settings.Designer.cs index 72c1dddaf..02bbee9b1 100644 --- a/OpenKh.Tools.Kh2MapStudio/Settings.Designer.cs +++ b/OpenKh.Tools.Kh2MapStudio/Settings.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 @@ -12,7 +12,7 @@ namespace OpenKh.Tools.Kh2MapStudio { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.9.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -94,7 +94,22 @@ public bool ViewMeshGroup { this["ViewMeshGroup"] = value; } } - + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool ViewCollision + { + get + { + return ((bool)(this["ViewCollision"])); + } + set + { + this["ViewCollision"] = value; + } + } + [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("False")] @@ -166,5 +181,137 @@ public bool ViewEventScript { this["ViewEventScript"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0.3")] + public float OpacityLevel { + get { + return ((float)(this["OpacityLevel"])); + } + set { + this["OpacityLevel"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("1")] + public float RedValue { + get { + return ((float)(this["RedValue"])); + } + set { + this["RedValue"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public float GreenValue { + get { + return ((float)(this["GreenValue"])); + } + set { + this["GreenValue"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public float BlueValue { + get { + return ((float)(this["BlueValue"])); + } + set { + this["BlueValue"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0.3")] + public float OpacityEntranceLevel { + get { + return ((float)(this["OpacityEntranceLevel"])); + } + set { + this["OpacityEntranceLevel"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("1")] + public float RedValueEntrance { + get { + return ((float)(this["RedValueEntrance"])); + } + set { + this["RedValueEntrance"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public float GreenValueEntrance { + get { + return ((float)(this["GreenValueEntrance"])); + } + set { + this["GreenValueEntrance"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public float BlueValueEntrance { + get { + return ((float)(this["BlueValueEntrance"])); + } + set { + this["BlueValueEntrance"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool SeparateCamera { + get { + return ((bool)(this["SeparateCamera"])); + } + set { + this["SeparateCamera"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("1000")] + public int InitialWindowWidth { + get { + return ((int)(this["InitialWindowWidth"])); + } + set { + this["InitialWindowWidth"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("800")] + public int InitialWindowHeight { + get { + return ((int)(this["InitialWindowHeight"])); + } + set { + this["InitialWindowHeight"] = value; + } + } } } diff --git a/OpenKh.Tools.Kh2MapStudio/Settings.settings b/OpenKh.Tools.Kh2MapStudio/Settings.settings index 4ed7d5d9c..15257201d 100644 --- a/OpenKh.Tools.Kh2MapStudio/Settings.settings +++ b/OpenKh.Tools.Kh2MapStudio/Settings.settings @@ -38,5 +38,38 @@ False + + 0.3 + + + 1 + + + 0 + + + 0 + + + 0.3 + + + 1 + + + 0 + + + 0 + + + False + + + 1000 + + + 800 + \ No newline at end of file diff --git a/OpenKh.Tools.Kh2MapStudio/Windows/BobDescriptorWindow.cs b/OpenKh.Tools.Kh2MapStudio/Windows/BobDescriptorWindow.cs index 3d321c0f8..3663ea481 100644 --- a/OpenKh.Tools.Kh2MapStudio/Windows/BobDescriptorWindow.cs +++ b/OpenKh.Tools.Kh2MapStudio/Windows/BobDescriptorWindow.cs @@ -1,89 +1,96 @@ -using ImGuiNET; -using Microsoft.Xna.Framework; -using OpenKh.Kh2.Models; -using System; -using System.Collections.Generic; -using static OpenKh.Tools.Common.CustomImGui.ImGuiEx; -using static OpenKh.Tools.Kh2MapStudio.ImGuiExHelpers; - -namespace OpenKh.Tools.Kh2MapStudio.Windows -{ - public class BobDescriptorWindow - { - public static bool Run(List bobDescs, int bobCount) => ForHeader("BOB descriptors", () => - { - var bobToRemove = -1; - for (int i = 0; i < bobDescs.Count; i++) - { - var desc = bobDescs[i]; - if (ImGui.CollapsingHeader($"BOB descriptor##{i}")) - { - if (ImGui.BeginCombo("BOB model", bobCount > 0 ? - $"BOB #{desc.BobIndex}" : "No bob exists in this map")) - { - for (var j = 0; j < bobCount; j++) - { - if (ImGui.Selectable($"BOB #{j}", j == desc.BobIndex)) - desc.BobIndex = j; - } - ImGui.EndCombo(); - } - - ForEdit3("Position", - () => new Vector3(desc.PositionX, desc.PositionY, desc.PositionZ), - x => - { - desc.PositionX = x.X; - desc.PositionY = x.Y; - desc.PositionZ = x.Z; - }, 10f); - ForEdit3("Rotation", - () => new Vector3( - (float)(desc.RotationX * 180.0 / Math.PI), - (float)(desc.RotationY * 180.0 / Math.PI), - (float)(desc.RotationZ * 180.0 / Math.PI)), - x => - { - desc.RotationX = (float)(x.X * Math.PI / 180.0); - desc.RotationY = (float)(x.Y * Math.PI / 180.0); - desc.RotationZ = (float)(x.Z * Math.PI / 180.0); - }); - ForEdit3("Scaling", - () => new Vector3(desc.ScalingX, desc.ScalingY, desc.ScalingZ), - x => - { - desc.ScalingX = x.X; - desc.ScalingY = x.Y; - desc.ScalingZ = x.Z; - }, 0.01f); - - ForEdit("Unk28", () => desc.Unknown28, x => desc.Unknown28 = x); - ForEdit("Unk2c", () => desc.Unknown2c, x => desc.Unknown2c = x); - ForEdit("Unk30", () => desc.Unknown30, x => desc.Unknown30 = x); - ForEdit("Unk34", () => desc.Unknown34, x => desc.Unknown34 = x); - ForEdit("Unk38", () => desc.Unknown38, x => desc.Unknown38 = x); - ForEdit("Unk3c", () => desc.Unknown3c, x => desc.Unknown3c = x); - ForEdit("Unk40", () => desc.Unknown40, x => desc.Unknown40 = x); - ForEdit("Unk44", () => desc.Unknown44, x => desc.Unknown44 = x); - ForEdit("Unk48", () => desc.Unknown48, x => desc.Unknown48 = x); - ForEdit("Unk4c", () => desc.Unknown4c, x => desc.Unknown4c = x); - ForEdit("Unk50", () => desc.Unknown50, x => desc.Unknown50 = x); - ForEdit("Unk54", () => desc.Unknown54, x => desc.Unknown54 = x); - ForEdit("Unk58", () => desc.Unknown58, x => desc.Unknown58 = x); - ForEdit("Unk5c", () => desc.Unknown5c, x => desc.Unknown5c = x); - ForEdit("Unk60", () => desc.Unknown60, x => desc.Unknown60 = x); - ForEdit("Unk64", () => desc.Unknown64, x => desc.Unknown64 = x); - - if (ImGui.SmallButton("Remove this BOB descriptor")) - bobToRemove = i; - } - } - - if (bobToRemove >= 0) - bobDescs.RemoveAt(bobToRemove); - - if (ImGui.SmallButton("Add a new BOB descriptor")) - bobDescs.Add(new BobDescriptor()); - }); - } -} +using ImGuiNET; +using Microsoft.Xna.Framework; +using OpenKh.Kh2.Models; +using System; +using System.Collections.Generic; +using static OpenKh.Tools.Common.CustomImGui.ImGuiEx; +using static OpenKh.Tools.Kh2MapStudio.ImGuiExHelpers; + +namespace OpenKh.Tools.Kh2MapStudio.Windows +{ + public class BobDescriptorWindow + { + public static bool Run(List bobDescs, int bobCount) => ForHeader("BOB descriptors", () => + { + var bobToRemove = -1; + if (ImGui.SmallButton("Add a new BOB descriptor")) + bobDescs.Add(new BobDescriptor()); + for (int i = 0; i < bobDescs.Count; i++) + { + var desc = bobDescs[i]; + ImGui.Indent(20.0f); + var headerLabel = $"BOB descriptor #{i}"; + if (desc.BobIndex >= 0 && desc.BobIndex < bobCount) + { + headerLabel += $" (Model #{desc.BobIndex})"; + } + ImGui.PushID(i); + if (ImGui.CollapsingHeader(headerLabel)) + { + if (ImGui.SmallButton("Remove this BOB descriptor")) + bobToRemove = i; + if (ImGui.BeginCombo("BOB model", bobCount > 0 ? + $"BOB #{desc.BobIndex}" : "No bob exists in this map")) + { + for (var j = 0; j < bobCount; j++) + { + if (ImGui.Selectable($"BOB #{j}", j == desc.BobIndex)) + desc.BobIndex = j; + } + ImGui.EndCombo(); + } + + ForEdit3("Position", + () => new Vector3(desc.PositionX, desc.PositionY, desc.PositionZ), + x => + { + desc.PositionX = x.X; + desc.PositionY = x.Y; + desc.PositionZ = x.Z; + }, 10f); + ForEdit3("Rotation", + () => new Vector3( + (float)(desc.RotationX * 180.0 / Math.PI), + (float)(desc.RotationY * 180.0 / Math.PI), + (float)(desc.RotationZ * 180.0 / Math.PI)), + x => + { + desc.RotationX = (float)(x.X * Math.PI / 180.0); + desc.RotationY = (float)(x.Y * Math.PI / 180.0); + desc.RotationZ = (float)(x.Z * Math.PI / 180.0); + }); + ForEdit3("Scaling", + () => new Vector3(desc.ScalingX, desc.ScalingY, desc.ScalingZ), + x => + { + desc.ScalingX = x.X; + desc.ScalingY = x.Y; + desc.ScalingZ = x.Z; + }, 0.01f); + + ForEdit("Unk28", () => desc.Unknown28, x => desc.Unknown28 = x); + ForEdit("Unk2c", () => desc.Unknown2c, x => desc.Unknown2c = x); + ForEdit("Unk30", () => desc.Unknown30, x => desc.Unknown30 = x); + ForEdit("Unk34", () => desc.Unknown34, x => desc.Unknown34 = x); + ForEdit("Unk38", () => desc.Unknown38, x => desc.Unknown38 = x); + ForEdit("Unk3c", () => desc.Unknown3c, x => desc.Unknown3c = x); + ForEdit("Unk40", () => desc.Unknown40, x => desc.Unknown40 = x); + ForEdit("Unk44", () => desc.Unknown44, x => desc.Unknown44 = x); + ForEdit("Unk48", () => desc.Unknown48, x => desc.Unknown48 = x); + ForEdit("Unk4c", () => desc.Unknown4c, x => desc.Unknown4c = x); + ForEdit("Unk50", () => desc.Unknown50, x => desc.Unknown50 = x); + ForEdit("Unk54", () => desc.Unknown54, x => desc.Unknown54 = x); + ForEdit("Unk58", () => desc.Unknown58, x => desc.Unknown58 = x); + ForEdit("Unk5c", () => desc.Unknown5c, x => desc.Unknown5c = x); + ForEdit("Unk60", () => desc.Unknown60, x => desc.Unknown60 = x); + ForEdit("Unk64", () => desc.Unknown64, x => desc.Unknown64 = x); + } + ImGui.PopID(); + ImGui.Unindent(20.0f); + } + + if (bobToRemove >= 0) + bobDescs.RemoveAt(bobToRemove); + }); + } +} diff --git a/OpenKh.Tools.Kh2MapStudio/Windows/CameraWindow.cs b/OpenKh.Tools.Kh2MapStudio/Windows/CameraWindow.cs index a0f7bef67..e68e1db13 100644 --- a/OpenKh.Tools.Kh2MapStudio/Windows/CameraWindow.cs +++ b/OpenKh.Tools.Kh2MapStudio/Windows/CameraWindow.cs @@ -15,5 +15,16 @@ public static bool Run(Camera camera) => ForHeader("Camera", () => x => camera.CameraRotationYawPitchRoll = new Vector3( -x.X, camera.CameraRotationYawPitchRoll.Y, -x.Y)); }); + } + static class SeparateWindow + { + public static bool Run(Camera camera) => ForWindow("Camera", () => + { + ForEdit3("Position", () => camera.CameraPosition, x => camera.CameraPosition = x); + ForEdit2("Rotation", + () => new Vector2(-camera.CameraRotationYawPitchRoll.X, -camera.CameraRotationYawPitchRoll.Z), + x => camera.CameraRotationYawPitchRoll = new Vector3( + -x.X, camera.CameraRotationYawPitchRoll.Y, -x.Y)); + }); } } diff --git a/OpenKh.Tools.Kh2MapStudio/Windows/CollisionWindow.cs b/OpenKh.Tools.Kh2MapStudio/Windows/CollisionWindow.cs index 4a3b2df2a..0f2d63d69 100644 --- a/OpenKh.Tools.Kh2MapStudio/Windows/CollisionWindow.cs +++ b/OpenKh.Tools.Kh2MapStudio/Windows/CollisionWindow.cs @@ -1,10 +1,14 @@ using ImGuiNET; +using OpenKh.Engine.MonoGame; using OpenKh.Kh2; using static OpenKh.Tools.Common.CustomImGui.ImGuiEx; - +using OpenKh.Kh2.Utils; +using System.Numerics; + +//Partially implemented. Allows you to view the data, namespace OpenKh.Tools.Kh2MapStudio.Windows -{ - static class CollisionWindow +{ + class CollisionWindow { public static void Run(Coct coct) => ForHeader("Collision", () => { @@ -17,8 +21,11 @@ private static void Node(Coct coct, int index) return; ForTreeNode($"Node {index}", () => { - var node = coct.Nodes[index]; - ImGui.Text($"Box {node.BoundingBox}"); + var node = coct.Nodes[index]; + //ImGui.Text($"Box {node.BoundingBox}"); + BoundingBoxInt16 boundingBoxCopy = node.BoundingBox; + ImGuiCollHelper.EditBoundingBox("Bounding Box (Node)", ref boundingBoxCopy); + node.BoundingBox = boundingBoxCopy; // Set the modified bounding box back Node(coct, node.Child1); Node(coct, node.Child2); Node(coct, node.Child3); @@ -31,25 +38,86 @@ private static void Node(Coct coct, int index) foreach (var mesh in node.Meshes) { ForTreeNode($"Mesh {mesh.GetHashCode()}", () => - { - ImGui.Text($"Box {mesh.BoundingBox}"); - ImGui.Text($"Visibility {mesh.Visibility}"); - ImGui.Text($"Group {mesh.Group}"); - + { + ForEdit("Visibility", () => mesh.Visibility, x => mesh.Visibility = x); + ForEdit("Group", () => mesh.Group, x => mesh.Group = x); + BoundingBoxInt16 boundingBoxCopy = mesh.BoundingBox; + ImGuiCollHelper.EditBoundingBox("Bounding Box (Mesh)", ref boundingBoxCopy); + mesh.BoundingBox = boundingBoxCopy; // Set the modified bounding box back + //ImGui.Text($"Box {mesh.BoundingBox}"); + //ImGui.Text($"Visibility {mesh.Visibility}"); + //ImGui.Text($"Group {mesh.Group}"); foreach (var collision in mesh.Collisions) { ForTreeNode($"Collision {collision.GetHashCode()}", () => { - ImGui.Text($"Ground {collision.Ground}"); - ImGui.Text($"Floor Level {collision.FloorLevel}"); - ImGui.Text($"Plane {collision.Plane}"); - ImGui.Text($"Bound Box {collision.BoundingBox}"); - ImGui.Text($"Flags {collision.Attributes:X08}"); + ForEdit("Ground", () => collision.Ground, x => collision.Ground = x); + ForEdit("Floor Level", () => collision.FloorLevel, x => collision.FloorLevel = x); + //ImGui.Text($"Plane {collision.Plane}"); + //ImGui.Text($"Bound Box {collision.BoundingBox}"); + ForEdit("Flags", () => collision.Attributes.Flags, x => collision.Attributes.Flags = x); + BoundingBoxInt16 boundingBoxCopy = collision.BoundingBox; + ImGuiCollHelper.EditBoundingBox("Bounding Box (Collision)", ref boundingBoxCopy); + collision.BoundingBox = boundingBoxCopy; // Set the modified bounding box back + //ForEdit("UV Scroll Index", () => vifPacket.UVScrollIndex, x => vifPacket.UVScrollIndex = x); + Plane plane = collision.Plane; + ImGuiCollHelper.EditPlane(ref plane); + collision.Plane = plane; // Update the collision plane if it was changed + //ImGui.Text($"Flags {collision.Attributes:X08}"); }); } }); } }); + } + //Helper for Bounding Box + public static class ImGuiCollHelper + { + public static void EditBoundingBox(string label, ref BoundingBoxInt16 boundingBox) + { + if (ImGui.TreeNode(label)) + { + Vector3Int16 min = boundingBox.Minimum; + Vector3Int16 max = boundingBox.Maximum; + + EditVector3Int16("Minimum", ref min); + EditVector3Int16("Maximum", ref max); + + boundingBox = new BoundingBoxInt16(min, max); + + ImGui.TreePop(); + } + } + + private static void EditVector3Int16(string label, ref Vector3Int16 vector) + { + int x = vector.X; + int y = vector.Y; + int z = vector.Z; + + if (ImGui.DragInt(label + " X", ref x)) + vector.X = (short)x; + if (ImGui.DragInt(label + " Y", ref y)) + vector.Y = (short)y; + if (ImGui.DragInt(label + " Z", ref z)) + vector.Z = (short)z; + } + + public static void EditPlane(ref Plane plane) + { + Vector3 normal = plane.Normal; + float d = plane.D; + if (ImGui.TreeNode("Plane")) + { + //ImGui.Text("Plane:"); + ImGui.DragFloat("X", ref normal.X); + ImGui.DragFloat("Y", ref normal.Y); + ImGui.DragFloat("Z", ref normal.Z); + ImGui.DragFloat("D", ref d); + plane = new Plane(normal, d); + ImGui.TreePop(); + } + } } } } diff --git a/OpenKh.Tools.Kh2MapStudio/Windows/MeshGroupWindow.cs b/OpenKh.Tools.Kh2MapStudio/Windows/MeshGroupWindow.cs index 958bf8213..419777543 100644 --- a/OpenKh.Tools.Kh2MapStudio/Windows/MeshGroupWindow.cs +++ b/OpenKh.Tools.Kh2MapStudio/Windows/MeshGroupWindow.cs @@ -34,13 +34,19 @@ private static void MeshGroup(MeshGroupModel meshGroup, int index) for (var i = 0; i < meshGroup.Map.vifPacketRenderingGroup.Count; i++) { ForTreeNode($"Mesh Rendering Group {i}##{index}", () => - { + { + // if (ImGui.SmallButton("Apply changes")) //Adds the button ONLY for the entire group. + // meshGroup.Invalidate(); var group = meshGroup.Map.vifPacketRenderingGroup[i]; for (var j = 0; j < group.Length; j++) { + //if (ImGui.SmallButton("Apply changes")) //Adds the button for EACH group. + // meshGroup.Invalidate(); var meshIndex = group[j]; ForTreeNode($"Index {j}, Mesh {meshIndex}##{index}", () => { + if (ImGui.SmallButton("Apply changes")) //Adds the button for EACH group. + meshGroup.Invalidate(); var vifPacket = meshGroup.Map.Chunks[meshIndex]; ForEdit("Texture", () => vifPacket.TextureId, @@ -59,6 +65,7 @@ private static void MeshGroup(MeshGroupModel meshGroup, int index) ForEdit("Priority", () => vifPacket.Priority, x => vifPacket.Priority = x); ForEdit("Draw priority", () => vifPacket.DrawPriority, x => vifPacket.DrawPriority = x); ForEdit("Alpha flag", () => vifPacket.TransparencyFlag, x => vifPacket.TransparencyFlag = x); + ForEdit("UV Scroll Index", () => vifPacket.UVScrollIndex, x => vifPacket.UVScrollIndex = x); ImGui.Text("DMA per VIF dump:"); ImGui.Text(string.Join(",", vifPacket.DmaPerVif.Select(x => $"{x}"))); }); diff --git a/OpenKh.Tools.Kh2MapStudio/Windows/SpawnPointWindow.cs b/OpenKh.Tools.Kh2MapStudio/Windows/SpawnPointWindow.cs index 8ad881af5..26d2c2dac 100644 --- a/OpenKh.Tools.Kh2MapStudio/Windows/SpawnPointWindow.cs +++ b/OpenKh.Tools.Kh2MapStudio/Windows/SpawnPointWindow.cs @@ -1,48 +1,243 @@ using ImGuiNET; +using OpenKh.Common; //New +using Xe.Tools.Wpf.Dialogs; //New using OpenKh.Kh2.Ard; using OpenKh.Tools.Kh2MapStudio.Interfaces; using OpenKh.Tools.Kh2MapStudio.Models; +using System.IO; //New using System; +using System.Collections.Generic; using System.Linq; -using System.Numerics; +using System.Numerics; +using static OpenKh.Kh2.Ard.SpawnPoint; //Newly added, for WalkPath Addition. using static OpenKh.Tools.Common.CustomImGui.ImGuiEx; - +using OpenKh.Kh2; + namespace OpenKh.Tools.Kh2MapStudio.Windows { static class SpawnPointWindow { private static string ObjectFilter = ""; - private static ISpawnPointController _ctrl; + private static ISpawnPointController _ctrl; + private static string _newSpawnPointName = "N_00"; // Default name for the new spawn point + + public static bool Run(ISpawnPointController ctrl) => ForHeader("Spawn point editor", () => + { + _ctrl = ctrl; + + // Check list of spawn points is null or empty + if (ctrl.SpawnPoints != null && ctrl.SpawnPoints.Any()) + { + ImGui.PushItemWidth(200); // Adjust width as needed + if (ImGui.BeginCombo(" ", ctrl.SelectSpawnPoint)) + { + foreach (var spawnPoint in ctrl.SpawnPoints) + { + if (ImGui.Selectable(spawnPoint.Name, spawnPoint.Name == ctrl.SelectSpawnPoint)) + { + ctrl.SelectSpawnPoint = spawnPoint.Name; + } + } + ImGui.EndCombo(); + } + // Add a button to save the file on the same line as the dropdown. + ImGui.SameLine(); + if (ImGui.Button("Save Spawnpoint as YML")) + { + SaveSpawnPointAsYaml(ctrl); + } + ImGui.PushItemWidth(50); + ImGui.InputText("", ref _newSpawnPointName, 4); // String of 4 characters long. + ImGui.PopItemWidth(); + ImGui.SameLine(); // Place the button on the same line as the text input + // Add a button to add a new spawn point entry + + //Rename/Add/Remove SpawnPoint butons. + if (ImGui.Button($"Rename '{ctrl.SelectSpawnPoint}' to '{_newSpawnPointName}'")) + { + RenameSpawnPoint(ctrl); + } + ImGui.SameLine(); + if (ImGui.Button($"Add new Spawnpoint '{_newSpawnPointName}'")) + { + AddNewSpawnPointEntry(ctrl); + } + ImGui.SameLine(); + if (ImGui.Button($"Remove '{ctrl.SelectSpawnPoint}'")) + { + RemoveSelectedSpawnPoint(ctrl); + } + ImGui.PopItemWidth(); + } + else + { + ImGui.Text("No spawn points available."); + } + if (ctrl.CurrentSpawnPoint != null) + Run(ctrl.CurrentSpawnPoint); + }); + private static void RenameSpawnPoint(ISpawnPointController ctrl) + { + var selectedSpawnPoint = ctrl.SpawnPoints.FirstOrDefault(sp => sp.Name == ctrl.SelectSpawnPoint); + if (selectedSpawnPoint != null) + { + // Check if the new name already exists + if (ctrl.SpawnPoints.Any(sp => sp.Name == _newSpawnPointName)) + { + //Insert warning here. Standard error msg seems to pop up and disappear immediately, omitted for now. + return; + } + + // Update the name of the selected spawn point + var oldName = selectedSpawnPoint.Name; + selectedSpawnPoint.Name = _newSpawnPointName; + ctrl.SelectSpawnPoint = _newSpawnPointName; + + // Rename the corresponding Bar.Entry as well + var barEntries = (ctrl as MapRenderer)?.ArdBarEntries; + var barEntry = barEntries?.FirstOrDefault(e => e.Name == oldName); + if (barEntry != null) + { + barEntry.Name = _newSpawnPointName; + } + } + } + + //Add a new spawn point entry + private static void AddNewSpawnPointEntry(ISpawnPointController ctrl) + { + // Use the specified name for the new spawn point + var newSpawnPointName = string.IsNullOrEmpty(_newSpawnPointName) ? "N_00" : _newSpawnPointName; + + // Check if the name already exists in the ARD + var barEntries = (ctrl as MapRenderer)?.ArdBarEntries; + if (barEntries != null && barEntries.Any(e => e.Name == newSpawnPointName)) + { + Console.WriteLine($"Spawn point with name {newSpawnPointName} already exists."); + return; + } + + // Create a new Bar.Entry for AreaDataSpawn + var newEntry = new Bar.Entry + { + Name = newSpawnPointName, + Type = Bar.EntryType.AreaDataSpawn, + Stream = new MemoryStream() + }; + + // Add to the Bar + if (barEntries != null) + { + barEntries.Add(newEntry); + } + + // Create and add a new spawn point model + var objEntryCtrl = (ctrl as MapRenderer)?.ObjEntryController; // Ensure the correct type cast + if (objEntryCtrl != null) + { + var newSpawnPoint = new SpawnPointModel(objEntryCtrl, newEntry.Name, new List()); + ctrl.SpawnPoints.Add(newSpawnPoint); + ctrl.SelectSpawnPoint = newSpawnPoint.Name; + } + } + + //Remove the currently selected spawn point entry + private static void RemoveSelectedSpawnPoint(ISpawnPointController ctrl) + { + if (ctrl.SelectSpawnPoint == null) + { + Console.WriteLine("No spawn point selected to remove."); + return; + } + + var barEntries = (ctrl as MapRenderer)?.ArdBarEntries; + if (barEntries == null) + { + Console.WriteLine("Bar entries not found."); + return; + } + + // Find the entry with the selected name and remove it + var entryToRemove = barEntries.FirstOrDefault(e => e.Name == ctrl.SelectSpawnPoint); + if (entryToRemove != null) + { + barEntries.Remove(entryToRemove); + ctrl.SpawnPoints.RemoveAll(sp => sp.Name == ctrl.SelectSpawnPoint); + ctrl.SelectSpawnPoint = ctrl.SpawnPoints.FirstOrDefault()?.Name; + Console.WriteLine($"Spawn point {entryToRemove.Name} removed."); + } + else + { + Console.WriteLine($"Spawn point with name {ctrl.SelectSpawnPoint} not found in bar entries."); + } + } + + + + //NEW: Easily export spawnpoint as a YML. QoL change to make patching via OpenKH easier, so you don't need to extract the spawnpoint, use OpenKh.Command.Spawnpoints, decompile, etc. + private static readonly List YamlFilter = FileDialogFilterComposer.Compose() + .AddExtensions("YAML file", "yml") + .AddAllFiles(); + + private static void SaveSpawnPointAsYaml(ISpawnPointController ctrl) + { + // Serialize the currently loaded SpawnPoint to YAML + var spawnPoint = ctrl.CurrentSpawnPoint.SpawnPoints; + if (spawnPoint != null) + { + var defaultName = $"{ctrl.CurrentSpawnPoint.Name}.yml"; // Set the default name to the current spawn point's name + Xe.Tools.Wpf.Dialogs.FileDialog.OnSave(savePath => + { + try + { + // Serialize and save the spawn point data to the selected file + File.WriteAllText(savePath, Helpers.YamlSerialize(spawnPoint)); + Console.WriteLine($"Spawn point saved to {savePath}"); + } + catch (Exception ex) + { + // Handle exceptions if needed + Console.WriteLine($"Error saving spawn point as YAML: {ex.Message}"); + } + }, YamlFilter, defaultName); + } + } - public static bool Run(ISpawnPointController ctrl) => ForHeader("Spawn point editor", () => - { - _ctrl = ctrl; - if (ImGui.BeginCombo("Spawn point", ctrl.SelectSpawnPoint)) + private static void Run(SpawnPointModel model) + { + if (ImGui.SmallButton("Add a new Spawn Group")) { - foreach (var spawnPoint in ctrl.SpawnPoints) - { - if (ImGui.Selectable(spawnPoint.Name, spawnPoint.Name == ctrl.SelectSpawnPoint)) - { - ctrl.SelectSpawnPoint = spawnPoint.Name; - } - } - - ImGui.EndCombo(); - } - - if (ctrl.CurrentSpawnPoint != null) - Run(ctrl.CurrentSpawnPoint); - }); + var newSpawnPoint = new Kh2.Ard.SpawnPoint + { + Entities = new List { }, + EventActivators = new List { }, + WalkPath = new List { }, + ReturnParameters = new List { }, + Signals = new List { }, + Teleport = new Kh2.Ard.SpawnPoint.TeleportDesc { } + }; + model.SpawnPoints.Add(newSpawnPoint); + } - private static void Run(SpawnPointModel model) - { - for (int i = 0; i < model.SpawnPoints.Count; i++) + ImGui.SameLine(); + //The above code copies the last spawngroup. + if (model.SpawnPoints.Count > 0) + if (ImGui.SmallButton("Remove last Spawn Group")) + model.SpawnPoints.RemoveAt(model.SpawnPoints.Count - 1); + ImGui.Separator(); + //Tree View of Spawn Groups + if (ImGui.CollapsingHeader("Spawn Groups")) { - var spawnGroup = model.SpawnPoints[i]; - if (ImGui.CollapsingHeader($"Spawn group #{i}")) + ImGui.Indent(20.0f); + for (int i = 0; i < model.SpawnPoints.Count; i++) { - Run(spawnGroup, i); + var spawnGroup = model.SpawnPoints[i]; + if (ImGui.CollapsingHeader($"Spawn group #{i}")) + { + Run(spawnGroup, i); + } } + ImGui.Unindent(20.0f); } } @@ -62,19 +257,74 @@ private static void Run(SpawnPoint point, int index) ForEdit($"Unknown##{index}", () => point.Teleport.Unknown, x => point.Teleport.Unknown = x); ImGui.Separator(); - for (var i = 0; i < point.Entities.Count; i++) - ForTreeNode($"Entity #{index}-{i}", () => Run(point.Entities[i], i)); - for (var i = 0; i < point.EventActivators.Count; i++) + //Entities + if (ImGui.SmallButton("Add a new Entity")) + point.Entities.Add(new SpawnPoint.Entity {ObjectId = 1 }); //Add ObjectId of 1. + ImGui.SameLine(); + if (point.Entities.Count > 0) //Check first to see if there are entities. + if (ImGui.SmallButton("Remove last Entity")) //Placed BEFORE, so that button doesnt repeat 3x. + point.Entities.RemoveAt(point.Entities.Count - 1); + ImGui.Separator(); + for (var i = 0; i < point.Entities.Count; i++) //Entities: Tree View + ForTreeNode($"Entity #{index}-{i}", () => Run(point.Entities[i], i)); + + //EventActivators, then Add/Remove Buttons. + if (ImGui.SmallButton("Add a new Event Activator")) + point.EventActivators.Add(new SpawnPoint.EventActivator()); + ImGui.SameLine(); + if (point.EventActivators.Count > 0) + if (ImGui.SmallButton("Remove last Activator")) + point.EventActivators.RemoveAt(point.EventActivators.Count - 1); + ImGui.Separator(); + for (var i = 0; i < point.EventActivators.Count; i++) //Event Activators: Tree View ForTreeNode($"Event activator #{index}-{i}", () => Run(point.EventActivators[i], i)); - for (var i = 0; i < point.WalkPath.Count; i++) + + //WalkPath, then Add/Remove Buttons. + if (ImGui.SmallButton("Add a new Walking Path")) + { + var newWalkPath = new SpawnPoint.WalkPathDesc(); + + // Ensure Position has at least one value + if (newWalkPath.Positions == null || newWalkPath.Positions.Count == 0) + { + newWalkPath.Positions = new List(); + } + point.WalkPath.Add(newWalkPath); + } + ImGui.SameLine(); + if (point.WalkPath.Count > 0) + if (ImGui.SmallButton("Remove last Walking Path")) + point.WalkPath.RemoveAt(point.WalkPath.Count - 1); + ImGui.Separator(); + for (var i = 0; i < point.WalkPath.Count; i++)//WalkPath: Tree View ForTreeNode($"Walking path #{index}-{i}", () => Run(point.WalkPath[i], i)); - for (var i = 0; i < point.ReturnParameters.Count; i++) + + //Return Parameters, then Add/Remove Buttons. + //Remove/Add + if (ImGui.SmallButton("Add a new Return Parameter")) + point.ReturnParameters.Add(new SpawnPoint.ReturnParameter()); + ImGui.SameLine(); + if (point.ReturnParameters.Count > 0) + if (ImGui.SmallButton("Remove last Return Parameter")) + point.ReturnParameters.RemoveAt(point.ReturnParameters.Count - 1); + ImGui.Separator(); + for (var i = 0; i < point.ReturnParameters.Count; i++)//Return parameters: Tree View ForTreeNode($"Parameter #{index}-{i}", () => Run(point.ReturnParameters[i], i)); - for (var i = 0; i < point.Signals.Count; i++) + + //Signal, then Add/Remove Buttons. + //Remove/Add + if (ImGui.SmallButton("Add a new Signal")) + point.Signals.Add(new SpawnPoint.Signal()); + ImGui.SameLine(); + if (point.Signals.Count > 0) + if (ImGui.SmallButton("Remove last Signal")) + point.Signals.RemoveAt(point.Signals.Count - 1); + ImGui.Separator(); + for (var i = 0; i < point.Signals.Count; i++)//Signals: Tree View ForTreeNode($"Signal #{index}-{i}", () => Run(point.Signals[i], i)); } @@ -91,8 +341,8 @@ private static void Run(SpawnPoint.Entity entity, int index) { if (ImGui.Selectable(obj.ModelName, obj.ObjectId == entity.ObjectId)) entity.ObjectId = (int)obj.ObjectId; - } + } ImGui.EndCombo(); } @@ -173,6 +423,18 @@ private static void Run(SpawnPoint.WalkPathDesc item, int index) ForEdit($"Serial##{index}", () => item.Serial, x => item.Serial = x); ForEdit($"Flag##{index}", () => item.Flag, x => item.Flag = x); ForEdit($"Id##{index}", () => item.Id, x => item.Id = x); + //Add new WalkingPath Positions so that NPCs have multiple possible paths. + if (ImGui.SmallButton($"Add a new position##{index}")) + { + item.Positions.Add(new Position()); + } + ImGui.SameLine(); + if (item.Positions.Count > 0) + if (ImGui.SmallButton($"Remove last position")) + { + item.Positions.RemoveAt(item.Positions.Count - 1); + } + ImGui.Separator(); for (var i = 0; i < item.Positions.Count; i++) { var pos = item.Positions[i]; @@ -189,10 +451,13 @@ private static void Run(SpawnPoint.WalkPathDesc item, int index) private static void Run(SpawnPoint.ReturnParameter item, int index) { - ForEdit($"Unk00##{index}", () => item.Id, x => item.Id = x); - ForEdit($"Unk01##{index}", () => item.Type, x => item.Type = x); - ForEdit($"Unk02##{index}", () => item.Rate, x => item.Rate = x); - ForEdit($"Unk03##{index}", () => item.EntryType, x => item.EntryType = x); + ForEdit($"Id##{index}", () => item.Id, x => item.Id = x); + ForEdit($"Type##{index}", () => item.Type, x => item.Type = x); + ForEdit($"Rate##{index}", () => item.Rate, x => item.Rate = x); + ForEdit($"Entry Type##{index}", () => item.EntryType, x => item.EntryType = x); + ForEdit($"Argument04##{index}", () => item.Argument04, x => item.Argument04 = x); + ForEdit($"Argument08##{index}", () => item.Argument08, x => item.Argument08 = x); + ForEdit($"Argument0c##{index}", () => item.Argument0c, x => item.Argument0c = x); } private static void Run(SpawnPoint.Signal item, int index) From df3c655e5d8a1f10ccfa25a1aff243747f50a754 Mon Sep 17 00:00:00 2001 From: Zurphing <72351816+Zurphing@users.noreply.github.com> Date: Mon, 29 Jul 2024 19:20:28 -0400 Subject: [PATCH 3/4] Update App.cs (test) --- OpenKh.Tools.Kh2MapStudio/App.cs | 892 +++++++++++++++---------------- 1 file changed, 446 insertions(+), 446 deletions(-) diff --git a/OpenKh.Tools.Kh2MapStudio/App.cs b/OpenKh.Tools.Kh2MapStudio/App.cs index 74bf4b69b..a00d6c2d4 100644 --- a/OpenKh.Tools.Kh2MapStudio/App.cs +++ b/OpenKh.Tools.Kh2MapStudio/App.cs @@ -1,59 +1,59 @@ -using Assimp; -using ImGuiNET; -using Microsoft.Xna.Framework.Input; +using Assimp; +using ImGuiNET; +using Microsoft.Xna.Framework.Input; using OpenKh.Engine; -using OpenKh.Kh2; -using OpenKh.Tools.Common.CustomImGui; +using OpenKh.Kh2; +using OpenKh.Tools.Common.CustomImGui; using OpenKh.Tools.Kh2MapStudio.Models; -using OpenKh.Tools.Kh2MapStudio.Windows; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Numerics; +using OpenKh.Tools.Kh2MapStudio.Windows; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; using System.Reflection; -using System.Windows; -using Xe.Tools.Wpf.Dialogs; -using static OpenKh.Tools.Common.CustomImGui.ImGuiEx; -using xna = Microsoft.Xna.Framework; - -namespace OpenKh.Tools.Kh2MapStudio -{ - class App : IDisposable - { - private static readonly List MapFilter = - FileDialogFilterComposer.Compose() - .AddExtensions("MAP file", "map") - .AddAllFiles(); - private static readonly List ArdFilter = - FileDialogFilterComposer.Compose() - .AddExtensions("ARD file", "ard") - .AddAllFiles(); - private static readonly List ModelFilter = - FileDialogFilterComposer.Compose() - .AddExtensions("glTF file (GL Transmission Format)", "gltf") - .AddExtensions("FBX file", "fbx") - .AddExtensions("DAE file (Collada) (might be unaccurate)", "dae") - .AddExtensions("OBJ file (Wavefront) (might lose some information)", "obj") - .AddAllFiles(); - +using System.Windows; +using Xe.Tools.Wpf.Dialogs; +using static OpenKh.Tools.Common.CustomImGui.ImGuiEx; +using xna = Microsoft.Xna.Framework; + +namespace OpenKh.Tools.Kh2MapStudio +{ + class App : IDisposable + { + private static readonly List MapFilter = + FileDialogFilterComposer.Compose() + .AddExtensions("MAP file", "map") + .AddAllFiles(); + private static readonly List ArdFilter = + FileDialogFilterComposer.Compose() + .AddExtensions("ARD file", "ard") + .AddAllFiles(); + private static readonly List ModelFilter = + FileDialogFilterComposer.Compose() + .AddExtensions("glTF file (GL Transmission Format)", "gltf") + .AddExtensions("FBX file", "fbx") + .AddExtensions("DAE file (Collada) (might be unaccurate)", "dae") + .AddExtensions("OBJ file (Wavefront) (might lose some information)", "obj") + .AddAllFiles(); + private const string SelectArdFilesCaption = "Select ard files"; - - private readonly Vector4 BgUiColor = new Vector4(0.0f, 0.0f, 0.0f, 0.5f); - private readonly MonoGameImGuiBootstrap _bootstrap; - private bool _exitFlag = false; - - private readonly Dictionary _keyMapping = new Dictionary(); + + private readonly Vector4 BgUiColor = new Vector4(0.0f, 0.0f, 0.0f, 0.5f); + private readonly MonoGameImGuiBootstrap _bootstrap; + private bool _exitFlag = false; + + private readonly Dictionary _keyMapping = new Dictionary(); private readonly MapRenderer _mapRenderer; - private string _gamePath; - private string _mapName; - private string _region; - private string _ardPath; - private string _mapPath; - private string _objPath; - private List _mapArdsList = new List(); - private ObjEntryController _objEntryController; - + private string _gamePath; + private string _mapName; + private string _region; + private string _ardPath; + private string _mapPath; + private string _objPath; + private List _mapArdsList = new List(); + private ObjEntryController _objEntryController; + private xna.Point _previousMousePosition; private MapArdsBefore _before; private MapArdsAfter _after; @@ -62,13 +62,13 @@ class App : IDisposable private record MapArdsBefore(string MapName, string MapFile, IEnumerable ArdFilesRelative) { - } - + } + private record MapArdsAfter(string MapName, string MapFile, string ArdFileRelativeInput, IEnumerable ArdFilesRelativeOutput) { - } - + } + private class SelectArdFilesState { public string InputArd { get; set; } @@ -79,15 +79,15 @@ public void Reset() InputArd = null; OutputArds.Clear(); } - } - - public string Title - { - get - { - var mapName = _mapName != null ? $"{_mapName}@" : string.Empty; - return $"{mapName}{_gamePath ?? "unloaded"} | {MonoGameImGuiBootstrap.ApplicationName}"; - } + } + + public string Title + { + get + { + var mapName = _mapName != null ? $"{_mapName}@" : string.Empty; + return $"{mapName}{_gamePath ?? "unloaded"} | {MonoGameImGuiBootstrap.ApplicationName}"; + } } private string GamePath @@ -117,65 +117,65 @@ private string GamePath Settings.Default.GamePath = value; Settings.Default.Save(); } - } - private string MapName - { - get => _mapName; - set - { - _mapName = value; - UpdateTitle(); - } - } - + } + private string MapName + { + get => _mapName; + set + { + _mapName = value; + UpdateTitle(); + } + } + private void LoadMapArd(MapArdsAfter after) { MapName = after.MapName; _mapRenderer.Close(); _mapRenderer.OpenMap(after.MapFile); - _mapRenderer.OpenArd(Path.Combine(_ardPath, after.ArdFileRelativeInput)); - _after = after; - } - - private bool IsGameOpen => !string.IsNullOrEmpty(_gamePath); - private bool IsMapOpen => !string.IsNullOrEmpty(_mapName); - private bool IsOpen => IsGameOpen && IsMapOpen; - - public App(MonoGameImGuiBootstrap bootstrap, string gamePath = null) - { - _bootstrap = bootstrap; - _bootstrap.Title = Title; - _mapRenderer = new MapRenderer(bootstrap.Content, bootstrap.GraphicsDeviceManager); - AddKeyMapping(Keys.O, MenuFileOpen); - AddKeyMapping(Keys.S, MenuFileSave); - AddKeyMapping(Keys.Q, MenuFileUnload); - - if (string.IsNullOrEmpty(gamePath)) - gamePath = Settings.Default.GamePath; - - if (!string.IsNullOrEmpty(gamePath)) - OpenFolder(gamePath); - - ImGui.PushStyleColor(ImGuiCol.MenuBarBg, BgUiColor); - } - - public bool MainLoop() - { - _bootstrap.GraphicsDevice.Clear(xna.Color.CornflowerBlue); - ProcessKeyMapping(); - if (!_bootstrap.ImGuiWantTextInput) - ProcessKeyboardInput(Keyboard.GetState(), 1f / 60); - if (!_bootstrap.ImGuiWantCaptureMouse) - ProcessMouseInput(Mouse.GetState()); - - ImGui.PushStyleColor(ImGuiCol.WindowBg, BgUiColor); - ForControl(ImGui.BeginMainMenuBar, ImGui.EndMainMenuBar, MainMenu); - - MainWindow(); - - ForWindow("Tools", () => - { + _mapRenderer.OpenArd(Path.Combine(_ardPath, after.ArdFileRelativeInput)); + _after = after; + } + + private bool IsGameOpen => !string.IsNullOrEmpty(_gamePath); + private bool IsMapOpen => !string.IsNullOrEmpty(_mapName); + private bool IsOpen => IsGameOpen && IsMapOpen; + + public App(MonoGameImGuiBootstrap bootstrap, string gamePath = null) + { + _bootstrap = bootstrap; + _bootstrap.Title = Title; + _mapRenderer = new MapRenderer(bootstrap.Content, bootstrap.GraphicsDeviceManager); + AddKeyMapping(Keys.O, MenuFileOpen); + AddKeyMapping(Keys.S, MenuFileSave); + AddKeyMapping(Keys.Q, MenuFileUnload); + + if (string.IsNullOrEmpty(gamePath)) + gamePath = Settings.Default.GamePath; + + if (!string.IsNullOrEmpty(gamePath)) + OpenFolder(gamePath); + + ImGui.PushStyleColor(ImGuiCol.MenuBarBg, BgUiColor); + } + + public bool MainLoop() + { + _bootstrap.GraphicsDevice.Clear(xna.Color.CornflowerBlue); + ProcessKeyMapping(); + if (!_bootstrap.ImGuiWantTextInput) + ProcessKeyboardInput(Keyboard.GetState(), 1f / 60); + if (!_bootstrap.ImGuiWantCaptureMouse) + ProcessMouseInput(Mouse.GetState()); + + ImGui.PushStyleColor(ImGuiCol.WindowBg, BgUiColor); + ForControl(ImGui.BeginMainMenuBar, ImGui.EndMainMenuBar, MainMenu); + + MainWindow(); + + ForWindow("Tools", () => + { if (_mapRenderer.CurrentArea.AreaSettingsMask is int areaSettingsMask) { ImGui.Text($"AreaSettings 0 -1"); @@ -188,58 +188,58 @@ public bool MainLoop() } } } - - - if (EditorSettings.ViewCamera) - CameraWindow.Run(_mapRenderer.Camera); - if (EditorSettings.ViewLayerControl) - LayerControllerWindow.Run(_mapRenderer); - if (EditorSettings.ViewSpawnPoint) - SpawnPointWindow.Run(_mapRenderer); - if (EditorSettings.ViewMeshGroup) + + + if (EditorSettings.ViewCamera) + CameraWindow.Run(_mapRenderer.Camera); + if (EditorSettings.ViewLayerControl) + LayerControllerWindow.Run(_mapRenderer); + if (EditorSettings.ViewSpawnPoint) + SpawnPointWindow.Run(_mapRenderer); + if (EditorSettings.ViewMeshGroup) MeshGroupWindow.Run(_mapRenderer.MapMeshGroups); - if (EditorSettings.ViewCollision && _mapRenderer.MapCollision != null) - CollisionWindow.Run(_mapRenderer.MapCollision.Coct); - if (EditorSettings.ViewBobDescriptor) - BobDescriptorWindow.Run(_mapRenderer.BobDescriptors, _mapRenderer.BobMeshGroups.Count); - if (EditorSettings.ViewSpawnScriptMap) - SpawnScriptWindow.Run("map", _mapRenderer.SpawnScriptMap); - if (EditorSettings.ViewSpawnScriptBattle) - SpawnScriptWindow.Run("btl", _mapRenderer.SpawnScriptBattle); - if (EditorSettings.ViewSpawnScriptEvent) + if (EditorSettings.ViewCollision && _mapRenderer.MapCollision != null) + CollisionWindow.Run(_mapRenderer.MapCollision.Coct); + if (EditorSettings.ViewBobDescriptor) + BobDescriptorWindow.Run(_mapRenderer.BobDescriptors, _mapRenderer.BobMeshGroups.Count); + if (EditorSettings.ViewSpawnScriptMap) + SpawnScriptWindow.Run("map", _mapRenderer.SpawnScriptMap); + if (EditorSettings.ViewSpawnScriptBattle) + SpawnScriptWindow.Run("btl", _mapRenderer.SpawnScriptBattle); + if (EditorSettings.ViewSpawnScriptEvent) SpawnScriptWindow.Run("evt", _mapRenderer.SpawnScriptEvent); - - + + if (EditorSettings.ViewEventScript && _mapRenderer.EventScripts != null) { foreach (var eventScript in _mapRenderer.EventScripts) { EventScriptWindow.Run(eventScript.Name, eventScript); - } - } + } + } }); //Add separate Camera Window if setting is toggled on. if (EditorSettings.SeparateCamera) { SeparateWindow.Run(_mapRenderer.Camera); - }; - - SelectArdFilesPopup(); - - ImGui.PopStyleColor(); - - return _exitFlag; - } - - public void Dispose() - { - _objEntryController?.Dispose(); - } - - private void SelectArdFilesPopup() + }; + + SelectArdFilesPopup(); + + ImGui.PopStyleColor(); + + return _exitFlag; + } + + public void Dispose() { - var dummy = true; + _objEntryController?.Dispose(); + } + + private void SelectArdFilesPopup() + { + var dummy = true; if (ImGui.BeginPopupModal(SelectArdFilesCaption, ref dummy, ImGuiWindowFlags.Popup | ImGuiWindowFlags.Modal | ImGuiWindowFlags.AlwaysAutoResize)) { @@ -287,51 +287,51 @@ private void SelectArdFilesPopup() _selectArdFilesState.InputArd, _selectArdFilesState.OutputArds ) - ); - - ImGui.CloseCurrentPopup(); + ); + + ImGui.CloseCurrentPopup(); } ImGui.EndDisabled(); ImGui.EndPopup(); - } - } - - private void MainWindow() - { - if (!IsGameOpen) - { - ImGui.Text("Game content not loaded."); - return; - } - - ForControl(() => - { - var nextPos = ImGui.GetCursorPos(); + } + } + + private void MainWindow() + { + if (!IsGameOpen) + { + ImGui.Text("Game content not loaded."); + return; + } + + ForControl(() => + { + var nextPos = ImGui.GetCursorPos(); var ret = ImGui.Begin("Map List", //List of all the maps, the left-side bar. //ImGuiWindowFlags.NoDecoration | //Removes the scroll-bar - ImGuiWindowFlags.NoCollapse | //Prevents it from being collapsible - ImGuiWindowFlags.AlwaysAutoResize | //NEW: Resizes the window to accomodate the "Please select a map" text. - ImGuiWindowFlags.NoMove); //Prevents it from being moved around - ImGui.SetWindowPos(nextPos); - ImGui.SetWindowSize(new Vector2(64, 0)); - return ret; - }, () => { }, (Action)(() => - { - foreach (var mapArds in _mapArdsList) - { - if (ImGui.Selectable(mapArds.MapName, MapName == mapArds.MapName)) - { + ImGuiWindowFlags.NoCollapse | //Prevents it from being collapsible + ImGuiWindowFlags.AlwaysAutoResize | //NEW: Resizes the window to accomodate maps of various name lengths. + ImGuiWindowFlags.NoMove); //Prevents it from being moved around + ImGui.SetWindowPos(nextPos); + ImGui.SetWindowSize(new Vector2(64, 0)); + return ret; + }, () => { }, (Action)(() => + { + foreach (var mapArds in _mapArdsList) + { + if (ImGui.Selectable(mapArds.MapName, MapName == mapArds.MapName)) + { if (mapArds.ArdFilesRelative.Count() == 1) { - LoadMapArd( - new MapArdsAfter( - mapArds.MapName, - mapArds.MapFile, - mapArds.ArdFilesRelative.Single(), - mapArds.ArdFilesRelative - ) - ); - } + LoadMapArd( + new MapArdsAfter( + mapArds.MapName, + mapArds.MapFile, + mapArds.ArdFilesRelative.Single(), + mapArds.ArdFilesRelative + ) + ); + } else { _before = mapArds; @@ -339,60 +339,60 @@ private void MainWindow() _selectArdFilesState.Reset(); ImGui.OpenPopup(SelectArdFilesCaption); - } - } - } - })); - //ImGui.SameLine(); - - if (!IsMapOpen) - { - //ImGui.Text("Select a map to edit."); //Text. Appears at the bottom of the list, commented out. - return; - } - - _mapRenderer.Update(1f / 60); - _mapRenderer.Draw(); - } - - void MainMenu() - { - ForMenuBar(() => - { - ForMenu("File", () => - { - ForMenuItem("Open extracted game folder...", "CTRL+O", MenuFileOpen); - ForMenuItem("Unload current map+ard", "CTRL+Q", MenuFileUnload, IsOpen); - ForMenuItem("Import extern MAP file", MenuFileOpenMap, IsGameOpen); - ForMenuItem("Import extern ARD file", MenuFileOpenArd, IsGameOpen); - ForMenuItem("Save map+ard", "CTRL+S", MenuFileSave, IsOpen); - ForMenuItem("Save map as...", MenuFileSaveMapAs, IsOpen); - ForMenuItem("Save ard as...", MenuFileSaveArdAs, IsOpen); - ImGui.Separator(); - ForMenu("Export", () => - { - ForMenuItem("Map Collision", ExportMapCollision, _mapRenderer.ShowMapCollision.HasValue); - ForMenuItem("Camera Collision", ExportCameraCollision, _mapRenderer.ShowCameraCollision.HasValue); - ForMenuItem("Light Collision", ExportLightCollision, _mapRenderer.ShowLightCollision.HasValue); - }); + } + } + } + })); + //ImGui.SameLine(); + + if (!IsMapOpen) + { + //ImGui.Text("Select a map to edit."); //Text. Appears at the bottom of the list, commented out. + return; + } + + _mapRenderer.Update(1f / 60); + _mapRenderer.Draw(); + } + + void MainMenu() + { + ForMenuBar(() => + { + ForMenu("File", () => + { + ForMenuItem("Open extracted game folder...", "CTRL+O", MenuFileOpen); + ForMenuItem("Unload current map+ard", "CTRL+Q", MenuFileUnload, IsOpen); + ForMenuItem("Import extern MAP file", MenuFileOpenMap, IsGameOpen); + ForMenuItem("Import extern ARD file", MenuFileOpenArd, IsGameOpen); + ForMenuItem("Save map+ard", "CTRL+S", MenuFileSave, IsOpen); + ForMenuItem("Save map as...", MenuFileSaveMapAs, IsOpen); + ForMenuItem("Save ard as...", MenuFileSaveArdAs, IsOpen); + ImGui.Separator(); + ForMenu("Export", () => + { + ForMenuItem("Map Collision", ExportMapCollision, _mapRenderer.ShowMapCollision.HasValue); + ForMenuItem("Camera Collision", ExportCameraCollision, _mapRenderer.ShowCameraCollision.HasValue); + ForMenuItem("Light Collision", ExportLightCollision, _mapRenderer.ShowLightCollision.HasValue); + }); ImGui.Separator(); - ForMenuItem("Exit", MenuFileExit); - }); - ForMenu("View", () => - { + ForMenuItem("Exit", MenuFileExit); + }); + ForMenu("View", () => + { ForMenuCheck("Camera", () => EditorSettings.ViewCamera, x => EditorSettings.ViewCamera = x); - ForMenuCheck("Separate Camera Window", () => EditorSettings.SeparateCamera, x => EditorSettings.SeparateCamera = x); - ForMenuCheck("Layer control", () => EditorSettings.ViewLayerControl, x => EditorSettings.ViewLayerControl = x); - ForMenuCheck("Spawn points", () => EditorSettings.ViewSpawnPoint, x => EditorSettings.ViewSpawnPoint = x); - ForMenuCheck("BOB descriptors", () => EditorSettings.ViewBobDescriptor, x => EditorSettings.ViewBobDescriptor = x); + ForMenuCheck("Separate Camera Window", () => EditorSettings.SeparateCamera, x => EditorSettings.SeparateCamera = x); + ForMenuCheck("Layer control", () => EditorSettings.ViewLayerControl, x => EditorSettings.ViewLayerControl = x); + ForMenuCheck("Spawn points", () => EditorSettings.ViewSpawnPoint, x => EditorSettings.ViewSpawnPoint = x); + ForMenuCheck("BOB descriptors", () => EditorSettings.ViewBobDescriptor, x => EditorSettings.ViewBobDescriptor = x); ForMenuCheck("Mesh group", () => EditorSettings.ViewMeshGroup, x => EditorSettings.ViewMeshGroup = x); - ForMenuCheck("Collision (Experimental)", () => EditorSettings.ViewCollision, x => EditorSettings.ViewCollision = x); - ForMenuCheck("Spawn script MAP", () => EditorSettings.ViewSpawnScriptMap, x => EditorSettings.ViewSpawnScriptMap = x); - ForMenuCheck("Spawn script BTL", () => EditorSettings.ViewSpawnScriptBattle, x => EditorSettings.ViewSpawnScriptBattle = x); - ForMenuCheck("Spawn script EVT", () => EditorSettings.ViewSpawnScriptEvent, x => EditorSettings.ViewSpawnScriptEvent = x); - ForMenuCheck("Event script", () => EditorSettings.ViewEventScript, x => EditorSettings.ViewEventScript = x); - }); - + ForMenuCheck("Collision (Experimental)", () => EditorSettings.ViewCollision, x => EditorSettings.ViewCollision = x); + ForMenuCheck("Spawn script MAP", () => EditorSettings.ViewSpawnScriptMap, x => EditorSettings.ViewSpawnScriptMap = x); + ForMenuCheck("Spawn script BTL", () => EditorSettings.ViewSpawnScriptBattle, x => EditorSettings.ViewSpawnScriptBattle = x); + ForMenuCheck("Spawn script EVT", () => EditorSettings.ViewSpawnScriptEvent, x => EditorSettings.ViewSpawnScriptEvent = x); + ForMenuCheck("Event script", () => EditorSettings.ViewEventScript, x => EditorSettings.ViewEventScript = x); + }); + ForMenu("Preferences", () => { ForMenu("Movement Speed", () => @@ -420,104 +420,104 @@ void MainMenu() ForEdit("Window Height", () => EditorSettings.InitialWindowHeight, x => EditorSettings.InitialWindowHeight = x); }); - }); - - ForMenu("Help", () => - { - ForMenuItem("About", ShowAboutDialog); - ForMenuItem("Preference Info", ShowPrefDialog); - ForMenuItem("Controls", ShowControlsDialog); - }); - }); - } - - private void MenuFileOpen() => FileDialog.OnFolder(OpenFolder); - private void MenuFileUnload() => _mapRenderer.Close(); - private void MenuFileOpenMap() => FileDialog.OnOpen(_mapRenderer.OpenMap, MapFilter); - private void MenuFileOpenArd() => FileDialog.OnOpen(_mapRenderer.OpenArd, ArdFilter); - - private void MenuFileSave() - { - _mapRenderer.SaveMap(_after.MapFile); - + }); + + ForMenu("Help", () => + { + ForMenuItem("About", ShowAboutDialog); + ForMenuItem("Preference Info", ShowPrefDialog); + ForMenuItem("Controls", ShowControlsDialog); + }); + }); + } + + private void MenuFileOpen() => FileDialog.OnFolder(OpenFolder); + private void MenuFileUnload() => _mapRenderer.Close(); + private void MenuFileOpenMap() => FileDialog.OnOpen(_mapRenderer.OpenMap, MapFilter); + private void MenuFileOpenArd() => FileDialog.OnOpen(_mapRenderer.OpenArd, ArdFilter); + + private void MenuFileSave() + { + _mapRenderer.SaveMap(_after.MapFile); + foreach (var ard in _after.ArdFilesRelativeOutput) { _mapRenderer.SaveArd(Path.Combine(_ardPath, ard)); - } - } - - private void MenuFileSaveMapAs() - { - var defaultName = MapName + ".map"; - FileDialog.OnSave(_mapRenderer.SaveMap, MapFilter, defaultName); - } - - private void MenuFileSaveArdAs() - { - var defaultName = MapName + ".ard"; - FileDialog.OnSave(_mapRenderer.SaveArd, ArdFilter, defaultName); - } - - private void ExportMapCollision() => FileDialog.OnSave(fileName => - { - ExportScene(fileName, _mapRenderer.MapCollision.Scene); - }, ModelFilter, $"{MapName}_map-collision.dae"); - - private void ExportCameraCollision() => FileDialog.OnSave(fileName => - { - ExportScene(fileName, _mapRenderer.CameraCollision.Scene); - }, ModelFilter, $"{MapName}_camera-collision.dae"); - - private void ExportLightCollision() => FileDialog.OnSave(fileName => - { - ExportScene(fileName, _mapRenderer.LightCollision.Scene); - }, ModelFilter, $"{MapName}_light-collision.dae"); - - private void MenuFileExit() => _exitFlag = true; - - public void OpenFolder(string gamePath) - { - try - { - if (!Directory.Exists(_ardPath = Path.Combine(gamePath, "ard")) || - !Directory.Exists(_mapPath = Path.Combine(gamePath, "map")) || - !Directory.Exists(_objPath = Path.Combine(gamePath, "obj"))) - throw new DirectoryNotFoundException( - "The specified directory must contain the full extracted copy of the game."); - - GamePath = gamePath; - } - catch (Exception ex) - { - ShowError(ex.Message); - } - } - - private void UpdateTitle() - { - _bootstrap.Title = Title; - } - - private void EnumerateMapList() - { - var mapFiles = Array.Empty(); - foreach (var region in Constants.Regions) - { - var testPath = Path.Combine(_mapPath, region); - if (Directory.Exists(testPath)) - { - mapFiles = Directory.GetFiles(testPath, "*.map"); - if (mapFiles.Length != 0) - { - _mapPath = testPath; - _region = region; - break; - } - } - } - - _mapArdsList.Clear(); - + } + } + + private void MenuFileSaveMapAs() + { + var defaultName = MapName + ".map"; + FileDialog.OnSave(_mapRenderer.SaveMap, MapFilter, defaultName); + } + + private void MenuFileSaveArdAs() + { + var defaultName = MapName + ".ard"; + FileDialog.OnSave(_mapRenderer.SaveArd, ArdFilter, defaultName); + } + + private void ExportMapCollision() => FileDialog.OnSave(fileName => + { + ExportScene(fileName, _mapRenderer.MapCollision.Scene); + }, ModelFilter, $"{MapName}_map-collision.dae"); + + private void ExportCameraCollision() => FileDialog.OnSave(fileName => + { + ExportScene(fileName, _mapRenderer.CameraCollision.Scene); + }, ModelFilter, $"{MapName}_camera-collision.dae"); + + private void ExportLightCollision() => FileDialog.OnSave(fileName => + { + ExportScene(fileName, _mapRenderer.LightCollision.Scene); + }, ModelFilter, $"{MapName}_light-collision.dae"); + + private void MenuFileExit() => _exitFlag = true; + + public void OpenFolder(string gamePath) + { + try + { + if (!Directory.Exists(_ardPath = Path.Combine(gamePath, "ard")) || + !Directory.Exists(_mapPath = Path.Combine(gamePath, "map")) || + !Directory.Exists(_objPath = Path.Combine(gamePath, "obj"))) + throw new DirectoryNotFoundException( + "The specified directory must contain the full extracted copy of the game."); + + GamePath = gamePath; + } + catch (Exception ex) + { + ShowError(ex.Message); + } + } + + private void UpdateTitle() + { + _bootstrap.Title = Title; + } + + private void EnumerateMapList() + { + var mapFiles = Array.Empty(); + foreach (var region in Constants.Regions) + { + var testPath = Path.Combine(_mapPath, region); + if (Directory.Exists(testPath)) + { + mapFiles = Directory.GetFiles(testPath, "*.map"); + if (mapFiles.Length != 0) + { + _mapPath = testPath; + _region = region; + break; + } + } + } + + _mapArdsList.Clear(); + foreach (var mapFile in mapFiles) { var mapName = Path.GetFileNameWithoutExtension(mapFile); @@ -528,115 +528,115 @@ private void EnumerateMapList() .ToArray(); _mapArdsList.Add(new MapArdsBefore(mapName, mapFile, ardFiles)); - } - } - - private void AddKeyMapping(Keys key, Action action) - { - _keyMapping[key] = action; - } - - private void ProcessKeyMapping() - { - var k = Keyboard.GetState(); - if (k.IsKeyDown(Keys.LeftControl)) - { - var keys = k.GetPressedKeys(); - foreach (var key in keys) - { - if (_keyMapping.TryGetValue(key, out var action)) - action(); - } - } - } - - private void ProcessKeyboardInput(KeyboardState keyboard, float deltaTime) - { - var speed = (float)(deltaTime * EditorSettings.MoveSpeed); - var moveSpeed = speed; - if (keyboard.IsKeyDown(Keys.LeftShift) || keyboard.IsKeyDown(Keys.RightShift)) - moveSpeed = (float)(deltaTime * EditorSettings.MoveSpeedShift); - - var camera = _mapRenderer.Camera; - if (keyboard.IsKeyDown(Keys.W)) - camera.CameraPosition += Vector3.Multiply(camera.CameraLookAtX, moveSpeed * 5); - if (keyboard.IsKeyDown(Keys.S)) - camera.CameraPosition -= Vector3.Multiply(camera.CameraLookAtX, moveSpeed * 5); - if (keyboard.IsKeyDown(Keys.D)) - camera.CameraPosition -= Vector3.Multiply(camera.CameraLookAtY, moveSpeed * 5); - if (keyboard.IsKeyDown(Keys.A)) - camera.CameraPosition += Vector3.Multiply(camera.CameraLookAtY, moveSpeed * 5); - if (keyboard.IsKeyDown(Keys.Q)) - camera.CameraPosition += Vector3.Multiply(camera.CameraLookAtZ, moveSpeed * 5); - if (keyboard.IsKeyDown(Keys.E)) - camera.CameraPosition -= Vector3.Multiply(camera.CameraLookAtZ, moveSpeed * 5); - if (keyboard.IsKeyDown(Keys.Space)) - camera.CameraPosition += new Vector3(0, 1 * moveSpeed * 5, 0); - if (keyboard.IsKeyDown(Keys.LeftControl)) - camera.CameraPosition += new Vector3(0, -1 * moveSpeed * 5, 0); - if (keyboard.IsKeyDown(Keys.Up)) - camera.CameraRotationYawPitchRoll += new Vector3(0, 0, 1 * speed); - if (keyboard.IsKeyDown(Keys.Down)) - camera.CameraRotationYawPitchRoll -= new Vector3(0, 0, 1 * speed); - if (keyboard.IsKeyDown(Keys.Left)) - camera.CameraRotationYawPitchRoll += new Vector3(1 * speed, 0, 0); - if (keyboard.IsKeyDown(Keys.Right)) - camera.CameraRotationYawPitchRoll -= new Vector3(1 * speed, 0, 0); - } - - private void ProcessMouseInput(MouseState mouse) - { - const float Speed = 0.25f; - if (mouse.LeftButton == ButtonState.Pressed) - { - var camera = _mapRenderer.Camera; - var xSpeed = (_previousMousePosition.X - mouse.Position.X) * Speed; - var ySpeed = (_previousMousePosition.Y - mouse.Position.Y) * Speed; - camera.CameraRotationYawPitchRoll += new Vector3(1 * -xSpeed, 0, 0); - camera.CameraRotationYawPitchRoll += new Vector3(0, 0, 1 * ySpeed); - } - - _previousMousePosition = mouse.Position; - } - - private static void ExportScene(string fileName, Scene scene) - { - using var ctx = new AssimpContext(); - var extension = Path.GetExtension(fileName).ToLower(); - var exportFormat = ctx.GetSupportedExportFormats(); - foreach (var format in exportFormat) - { - if ($".{format.FileExtension}" == extension) - { - var material = new Material(); - material.Clear(); - - scene.Materials.Add(material); - ctx.ExportFile(scene, fileName, format.FormatId); - return; - } - } - - ShowError($"Unable to export with '{extension}' extension."); - } - - public static void ShowError(string message, string title = "Error") => - MessageBox.Show(message, title, MessageBoxButton.OK, MessageBoxImage.Error); - + } + } + + private void AddKeyMapping(Keys key, Action action) + { + _keyMapping[key] = action; + } + + private void ProcessKeyMapping() + { + var k = Keyboard.GetState(); + if (k.IsKeyDown(Keys.LeftControl)) + { + var keys = k.GetPressedKeys(); + foreach (var key in keys) + { + if (_keyMapping.TryGetValue(key, out var action)) + action(); + } + } + } + + private void ProcessKeyboardInput(KeyboardState keyboard, float deltaTime) + { + var speed = (float)(deltaTime * EditorSettings.MoveSpeed); + var moveSpeed = speed; + if (keyboard.IsKeyDown(Keys.LeftShift) || keyboard.IsKeyDown(Keys.RightShift)) + moveSpeed = (float)(deltaTime * EditorSettings.MoveSpeedShift); + + var camera = _mapRenderer.Camera; + if (keyboard.IsKeyDown(Keys.W)) + camera.CameraPosition += Vector3.Multiply(camera.CameraLookAtX, moveSpeed * 5); + if (keyboard.IsKeyDown(Keys.S)) + camera.CameraPosition -= Vector3.Multiply(camera.CameraLookAtX, moveSpeed * 5); + if (keyboard.IsKeyDown(Keys.D)) + camera.CameraPosition -= Vector3.Multiply(camera.CameraLookAtY, moveSpeed * 5); + if (keyboard.IsKeyDown(Keys.A)) + camera.CameraPosition += Vector3.Multiply(camera.CameraLookAtY, moveSpeed * 5); + if (keyboard.IsKeyDown(Keys.Q)) + camera.CameraPosition += Vector3.Multiply(camera.CameraLookAtZ, moveSpeed * 5); + if (keyboard.IsKeyDown(Keys.E)) + camera.CameraPosition -= Vector3.Multiply(camera.CameraLookAtZ, moveSpeed * 5); + if (keyboard.IsKeyDown(Keys.Space)) + camera.CameraPosition += new Vector3(0, 1 * moveSpeed * 5, 0); + if (keyboard.IsKeyDown(Keys.LeftControl)) + camera.CameraPosition += new Vector3(0, -1 * moveSpeed * 5, 0); + if (keyboard.IsKeyDown(Keys.Up)) + camera.CameraRotationYawPitchRoll += new Vector3(0, 0, 1 * speed); + if (keyboard.IsKeyDown(Keys.Down)) + camera.CameraRotationYawPitchRoll -= new Vector3(0, 0, 1 * speed); + if (keyboard.IsKeyDown(Keys.Left)) + camera.CameraRotationYawPitchRoll += new Vector3(1 * speed, 0, 0); + if (keyboard.IsKeyDown(Keys.Right)) + camera.CameraRotationYawPitchRoll -= new Vector3(1 * speed, 0, 0); + } + + private void ProcessMouseInput(MouseState mouse) + { + const float Speed = 0.25f; + if (mouse.LeftButton == ButtonState.Pressed) + { + var camera = _mapRenderer.Camera; + var xSpeed = (_previousMousePosition.X - mouse.Position.X) * Speed; + var ySpeed = (_previousMousePosition.Y - mouse.Position.Y) * Speed; + camera.CameraRotationYawPitchRoll += new Vector3(1 * -xSpeed, 0, 0); + camera.CameraRotationYawPitchRoll += new Vector3(0, 0, 1 * ySpeed); + } + + _previousMousePosition = mouse.Position; + } + + private static void ExportScene(string fileName, Scene scene) + { + using var ctx = new AssimpContext(); + var extension = Path.GetExtension(fileName).ToLower(); + var exportFormat = ctx.GetSupportedExportFormats(); + foreach (var format in exportFormat) + { + if ($".{format.FileExtension}" == extension) + { + var material = new Material(); + material.Clear(); + + scene.Materials.Add(material); + ctx.ExportFile(scene, fileName, format.FormatId); + return; + } + } + + ShowError($"Unable to export with '{extension}' extension."); + } + + public static void ShowError(string message, string title = "Error") => + MessageBox.Show(message, title, MessageBoxButton.OK, MessageBoxImage.Error); + private void ShowAboutDialog() => //MessageBox.Show("OpenKH is amazing."); - MessageBox.Show("Welcome to OpenKH MapStudio." + - "\n\nThis tool allows you to view .map files along with their associated .ard files." + + MessageBox.Show("Welcome to OpenKH MapStudio." + + "\n\nThis tool allows you to view .map files along with their associated .ard files." + "\n\nThe .map and .ard files are loaded using the extracted game data. " + - "\n\nEntities are loaded from the extracted 00objentry.bin & obj folder. New maps and entities can be added into the extracted game data to have them usable in MapStudio." + - "\n\nAlternatively, you can create a folder named mapstudio in your extracted game folder. Placing a modified 00objentry.bin as well as any MDLXs inside that folder will cause MapStudio to prioritize loading from that folder instead." + - "\n\nA .map file contains the geometry and collision of the map." + + "\n\nEntities are loaded from the extracted 00objentry.bin & obj folder. New maps and entities can be added into the extracted game data to have them usable in MapStudio." + + "\n\nAlternatively, you can create a folder named mapstudio in your extracted game folder. Placing a modified 00objentry.bin as well as any MDLXs inside that folder will cause MapStudio to prioritize loading from that folder instead." + + "\n\nA .map file contains the geometry and collision of the map." + "\n\nAn .ard file controls what spawns inside of a map." + - "\n\nSpawn points, where you can encounter enemies, cutscenes, cutscene triggers, chest locations, etc. are all handled by .ard files." + + "\n\nSpawn points, where you can encounter enemies, cutscenes, cutscene triggers, chest locations, etc. are all handled by .ard files." + "\n\nView documentation on openkh.dev to learn more about the file." - ); - - private void ShowPrefDialog() => + ); + + private void ShowPrefDialog() => MessageBox.Show("Movement speed will alter how fast you can move through the map." + "\n\nEvent Activator Opacity & Red, Green, and Blue Values all control how the triggers that send you to different areas & spawn enemies will look." + "\n\nEntrance Marker will mark the entrances of warp points with that color, so that you can properly orient the entrance in the map." + @@ -647,6 +647,6 @@ private void ShowControlsDialog() => MessageBox.Show("W/A/S/D/E/Q: Moves in any direction, influenced by the camera's rotation." + "\n\nLeft Control/Space: Move directly down/up, regardless of camera's rotation." + "\n\nShift: Increase movement speed (can be changed under Preferences)." + - "\n\nLeft Click/Arrow Keys: Rotate Camera"); - } -} + "\n\nLeft Click/Arrow Keys: Rotate Camera"); + } +} From 85ef3652769270e44ac5ebf7455ef5ecf62a89fa Mon Sep 17 00:00:00 2001 From: Zurphing <72351816+Zurphing@users.noreply.github.com> Date: Mon, 29 Jul 2024 19:26:40 -0400 Subject: [PATCH 4/4] tr02 crash fix w/ try/catch --- OpenKh.Kh2/ModelMultiple.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/OpenKh.Kh2/ModelMultiple.cs b/OpenKh.Kh2/ModelMultiple.cs index 453083d33..f8dfbdaf6 100644 --- a/OpenKh.Kh2/ModelMultiple.cs +++ b/OpenKh.Kh2/ModelMultiple.cs @@ -1,15 +1,28 @@ -using System; +using System; using System.IO; namespace OpenKh.Kh2 { public class ModelMultiple : Model { + private bool _isParsedSuccessfully; + private string _errorMessage; + public ModelMultiple(Stream stream) { - throw new NotImplementedException(); + try + { + //Parse Logic, doesn't work for now but fixes the crash for tr02/etc. + _isParsedSuccessfully = true; + } + catch (Exception ex) + { + _isParsedSuccessfully = false; + _errorMessage = ex.Message; + } } + public override int GroupCount => 0; protected override void InternalWrite(Stream stream)