diff --git a/Fushigi/Fushigi.csproj b/Fushigi/Fushigi.csproj index 442c7791..bf10223b 100644 --- a/Fushigi/Fushigi.csproj +++ b/Fushigi/Fushigi.csproj @@ -11,7 +11,7 @@ - + diff --git a/Fushigi/Program.cs b/Fushigi/Program.cs index 0bf9c465..a4c38273 100644 --- a/Fushigi/Program.cs +++ b/Fushigi/Program.cs @@ -3,6 +3,7 @@ using Fushigi.ui; using System.Runtime.InteropServices; + FileStream outputStream = new FileStream("output.log", FileMode.Create); var consoleWriter = new StreamWriter(outputStream); consoleWriter.AutoFlush = true; diff --git a/Fushigi/actor_pack/ActorPack.cs b/Fushigi/actor_pack/ActorPack.cs index 109cb978..a79242fe 100644 --- a/Fushigi/actor_pack/ActorPack.cs +++ b/Fushigi/actor_pack/ActorPack.cs @@ -1,11 +1,14 @@ using Fushigi.actor_pack.components; +using Fushigi.Bfres; using Fushigi.Byml.Serializer; using Fushigi.gl.Bfres; using Fushigi.SARC; using Fushigi.util; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using System.Numerics; using System.Text; using System.Threading.Tasks; @@ -30,9 +33,14 @@ public static ActorPack Load(string gyml) public class ActorPack { + Dictionary paramTree = []; public ModelInfo DrawArrayModelInfoRef; public ModelInfo ModelInfoRef; public ModelExpandParam ModelExpandParamRef; + public DrainPipe DrainPipeRef; + public GamePhysics GamePhysicsRef; + public ControllerSetParam ControllerPath; + public ShapeParamList ShapeParams; public string Category = ""; @@ -77,11 +85,35 @@ private void Load(string path) { var paramInfo = BymlSerialize.Deserialize(sarc.OpenFile(file)); - LoadComponents(sarc, paramInfo); + paramInfo.path = file; + if(paramInfo.Components != null) + paramTree.Add(GetPathGyml(paramInfo.parent ?? "root"), paramInfo); + } + + foreach (var param in paramTree) + { + if(param.Key == "root") + { + LoadComponents(sarc, param.Value); + + if (!string.IsNullOrEmpty(param.Value.Category)) + this.Category = param.Value.Category; + + var parFile = param.Value.path; + while(paramTree.ContainsKey(parFile)) + { + var parent = paramTree[parFile]; + + LoadComponents(sarc, parent); - if (!string.IsNullOrEmpty(paramInfo.Category)) - this.Category = paramInfo.Category; + if (!string.IsNullOrEmpty(parent.Category)) + this.Category = parent.Category; + + parFile = parent.path; + } + } } + stream.Dispose(); } @@ -102,16 +134,92 @@ private void LoadComponents(SARC.SARC sarc, ActorParam param) switch (component.Key) { case "DrawArrayModelInfoRef": - this.DrawArrayModelInfoRef = BymlSerialize.Deserialize(data); + if(DrawArrayModelInfoRef == null) + this.DrawArrayModelInfoRef = BymlSerialize.Deserialize(data); + else{ + var child = BymlSerialize.Deserialize(data); + foreach(var v in DrawArrayModelInfoRef.GetType().GetProperties()) + { + if (v.GetValue(child) != null && v.GetValue(child) != default) + v.SetValue(DrawArrayModelInfoRef, v.GetValue(child)); + } + } break; case "ModelInfoRef": - this.ModelInfoRef = BymlSerialize.Deserialize(data); + if(ModelInfoRef == null) + this.ModelInfoRef = BymlSerialize.Deserialize(data); + else{ + var child = BymlSerialize.Deserialize(data); + foreach(var v in ModelInfoRef.GetType().GetProperties()) + { + + if (v.GetValue(child) != null && v.GetValue(child) != default) + v.SetValue(ModelInfoRef, v.GetValue(child)); + } + } break; case "ModelExpandRef": this.ModelExpandParamRef = BymlSerialize.Deserialize(data); break; + case "DrainPipeRef": + this.DrainPipeRef = BymlSerialize.Deserialize(data); + break; + case "GamePhysicsRef": + this.GamePhysicsRef = BymlSerialize.Deserialize(data); + if(!string.IsNullOrEmpty(GamePhysicsRef.mPath)) + ShapeParams = GetActorShape(sarc, data, filePath); + break; + } + } + } + + private ShapeParamList GetActorShape(SARC.SARC sarc, byte[] data, string filePath) + { + filePath = GetPathGyml(GamePhysicsRef.mPath); + data = sarc.OpenFile(filePath); + ControllerPath = BymlSerialize.Deserialize(data); + if(ControllerPath.ShapeNamePathAry != null) + { + var shapes = ControllerPath.ShapeNamePathAry; + while (!string.IsNullOrEmpty(ControllerPath.parent) && + ControllerPath.mRigids == null && ControllerPath.mEntity == null) + { + filePath = GetPathGyml(ControllerPath.parent); + data = sarc.OpenFile(filePath); + ControllerPath = BymlSerialize.Deserialize(data); + } + var rigidBodies = (ControllerPath.mRigids ?? new()).Concat(ControllerPath.mEntity ?? new()); + + foreach(var rigid in rigidBodies) + { + filePath = GetPathGyml(rigid.FilePath); + data = sarc.OpenFile(filePath); + var body = BymlSerialize.Deserialize(data); + + foreach(var shape in shapes) + { + if(body.ShapeName != null) + { + if(body.ShapeName == shape.Name && shape.FilePath != null) + { + filePath = GetPathGyml(shape.FilePath); + data = sarc.OpenFile(filePath); + return BymlSerialize.Deserialize(data); + } + } + else if(body.ShapeNames != null) + { + if(body.ShapeNames.Cast().Contains(shape.Name) && shape.FilePath != null) + { + filePath = GetPathGyml(shape.FilePath); + data = sarc.OpenFile(filePath); + return BymlSerialize.Deserialize(data); + } + } + } } } + return null; } private string GetPathGyml(string path) @@ -122,6 +230,11 @@ private string GetPathGyml(string path) class ActorParam { + public string path; + + [BymlProperty("$parent")] + public string parent { get; set; } + public string Category { get; set; } public Dictionary Components { get; set; } } diff --git a/Fushigi/actor_pack/components/DrainPipe.cs b/Fushigi/actor_pack/components/DrainPipe.cs new file mode 100644 index 00000000..7d822a5e --- /dev/null +++ b/Fushigi/actor_pack/components/DrainPipe.cs @@ -0,0 +1,17 @@ +using Fushigi.Byml.Serializer; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace Fushigi.actor_pack.components +{ + [Serializable] + public class DrainPipe + { + public string ModelKeyMiddle { get; set; } + public string ModelKeyTop { get; set; } + } +} diff --git a/Fushigi/actor_pack/components/GamePhysics.cs b/Fushigi/actor_pack/components/GamePhysics.cs new file mode 100644 index 00000000..5a6d77f1 --- /dev/null +++ b/Fushigi/actor_pack/components/GamePhysics.cs @@ -0,0 +1,110 @@ +using Fushigi.Byml.Serializer; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace Fushigi.actor_pack.components +{ + [Serializable] + public class GamePhysics + { + [BymlProperty("ControllerSetPath", DefaultValue = "")] + public string mPath { get; set; } + } + + [Serializable] + public class ControllerSetParam + { + [BymlProperty("$parent")] + public string parent { get; set; } + + public List ShapeNamePathAry { get; set; } + + [BymlProperty("MatterRigidBodyNamePathAry", DefaultValue = "")] + public List mRigids { get; set; } + + [BymlProperty("RigidBodyEntityNamePathAry", DefaultValue = "")] + public List mEntity { get; set; } + } + + [Serializable] + public class ShapeName + { + public string FilePath { get; set; } + public string Name { get; set; } + } + + [Serializable] + public class ShapeParamList + { + [BymlProperty("AutoCalc")] + public AutoCalc mCalc { get; set; } + + [BymlProperty("Box", DefaultValue = "")] + public List mBox { get; set; } + + [BymlProperty("Sphere", DefaultValue = "")] + public List mSphere { get; set; } + + [BymlProperty("Capsule", DefaultValue = "")] + public List mCapsule { get; set; } + + [BymlProperty("Polytope", DefaultValue = "")] + public List mPoly { get; set; } + } + + [Serializable] + public class RigidParam + { + public string ShapeName { get; set; } + + public List ShapeNames { get; set; } + } + + [Serializable] + public class AutoCalc + { + [BymlProperty("Axis")] + public Vector3 mAxis { get; set; } + + [BymlProperty("Center")] + public Vector3 mCenter { get; set; } + + [BymlProperty("Min")] + public Vector3 mMin { get; set; } + + [BymlProperty("Max")] + public Vector3 mMax { get; set; } + } + + [Serializable] + public class ShapeParam + { + [BymlProperty("AutoCalc", DefaultValue = "")] + public AutoCalc mCalc { get; set; } + + public float Radius { get; set; } + + [BymlProperty("Center")] + public Vector3 mCenter { get; set; } + + [BymlProperty("HalfExtents")] + public Vector3 mExtents { get; set; } + + } + + [Serializable] + public class Capsule + { + public float Radius { get; set; } + + [BymlProperty("CenterA")] + public Vector3 mCenterA { get; set; } + + [BymlProperty("CenterB")] + public Vector3 mCenterB { get; set; } + } +} \ No newline at end of file diff --git a/Fushigi/actor_pack/components/ModelInfo.cs b/Fushigi/actor_pack/components/ModelInfo.cs index 9633cb03..2a59b414 100644 --- a/Fushigi/actor_pack/components/ModelInfo.cs +++ b/Fushigi/actor_pack/components/ModelInfo.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Numerics; using System.Text; using System.Threading.Tasks; @@ -10,12 +11,17 @@ namespace Fushigi.actor_pack.components [Serializable] public class ModelInfo { + [BymlProperty("$parent")] + public string parent { get; set; } + [BymlProperty("FmdbName", DefaultValue = "")] public string mModelName { get; set; } [BymlProperty("ModelProjectName", DefaultValue = "")] public string mFilePath { get; set; } + [BymlProperty("DebugModelScale")] + public Vector3 mModelScale { get; set; } public string SearchModelKey { get; set; } public List SubModels { get; set; } @@ -24,6 +30,10 @@ public class ModelInfo public class SubModel { public string FmdbName { get; set; } + + public string ModelProjectName { get; set; } + + public string SearchModelKey { get; set; } } [Serializable] diff --git a/Fushigi/course/CourseActor.cs b/Fushigi/course/CourseActor.cs index b80b2fd0..56709a9f 100644 --- a/Fushigi/course/CourseActor.cs +++ b/Fushigi/course/CourseActor.cs @@ -250,6 +250,7 @@ public BymlHashTable BuildNode(CourseLinkHolder linkHolder) public string mPackName; public string mName; public string mLayer; + public System.Numerics.Vector3 mStartingTrans; public System.Numerics.Vector3 mTranslation; public System.Numerics.Vector3 mRotation; public System.Numerics.Vector3 mScale; diff --git a/Fushigi/ui/widgets/CourseMiniView.cs b/Fushigi/ui/widgets/CourseMiniView.cs new file mode 100644 index 00000000..ee0593be --- /dev/null +++ b/Fushigi/ui/widgets/CourseMiniView.cs @@ -0,0 +1,81 @@ +using Fushigi.course; +using ImGuiNET; +using System.Numerics; + +namespace Fushigi.ui.widgets +{ + internal class CourseMiniView + { + float ratio; + Vector2 center; + + Vector4 levelBounds; + Vector2 levelRect; + Vector2 miniLevelRect; + + Vector2 miniCamPos; + Vector2 miniCamSize; + + Vector3 camSave; + + public void Draw(CourseArea area, CourseAreaEditContext editContext, LevelViewport viewport) + { + var topLeft = ImGui.GetCursorScreenPos(); + ImGui.SetCursorScreenPos(topLeft); + + var size = ImGui.GetContentRegionAvail(); + + var cam = viewport.Camera; + var camSize = viewport.GetCameraSizeIn2DWorldSpace(); + + foreach(var actor in area.GetActors()) + { + levelBounds = new(Math.Min(levelBounds.X, actor.mTranslation.X), + Math.Min(levelBounds.Y, actor.mTranslation.Y), + Math.Max(levelBounds.Z, actor.mTranslation.X), + Math.Max(levelBounds.W, actor.mTranslation.Y)); + } + levelRect = new Vector2(levelBounds.Z-levelBounds.X, levelBounds.W - levelBounds.Y); + + ratio = size.X/levelBounds.X < size.Y/levelBounds.Y ? + size.X/levelBounds.X : size.Y/levelBounds.Y; + + miniLevelRect = levelRect*ratio; + + miniCamPos = new Vector2(cam.Target.X - levelBounds.X, -cam.Target.Y + levelBounds.Y)*ratio-miniCamSize/2; + miniCamSize = camSize*ratio; + center = new Vector2((size.X - levelRect.X)/2, (size.Y - levelRect.Y)/2); + + var lvlTopLeft = topLeft + center; + + ImGui.GetWindowDrawList().AddRect(lvlTopLeft, + lvlTopLeft + miniLevelRect, ImGui.ColorConvertFloat4ToU32(new(1, 1, 1, 1))); + + ImGui.GetWindowDrawList().AddRect(lvlTopLeft + miniCamPos + new Vector2(0, miniLevelRect.Y), + lvlTopLeft + miniCamPos + miniCamSize + new Vector2(0, miniLevelRect.Y), ImGui.ColorConvertFloat4ToU32(new(0, 0, 1, 1))); + + if (ImGui.IsMouseClicked(ImGuiMouseButton.Right) && !ImGui.IsMouseDown(ImGuiMouseButton.Left) + && ImGui.IsWindowHovered()) + { + camSave = cam.Target; + } + + if ((ImGui.IsMouseDown(ImGuiMouseButton.Left) || ImGui.IsMouseDown(ImGuiMouseButton.Right)) + && ImGui.IsWindowFocused() && + ((!ImGui.IsMouseClicked(ImGuiMouseButton.Left) && !ImGui.IsMouseClicked(ImGuiMouseButton.Right)) + || ImGui.IsWindowHovered())) + { + var pos = ImGui.GetMousePos(); + pos.Y *= -1; + cam.Target = new((pos - lvlTopLeft)/ratio + new Vector2(levelBounds.X, levelBounds.Y), + cam.Target.Z); + } + + + if (ImGui.IsMouseReleased(ImGuiMouseButton.Right) && !ImGui.IsMouseDown(ImGuiMouseButton.Left)) + { + cam.Target = camSave; + } + } + } +} \ No newline at end of file diff --git a/Fushigi/ui/widgets/CourseScene.cs b/Fushigi/ui/widgets/CourseScene.cs index b3c42eca..febd09f2 100644 --- a/Fushigi/ui/widgets/CourseScene.cs +++ b/Fushigi/ui/widgets/CourseScene.cs @@ -1,4 +1,5 @@ using Fushigi.course; +using Fushigi.gl; using Fushigi.gl.Bfres; using Fushigi.param; using Fushigi.ui.modal; @@ -9,6 +10,7 @@ using ImGuiNET; using Silk.NET.OpenGL; using System.Collections.Immutable; +using System.Drawing; using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; @@ -24,6 +26,7 @@ class CourseScene Dictionary? lastCreatedViewports; public LevelViewport activeViewport; UndoWindow undoWindow; + Vector3 camSave; (object? courseObj, PropertyFieldsCapture placementPropCapture, PropertyDictCapture dynamicPropCapture) propertyCapture = (null, @@ -181,8 +184,12 @@ public void DrawUI(GL gl, double deltaSeconds) GlobalLinksPanel(); RailLinksPanel(); + LocalLinksPanel(); + BGUnitPanel(); + CourseMiniView(); + for (int i = 0; i < mOpenToolWindows.Count; i++) { var window = mOpenToolWindows[i]; @@ -236,9 +243,10 @@ public void DrawUI(GL gl, double deltaSeconds) //Load popup when button is pressed if (ImGui.Button("Area Parameters")) ImGui.OpenPopup("AreaParams"); + ImGui.SameLine(); //Display Mouse Position - if (ImGui.IsWindowHovered()) + if (ImGui.IsMouseHoveringRect(topLeft, topLeft + size)) { var _mousePos = activeViewport.ScreenToWorld(ImGui.GetMousePos()); ImGui.Text("X: " + Math.Round(_mousePos.X, 3) + "\nY: " + Math.Round(_mousePos.Y, 3)); @@ -273,6 +281,8 @@ public void DrawUI(GL gl, double deltaSeconds) lastCreatedViewports = viewports; } + //minimap.Draw(selectedArea, areaScenes[selectedArea].EditContext, viewports[selectedArea]); + if (status) ImGui.End(); } @@ -354,6 +364,19 @@ private void GlobalLinksPanel() ImGui.End(); } + private void LocalLinksPanel() + { + ImGui.Begin("Local Links"); + + ImGui.Checkbox("Wonder View", ref activeViewport.IsWonderView); + + ImGui.Separator(); + + AreaLocalLinksView(selectedArea); + + ImGui.End(); + } + private void RailLinksPanel() { ImGui.Begin("Actor to Rail Links"); @@ -1286,6 +1309,112 @@ private void CourseGlobalLinksView(CourseLinkHolder linkHolder) } } } + + //VERY ROUGH BASE + //Still need to implement recursion on getting links, currently just displays the top most links + private void AreaLocalLinksView(CourseArea area) + { + var links = area.mLinkHolder; + var editContext = areaScenes[selectedArea].EditContext; + + float em = ImGui.GetFrameHeight(); + var wcMin = ImGui.GetCursorScreenPos() + new Vector2(0, ImGui.GetScrollY()); + var wcMax = wcMin + ImGui.GetContentRegionAvail(); + + RecursiveLinkFind(area, links, editContext, em); + + ImGui.PopClipRect(); + + ImGui.EndChild(); + } + + private void RecursiveLinkFind(CourseArea area, CourseLinkHolder links, CourseAreaEditContext editContext, float em) + { + foreach (CourseActor actor in area.GetActors().Where(x => !links.GetSrcHashesFromDest(x.mHash).Any() && links.GetDestHashesFromSrc(x.mHash).Any())) + { + ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags.FramePadding | ImGuiTreeNodeFlags.OpenOnArrow; + ImGui.PushID(actor.mHash.ToString()); + bool expanded = false; + bool isVisible = true; + float margin = 1.5f * em; + float headerHeight = 1.4f * em; + Vector2 cp = ImGui.GetCursorScreenPos(); + expanded = ImGui.TreeNodeEx(actor.mHash.ToString(), node_flags, actor.mPackName); + + if (ImGui.IsItemFocused()) + { + activeViewport.SelectedActor(actor); + } + + if (ImGui.IsItemHovered() && ImGui.IsMouseDoubleClicked(0)) + { + activeViewport.FrameSelectedActor(actor); + } + + if (!isVisible) + ImGui.BeginDisabled(); + + if (expanded) + { + foreach (var link in links.GetDestHashesFromSrc(actor.mHash)) + { + if(ImGui.TreeNodeEx(actor.mHash.ToString() + link.Key, ImGuiTreeNodeFlags.FramePadding, link.Key)) + { + foreach (CourseActor linkActor in area.GetActors().Where(x => link.Value.Contains(x.mHash))) + { + var act = linkActor; + string actorName = act.mPackName; + string name = act.mName; + ulong actorHash = act.mHash; + string actorLink = link.Key; + //Check if the node is within the necessary search filter requirements if search is used + bool HasText = act.mName.IndexOf(mActorSearchText, StringComparison.OrdinalIgnoreCase) >= 0 || + act.mPackName.IndexOf(mActorSearchText, StringComparison.OrdinalIgnoreCase) >= 0 || + act.ToString().Equals(mActorSearchText); + + if (!HasText) + continue; + + bool isSelected = editContext.IsSelected(act); + + ImGui.PushID(actorHash.ToString()); + ImGui.Columns(2); + + if (ImGui.Selectable(actorName, isSelected, ImGuiSelectableFlags.SpanAllColumns)) + { + activeViewport.SelectedActor(act); + } + else if (ImGui.IsItemFocused()) + { + activeViewport.SelectedActor(act); + } + + if (ImGui.IsItemHovered() && ImGui.IsMouseDoubleClicked(0)) + { + activeViewport.FrameSelectedActor(act); + } + + + ImGui.NextColumn(); + ImGui.BeginDisabled(); + ImGui.Text(name); + ImGui.EndDisabled(); + ImGui.Columns(1); + + ImGui.PopID(); + ImGui.TreePop(); + } + } + } + ImGui.TreePop(); + } + + if (!isVisible) + ImGui.EndDisabled(); + + ImGui.PopID(); + } + } private void UpdateAllLayerVisiblity() { @@ -1462,6 +1591,93 @@ private void CourseActorsLayerView(CourseActorHolder actorArray) ImGui.EndChild(); } + private void CourseMiniView() + { + var area = selectedArea; + var editContext = areaScenes[area].EditContext; + var view = viewports[area]; + bool status = ImGui.Begin("Minimap", ImGuiWindowFlags.NoNav); + + var topLeft = ImGui.GetCursorScreenPos(); + + ImGui.SetNextItemAllowOverlap(); + ImGui.SetCursorScreenPos(topLeft); + + //ImGui.SetNextItemAllowOverlap(); + var size = ImGui.GetContentRegionAvail(); + + ImGui.SetNextItemAllowOverlap(); + ImGui.SetCursorScreenPos(topLeft); + + var cam = view.Camera; + var camSize = view.GetCameraSizeIn2DWorldSpace(); + + Vector4 bounds = Vector4.Zero; + foreach(var actor in area.GetActors()) + { + bounds = new(Math.Min(bounds.X, actor.mTranslation.X), + Math.Min(bounds.Y, actor.mTranslation.Y), + Math.Max(bounds.Z, actor.mTranslation.X), + Math.Max(bounds.W, actor.mTranslation.Y)); + } + var levelRect = new Vector2(bounds.Z-bounds.X, bounds.W - bounds.Y); + + float tanFOV = MathF.Tan(cam.Fov / 2); + + var ratio = size.X/levelRect.X < size.Y/levelRect.Y ? size.X/levelRect.X : size.Y/levelRect.Y; + var miniRect = levelRect*ratio; + var miniCam = new Vector2(cam.Target.X, -cam.Target.Y)*ratio; + var miniCamSize = camSize*ratio; + var miniSaveCam = new Vector2(camSave.X, -camSave.Y)*ratio; + var center = new Vector2((size.X - miniRect.X)/2, (size.Y - miniRect.Y)/2); + + var col = ImGuiCol.ButtonActive; + + //ImGui.SetNextItemAllowOverlap(); + if (ImGui.IsMouseClicked(ImGuiMouseButton.Right) && !ImGui.IsMouseDown(ImGuiMouseButton.Left) + && ImGui.IsWindowHovered()) + { + camSave = cam.Target; + } + + if ((ImGui.IsMouseDown(ImGuiMouseButton.Left) || ImGui.IsMouseDown(ImGuiMouseButton.Right)) + && ImGui.IsWindowFocused() && + ((!ImGui.IsMouseClicked(ImGuiMouseButton.Right) && !ImGui.IsMouseClicked(ImGuiMouseButton.Left)) + || ImGui.IsWindowHovered())) + { + if (camSave != default) + { + col = ImGuiCol.TextDisabled; + ImGui.GetWindowDrawList().AddRect(topLeft + miniSaveCam - miniCamSize/2 + new Vector2(0, miniRect.Y) + center, + topLeft + miniSaveCam + miniCamSize/2 + new Vector2(0, miniRect.Y) + center, + ImGui.ColorConvertFloat4ToU32(ImGui.GetStyle().Colors[(int)ImGuiCol.Button]),6,0,3); + } + + var pos = ImGui.GetMousePos(); + cam.Target = new((pos.X - (topLeft.X + center.X))/ratio, + (-pos.Y + topLeft.Y + center.Y + miniRect.Y)/ratio, cam.Target.Z); + } + + if (ImGui.IsMouseReleased(ImGuiMouseButton.Right) && !ImGui.IsMouseDown(ImGuiMouseButton.Left) + && camSave != default) + { + cam.Target = camSave; + camSave = default; + } + + ImGui.GetWindowDrawList().AddRect(topLeft + center, + topLeft + miniRect + center, + ImGui.ColorConvertFloat4ToU32(ImGui.GetStyle().Colors[(int)ImGuiCol.Text]),6,0,3); + + ImGui.GetWindowDrawList().AddRect(topLeft + miniCam - miniCamSize/2 + new Vector2(0, miniRect.Y) + center, + topLeft + miniCam + miniCamSize/2 + new Vector2(0, miniRect.Y) + center, + ImGui.ColorConvertFloat4ToU32(ImGui.GetStyle().Colors[(int)col]),6,0,3); + + if (status) + ImGui.End(); + + } + private static void PlacementNode(CourseActor actor) { static void EditFloat3RadAsDeg(string label, ref System.Numerics.Vector3 rad, float speed) diff --git a/Fushigi/ui/widgets/LevelViewport.cs b/Fushigi/ui/widgets/LevelViewport.cs index 19cf7fbc..be9eaf34 100644 --- a/Fushigi/ui/widgets/LevelViewport.cs +++ b/Fushigi/ui/widgets/LevelViewport.cs @@ -4,6 +4,7 @@ using Fushigi.gl.Bfres; using Fushigi.util; using ImGuiNET; +using Silk.NET.Maths; using Silk.NET.OpenGL; using System.Drawing; using System.Numerics; @@ -27,14 +28,17 @@ public static void DefaultSelect(CourseAreaEditContext ctx, object selectable) { ctx.Select(selectable); } - else + else if(!ctx.IsSelected(selectable)) { ctx.WithSuspendUpdateDo(() => { ctx.DeselectAll(); ctx.Select(selectable); }); - + } + foreach(CourseActor act in ctx.GetSelectedObjects()) + { + act.mStartingTrans = act.mTranslation; } } } @@ -67,8 +71,11 @@ internal class LevelViewport(CourseArea area, GL gl, CourseAreaScene areaScene) public bool IsViewportHovered; public bool IsViewportActive; + public bool IsWonderView; Vector2 mSize = Vector2.Zero; + + public ulong prevSelectVersion { get; private set; } = 0; private IDictionary? mLayersVisibility; Vector2 mTopLeft = Vector2.Zero; @@ -129,6 +136,12 @@ private void CancelOngoingPickingRequests() public Matrix4x4 GetCameraMatrix() => Camera.ViewProjectionMatrix; + public Vector2 GetCameraSizeIn2DWorldSpace() + { + var cameraBoundsSize = ScreenToWorld(mSize) - ScreenToWorld(new Vector2(0)); + return new Vector2(cameraBoundsSize.X, Math.Abs(cameraBoundsSize.Y)); + } + public Vector2 WorldToScreen(Vector3 pos) => WorldToScreen(pos, out _); public Vector2 WorldToScreen(Vector3 pos, out float ndcDepth) { @@ -185,8 +198,8 @@ public void SelectedActor(CourseActor actor) public void HandleCameraControls(double deltaSeconds) { - bool isPanGesture = (ImGui.IsMouseDragging(ImGuiMouseButton.Middle)) || - (ImGui.IsMouseDragging(ImGuiMouseButton.Left) && ImGui.GetIO().KeyShift); + bool isPanGesture = ImGui.IsMouseDragging(ImGuiMouseButton.Middle) || + (ImGui.IsMouseDragging(ImGuiMouseButton.Left) && ImGui.GetIO().KeyShift && !mEditContext.IsAnySelected()); if (IsViewportActive && isPanGesture) { @@ -293,31 +306,35 @@ private void RenderActor(CourseActor actor, ModelInfo modelInfo) var rotMat = Matrix4x4.CreateRotationX(actor.mRotation.X) * Matrix4x4.CreateRotationY(actor.mRotation.Y) * Matrix4x4.CreateRotationZ(actor.mRotation.Z); + + var debugSMat = Matrix4x4.CreateScale(modelInfo.mModelScale != default ? modelInfo.mModelScale:Vector3.One); - var mat = scaleMat * rotMat * transMat; + var mat = debugSMat * scaleMat * rotMat * transMat; var model = render.Models[modelName]; //switch for drawing models with different methods easier - switch (modelName) + if(actor.mActorPack.DrainPipeRef != null){ + var drainRef = actor.mActorPack.DrainPipeRef; + var calc = actor.mActorPack.ShapeParams.mCalc; + var KeyMats = new Dictionary{ + {drainRef.ModelKeyTop ?? "Top", debugSMat * + Matrix4x4.CreateScale(actor.mScale.X, actor.mScale.X, actor.mScale.Z) * + Matrix4x4.CreateTranslation(0, (actor.mScale.Y-actor.mScale.X)*(calc.mMax.Y-calc.mMin.Y), 0) * + rotMat * + transMat}, + + {drainRef.ModelKeyMiddle ?? "Middle", debugSMat * + Matrix4x4.CreateScale(actor.mScale.X, (actor.mScale.Y-1)*2, actor.mScale.Z) * + rotMat * + transMat}}; + + render.Models[modelName].Render(gl, render, KeyMats[modelInfo.SearchModelKey], this.Camera); + if(modelInfo.SubModels?.Any() ?? false) + render.Models[modelInfo.SubModels[0].FmdbName].Render(gl, render, KeyMats[modelInfo.SubModels[0].SearchModelKey], this.Camera); + } + else { - case "DokanTop": - var matPTop = - Matrix4x4.CreateScale(actor.mScale.X, actor.mScale.X, actor.mScale.Z) * - Matrix4x4.CreateTranslation(0, (actor.mScale.Y - actor.mScale.X) * 2, 0) * - rotMat * - transMat; - - var matPMid = - Matrix4x4.CreateScale(actor.mScale.X, actor.mScale.Y * 2, actor.mScale.Z) * - rotMat * - transMat; - - model.Render(gl, render, matPTop, this.Camera); - render.Models["DokanMiddle"].Render(gl, render, matPMid, this.Camera); - break; - default: - model.Render(gl, render, mat, this.Camera); - break; + model.Render(gl, render, mat, this.Camera); } } @@ -397,7 +414,6 @@ void InteractionWithFocus(KeyboardModifier modifiers) if (IsViewportHovered && mObjectPickingRequest.TryGetValue(out var objectPickingRequest)) { - bool isValid = objectPickingRequest.predicate(mHoveredObject); string currentlyHoveredObjText = ""; @@ -438,23 +454,27 @@ void InteractionWithFocus(KeyboardModifier modifiers) return; } - + if (ImGui.IsMouseDragging(ImGuiMouseButton.Left)) { - if (mEditContext.IsSingleObjectSelected(out CourseActor? actor)) + if (mEditContext.IsAnySelected()) { - Vector3 posVec = ScreenToWorld(ImGui.GetMousePos()); - - if (ImGui.GetIO().KeyShift) + foreach(CourseActor actor in mEditContext.GetSelectedObjects()) { - actor.mTranslation = posVec; - } - else - { - posVec.X = MathF.Round(posVec.X * 2, MidpointRounding.AwayFromZero) / 2; - posVec.Y = MathF.Round(posVec.Y * 2, MidpointRounding.AwayFromZero) / 2; - posVec.Z = actor.mTranslation.Z; - actor.mTranslation = posVec; + Vector3 posVec = ScreenToWorld(ImGui.GetMousePos()); + posVec -= ScreenToWorld(ImGui.GetIO().MouseClickedPos[0]) - actor.mStartingTrans; + + if (ImGui.GetIO().KeyShift) + { + actor.mTranslation = posVec; + } + else + { + posVec.X = MathF.Round(posVec.X * 2, MidpointRounding.AwayFromZero) / 2; + posVec.Y = MathF.Round(posVec.Y * 2, MidpointRounding.AwayFromZero) / 2; + posVec.Z = actor.mTranslation.Z; + actor.mTranslation = posVec; + } } } if (mEditContext.IsSingleObjectSelected(out CourseRail.CourseRailPoint? rail)) @@ -475,28 +495,63 @@ void InteractionWithFocus(KeyboardModifier modifiers) } } + if (ImGui.IsItemClicked()) { + bool isModeActor = mHoveredObject != null; + bool isModeUnit = HoveredPoint != null; + + if (isModeActor && !isModeUnit) + { + mEditorMode = EditorMode.Actors; + } + + if (isModeUnit && !isModeActor) + { + mEditorMode = EditorMode.Units; + } + /* if the user clicked somewhere and it was not hovered over an element, * we clear our selected actors array */ if (mHoveredObject == null) { - mEditContext.DeselectAll(); + if(!ImGui.IsKeyDown(ImGuiKey.LeftShift)) + mEditContext.DeselectAll(); } else if (mHoveredObject is IViewportSelectable obj) { + prevSelectVersion = mEditContext.SelectionVersion; obj.OnSelect(mEditContext); } else { //TODO remove this once all course objects have IViewportSelectable SceneObjs + prevSelectVersion = mEditContext.SelectionVersion; IViewportSelectable.DefaultSelect(mEditContext, mHoveredObject); } } + if(mHoveredObject != null && mHoveredObject is CourseActor && + ImGui.IsMouseReleased(ImGuiMouseButton.Left)) + { + if (ImGui.GetIO().MouseDragMaxDistanceSqr[0] <= ImGui.GetIO().MouseDragThreshold) + { + if(ImGui.IsKeyDown(ImGuiKey.LeftShift) + && prevSelectVersion == mEditContext.SelectionVersion) + { + mEditContext.Deselect(mHoveredObject!); + } + else if(!ImGui.IsKeyDown(ImGuiKey.LeftShift)) + { + mEditContext.DeselectAll(); + IViewportSelectable.DefaultSelect(mEditContext, mHoveredObject); + } + } + } + if (ImGui.IsKeyPressed(ImGuiKey.Delete)) { - ObjectDeletionRequested?.Invoke(mEditContext.GetSelectedObjects().ToList()); + mEditorState = EditorState.DeleteActorLinkCheck; } if (ImGui.IsKeyPressed(ImGuiKey.Escape)) @@ -719,7 +774,7 @@ Vector2[] GetPoints() //Delete selected if (selectedPoint != null && ImGui.IsKeyPressed(ImGuiKey.Delete)) { - rail.mPoints.Remove(selectedPoint); + rail.mPoints.Remove(selectedPoint); } if (selectedPoint != null && ImGui.IsMouseReleased(0)) { @@ -728,7 +783,7 @@ Vector2[] GetPoints() if (matching.Count > 1) rail.mPoints.Remove(selectedPoint); } - + bool add_point = ImGui.IsMouseClicked(0) && ImGui.IsMouseDown(0) && ImGui.GetIO().KeyAlt; //Insert point to selected @@ -739,9 +794,9 @@ Vector2[] GetPoints() var index = rail.mPoints.IndexOf(selectedPoint); var newPoint = new CourseRail.CourseRailPoint(selectedPoint); newPoint.mTranslate = new( - MathF.Round(posVec.X, MidpointRounding.AwayFromZero), - MathF.Round(posVec.Y, MidpointRounding.AwayFromZero), - selectedPoint.mTranslate.Z); + MathF.Round(posVec.X, MidpointRounding.AwayFromZero), + MathF.Round(posVec.Y, MidpointRounding.AwayFromZero), + selectedPoint.mTranslate.Z); if (rail.mPoints.Count - 1 == index) rail.mPoints.Add(newPoint); @@ -758,9 +813,9 @@ Vector2[] GetPoints() var newPoint = new CourseRail.CourseRailPoint(); newPoint.mTranslate = new( - MathF.Round(posVec.X, MidpointRounding.AwayFromZero), - MathF.Round(posVec.Y, MidpointRounding.AwayFromZero), - 0); + MathF.Round(posVec.X, MidpointRounding.AwayFromZero), + MathF.Round(posVec.Y, MidpointRounding.AwayFromZero), + 0); rail.mPoints.Add(newPoint); @@ -834,6 +889,31 @@ Vector2[] GetPoints() foreach (CourseActor actor in mArea.GetActors()) { + Vector3 min = new(-.5f); + Vector3 max = new(.5f); + Vector3 off = new(0f); + Vector3 center = new(0f); + var drawing = "box"; + + if (actor.mActorPack.ShapeParams != null) + { + var calc = actor.mActorPack.ShapeParams.mCalc; + + if(((actor.mActorPack.ShapeParams.mSphere?.Count ?? 0) > 0) || + ((actor.mActorPack.ShapeParams.mCapsule?.Count?? 0) > 0)) + { + drawing = "sphere"; + } + else if((actor.mActorPack.ShapeParams.mPoly?.Count ?? 0) > 0) + { + calc = actor.mActorPack.ShapeParams.mPoly[0].mCalc; + } + + min = calc.mMin; + max = calc.mMax; + center = calc.mCenter; + } + string layer = actor.mLayer; if (mLayersVisibility!.TryGetValue(layer, out bool isVisible) && isVisible) @@ -856,27 +936,17 @@ Vector2[] GetPoints() { if (actor.mPackName.Contains("CameraArea")) color = ImGui.ColorConvertFloat4ToU32(new(1, 0, 0, 1)); - - //topLeft - s_actorRectPolygon[0] = WorldToScreen(Vector3.Transform(new(-0.5f, 1f, 0), transform)); - //topRight - s_actorRectPolygon[1] = WorldToScreen(Vector3.Transform(new(0.5f, 1f, 0), transform)); - //bottomRight - s_actorRectPolygon[2] = WorldToScreen(Vector3.Transform(new(0.5f, 0, 0), transform)); - //bottomLeft - s_actorRectPolygon[3] = WorldToScreen(Vector3.Transform(new(-0.5f, 0, 0), transform)); - } - else - { - //topLeft - s_actorRectPolygon[0] = WorldToScreen(Vector3.Transform(new(-0.5f, 0.5f, 0), transform)); - //topRight - s_actorRectPolygon[1] = WorldToScreen(Vector3.Transform(new(0.5f, 0.5f, 0), transform)); - //bottomRight - s_actorRectPolygon[2] = WorldToScreen(Vector3.Transform(new(0.5f, -0.5f, 0), transform)); - //bottomLeft - s_actorRectPolygon[3] = WorldToScreen(Vector3.Transform(new(-0.5f, -0.5f, 0), transform)); + + off = new(0, .5f, 0); } + //topLeft + s_actorRectPolygon[0] = WorldToScreen(Vector3.Transform(new(min.X, off.Y+max.Y, 0), transform)); + //topRight + s_actorRectPolygon[1] = WorldToScreen(Vector3.Transform(new(max.X, off.Y+max.Y, 0), transform)); + //bottomRight + s_actorRectPolygon[2] = WorldToScreen(Vector3.Transform(new(max.X, off.Y+min.Y, 0), transform)); + //bottomLeft + s_actorRectPolygon[3] = WorldToScreen(Vector3.Transform(new(min.X, off.Y+min.Y, 0), transform)); if (mEditContext.IsSelected(actor)) { @@ -885,17 +955,37 @@ Vector2[] GetPoints() bool isHovered = mHoveredObject == actor; - for (int i = 0; i < 4; i++) + switch(drawing) { - if (mEditContext.IsSelected(actor)) + default: + for (int i = 0; i < 4; i++) + { + mDrawList.AddLine( + s_actorRectPolygon[i], + s_actorRectPolygon[(i+1) % 4 ], + color, isHovered ? 2.5f : 1.5f); + } + break; + case "sphere": + var pos = WorldToScreen(Vector3.Transform(center, transform)); + var scale = Matrix4x4.CreateScale(actor.mScale); + Vector2 rad = (WorldToScreen(Vector3.Transform(max, scale))-WorldToScreen(Vector3.Transform(min, scale)))/2; + mDrawList.AddEllipse(pos, Math.Abs(rad.X), Math.Abs(rad.Y), color, -actor.mRotation.Z, 0, isHovered ? 2.5f : 1.5f); + + break; + } + if (mEditContext.IsSelected(actor)) + { + for (int i = 0; i < 4; i++) { mDrawList.AddCircleFilled(s_actorRectPolygon[i], pointSize, color); - } - mDrawList.AddLine( + mDrawList.AddLine( s_actorRectPolygon[i], - s_actorRectPolygon[(i + 1) % 4], + s_actorRectPolygon[(i+1) % 4 ], color, isHovered ? 2.5f : 1.5f); + } + mDrawList.AddEllipse(WorldToScreen(Vector3.Transform(new(0), transform)), pointSize*3, pointSize*3, color, -actor.mRotation.Z, 4, 2); } string name = actor.mPackName; diff --git a/Fushigi/windowing/ImGuiController.cs b/Fushigi/windowing/ImGuiController.cs index 77cabd59..20b49a71 100644 --- a/Fushigi/windowing/ImGuiController.cs +++ b/Fushigi/windowing/ImGuiController.cs @@ -16,6 +16,9 @@ using Silk.NET.Windowing.Glfw; using Sdl = Silk.NET.SDL.Sdl; using Silk.NET.Windowing.Sdl; +using Silk.NET.SDL; +using PixelFormat = Silk.NET.OpenGL.PixelFormat; +using PixelType = Silk.NET.OpenGL.PixelType; namespace Fushigi.windowing; @@ -109,7 +112,13 @@ public ImGuiController(GL gl, IWindow window, IInputContext input, Action? onCon CreateDeviceResources(); - SetKeyMappings(); + foreach (var key in input.Keyboards[0].SupportedKeys) + { + if (TryMapKey(key, out ImGuiKey imguikey)) + { + io.AddKeyEvent(imguikey, input.Keyboards[0].IsKeyPressed(key)); + } + } SetPerFrameImGuiData(1f / 60f); @@ -157,9 +166,10 @@ private void OnKeyDown(IKeyboard keyboard, Key key, int scanCode) if (key == Key.Unknown) return; - key = TranslateKeyFunc?.Invoke(key, scanCode) ?? key; - - ImGui.GetIO().KeysDown[(int)key] = true; + if (TryMapKey(key, out ImGuiKey imguikey)) + { + ImGui.GetIO().AddKeyEvent(imguikey, true); + } } private void OnKeyUp(IKeyboard keyboard, Key key, int scanCode) @@ -167,9 +177,10 @@ private void OnKeyUp(IKeyboard keyboard, Key key, int scanCode) if (key == Key.Unknown) return; - key = TranslateKeyFunc?.Invoke(key, scanCode) ?? key; - - ImGui.GetIO().KeysDown[(int)key] = false; + if (TryMapKey(key, out ImGuiKey imguikey)) + { + ImGui.GetIO().AddKeyEvent(imguikey, false); + } } private void WindowResized(Vector2D size) @@ -224,6 +235,7 @@ public void Update(float deltaSeconds) } SetPerFrameImGuiData(deltaSeconds); + UpdateImGuiInput(); _frameBegun = true; @@ -252,62 +264,104 @@ private void SetPerFrameImGuiData(float deltaSeconds) io.DeltaTime = deltaSeconds; // DeltaTime is in seconds. } - private void UpdateImGuiInput() - { - var io = ImGuiNET.ImGui.GetIO(); - - var mouseState = _input.Mice[0].CaptureState(); - var keyboardState = _input.Keyboards[0]; - - io.MouseDown[0] = mouseState.IsButtonPressed(MouseButton.Left); - io.MouseDown[1] = mouseState.IsButtonPressed(MouseButton.Right); - io.MouseDown[2] = mouseState.IsButtonPressed(MouseButton.Middle); + private bool TryMapKey(Key key, out ImGuiKey result) + { + ImGuiKey KeyToImGuiKeyShortcut(Key keyToConvert, Key startKey1, ImGuiKey startKey2) + { + int changeFromStart1 = (int)keyToConvert - (int)startKey1; + return startKey2 + changeFromStart1; + } - io.MousePos = new Vector2((int)mouseState.Position.X, (int)mouseState.Position.Y); + result = key switch + { + >= Key.F1 and <= Key.F24 => KeyToImGuiKeyShortcut(key, Key.F1, ImGuiKey.F1), + >= Key.Keypad0 and <= Key.Keypad9 => KeyToImGuiKeyShortcut(key, Key.Keypad0, ImGuiKey.Keypad0), + >= Key.A and <= Key.Z => KeyToImGuiKeyShortcut(key, Key.A, ImGuiKey.A), + >= Key.Number0 and <= Key.Number9 => KeyToImGuiKeyShortcut(key, Key.Number0, ImGuiKey._0), + Key.ShiftLeft => ImGuiKey.LeftShift, + Key.ShiftRight => ImGuiKey.RightShift, + Key.ControlLeft => ImGuiKey.LeftCtrl, + Key.ControlRight => ImGuiKey.RightCtrl, + Key.AltLeft => ImGuiKey.LeftAlt, + Key.AltRight => ImGuiKey.RightAlt, + Key.SuperLeft => ImGuiKey.LeftSuper, + Key.SuperRight => ImGuiKey.RightSuper, + Key.Menu => ImGuiKey.Menu, + Key.Up => ImGuiKey.UpArrow, + Key.Down => ImGuiKey.DownArrow, + Key.Left => ImGuiKey.LeftArrow, + Key.Right => ImGuiKey.RightArrow, + Key.Enter => ImGuiKey.Enter, + Key.Escape => ImGuiKey.Escape, + Key.Space => ImGuiKey.Space, + Key.Tab => ImGuiKey.Tab, + Key.Backspace => ImGuiKey.Backspace, + Key.Insert => ImGuiKey.Insert, + Key.Delete => ImGuiKey.Delete, + Key.PageUp => ImGuiKey.PageUp, + Key.PageDown => ImGuiKey.PageDown, + Key.Home => ImGuiKey.Home, + Key.End => ImGuiKey.End, + Key.CapsLock => ImGuiKey.CapsLock, + Key.ScrollLock => ImGuiKey.ScrollLock, + Key.PrintScreen => ImGuiKey.PrintScreen, + Key.Pause => ImGuiKey.Pause, + Key.NumLock => ImGuiKey.NumLock, + Key.KeypadDivide => ImGuiKey.KeypadDivide, + Key.KeypadMultiply => ImGuiKey.KeypadMultiply, + Key.KeypadSubtract => ImGuiKey.KeypadSubtract, + Key.KeypadAdd => ImGuiKey.KeypadAdd, + Key.KeypadDecimal => ImGuiKey.KeypadDecimal, + Key.KeypadEnter => ImGuiKey.KeypadEnter, + Key.GraveAccent => ImGuiKey.GraveAccent, + Key.Minus => ImGuiKey.Minus, + Key.Equal => ImGuiKey.Equal, + Key.LeftBracket => ImGuiKey.LeftBracket, + Key.RightBracket => ImGuiKey.RightBracket, + Key.Semicolon => ImGuiKey.Semicolon, + Key.Apostrophe => ImGuiKey.Apostrophe, + Key.Comma => ImGuiKey.Comma, + Key.Period => ImGuiKey.Period, + Key.Slash => ImGuiKey.Slash, + Key.BackSlash => ImGuiKey.Backslash, + _ => ImGuiKey.None + }; - var wheel = mouseState.GetScrollWheels()[0]; - io.MouseWheel = wheel.Y; - io.MouseWheelH = wheel.X; + return result != ImGuiKey.None; + } - foreach (var c in _pressedChars) + internal void PressChar(char keyChar) { - io.AddInputCharacter(c); + _pressedChars.Add(keyChar); } - _pressedChars.Clear(); + private void UpdateImGuiInput() + { + ImGuiIOPtr io = ImGui.GetIO(); - io.KeyCtrl = keyboardState.IsKeyPressed(Key.ControlLeft) || keyboardState.IsKeyPressed(Key.ControlRight); - io.KeyAlt = keyboardState.IsKeyPressed(Key.AltLeft) || keyboardState.IsKeyPressed(Key.AltRight); - io.KeyShift = keyboardState.IsKeyPressed(Key.ShiftLeft) || keyboardState.IsKeyPressed(Key.ShiftRight); - io.KeySuper = keyboardState.IsKeyPressed(Key.SuperLeft) || keyboardState.IsKeyPressed(Key.SuperRight); - } + var mouseState = _input.Mice[0].CaptureState(); + var keyboardState = _input.Keyboards[0]; - internal void PressChar(char keyChar) - { - _pressedChars.Add(keyChar); - } - private static void SetKeyMappings() - { - var io = ImGuiNET.ImGui.GetIO(); - io.KeyMap[(int)ImGuiKey.Tab] = (int)Key.Tab; - io.KeyMap[(int)ImGuiKey.LeftArrow] = (int)Key.Left; - io.KeyMap[(int)ImGuiKey.RightArrow] = (int)Key.Right; - io.KeyMap[(int)ImGuiKey.UpArrow] = (int)Key.Up; - io.KeyMap[(int)ImGuiKey.DownArrow] = (int)Key.Down; - io.KeyMap[(int)ImGuiKey.PageUp] = (int)Key.PageUp; - io.KeyMap[(int)ImGuiKey.PageDown] = (int)Key.PageDown; - io.KeyMap[(int)ImGuiKey.Home] = (int)Key.Home; - io.KeyMap[(int)ImGuiKey.End] = (int)Key.End; - io.KeyMap[(int)ImGuiKey.Delete] = (int)Key.Delete; - io.KeyMap[(int)ImGuiKey.Backspace] = (int)Key.Backspace; - io.KeyMap[(int)ImGuiKey.Enter] = (int)Key.Enter; - io.KeyMap[(int)ImGuiKey.Escape] = (int)Key.Escape; - - for (int i = 0; i < (Key.Z - Key.A)+1; i++) - { - io.KeyMap[(int)ImGuiKey.A+i] = (int)Key.A+i; + io.AddMousePosEvent(mouseState.Position.X, mouseState.Position.Y); + io.AddMouseButtonEvent(0, mouseState.IsButtonPressed(MouseButton.Left)); + io.AddMouseButtonEvent(1, mouseState.IsButtonPressed(MouseButton.Right)); + io.AddMouseButtonEvent(2, mouseState.IsButtonPressed(MouseButton.Middle)); + io.AddMouseButtonEvent(3, mouseState.IsButtonPressed(MouseButton.Button4)); + io.AddMouseButtonEvent(4, mouseState.IsButtonPressed(MouseButton.Button5)); + + io.AddMouseWheelEvent(mouseState.GetScrollWheels()[0].X, mouseState.GetScrollWheels()[0].Y); + foreach (var c in _pressedChars) + { + io.AddInputCharacter(c); + } + + _pressedChars.Clear(); + + ImGui.GetIO().AddKeyEvent(ImGuiKey.ModCtrl, ImGui.IsKeyDown(ImGuiKey.LeftCtrl) || ImGui.IsKeyDown(ImGuiKey.RightCtrl)); + ImGui.GetIO().AddKeyEvent(ImGuiKey.ModAlt, ImGui.IsKeyDown(ImGuiKey.LeftAlt) || ImGui.IsKeyDown(ImGuiKey.RightAlt)); + ImGui.GetIO().AddKeyEvent(ImGuiKey.ModShift, ImGui.IsKeyDown(ImGuiKey.LeftShift) || ImGui.IsKeyDown(ImGuiKey.RightShift)); + ImGui.GetIO().AddKeyEvent(ImGuiKey.ModSuper, ImGui.IsKeyDown(ImGuiKey.LeftSuper) || ImGui.IsKeyDown(ImGuiKey.RightSuper)); } - } private unsafe void SetupRenderState(ImDrawDataPtr drawDataPtr, int framebufferWidth, int framebufferHeight) {