From 871fc44178cc4e39554307f19722cfc5696ad0ce Mon Sep 17 00:00:00 2001 From: KillzXGaming Date: Sun, 20 Oct 2019 12:57:48 -0400 Subject: [PATCH] More additions. More progress on the basic pane animation editor. It can add and clear entries for frames, groups, etc. Add the latest muunt editor files. A wip editor which is currently disabled. Planned to edit object placement paths paths supporting both 2D and 3D views. --- .../Syroot.NintenTools.NSW.Bfres.dll | Bin 216576 -> 216576 bytes .../Syroot.NintenTools.NSW.Bfres.pdb | Bin 84908 -> 84908 bytes .../FileFormats/Byaml/BYAML.cs | 8 +- .../FileFormats/Layout/CAFE/BFLAN.cs | 23 ++ .../FileFormats/Layout/Common.cs | 62 +++- .../File_Format_Library.csproj | 134 ++++++--- .../Basic/AddAnimGroupDialog.Designer.cs | 141 +++++++++ .../Animations/Basic/AddAnimGroupDialog.cs | 64 +++++ .../AddAnimGroupDialog.resx} | 0 .../Basic/AddGroupTargetDialog.Designer.cs | 128 +++++++++ .../Animations/Basic/AddGroupTargetDialog.cs | 81 ++++++ .../Basic/AddGroupTargetDialog.resx | 120 ++++++++ .../Basic/AddGroupTypeDialog.Designer.cs | 98 +++++++ .../Animations/Basic/AddGroupTypeDialog.cs | 39 +++ .../Animations/Basic/AddGroupTypeDialog.resx | 120 ++++++++ .../LayoutAnimEditorBasic.Designer.cs | 3 + .../{ => Basic}/LayoutAnimEditorBasic.cs | 149 +++++++++- .../Basic/LayoutAnimEditorBasic.resx | 120 ++++++++ File_Format_Library/GUI/BFLYT/LayoutEditor.cs | 9 +- .../Byaml/CourseMuunt/Base/BasePathGroup.cs | 11 - .../GUI/Byaml/CourseMuunt2D/TrackEditor2D.cs | 17 -- .../MuuntEditor/Interfaces/IDrawableObject.cs | 14 + .../MuuntEditor/Interfaces/IMuuntLoader.cs | 16 ++ .../Interfaces/IdrawableContainer.cs} | 6 +- .../GUI/Byaml/MuuntEditor/MapObject.cs | 14 + .../MuuntEditor.Designer.cs | 59 ++-- .../GUI/Byaml/MuuntEditor/MuuntEditor.cs | 109 +++++++ .../MuuntEditor.resx | 0 .../GUI/Byaml/MuuntEditor/MuuntEditor2D.cs | 52 ++++ .../Byaml/MuuntEditor/MuuntEditorDocker.cs | 19 ++ .../MuuntEditor/MuuntObjectList.Designer.cs | 79 ++++++ .../GUI/Byaml/MuuntEditor/MuuntObjectList.cs | 31 ++ .../Byaml/MuuntEditor/MuuntObjectList.resx | 120 ++++++++ .../MuuntPropertiesEditor.Designer.cs | 46 +++ .../MuuntPropertiesEditor.cs} | 11 +- .../MuuntEditor/MuuntPropertiesEditor.resx | 120 ++++++++ .../GUI/Byaml/MuuntEditor/ObjectGroup.cs | 32 +++ .../Plugins/MK8/PathDrawableContainer.cs | 39 +++ .../Plugins/MK8/TrackMuuntLoader.cs | 50 ++++ .../MuuntEditor/PropertyGridConverters.cs | 268 ++++++++++++++++++ .../GUI/Byaml/MuuntEditor/PropertyObject.cs | 25 ++ .../Base/BaseControlPoint.cs | 0 .../Base/BaseObjPt.cs | 0 .../TurboCourseMuunt/Base/BasePathGroup.cs | 22 ++ .../Base/BasePathPoint.cs | 46 ++- .../Base/PointID.cs | 0 .../Base/RenderableConnectedMapPoints.cs | 0 .../Base/RenderablePathPoint.cs | 0 .../CourseMuuntStructs.cs | 0 .../IObject.cs | 0 .../IntroCamera.cs | 0 .../Paths/EnemyPaths.cs | 3 - .../Paths/GliderPaths.cs | 0 .../Paths/GravityPaths.cs | 0 .../Paths/ItemPaths.cs | 0 .../Paths/JugemPath.cs | 0 .../Paths/LapPaths.cs | 0 .../Paths/ObjPath.cs | 0 .../Paths/Paths.cs | 0 .../Paths/PullPath.cs | 0 .../Paths/RenderableConnectedPaths.cs | 0 .../Paths/ReturnPoint.cs | 0 .../Paths/SteerAssistPath.cs | 0 .../Byaml/TurboCourseMuunt/RenderablePath.cs | 67 +++++ .../TurboMunntEditor.Designer.cs | 0 .../TurboMunntEditor.cs | 0 .../TurboMunntEditor.resx | 0 .../Wrappers/PathCollectionNode.cs | 0 .../Wrappers/PathGroupNode.cs | 0 .../Wrappers/PathPointNode.cs | 0 .../Wrappers/ProbeLightingEntryWrapper.cs | 0 .../Wrappers/ProbeLightingWrapper.cs | 0 .../Forms/Custom/BarSlider/BarSlider.cs | 4 +- .../Forms/Custom/STComboBox.cs | 6 + .../Forms/Editors/UV/UVEditorForm.cs | 2 + .../OpenGL/IPickableObject.cs | 16 ++ Switch_Toolbox_Library/OpenGL/OpenGLHelper.cs | 14 +- Switch_Toolbox_Library/OpenGL/Render2D.cs | 27 +- Switch_Toolbox_Library/OpenGL/STRectangle.cs | 46 +++ Switch_Toolbox_Library/OpenGL/Viewport2D.cs | 144 +++++++++- Switch_Toolbox_Library/Toolbox_Library.csproj | 2 + Toolbox/Gl_EditorFramework.dll | Bin 166400 -> 166400 bytes Toolbox/Gl_EditorFramework.pdb | Bin 374272 -> 374272 bytes Toolbox/Lib/Syroot.NintenTools.NSW.Bfres.dll | Bin 216576 -> 216576 bytes Toolbox/Lib/Syroot.NintenTools.NSW.Bfres.pdb | Bin 84908 -> 84908 bytes 85 files changed, 2697 insertions(+), 139 deletions(-) create mode 100644 File_Format_Library/GUI/BFLYT/Animations/Basic/AddAnimGroupDialog.Designer.cs create mode 100644 File_Format_Library/GUI/BFLYT/Animations/Basic/AddAnimGroupDialog.cs rename File_Format_Library/GUI/BFLYT/Animations/{LayoutAnimEditorBasic.resx => Basic/AddAnimGroupDialog.resx} (100%) create mode 100644 File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTargetDialog.Designer.cs create mode 100644 File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTargetDialog.cs create mode 100644 File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTargetDialog.resx create mode 100644 File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTypeDialog.Designer.cs create mode 100644 File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTypeDialog.cs create mode 100644 File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTypeDialog.resx rename File_Format_Library/GUI/BFLYT/Animations/{ => Basic}/LayoutAnimEditorBasic.Designer.cs (92%) rename File_Format_Library/GUI/BFLYT/Animations/{ => Basic}/LayoutAnimEditorBasic.cs (50%) create mode 100644 File_Format_Library/GUI/BFLYT/Animations/Basic/LayoutAnimEditorBasic.resx delete mode 100644 File_Format_Library/GUI/Byaml/CourseMuunt/Base/BasePathGroup.cs delete mode 100644 File_Format_Library/GUI/Byaml/CourseMuunt2D/TrackEditor2D.cs create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/Interfaces/IDrawableObject.cs create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/Interfaces/IMuuntLoader.cs rename File_Format_Library/GUI/Byaml/{CourseMuunt2D/MuuntEditorDocker.cs => MuuntEditor/Interfaces/IdrawableContainer.cs} (53%) create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/MapObject.cs rename File_Format_Library/GUI/Byaml/{CourseMuunt2D => MuuntEditor}/MuuntEditor.Designer.cs (94%) create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor.cs rename File_Format_Library/GUI/Byaml/{CourseMuunt2D => MuuntEditor}/MuuntEditor.resx (100%) create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor2D.cs create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditorDocker.cs create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/MuuntObjectList.Designer.cs create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/MuuntObjectList.cs create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/MuuntObjectList.resx create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/MuuntPropertiesEditor.Designer.cs rename File_Format_Library/GUI/Byaml/{CourseMuunt2D/MuuntEditor.cs => MuuntEditor/MuuntPropertiesEditor.cs} (55%) create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/MuuntPropertiesEditor.resx create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/ObjectGroup.cs create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/Plugins/MK8/PathDrawableContainer.cs create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/Plugins/MK8/TrackMuuntLoader.cs create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/PropertyGridConverters.cs create mode 100644 File_Format_Library/GUI/Byaml/MuuntEditor/PropertyObject.cs rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Base/BaseControlPoint.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Base/BaseObjPt.cs (100%) create mode 100644 File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/BasePathGroup.cs rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Base/BasePathPoint.cs (76%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Base/PointID.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Base/RenderableConnectedMapPoints.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Base/RenderablePathPoint.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/CourseMuuntStructs.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/IObject.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/IntroCamera.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Paths/EnemyPaths.cs (95%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Paths/GliderPaths.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Paths/GravityPaths.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Paths/ItemPaths.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Paths/JugemPath.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Paths/LapPaths.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Paths/ObjPath.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Paths/Paths.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Paths/PullPath.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Paths/RenderableConnectedPaths.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Paths/ReturnPoint.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Paths/SteerAssistPath.cs (100%) create mode 100644 File_Format_Library/GUI/Byaml/TurboCourseMuunt/RenderablePath.cs rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/TurboMunntEditor.Designer.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/TurboMunntEditor.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/TurboMunntEditor.resx (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Wrappers/PathCollectionNode.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Wrappers/PathGroupNode.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Wrappers/PathPointNode.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Wrappers/ProbeLightingEntryWrapper.cs (100%) rename File_Format_Library/GUI/Byaml/{CourseMuunt => TurboCourseMuunt}/Wrappers/ProbeLightingWrapper.cs (100%) create mode 100644 Switch_Toolbox_Library/OpenGL/IPickableObject.cs create mode 100644 Switch_Toolbox_Library/OpenGL/STRectangle.cs diff --git a/BrawlboxHelper/Syroot.NintenTools.NSW.Bfres.dll b/BrawlboxHelper/Syroot.NintenTools.NSW.Bfres.dll index dd7a71628c88294d862d8a6e3d87a5784b1f279b..78e1fe6f44d7c066e4002255144412bf580f5ea8 100644 GIT binary patch delta 116 zcmZpe!`m>2cR~k?!T!8`jXkYBj9Yt{9{d-$c!_yJkJcy0)p5PsSWBFyY^`Bl;>403 zx%c*T6=&uEfzwZ&i%*nlyHC2cR~lt?2q5BH1@RiFmCN(dhlOBq3=feBw0(L;-I KyQd5Dc1{3_2sJDK diff --git a/BrawlboxHelper/Syroot.NintenTools.NSW.Bfres.pdb b/BrawlboxHelper/Syroot.NintenTools.NSW.Bfres.pdb index 63e8bf10498d367228f8a08098f2239656366a79..9e77bfc0d4812466c359ced5838e0298d8935648 100644 GIT binary patch delta 161 zcmZ28opsH0)(JHtr=L0(pD5LKpQN+APm1q$e0t>G+l>>pPGH=lBJ%Xk)lA*wYo9+j zxvezk5V`v4h^@i)1XadGvWz^_nVlIAi9F0XV7%v-x0SkvHg9y|FX$A%c MhtA~bao&u60CXQRxBvhE delta 161 zcmZ28opsH0)(JHten0-aSNJRHzeuMfj%T9Mq`eaBFEvisI)QPIiipL;$$w+EIX^xA z@(k0r`f9EvE=8={6I2-&$ue?HXLe>hB=Ufloq>;uft`VosWPHr5d#BP$J6OIof#t- ze@{1ZVbo=0+n(UUn8n5@IsLR3qY0zwG;c-)Mz`sT-i)dep}cGi1}q$+3?fhyq!}0( N96FPx$9XgQ0RU@7GKv5I diff --git a/File_Format_Library/FileFormats/Byaml/BYAML.cs b/File_Format_Library/FileFormats/Byaml/BYAML.cs index 1aa1dd60..77f27bda 100644 --- a/File_Format_Library/FileFormats/Byaml/BYAML.cs +++ b/File_Format_Library/FileFormats/Byaml/BYAML.cs @@ -10,7 +10,6 @@ using Toolbox.Library.Forms; using Toolbox.Library.IO; using ByamlExt.Byaml; using ByamlExt; -using FirstPlugin.Turbo; namespace FirstPlugin { @@ -166,6 +165,13 @@ namespace FirstPlugin editor.FileFormat = this; editor.Text = FileName; editor.Dock = DockStyle.Fill; + + /* if (FileName.Contains("_muunt")) + { + var muuntEditor = new MuuntEditor.MuuntEditor(); + muuntEditor.LoadByaml(data.RootNode, FileName); + muuntEditor.Show(); + }*/ return editor; } diff --git a/File_Format_Library/FileFormats/Layout/CAFE/BFLAN.cs b/File_Format_Library/FileFormats/Layout/CAFE/BFLAN.cs index f0be3fba..f5b91ab5 100644 --- a/File_Format_Library/FileFormats/Layout/CAFE/BFLAN.cs +++ b/File_Format_Library/FileFormats/Layout/CAFE/BFLAN.cs @@ -273,6 +273,12 @@ namespace LayoutBXLYT Textures = new List(); } + public override BxlanPaiEntry AddEntry(string name, byte target) { + var entry = new PaiEntry(name, target); + Entries.Add(entry); + return entry; + } + public PAI1(FileReader reader, Header header) { long startPos = reader.Position - 8; @@ -342,6 +348,18 @@ namespace LayoutBXLYT public class PaiEntry : BxlanPaiEntry { + public override BxlanPaiTag AddEntry(string tag) { + var paiTag = new PaiTag(tag); + Tags.Add(paiTag); + return paiTag; + } + + public PaiEntry(string name, byte target) + { + Name = name; + Target = (AnimationTarget)target; + } + public PaiEntry(FileReader reader, Header header) { long startPos = reader.Position; @@ -383,6 +401,11 @@ namespace LayoutBXLYT { private uint Unknown {get;set;} + public PaiTag(string tag) + { + Tag = tag; + } + public PaiTag(FileReader reader, BxlanHeader header, AnimationTarget target) { if ((byte)target == 2) diff --git a/File_Format_Library/FileFormats/Layout/Common.cs b/File_Format_Library/FileFormats/Layout/Common.cs index 14868445..e5a538e6 100644 --- a/File_Format_Library/FileFormats/Layout/Common.cs +++ b/File_Format_Library/FileFormats/Layout/Common.cs @@ -1420,12 +1420,27 @@ namespace LayoutBXLYT public ushort FrameSize; public bool Loop; - public List Textures { get; set; } + public bool ContainsEntry(string name) + { + return Entries.Any(x => x.Name == name); + } + + public virtual BxlanPaiEntry AddEntry(string name, byte target) + { + return new BxlanPaiEntry(); + } + + public List Textures { get; set; } = new List(); public List Entries = new List(); } public class BxlanPaiEntry { + public virtual BxlanPaiTag AddEntry(string tag) + { + return new BxlanPaiTag(); + } + [DisplayName("Name"), CategoryAttribute("Animation")] public string Name { get; set; } @@ -1447,6 +1462,29 @@ namespace LayoutBXLYT Tag = tag; } + public BxlanPaiTagEntry CreateTarget(object TargetType, byte interpolationType) + { + byte target = (byte)TargetType; + string tagType = Tag.Remove(0, 1); + switch (Tag) + { + case "LPA": + return new LPATagEntry(target, interpolationType); + case "LTS": + return new LTSTagEntry(target, interpolationType); + case "LVI": + return new LVITagEntry(target, interpolationType); + case "LVC": + return new LVCTagEntry(target, interpolationType); + case "LMC": + return new LMCTagEntry(target, interpolationType); + case "LTP": + return new LTPTagEntry(target, interpolationType); + default: + return new BxlanPaiTagEntry(target, interpolationType); + } + } + public List Entries = new List(); public string Tag; @@ -1456,7 +1494,7 @@ namespace LayoutBXLYT get { return TypeDefine.ContainsKey(Tag) ? TypeDefine[Tag] : Tag; } } - public Dictionary TypeDefine = new Dictionary() + public static Dictionary TypeDefine = new Dictionary() { {"FLPA","PaneSRT" }, {"FLVI","Visibility" }, @@ -1504,6 +1542,7 @@ namespace LayoutBXLYT set { AnimationTarget = (byte)value; } } + public LPATagEntry(byte target, byte curveType) : base(target, curveType) { } public LPATagEntry(FileReader reader, BxlanHeader header) : base(reader, header) { } } @@ -1517,6 +1556,7 @@ namespace LayoutBXLYT set { AnimationTarget = (byte)value; } } + public LTSTagEntry(byte target, byte curveType) : base(target, curveType) { } public LTSTagEntry(FileReader reader, BxlanHeader header) : base(reader, header) { } } @@ -1530,6 +1570,7 @@ namespace LayoutBXLYT set { AnimationTarget = (byte)value; } } + public LVITagEntry(byte target, byte curveType) : base(target, curveType) { } public LVITagEntry(FileReader reader, BxlanHeader header) : base(reader, header) { } } @@ -1543,6 +1584,7 @@ namespace LayoutBXLYT set { AnimationTarget = (byte)value; } } + public LVCTagEntry(byte target, byte curveType) : base(target, curveType) { } public LVCTagEntry(FileReader reader, BxlanHeader header) : base(reader, header) { } } @@ -1556,6 +1598,7 @@ namespace LayoutBXLYT set { AnimationTarget = (byte)value; } } + public LMCTagEntry(byte target, byte curveType) : base(target, curveType) { } public LMCTagEntry(FileReader reader, BxlanHeader header) : base(reader, header) { } } @@ -1569,6 +1612,7 @@ namespace LayoutBXLYT set { AnimationTarget = (byte)value; } } + public LTPTagEntry(byte target, byte curveType) : base(target, curveType) { } public LTPTagEntry(FileReader reader, BxlanHeader header) : base(reader, header) { } } @@ -1590,6 +1634,11 @@ namespace LayoutBXLYT public List KeyFrames = new List(); + public BxlanPaiTagEntry(byte target, byte curveType) + { + AnimationTarget = target; + CurveType = (CurveType)curveType; + } public BxlanPaiTagEntry(FileReader reader, BxlanHeader header) { @@ -1659,6 +1708,13 @@ namespace LayoutBXLYT [DisplayName("Value"), CategoryAttribute("Key Frame")] public float Value { get; set; } + public KeyFrame(float frame) + { + Frame = frame; + Value = 0; + Slope = 0; + } + public KeyFrame(FileReader reader, CurveType curveType) { switch (curveType) @@ -1718,7 +1774,7 @@ namespace LayoutBXLYT public virtual Dictionary GetTextures { get; } [Browsable(false)] - public virtual List Textures { get; } + public virtual List Textures { get; } [Browsable(false)] public virtual List Fonts { get; } diff --git a/File_Format_Library/File_Format_Library.csproj b/File_Format_Library/File_Format_Library.csproj index d680e6e5..c059e424 100644 --- a/File_Format_Library/File_Format_Library.csproj +++ b/File_Format_Library/File_Format_Library.csproj @@ -354,16 +354,34 @@ + + Form + + + AddAnimGroupDialog.cs + + + Form + + + AddGroupTypeDialog.cs + + + Form + + + AddGroupTargetDialog.cs + Form LayoutAnimEditor.cs - + Form - + LayoutAnimEditorBasic.cs @@ -648,16 +666,40 @@ SmoothNormalsMultiMeshForm.cs - + + + + + + + + Form - + MuuntEditor.cs - + Form - + + UserControl + + + Form + + + MuuntObjectList.cs + + + Form + + + MuuntPropertiesEditor.cs + + + + UserControl @@ -853,39 +895,39 @@ TexPatternMaterialEditor.cs - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + UserControl - + TurboMunntEditor.cs - - - - - + + + + + UserControl @@ -1339,10 +1381,19 @@ BffntEditor.cs + + AddAnimGroupDialog.cs + + + AddGroupTypeDialog.cs + + + AddGroupTargetDialog.cs + LayoutAnimEditor.cs - + LayoutAnimEditorBasic.cs @@ -1600,10 +1651,16 @@ BotwActorEditorControl.cs - + MuuntEditor.cs - + + MuuntObjectList.cs + + + MuuntPropertiesEditor.cs + + TurboMunntEditor.cs @@ -1801,6 +1858,7 @@ + diff --git a/File_Format_Library/GUI/BFLYT/Animations/Basic/AddAnimGroupDialog.Designer.cs b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddAnimGroupDialog.Designer.cs new file mode 100644 index 00000000..b472827d --- /dev/null +++ b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddAnimGroupDialog.Designer.cs @@ -0,0 +1,141 @@ +namespace LayoutBXLYT +{ + partial class AddAnimGroupDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.typeCB = new Toolbox.Library.Forms.STComboBox(); + this.stTextBox1 = new Toolbox.Library.Forms.STTextBox(); + this.objectTargetsCB = new Toolbox.Library.Forms.STComboBox(); + this.stLabel1 = new Toolbox.Library.Forms.STLabel(); + this.stLabel2 = new Toolbox.Library.Forms.STLabel(); + this.stButton1 = new Toolbox.Library.Forms.STButton(); + this.contentContainer.SuspendLayout(); + this.SuspendLayout(); + // + // contentContainer + // + this.contentContainer.Controls.Add(this.stButton1); + this.contentContainer.Controls.Add(this.stLabel2); + this.contentContainer.Controls.Add(this.stLabel1); + this.contentContainer.Controls.Add(this.objectTargetsCB); + this.contentContainer.Controls.Add(this.stTextBox1); + this.contentContainer.Controls.Add(this.typeCB); + this.contentContainer.Size = new System.Drawing.Size(375, 155); + this.contentContainer.Controls.SetChildIndex(this.typeCB, 0); + this.contentContainer.Controls.SetChildIndex(this.stTextBox1, 0); + this.contentContainer.Controls.SetChildIndex(this.objectTargetsCB, 0); + this.contentContainer.Controls.SetChildIndex(this.stLabel1, 0); + this.contentContainer.Controls.SetChildIndex(this.stLabel2, 0); + this.contentContainer.Controls.SetChildIndex(this.stButton1, 0); + // + // typeCB + // + this.typeCB.BorderColor = System.Drawing.Color.Empty; + this.typeCB.BorderStyle = System.Windows.Forms.ButtonBorderStyle.Solid; + this.typeCB.ButtonColor = System.Drawing.Color.Empty; + this.typeCB.FormattingEnabled = true; + this.typeCB.IsReadOnly = false; + this.typeCB.Location = new System.Drawing.Point(74, 45); + this.typeCB.Name = "typeCB"; + this.typeCB.Size = new System.Drawing.Size(285, 21); + this.typeCB.TabIndex = 11; + this.typeCB.SelectedIndexChanged += new System.EventHandler(this.typeCB_SelectedIndexChanged); + // + // stTextBox1 + // + this.stTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.stTextBox1.Location = new System.Drawing.Point(74, 83); + this.stTextBox1.Name = "stTextBox1"; + this.stTextBox1.Size = new System.Drawing.Size(145, 20); + this.stTextBox1.TabIndex = 12; + // + // objectTargetsCB + // + this.objectTargetsCB.BorderColor = System.Drawing.Color.Empty; + this.objectTargetsCB.BorderStyle = System.Windows.Forms.ButtonBorderStyle.Solid; + this.objectTargetsCB.ButtonColor = System.Drawing.Color.Empty; + this.objectTargetsCB.FormattingEnabled = true; + this.objectTargetsCB.IsReadOnly = false; + this.objectTargetsCB.Location = new System.Drawing.Point(225, 82); + this.objectTargetsCB.Name = "objectTargetsCB"; + this.objectTargetsCB.Size = new System.Drawing.Size(134, 21); + this.objectTargetsCB.TabIndex = 13; + this.objectTargetsCB.SelectedIndexChanged += new System.EventHandler(this.objectTargetsCB_SelectedIndexChanged); + // + // stLabel1 + // + this.stLabel1.AutoSize = true; + this.stLabel1.Location = new System.Drawing.Point(34, 48); + this.stLabel1.Name = "stLabel1"; + this.stLabel1.Size = new System.Drawing.Size(34, 13); + this.stLabel1.TabIndex = 14; + this.stLabel1.Text = "Type:"; + // + // stLabel2 + // + this.stLabel2.AutoSize = true; + this.stLabel2.Location = new System.Drawing.Point(34, 85); + this.stLabel2.Name = "stLabel2"; + this.stLabel2.Size = new System.Drawing.Size(38, 13); + this.stLabel2.TabIndex = 15; + this.stLabel2.Text = "Name:"; + // + // stButton1 + // + this.stButton1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.stButton1.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.stButton1.Location = new System.Drawing.Point(291, 123); + this.stButton1.Name = "stButton1"; + this.stButton1.Size = new System.Drawing.Size(75, 23); + this.stButton1.TabIndex = 16; + this.stButton1.Text = "Ok"; + this.stButton1.UseVisualStyleBackColor = false; + // + // AddAnimGroupDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(381, 160); + this.Name = "AddAnimGroupDialog"; + this.Text = "Add Group"; + this.contentContainer.ResumeLayout(false); + this.contentContainer.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private Toolbox.Library.Forms.STButton stButton1; + private Toolbox.Library.Forms.STLabel stLabel2; + private Toolbox.Library.Forms.STLabel stLabel1; + private Toolbox.Library.Forms.STComboBox objectTargetsCB; + private Toolbox.Library.Forms.STTextBox stTextBox1; + private Toolbox.Library.Forms.STComboBox typeCB; + } +} \ No newline at end of file diff --git a/File_Format_Library/GUI/BFLYT/Animations/Basic/AddAnimGroupDialog.cs b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddAnimGroupDialog.cs new file mode 100644 index 00000000..64d4dda0 --- /dev/null +++ b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddAnimGroupDialog.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Toolbox.Library.Forms; + +namespace LayoutBXLYT +{ + public partial class AddAnimGroupDialog : STForm + { + private BxlanPAI1 AnimInfo; + private BxlytHeader ParentLayout; + + public AddAnimGroupDialog(BxlanPAI1 bxlanPai, BxlytHeader parentLayout) + { + InitializeComponent(); + CanResize = false; + + AnimInfo = bxlanPai; + ParentLayout = parentLayout; + + typeCB.LoadEnum(typeof(AnimationTarget)); + typeCB.SelectedIndex = 0; + } + + public BxlanPaiEntry AddEntry() + { + return AnimInfo.AddEntry(stTextBox1.Text, (byte)typeCB.SelectedItem); + } + + private void typeCB_SelectedIndexChanged(object sender, EventArgs e) + { + if (ParentLayout != null && typeCB.SelectedItem is AnimationTarget) + { + objectTargetsCB.Items.Clear(); + if ((AnimationTarget)typeCB.SelectedItem == AnimationTarget.Pane) + { + foreach (var pane in ParentLayout.PaneLookup.Keys) + if (!AnimInfo.ContainsEntry(pane)) + objectTargetsCB.Items.Add(pane); + } + else if ((AnimationTarget)typeCB.SelectedItem == AnimationTarget.Material) + { + foreach (var mat in ParentLayout.GetMaterials()) + if (!AnimInfo.ContainsEntry(mat.Name)) + objectTargetsCB.Items.Add(mat.Name); + } + + if (objectTargetsCB.Items.Count > 0) + objectTargetsCB.SelectedIndex = 0; + } + } + + private void objectTargetsCB_SelectedIndexChanged(object sender, EventArgs e) + { + stTextBox1.Text = (string)objectTargetsCB.SelectedItem; + } + } +} diff --git a/File_Format_Library/GUI/BFLYT/Animations/LayoutAnimEditorBasic.resx b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddAnimGroupDialog.resx similarity index 100% rename from File_Format_Library/GUI/BFLYT/Animations/LayoutAnimEditorBasic.resx rename to File_Format_Library/GUI/BFLYT/Animations/Basic/AddAnimGroupDialog.resx diff --git a/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTargetDialog.Designer.cs b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTargetDialog.Designer.cs new file mode 100644 index 00000000..26651da5 --- /dev/null +++ b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTargetDialog.Designer.cs @@ -0,0 +1,128 @@ +namespace LayoutBXLYT +{ + partial class AddGroupTargetDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.targetCB = new Toolbox.Library.Forms.STComboBox(); + this.stLabel1 = new Toolbox.Library.Forms.STLabel(); + this.stButton1 = new Toolbox.Library.Forms.STButton(); + this.stLabel2 = new Toolbox.Library.Forms.STLabel(); + this.curveTypeCB = new Toolbox.Library.Forms.STComboBox(); + this.contentContainer.SuspendLayout(); + this.SuspendLayout(); + // + // contentContainer + // + this.contentContainer.Controls.Add(this.stLabel2); + this.contentContainer.Controls.Add(this.curveTypeCB); + this.contentContainer.Controls.Add(this.stButton1); + this.contentContainer.Controls.Add(this.stLabel1); + this.contentContainer.Controls.Add(this.targetCB); + this.contentContainer.Size = new System.Drawing.Size(316, 143); + this.contentContainer.Controls.SetChildIndex(this.targetCB, 0); + this.contentContainer.Controls.SetChildIndex(this.stLabel1, 0); + this.contentContainer.Controls.SetChildIndex(this.stButton1, 0); + this.contentContainer.Controls.SetChildIndex(this.curveTypeCB, 0); + this.contentContainer.Controls.SetChildIndex(this.stLabel2, 0); + // + // targetCB + // + this.targetCB.BorderColor = System.Drawing.Color.Empty; + this.targetCB.BorderStyle = System.Windows.Forms.ButtonBorderStyle.Solid; + this.targetCB.ButtonColor = System.Drawing.Color.Empty; + this.targetCB.FormattingEnabled = true; + this.targetCB.IsReadOnly = false; + this.targetCB.Location = new System.Drawing.Point(96, 35); + this.targetCB.Name = "targetCB"; + this.targetCB.Size = new System.Drawing.Size(208, 21); + this.targetCB.TabIndex = 11; + // + // stLabel1 + // + this.stLabel1.AutoSize = true; + this.stLabel1.Location = new System.Drawing.Point(20, 38); + this.stLabel1.Name = "stLabel1"; + this.stLabel1.Size = new System.Drawing.Size(41, 13); + this.stLabel1.TabIndex = 12; + this.stLabel1.Text = "Target:"; + // + // stButton1 + // + this.stButton1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.stButton1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.stButton1.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.stButton1.Location = new System.Drawing.Point(232, 111); + this.stButton1.Name = "stButton1"; + this.stButton1.Size = new System.Drawing.Size(75, 23); + this.stButton1.TabIndex = 13; + this.stButton1.Text = "Ok"; + this.stButton1.UseVisualStyleBackColor = false; + // + // stLabel2 + // + this.stLabel2.AutoSize = true; + this.stLabel2.Location = new System.Drawing.Point(20, 65); + this.stLabel2.Name = "stLabel2"; + this.stLabel2.Size = new System.Drawing.Size(68, 13); + this.stLabel2.TabIndex = 15; + this.stLabel2.Text = "Curve Type::"; + // + // curveTypeCB + // + this.curveTypeCB.BorderColor = System.Drawing.Color.Empty; + this.curveTypeCB.BorderStyle = System.Windows.Forms.ButtonBorderStyle.Solid; + this.curveTypeCB.ButtonColor = System.Drawing.Color.Empty; + this.curveTypeCB.FormattingEnabled = true; + this.curveTypeCB.IsReadOnly = false; + this.curveTypeCB.Location = new System.Drawing.Point(96, 62); + this.curveTypeCB.Name = "curveTypeCB"; + this.curveTypeCB.Size = new System.Drawing.Size(208, 21); + this.curveTypeCB.TabIndex = 14; + // + // AddGroupTargetDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(322, 148); + this.Name = "AddGroupTargetDialog"; + this.Text = "Add Target"; + this.contentContainer.ResumeLayout(false); + this.contentContainer.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private Toolbox.Library.Forms.STLabel stLabel1; + private Toolbox.Library.Forms.STComboBox targetCB; + private Toolbox.Library.Forms.STLabel stLabel2; + private Toolbox.Library.Forms.STComboBox curveTypeCB; + private Toolbox.Library.Forms.STButton stButton1; + } +} \ No newline at end of file diff --git a/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTargetDialog.cs b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTargetDialog.cs new file mode 100644 index 00000000..70609307 --- /dev/null +++ b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTargetDialog.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Toolbox.Library.Forms; + +namespace LayoutBXLYT +{ + public partial class AddGroupTargetDialog : STForm + { + private BxlanPaiTag activeTag; + + public AddGroupTargetDialog() + { + InitializeComponent(); + CanResize = false; + } + + public bool LoadTag(BxlanPaiTag group) + { + activeTag = group; + + curveTypeCB.LoadEnum(typeof(CurveType)); + curveTypeCB.SelectedItem = CurveType.Hermite; + + //Go through each group type + //If either all targets are used, or is not supported we will return false + if (group.Type == "PaneSRT") + return LoadEnum(typeof(LPATarget)); + else if (group.Type == "Visibility") + return LoadEnum(typeof(LVITarget)); + else if (group.Type == "TextureSRT") + return LoadEnum(typeof(LTSTarget)); + else if (group.Type == "VertexColor") + return LoadEnum(typeof(LVCTarget)); + else if (group.Type == "TexturePattern") + return LoadEnum(typeof(LTPTarget)); + else if (group.Type == "IndTextureSRT") + return LoadEnum(typeof(LIMTarget)); + else if (group.Type == "AlphaTest") + { + + } + else if (group.Type == "FontShadow") + return LoadEnum(typeof(LCTTarget)); + else if (group.Type == "PerCharacterTransformCurve") + { + + } + + return false; + } + + private bool LoadEnum(Type type) + { + targetCB.Items.Clear(); + var enums = Enum.GetValues(type); + foreach (var val in Enum.GetValues(type)) + { + if (!activeTag.Entries.Any(x => byte.Equals((byte)val, x.AnimationTarget))) + targetCB.Items.Add(val); + } + + if (targetCB.Items.Count > 0) + targetCB.SelectedIndex = 0; + + //Check if it loaded enums properly + return targetCB.Items.Count > 0; + } + + public BxlanPaiTagEntry GetGroupTarget() + { + return activeTag.CreateTarget(targetCB.SelectedItem, (byte)curveTypeCB.SelectedItem); + } + } +} diff --git a/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTargetDialog.resx b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTargetDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTargetDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTypeDialog.Designer.cs b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTypeDialog.Designer.cs new file mode 100644 index 00000000..02ad549b --- /dev/null +++ b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTypeDialog.Designer.cs @@ -0,0 +1,98 @@ +namespace LayoutBXLYT +{ + partial class AddGroupTypeDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.stComboBox1 = new Toolbox.Library.Forms.STComboBox(); + this.stLabel1 = new Toolbox.Library.Forms.STLabel(); + this.stButton1 = new Toolbox.Library.Forms.STButton(); + this.contentContainer.SuspendLayout(); + this.SuspendLayout(); + // + // contentContainer + // + this.contentContainer.Controls.Add(this.stButton1); + this.contentContainer.Controls.Add(this.stLabel1); + this.contentContainer.Controls.Add(this.stComboBox1); + this.contentContainer.Size = new System.Drawing.Size(278, 112); + this.contentContainer.Controls.SetChildIndex(this.stComboBox1, 0); + this.contentContainer.Controls.SetChildIndex(this.stLabel1, 0); + this.contentContainer.Controls.SetChildIndex(this.stButton1, 0); + // + // stComboBox1 + // + this.stComboBox1.BorderColor = System.Drawing.Color.Empty; + this.stComboBox1.BorderStyle = System.Windows.Forms.ButtonBorderStyle.Solid; + this.stComboBox1.ButtonColor = System.Drawing.Color.Empty; + this.stComboBox1.FormattingEnabled = true; + this.stComboBox1.IsReadOnly = false; + this.stComboBox1.Location = new System.Drawing.Point(74, 45); + this.stComboBox1.Name = "stComboBox1"; + this.stComboBox1.Size = new System.Drawing.Size(196, 21); + this.stComboBox1.TabIndex = 11; + // + // stLabel1 + // + this.stLabel1.AutoSize = true; + this.stLabel1.Location = new System.Drawing.Point(23, 48); + this.stLabel1.Name = "stLabel1"; + this.stLabel1.Size = new System.Drawing.Size(34, 13); + this.stLabel1.TabIndex = 12; + this.stLabel1.Text = "Type:"; + // + // stButton1 + // + this.stButton1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.stButton1.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.stButton1.Location = new System.Drawing.Point(195, 81); + this.stButton1.Name = "stButton1"; + this.stButton1.Size = new System.Drawing.Size(75, 23); + this.stButton1.TabIndex = 13; + this.stButton1.Text = "Ok"; + this.stButton1.UseVisualStyleBackColor = false; + // + // AddGroupTypeDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(284, 117); + this.Name = "AddGroupTypeDialog"; + this.Text = "Add Group Type"; + this.contentContainer.ResumeLayout(false); + this.contentContainer.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private Toolbox.Library.Forms.STButton stButton1; + private Toolbox.Library.Forms.STLabel stLabel1; + private Toolbox.Library.Forms.STComboBox stComboBox1; + } +} \ No newline at end of file diff --git a/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTypeDialog.cs b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTypeDialog.cs new file mode 100644 index 00000000..b32bb0da --- /dev/null +++ b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTypeDialog.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Toolbox.Library.Forms; + +namespace LayoutBXLYT +{ + public partial class AddGroupTypeDialog : STForm + { + private BxlanPaiEntry ActiveGroup; + + public AddGroupTypeDialog(BxlanPaiEntry animGroup) + { + InitializeComponent(); + CanResize = false; + ActiveGroup = animGroup; + + foreach (var tagDefine in BxlanPaiTag.TypeDefine) + { + if (!animGroup.Tags.Any(x => x.Tag == tagDefine.Key )) + stComboBox1.Items.Add(tagDefine.Value); + } + + stComboBox1.SelectedIndex = 0; + } + + public BxlanPaiTag AddEntry() + { + var tagValue = BxlanPaiTag.TypeDefine.FirstOrDefault(x => x.Value == (string)stComboBox1.SelectedItem).Key; + return ActiveGroup.AddEntry(tagValue); + } + } +} diff --git a/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTypeDialog.resx b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTypeDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/File_Format_Library/GUI/BFLYT/Animations/Basic/AddGroupTypeDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/File_Format_Library/GUI/BFLYT/Animations/LayoutAnimEditorBasic.Designer.cs b/File_Format_Library/GUI/BFLYT/Animations/Basic/LayoutAnimEditorBasic.Designer.cs similarity index 92% rename from File_Format_Library/GUI/BFLYT/Animations/LayoutAnimEditorBasic.Designer.cs rename to File_Format_Library/GUI/BFLYT/Animations/Basic/LayoutAnimEditorBasic.Designer.cs index 681918ad..55a3c3c4 100644 --- a/File_Format_Library/GUI/BFLYT/Animations/LayoutAnimEditorBasic.Designer.cs +++ b/File_Format_Library/GUI/BFLYT/Animations/Basic/LayoutAnimEditorBasic.Designer.cs @@ -62,6 +62,9 @@ this.treeView1.Size = new System.Drawing.Size(266, 450); this.treeView1.TabIndex = 0; this.treeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterSelect); + this.treeView1.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeView1_NodeMouseClick); + this.treeView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeView1_KeyPress); + this.treeView1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.treeView1_MouseClick); // // stPropertyGrid1 // diff --git a/File_Format_Library/GUI/BFLYT/Animations/LayoutAnimEditorBasic.cs b/File_Format_Library/GUI/BFLYT/Animations/Basic/LayoutAnimEditorBasic.cs similarity index 50% rename from File_Format_Library/GUI/BFLYT/Animations/LayoutAnimEditorBasic.cs rename to File_Format_Library/GUI/BFLYT/Animations/Basic/LayoutAnimEditorBasic.cs index f2136ff3..e3508eab 100644 --- a/File_Format_Library/GUI/BFLYT/Animations/LayoutAnimEditorBasic.cs +++ b/File_Format_Library/GUI/BFLYT/Animations/Basic/LayoutAnimEditorBasic.cs @@ -14,6 +14,7 @@ namespace LayoutBXLYT { public partial class LayoutAnimEditorBasic : LayoutDocked { + private BxlytHeader ParentLayout; private BxlanHeader ActiveAnim; public EventHandler OnPropertyChanged; @@ -26,8 +27,9 @@ namespace LayoutBXLYT splitContainer1.BackColor = FormThemes.BaseTheme.FormBackColor; } - public void LoadAnim(BxlanHeader bxlan) + public void LoadAnim(BxlanHeader bxlan, BxlytHeader parentLayout = null) { + ParentLayout = parentLayout; LoadAnimations(bxlan, new TreeNode(bxlan.FileName) { Tag = bxlan }); } @@ -42,7 +44,7 @@ namespace LayoutBXLYT { var header = bxlan as BxlanHeader; var pat1 = new TreeNode("Tag Info") { Tag = header.AnimationTag }; - var pai1 = new TreeNode("Animation Info") { Tag = header.AnimationInfo }; + var pai1 = new AnimInfoWrapper("Animation Info", ParentLayout) { Tag = header.AnimationInfo }; for (int i = 0; i < header.AnimationInfo.Entries.Count; i++) LoadAnimationEntry(header.AnimationInfo.Entries[i], pai1); @@ -54,12 +56,12 @@ namespace LayoutBXLYT private void LoadAnimationEntry(BxlanPaiEntry entry, TreeNode root) { - var nodeEntry = new TreeNode(entry.Name) { Tag = entry }; + var nodeEntry = new GroupAnimWrapper(entry.Name) { Tag = entry }; root.Nodes.Add(nodeEntry); for (int i = 0; i < entry.Tags.Count; i++) { - var nodeTag = new TreeNode(entry.Tags[i].Type) { Tag = entry.Tags[i] }; + var nodeTag = new GroupWrapper(entry.Tags[i].Type) { Tag = entry.Tags[i] }; nodeEntry.Nodes.Add(nodeTag); for (int j = 0; j < entry.Tags[i].Entries.Count; j++) LoadTagEntry(entry.Tags[i].Entries[j], nodeTag, j); @@ -68,12 +70,12 @@ namespace LayoutBXLYT private void LoadTagEntry(BxlanPaiTagEntry entry, TreeNode root, int index) { - var nodeEntry = new TreeNode(entry.TargetName) { Tag = entry }; + var nodeEntry = new GroupTargetWrapper(entry.TargetName) { Tag = entry }; root.Nodes.Add(nodeEntry); for (int i = 0; i < entry.KeyFrames.Count; i++) { - var keyNode = new TreeNode($"Key Frame {i}") { Tag = entry.KeyFrames[i] }; + var keyNode = new KeyNodeWrapper($"Key Frame {i}") { Tag = entry.KeyFrames[i] }; nodeEntry.Nodes.Add(keyNode); } } @@ -94,6 +96,43 @@ namespace LayoutBXLYT ActiveAnim.FileInfo.CanSave = true; } + public class AnimInfoWrapper : TreeNode, IContextMenuNode + { + private BxlytHeader ParentLayout; + public BxlanPAI1 bxlanPai => (BxlanPAI1)Tag; + + public AnimInfoWrapper(string text, BxlytHeader parentLayout) + { + Text = text; + ParentLayout = parentLayout; + } + + public ToolStripItem[] GetContextMenuItems() + { + List Items = new List(); + Items.Add(new ToolStripMenuItem("Add Animation Group", null, AddGroup, Keys.Control | Keys.A)); + Items.Add(new ToolStripMenuItem("Clear Groups", null, ClearGroups, Keys.Control | Keys.C)); + return Items.ToArray(); + } + + private void AddGroup(object sender, EventArgs e) + { + AddAnimGroupDialog dlg = new AddAnimGroupDialog(bxlanPai, ParentLayout); + if (dlg.ShowDialog() == DialogResult.OK) + { + var entry = dlg.AddEntry(); + var nodeEntry = new GroupAnimWrapper(entry.Name) { Tag = entry }; + Nodes.Add(nodeEntry); + } + } + + private void ClearGroups(object sender, EventArgs e) + { + bxlanPai.Entries.Clear(); + Nodes.Clear(); + } + } + public class GroupAnimWrapper : TreeNode, IContextMenuNode { public BxlanPaiEntry PaiEntry => (BxlanPaiEntry)Tag; @@ -112,7 +151,13 @@ namespace LayoutBXLYT private void AddGroup(object sender, EventArgs e) { - + AddGroupTypeDialog dlg = new AddGroupTypeDialog(PaiEntry); + if (dlg.ShowDialog() == DialogResult.OK) + { + var tag = dlg.AddEntry(); + var nodeEntry = new GroupWrapper(tag.Type) { Tag = tag }; + Nodes.Add(nodeEntry); + } } private void ClearGroups(object sender, EventArgs e) @@ -124,6 +169,8 @@ namespace LayoutBXLYT public class GroupWrapper : TreeNode, IContextMenuNode { + public BxlanPaiEntry ParentPaiEntry => (BxlanPaiEntry)Parent.Tag; + public BxlanPaiTag GroupTag => (BxlanPaiTag)Tag; public GroupWrapper(string text) { @@ -140,18 +187,31 @@ namespace LayoutBXLYT private void AddTarget(object sender, EventArgs e) { + AddGroupTargetDialog dlg = new AddGroupTargetDialog(); + bool canLoad = dlg.LoadTag(GroupTag); + if (dlg.ShowDialog() == DialogResult.OK && canLoad) + { + BxlanPaiTagEntry target = dlg.GetGroupTarget(); + target.Index = (byte)GroupTag.Entries.Count; + GroupTag.Entries.Add(target); + var nodeEntry = new GroupTargetWrapper(target.TargetName) { Tag = target }; + Nodes.Add(nodeEntry); + } } private void ClearTargets(object sender, EventArgs e) { - + GroupTag.Entries.Clear(); + Nodes.Clear(); } } public class GroupTargetWrapper : TreeNode, IContextMenuNode { + public BxlanPaiTag GroupTag => (BxlanPaiTag)Parent.Tag; + public BxlanPaiTagEntry TypeTag => (BxlanPaiTagEntry)Tag; public GroupTargetWrapper(string text) { @@ -161,30 +221,55 @@ namespace LayoutBXLYT public ToolStripItem[] GetContextMenuItems() { List Items = new List(); - Items.Add(new ToolStripMenuItem("Add Keyframe", null, AddeKey, Keys.Control | Keys.A)); + Items.Add(new ToolStripMenuItem("Add Keyframe", null, AddKey, Keys.Control | Keys.A)); Items.Add(new ToolStripMenuItem("Remove Target", null, RemoveTarget, Keys.Delete)); Items.Add(new ToolStripMenuItem("Clear Keys", null, RemoveKeys, Keys.Control | Keys.C)); return Items.ToArray(); } - private void AddeKey(object sender, EventArgs e) + private void AddKey(object sender, EventArgs e) { + float frame = 0; + if (TypeTag.KeyFrames.Count > 0) + frame = TypeTag.KeyFrames.Max(k => k.Frame) + 1; + var keyFrame = new KeyFrame(frame); + var keyNode = new KeyNodeWrapper($"Key Frame {TypeTag.KeyFrames.Count}") + { Tag = keyFrame }; + + TypeTag.KeyFrames.Add(keyFrame); + Nodes.Add(keyNode); } private void RemoveKeys(object sender, EventArgs e) { - + TypeTag.KeyFrames.Clear(); + Nodes.Clear(); } private void RemoveTarget(object sender, EventArgs e) { + GroupTag.Entries.Remove(TypeTag); + Parent.Nodes.Remove(this); + } + public void UpdateKeys(TreeNode removedNode) + { + int index = 0; + foreach (TreeNode node in Nodes) + { + if (node == removedNode) + continue; + + node.Text = $"Key Frame {index++}"; + } } } public class KeyNodeWrapper : TreeNode, IContextMenuNode { + public BxlanPaiTagEntry TypeTag => (BxlanPaiTagEntry)Parent.Tag; + public KeyFrame KeyFrame => (KeyFrame)Tag; public KeyNodeWrapper(string text) { @@ -194,13 +279,53 @@ namespace LayoutBXLYT public ToolStripItem[] GetContextMenuItems() { List Items = new List(); - Items.Add(new ToolStripMenuItem("Rename Actor Files (Odyssey)", null, RemoveKey, Keys.Delete)); + Items.Add(new ToolStripMenuItem("Remove Key", null, RemoveKey, Keys.Delete)); return Items.ToArray(); } private void RemoveKey(object sender, EventArgs e) { + TypeTag.KeyFrames.Remove(KeyFrame); + ((GroupTargetWrapper)Parent).UpdateKeys(this); + Parent.Nodes.Remove(this); + } + } + private void treeView1_MouseClick(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + + } + } + + private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) + { + if (e.Button == MouseButtons.Right) { + if (e.Node is IContextMenuNode) + { + STContextMenuStrip contextMenu = new STContextMenuStrip(); + contextMenu.Items.AddRange(((IContextMenuNode)e.Node).GetContextMenuItems()); + contextMenu.Show(Cursor.Position); + } + } + } + + private void treeView1_KeyPress(object sender, KeyEventArgs e) + { + if (treeView1.SelectedNode != null && treeView1.SelectedNode is IContextMenuNode) + { + IContextMenuNode node = (IContextMenuNode)treeView1.SelectedNode; + + var Items = node.GetContextMenuItems(); + foreach (ToolStripItem toolstrip in Items) + { + if (toolstrip is ToolStripMenuItem) + { + if (((ToolStripMenuItem)toolstrip).ShortcutKeys == e.KeyData) + toolstrip.PerformClick(); + } + } } } } diff --git a/File_Format_Library/GUI/BFLYT/Animations/Basic/LayoutAnimEditorBasic.resx b/File_Format_Library/GUI/BFLYT/Animations/Basic/LayoutAnimEditorBasic.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/File_Format_Library/GUI/BFLYT/Animations/Basic/LayoutAnimEditorBasic.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/File_Format_Library/GUI/BFLYT/LayoutEditor.cs b/File_Format_Library/GUI/BFLYT/LayoutEditor.cs index fe5e2a5b..064f4899 100644 --- a/File_Format_Library/GUI/BFLYT/LayoutEditor.cs +++ b/File_Format_Library/GUI/BFLYT/LayoutEditor.cs @@ -51,7 +51,8 @@ namespace LayoutBXLYT { InitializeComponent(); - chkAutoKey.Hide(); + chkAutoKey.Enabled = false; + chkAutoKey.ForeColor = FormThemes.BaseTheme.FormForeColor; CustomMapper = new LayoutCustomPaneMapper(); @@ -415,7 +416,7 @@ namespace LayoutBXLYT public void ShowBxlanEditor(BxlanHeader bxlan) { LayoutAnimEditorBasic editor = new LayoutAnimEditorBasic(); - editor.LoadAnim(bxlan); + editor.LoadAnim(bxlan, ActiveLayout); editor.OnPropertyChanged += AnimPropertyChanged; editor.Show(this); @@ -1122,9 +1123,9 @@ namespace LayoutBXLYT { Runtime.LayoutEditor.AnimationEditMode = editorModeCB.SelectedIndex == 1; if (Runtime.LayoutEditor.AnimationEditMode) - chkAutoKey.Show(); + chkAutoKey.Enabled = true; else - chkAutoKey.Hide(); + chkAutoKey.Enabled = false; if (LayoutPaneEditor != null) LayoutPaneEditor.ReloadEditor(); diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Base/BasePathGroup.cs b/File_Format_Library/GUI/Byaml/CourseMuunt/Base/BasePathGroup.cs deleted file mode 100644 index 8d32b744..00000000 --- a/File_Format_Library/GUI/Byaml/CourseMuunt/Base/BasePathGroup.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -namespace FirstPlugin.Turbo.CourseMuuntStructs -{ - public class BasePathGroup - { - public bool ConnectGroups = true; - - public List PathPoints = new List(); - } -} diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt2D/TrackEditor2D.cs b/File_Format_Library/GUI/Byaml/CourseMuunt2D/TrackEditor2D.cs deleted file mode 100644 index e8267090..00000000 --- a/File_Format_Library/GUI/Byaml/CourseMuunt2D/TrackEditor2D.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Toolbox.Library.Forms; -using Toolbox.Library; -using OpenTK; -using OpenTK.Graphics.OpenGL; - -namespace FirstPlugin.Turbo -{ - public class MuuntEditor2D - { - - } -} diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/Interfaces/IDrawableObject.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/Interfaces/IDrawableObject.cs new file mode 100644 index 00000000..6adb9dc4 --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/Interfaces/IDrawableObject.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK; + +namespace FirstPlugin.MuuntEditor +{ + public interface IDrawableObject + { + void Draw(Matrix4 mvp); + } +} diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/Interfaces/IMuuntLoader.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/Interfaces/IMuuntLoader.cs new file mode 100644 index 00000000..96a715c9 --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/Interfaces/IMuuntLoader.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FirstPlugin.MuuntEditor +{ + public interface IMuuntLoader + { + List Groups { get; set; } + + bool Identify(dynamic byml, string fileName); + void Load(dynamic byml); + } +} diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt2D/MuuntEditorDocker.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/Interfaces/IdrawableContainer.cs similarity index 53% rename from File_Format_Library/GUI/Byaml/CourseMuunt2D/MuuntEditorDocker.cs rename to File_Format_Library/GUI/Byaml/MuuntEditor/Interfaces/IdrawableContainer.cs index 71c9b7af..f40d61d8 100644 --- a/File_Format_Library/GUI/Byaml/CourseMuunt2D/MuuntEditorDocker.cs +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/Interfaces/IdrawableContainer.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using WeifenLuo.WinFormsUI.Docking; -namespace FirstPlugin.Forms +namespace FirstPlugin.MuuntEditor { - public class MuuntEditorDocker : DockContent + public interface IDrawableContainer { + IDrawableObject Drawable { get; } } } diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/MapObject.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/MapObject.cs new file mode 100644 index 00000000..86071e9c --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/MapObject.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.ComponentModel; + +namespace FirstPlugin.MuuntEditor +{ + public class MapObject : PropertyObject + { + public IDrawableObject Drawable { get; set; } + } +} diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt2D/MuuntEditor.Designer.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor.Designer.cs similarity index 94% rename from File_Format_Library/GUI/Byaml/CourseMuunt2D/MuuntEditor.Designer.cs rename to File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor.Designer.cs index 51a88ced..df5c85f5 100644 --- a/File_Format_Library/GUI/Byaml/CourseMuunt2D/MuuntEditor.Designer.cs +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor.Designer.cs @@ -1,4 +1,4 @@ -namespace FirstPlugin.Forms +namespace FirstPlugin.MuuntEditor { partial class MuuntEditor { @@ -31,12 +31,12 @@ this.dockPanel1 = new WeifenLuo.WinFormsUI.Docking.DockPanel(); this.stMenuStrip1 = new Toolbox.Library.Forms.STMenuStrip(); this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toggle3DViewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toggle3DViewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.stToolStrip1 = new Toolbox.Library.Forms.STToolStrip(); this.toolStripButton1 = new System.Windows.Forms.ToolStripButton(); this.stMenuStrip1.SuspendLayout(); @@ -48,9 +48,9 @@ this.dockPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.dockPanel1.Location = new System.Drawing.Point(0, 52); + this.dockPanel1.Location = new System.Drawing.Point(0, 48); this.dockPanel1.Name = "dockPanel1"; - this.dockPanel1.Size = new System.Drawing.Size(471, 363); + this.dockPanel1.Size = new System.Drawing.Size(574, 349); this.dockPanel1.TabIndex = 0; // // stMenuStrip1 @@ -62,7 +62,7 @@ this.viewToolStripMenuItem}); this.stMenuStrip1.Location = new System.Drawing.Point(0, 0); this.stMenuStrip1.Name = "stMenuStrip1"; - this.stMenuStrip1.Size = new System.Drawing.Size(471, 24); + this.stMenuStrip1.Size = new System.Drawing.Size(574, 24); this.stMenuStrip1.TabIndex = 2; this.stMenuStrip1.Text = "stMenuStrip1"; // @@ -76,6 +76,24 @@ this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); this.fileToolStripMenuItem.Text = "File"; // + // openToolStripMenuItem + // + this.openToolStripMenuItem.Name = "openToolStripMenuItem"; + this.openToolStripMenuItem.Size = new System.Drawing.Size(114, 22); + this.openToolStripMenuItem.Text = "Open"; + // + // saveToolStripMenuItem + // + this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; + this.saveToolStripMenuItem.Size = new System.Drawing.Size(114, 22); + this.saveToolStripMenuItem.Text = "Save"; + // + // saveAsToolStripMenuItem + // + this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem"; + this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(114, 22); + this.saveAsToolStripMenuItem.Text = "Save As"; + // // editToolStripMenuItem // this.editToolStripMenuItem.Name = "editToolStripMenuItem"; @@ -93,27 +111,9 @@ // toggle3DViewToolStripMenuItem // this.toggle3DViewToolStripMenuItem.Name = "toggle3DViewToolStripMenuItem"; - this.toggle3DViewToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.toggle3DViewToolStripMenuItem.Size = new System.Drawing.Size(155, 22); this.toggle3DViewToolStripMenuItem.Text = "Toggle 3D View"; // - // openToolStripMenuItem - // - this.openToolStripMenuItem.Name = "openToolStripMenuItem"; - this.openToolStripMenuItem.Size = new System.Drawing.Size(180, 22); - this.openToolStripMenuItem.Text = "Open"; - // - // saveToolStripMenuItem - // - this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; - this.saveToolStripMenuItem.Size = new System.Drawing.Size(180, 22); - this.saveToolStripMenuItem.Text = "Save"; - // - // saveAsToolStripMenuItem - // - this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem"; - this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(180, 22); - this.saveAsToolStripMenuItem.Text = "Save As"; - // // stToolStrip1 // this.stToolStrip1.HighlightSelectedTab = false; @@ -121,7 +121,7 @@ this.toolStripButton1}); this.stToolStrip1.Location = new System.Drawing.Point(0, 24); this.stToolStrip1.Name = "stToolStrip1"; - this.stToolStrip1.Size = new System.Drawing.Size(471, 25); + this.stToolStrip1.Size = new System.Drawing.Size(574, 25); this.stToolStrip1.TabIndex = 3; this.stToolStrip1.Text = "stToolStrip1"; // @@ -138,13 +138,14 @@ // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(471, 412); + this.ClientSize = new System.Drawing.Size(574, 394); this.Controls.Add(this.stToolStrip1); this.Controls.Add(this.dockPanel1); this.Controls.Add(this.stMenuStrip1); + this.IsMdiContainer = true; this.MainMenuStrip = this.stMenuStrip1; this.Name = "MuuntEditor"; - this.Text = "MarioKartMuuntEditor"; + this.Text = "Map Unit Editor"; this.stMenuStrip1.ResumeLayout(false); this.stMenuStrip1.PerformLayout(); this.stToolStrip1.ResumeLayout(false); diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor.cs new file mode 100644 index 00000000..dc8e9352 --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Toolbox.Library.Forms; +using WeifenLuo.WinFormsUI.Docking; +using FirstPlugin; + +namespace FirstPlugin.MuuntEditor +{ + public partial class MuuntEditor : Form + { + public List Groups = new List(); + public EventHandler ObjectSelected; + + private List Plugins = new List(); + + private dynamic ActiveByml; + + private MuuntEditor2D Viewport2D; + private MuuntObjectList ObjectList; + private MuuntPropertiesEditor PropertiesEditor; + + public MuuntEditor() + { + InitializeComponent(); + + ThemeBase theme = new VS2015DarkTheme(); + if (FormThemes.ActivePreset == FormThemes.Preset.White) + theme = new VS2015LightTheme(); + + this.dockPanel1.Theme = theme; + this.dockPanel1.BackColor = FormThemes.BaseTheme.FormBackColor; + this.BackColor = FormThemes.BaseTheme.FormBackColor; + + Plugins.Add(new TrackMuuntLoader()); + + ObjectSelected += OnObjectSelected; + } + + public void LoadByaml(dynamic byml, string fileName) { + ActiveByml = byml; + LoadPlugins(byml, fileName); + + LoadPanels(); + } + + private void LoadPanels() + { + ShowObjectList(); + ShowPropertiesEditor(); + } + + private void LoadPlugins(dynamic byml, string fileName) + { + for (int i = 0; i < Plugins.Count; i++) { + if (Plugins[i].Identify(byml, fileName)) { + Plugins[i].Load(byml); + Groups = Plugins[i].Groups; + } + } + + LoadViewport(); + } + + private void LoadViewport() + { + DockContent dockContent = new DockContent(); + Viewport2D = new MuuntEditor2D(this); + Viewport2D.Dock = DockStyle.Fill; + dockContent.Controls.Add(Viewport2D); + + dockContent.Show(dockPanel1, DockState.Document); + dockContent.DockHandler.AllowEndUserDocking = false; + } + + private void ShowObjectList() + { + if (ObjectList != null) + return; + + ObjectList = new MuuntObjectList(this); + ObjectList.LoadObjects(Groups); + ObjectList.Show(dockPanel1, DockState.DockLeft); + } + + private void ShowPropertiesEditor() + { + if (PropertiesEditor != null) + return; + + PropertiesEditor = new MuuntPropertiesEditor(this); + + if (ObjectList != null) + PropertiesEditor.Show(ObjectList.Pane, DockAlignment.Bottom, 0.5); + PropertiesEditor.Show(dockPanel1, DockState.DockLeft); + } + + private void OnObjectSelected(object sender, EventArgs e) + { + + } + } +} diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt2D/MuuntEditor.resx b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor.resx similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt2D/MuuntEditor.resx rename to File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor.resx diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor2D.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor2D.cs new file mode 100644 index 00000000..ec0c1258 --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditor2D.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.Forms; +using Toolbox.Library; +using OpenTK; +using OpenTK.Graphics.OpenGL; + +namespace FirstPlugin.MuuntEditor +{ + public class MuuntEditor2D : Viewport2D + { + private MuuntEditor ParentEditor; + + public MuuntEditor2D(MuuntEditor editor) + { + ParentEditor = editor; + } + + public override void RenderSceme() + { + foreach (var group in ParentEditor.Groups) + { + if (group is IDrawableContainer) + ((IDrawableContainer)group).Drawable?.Draw(Camera.ModelMatrix); + } + } + + public override List GetPickableObjects() + { + List picks = new List(); + foreach (var group in ParentEditor.Groups) + { + foreach (var obj in group.Objects) + { + if (obj is IPickable2DObject) + picks.Add((IPickable2DObject)obj); + + foreach (var subobj in obj.SubObjects) + { + if (subobj is IPickable2DObject) + picks.Add((IPickable2DObject)subobj); + } + } + } + + return picks; + } + } +} diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditorDocker.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditorDocker.cs new file mode 100644 index 00000000..fe0a7cc0 --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntEditorDocker.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WeifenLuo.WinFormsUI.Docking; +using Toolbox.Library.Forms; + +namespace FirstPlugin.MuuntEditor +{ + public class MuuntEditorDocker : DockContent + { + public MuuntEditorDocker() + { + BackColor = FormThemes.BaseTheme.FormBackColor; + ForeColor = FormThemes.BaseTheme.FormForeColor; + } + } +} diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntObjectList.Designer.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntObjectList.Designer.cs new file mode 100644 index 00000000..3293c4d6 --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntObjectList.Designer.cs @@ -0,0 +1,79 @@ +namespace FirstPlugin.MuuntEditor +{ + partial class MuuntObjectList + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.stComboBox1 = new Toolbox.Library.Forms.STComboBox(); + this.listViewCustom1 = new Toolbox.Library.Forms.ListViewCustom(); + this.SuspendLayout(); + // + // stComboBox1 + // + this.stComboBox1.BorderColor = System.Drawing.Color.Empty; + this.stComboBox1.BorderStyle = System.Windows.Forms.ButtonBorderStyle.Solid; + this.stComboBox1.ButtonColor = System.Drawing.Color.Empty; + this.stComboBox1.FormattingEnabled = true; + this.stComboBox1.IsReadOnly = false; + this.stComboBox1.Location = new System.Drawing.Point(12, 12); + this.stComboBox1.Name = "stComboBox1"; + this.stComboBox1.Size = new System.Drawing.Size(257, 21); + this.stComboBox1.TabIndex = 0; + // + // listViewCustom1 + // + this.listViewCustom1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listViewCustom1.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.listViewCustom1.HideSelection = false; + this.listViewCustom1.Location = new System.Drawing.Point(12, 39); + this.listViewCustom1.Name = "listViewCustom1"; + this.listViewCustom1.OwnerDraw = true; + this.listViewCustom1.Size = new System.Drawing.Size(257, 265); + this.listViewCustom1.TabIndex = 1; + this.listViewCustom1.UseCompatibleStateImageBehavior = false; + // + // MuuntObjectList + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(281, 316); + this.Controls.Add(this.listViewCustom1); + this.Controls.Add(this.stComboBox1); + this.Name = "MuuntObjectList"; + this.Text = "MuuntObjectList"; + this.ResumeLayout(false); + + } + + #endregion + + private Toolbox.Library.Forms.STComboBox stComboBox1; + private Toolbox.Library.Forms.ListViewCustom listViewCustom1; + } +} \ No newline at end of file diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntObjectList.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntObjectList.cs new file mode 100644 index 00000000..20829476 --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntObjectList.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace FirstPlugin.MuuntEditor +{ + public partial class MuuntObjectList : MuuntEditorDocker + { + private MuuntEditor ParentEditor; + + public MuuntObjectList(MuuntEditor editor) + { + InitializeComponent(); + ParentEditor = editor; + } + + public void LoadObjects(List groups) + { + for (int i = 0; i < groups.Count; i++) + { + stComboBox1.Items.Add(groups[i].Name); + } + } + } +} diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntObjectList.resx b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntObjectList.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntObjectList.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntPropertiesEditor.Designer.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntPropertiesEditor.Designer.cs new file mode 100644 index 00000000..e3d90414 --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntPropertiesEditor.Designer.cs @@ -0,0 +1,46 @@ +namespace FirstPlugin.MuuntEditor +{ + partial class MuuntPropertiesEditor + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // MuuntPropertiesEditor + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(395, 314); + this.Name = "MuuntPropertiesEditor"; + this.Text = "Properties Editor"; + this.ResumeLayout(false); + + } + + #endregion + } +} \ No newline at end of file diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt2D/MuuntEditor.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntPropertiesEditor.cs similarity index 55% rename from File_Format_Library/GUI/Byaml/CourseMuunt2D/MuuntEditor.cs rename to File_Format_Library/GUI/Byaml/MuuntEditor/MuuntPropertiesEditor.cs index c8ecf4e1..e6cea57f 100644 --- a/File_Format_Library/GUI/Byaml/CourseMuunt2D/MuuntEditor.cs +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntPropertiesEditor.cs @@ -7,16 +7,17 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; -using Toolbox.Library.Forms; -using WeifenLuo.WinFormsUI.Docking; -namespace FirstPlugin.Forms +namespace FirstPlugin.MuuntEditor { - public partial class MuuntEditor : Form + public partial class MuuntPropertiesEditor : MuuntEditorDocker { - public MuuntEditor() + private MuuntEditor ParentEditor; + + public MuuntPropertiesEditor(MuuntEditor editor) { InitializeComponent(); + ParentEditor = editor; } } } diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntPropertiesEditor.resx b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntPropertiesEditor.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/MuuntPropertiesEditor.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/ObjectGroup.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/ObjectGroup.cs new file mode 100644 index 00000000..1710b03f --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/ObjectGroup.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FirstPlugin.MuuntEditor +{ + public class ObjectGroup + { + public ObjectGroup() { } + + public ObjectGroup(string name) { + Name = name; + } + + public ObjectGroup(string name, PropertyObject property) { + Name = name; + Objects.Add(property); + } + + /// + /// Name of the group. + /// + public string Name { get; set; } + + /// + /// List of properties in the group. + /// + public virtual List Objects { get; } = new List(); + } +} diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/Plugins/MK8/PathDrawableContainer.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/Plugins/MK8/PathDrawableContainer.cs new file mode 100644 index 00000000..899e455c --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/Plugins/MK8/PathDrawableContainer.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FirstPlugin.Turbo.CourseMuuntStructs; + +namespace FirstPlugin.MuuntEditor +{ + public class PathDrawableContainer : ObjectGroup, IDrawableContainer + { + public PathDrawableContainer(string name) { + Name = name; + } + + public List PathGroups + { + get + { + var groups = new List(); + foreach (var group in Objects) + groups.Add((BasePathGroup)group); + return groups; + } + } + + private IDrawableObject drawable; + public IDrawableObject Drawable + { + get + { + if (drawable == null) + drawable = new RenderablePath(PathGroups); + + return drawable; + } + } + } +} diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/Plugins/MK8/TrackMuuntLoader.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/Plugins/MK8/TrackMuuntLoader.cs new file mode 100644 index 00000000..d2b208df --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/Plugins/MK8/TrackMuuntLoader.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FirstPlugin.Turbo.CourseMuuntStructs; +using FirstPlugin.Turbo; + +namespace FirstPlugin.MuuntEditor +{ + public class TrackMuuntLoader : IMuuntLoader + { + public List Groups { get; set; } + + public bool Identify(dynamic byml, string fileName) + { + return fileName.Contains("_muunt"); + } + + public void Load(dynamic byml) + { + var courseMuunt = new CourseMuuntScene(byml); + + Groups = new List(); + Groups.Add(new ObjectGroup("Scene Properties", new PropertyObject() + { + Name = "", + Prop = (Dictionary)byml, + })); + + PathDrawableContainer lapPaths = new PathDrawableContainer("Lap Paths"); + PathDrawableContainer enemyPaths = new PathDrawableContainer("Enemy Paths"); + Groups.Add(lapPaths); + Groups.Add(enemyPaths); + + for (int i = 0; i < courseMuunt.LapPaths.Count; i++) + { + courseMuunt.LapPaths[i].Name = $"Group [{i}]"; + lapPaths.Objects.Add(courseMuunt.LapPaths[i]); + } + + for (int i = 0; i < courseMuunt.EnemyPaths.Count; i++) + { + courseMuunt.EnemyPaths[i].Name = $"Group [{i}]"; + enemyPaths.Objects.Add(courseMuunt.EnemyPaths[i]); + } + + } + } +} diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/PropertyGridConverters.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/PropertyGridConverters.cs new file mode 100644 index 00000000..b2b7babd --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/PropertyGridConverters.cs @@ -0,0 +1,268 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.ComponentModel; +using System.Collections; +using System.Linq; + +namespace FirstPlugin.MuuntEditor +{ + public class PropertyGridTypes + { + public static Dictionary CustomClassConverter = new Dictionary(); + + public static class GetTypeConv + { + public static TypeConverter Get(string _key, dynamic _obj) + { + if (_obj == null) return new NullConverter(); + else if (CustomClassConverter.ContainsKey(_obj.GetType())) + return Activator.CreateInstance(CustomClassConverter[_obj.GetType()]); + else if (_obj is IDictionary) + { + if (_obj.Keys.Count == 3 && _obj.ContainsKey("X") && _obj.ContainsKey("Y") && _obj.ContainsKey("Z")) return new Vector3DDictionaryConverter(); + return new DictionaryConverter(); + } + else if (_obj is IList) return new ArrayNodeConverter(); + else return TypeDescriptor.GetConverter(_obj); + } + } + + public class NullConverter : System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType) + { + return false; + } + + public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + { + return (string)value; + } + + public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + return ""; + } + } + + public class Vector3DDictionaryConverter : System.ComponentModel.TypeConverter + { + public override bool GetPropertiesSupported(ITypeDescriptorContext context) => true; + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + ArrayList properties = new ArrayList(); + foreach (string e in ((Dictionary)value).Keys) + { + properties.Add(new DictionaryConverter.DictionaryPropertyDescriptor((Dictionary)value, e)); + } + + PropertyDescriptor[] props = + (PropertyDescriptor[])properties.ToArray(typeof(PropertyDescriptor)); + + return new PropertyDescriptorCollection(props); + } + + public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType) => sourceType == typeof(string); + + public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + { + string[] tokens = ((string)value).Split(';'); + IDictionary dict = new Dictionary(); + dict["X"] = Single.Parse(tokens[0]); + dict["Y"] = Single.Parse(tokens[1]); + dict["Z"] = Single.Parse(tokens[2]); + return dict; + } + + public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + var v = value as IDictionary; + if (v == null) //MultiMergeCollection workaround + { + var values = new float[3]; + int count = 0; + foreach (object o in (ICollection)value) + values[count++] = ((KeyValuePair)o).Value; + return $"{Math.Round(values[0], 2)}; {Math.Round(values[1], 2)}; {Math.Round(values[2], 2)}"; + } + return $"{Math.Round(v["X"], 2)}; {Math.Round(v["Y"], 2)}; {Math.Round(v["Z"], 2)}"; + } + } + + public class DictionaryConverter : System.ComponentModel.TypeConverter + { + public override bool GetPropertiesSupported(ITypeDescriptorContext context) + { + return true; + } + + public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + return ""; + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + ArrayList properties = new ArrayList(); + foreach (string e in ((Dictionary)value).Keys) + { + properties.Add(new DictionaryPropertyDescriptor((Dictionary)value, e)); + } + + PropertyDescriptor[] props = + (PropertyDescriptor[])properties.ToArray(typeof(PropertyDescriptor)); + + return new PropertyDescriptorCollection(props); + } + + public class DictionaryPropertyDescriptor : PropertyDescriptor //TODO Fix JIS encoding + { + IDictionary _dictionary; + string _key; + + public override TypeConverter Converter + { + get + { + return GetTypeConv.Get(_key, _dictionary[_key]); + } + } + + internal DictionaryPropertyDescriptor(IDictionary d, string key) + : base(key, null) + { + _dictionary = d; + _key = key; + } + + public override Type PropertyType + { + get { return _dictionary[_key] == null ? typeof(string) : _dictionary[_key].GetType(); } + } + + public override void SetValue(object component, object value) + { + _dictionary[_key] = value; + } + + public override object GetValue(object component) + { + return _dictionary[_key]; + } + + public override bool IsReadOnly + { + get { return false; } + } + + public override Type ComponentType + { + get { return null; } + } + + public override bool CanResetValue(object component) + { + return false; + } + + public override void ResetValue(object component) + { + } + + public override bool ShouldSerializeValue(object component) + { + return false; + } + } + } + + public class ArrayNodeConverter : System.ComponentModel.TypeConverter + { + public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + return ""; + } + + public override bool GetPropertiesSupported(ITypeDescriptorContext context) + { + return true; + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + ArrayList properties = new ArrayList(); + for (int i = 0; i < ((List)value).Count; i++) + { + properties.Add(new ArrayPropertyDescriptor(((List)value)[i], "Item " + i.ToString() + " :")); + } + + PropertyDescriptor[] props = + (PropertyDescriptor[])properties.ToArray(typeof(PropertyDescriptor)); + + return new PropertyDescriptorCollection(props); + } + + public class ArrayPropertyDescriptor : PropertyDescriptor //TODO Fix JIS encoding + { + dynamic _obj; + string _key; + + public override TypeConverter Converter + { + get + { + return GetTypeConv.Get(_key, _obj); + } + } + + internal ArrayPropertyDescriptor(dynamic obj, string key) + : base(key, null) + { + _obj = obj; + _key = key; + } + + public override Type PropertyType + { + get { return _obj == null ? typeof(string) : _obj.GetType(); } + } + + public override void SetValue(object component, object value) + { + _obj = value; + } + + public override object GetValue(object component) + { + return _obj; + } + + public override bool IsReadOnly + { + get { return false; } + } + + public override Type ComponentType + { + get { return null; } + } + + public override bool CanResetValue(object component) + { + return false; + } + + public override void ResetValue(object component) + { + } + + public override bool ShouldSerializeValue(object component) + { + return false; + } + } + } + } +} diff --git a/File_Format_Library/GUI/Byaml/MuuntEditor/PropertyObject.cs b/File_Format_Library/GUI/Byaml/MuuntEditor/PropertyObject.cs new file mode 100644 index 00000000..df3f245f --- /dev/null +++ b/File_Format_Library/GUI/Byaml/MuuntEditor/PropertyObject.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.ComponentModel; + +namespace FirstPlugin.MuuntEditor +{ + public class PropertyObject + { + /// + /// Child properties to be added to the tree. + /// + public virtual List SubObjects { get; } = new List(); + + /// + /// The name of the property + /// + public string Name { get; set; } + + [TypeConverter(typeof(PropertyGridTypes.DictionaryConverter))] + public Dictionary Prop { get; set; } + } +} diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Base/BaseControlPoint.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/BaseControlPoint.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Base/BaseControlPoint.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/BaseControlPoint.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Base/BaseObjPt.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/BaseObjPt.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Base/BaseObjPt.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/BaseObjPt.cs diff --git a/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/BasePathGroup.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/BasePathGroup.cs new file mode 100644 index 00000000..5ddb1167 --- /dev/null +++ b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/BasePathGroup.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using FirstPlugin.MuuntEditor; + +namespace FirstPlugin.Turbo.CourseMuuntStructs +{ + public class BasePathGroup : PropertyObject + { + public bool ConnectGroups = true; + + public List PathPoints = new List(); + + public override List SubObjects + { + get { + var props = new List(); + foreach (var path in PathPoints) + props.Add(path); + return props; + } + } + } +} diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Base/BasePathPoint.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/BasePathPoint.cs similarity index 76% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Base/BasePathPoint.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/BasePathPoint.cs index 4c73d64b..0272e9d7 100644 --- a/File_Format_Library/GUI/Byaml/CourseMuunt/Base/BasePathPoint.cs +++ b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/BasePathPoint.cs @@ -3,10 +3,12 @@ using System.Collections.Generic; using System.ComponentModel; using OpenTK; using GL_EditorFramework.EditorDrawables; +using FirstPlugin.MuuntEditor; +using Toolbox.Library; namespace FirstPlugin.Turbo.CourseMuuntStructs { - public class BasePathPoint : IObject + public class BasePathPoint : PropertyObject, IObject, IPickable2DObject { public Action OnPathMoved; @@ -20,15 +22,51 @@ namespace FirstPlugin.Turbo.CourseMuuntStructs } } + public bool IsSelected { get; set; } + public bool IsHovered { get; set; } + + public bool IsHit(float X, float Y) + { + return new STRectangle(Translate.X, Translate.Z, 40, 40).IsHit((int)X, (int)Y); + + for (int i = 0; i <= 300; i++) + { + double angle = 2 * Math.PI * i / 300; + double x = Math.Cos(angle); + double y = Math.Sin(angle); + + if (angle < 90) + { + + } + if (angle < 90 && angle < 180) + { + + } + if (angle < 270) + { + + } + if (angle < 360) + { + + } + } + + return false; + } + + public void PickTranslate(float X, float Y, float Z) + { + Translate = new Vector3(X, Y, Z); + } + public const string N_Translate = "Translate"; public const string N_Rotate = "Rotate"; public const string N_Scale = "Scale"; public const string N_Id = "UnitIdNum"; public const string N_ObjectID = "ObjId"; - [Browsable(false)] - public Dictionary Prop { get; set; } = new Dictionary(); - public dynamic this[string name] { get diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Base/PointID.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/PointID.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Base/PointID.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/PointID.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Base/RenderableConnectedMapPoints.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/RenderableConnectedMapPoints.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Base/RenderableConnectedMapPoints.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/RenderableConnectedMapPoints.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Base/RenderablePathPoint.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/RenderablePathPoint.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Base/RenderablePathPoint.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Base/RenderablePathPoint.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/CourseMuuntStructs.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/CourseMuuntStructs.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/CourseMuuntStructs.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/CourseMuuntStructs.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/IObject.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/IObject.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/IObject.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/IObject.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/IntroCamera.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/IntroCamera.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/IntroCamera.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/IntroCamera.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/EnemyPaths.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/EnemyPaths.cs similarity index 95% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Paths/EnemyPaths.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/EnemyPaths.cs index a5f8cc97..7fcc2f80 100644 --- a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/EnemyPaths.cs +++ b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/EnemyPaths.cs @@ -27,9 +27,6 @@ namespace FirstPlugin.Turbo.CourseMuuntStructs } } - [Browsable(false)] - public Dictionary Prop { get; set; } = new Dictionary(); - public int EnemyPathGroupId { get { return this[N_EnemyPathGroup] != null ? this[N_EnemyPathGroup] : -1; } diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/GliderPaths.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/GliderPaths.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Paths/GliderPaths.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/GliderPaths.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/GravityPaths.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/GravityPaths.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Paths/GravityPaths.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/GravityPaths.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/ItemPaths.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/ItemPaths.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Paths/ItemPaths.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/ItemPaths.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/JugemPath.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/JugemPath.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Paths/JugemPath.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/JugemPath.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/LapPaths.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/LapPaths.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Paths/LapPaths.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/LapPaths.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/ObjPath.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/ObjPath.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Paths/ObjPath.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/ObjPath.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/Paths.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/Paths.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Paths/Paths.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/Paths.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/PullPath.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/PullPath.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Paths/PullPath.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/PullPath.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/RenderableConnectedPaths.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/RenderableConnectedPaths.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Paths/RenderableConnectedPaths.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/RenderableConnectedPaths.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/ReturnPoint.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/ReturnPoint.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Paths/ReturnPoint.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/ReturnPoint.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Paths/SteerAssistPath.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/SteerAssistPath.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Paths/SteerAssistPath.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Paths/SteerAssistPath.cs diff --git a/File_Format_Library/GUI/Byaml/TurboCourseMuunt/RenderablePath.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/RenderablePath.cs new file mode 100644 index 00000000..efdfe77c --- /dev/null +++ b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/RenderablePath.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using OpenTK; +using OpenTK.Graphics.OpenGL; +using FirstPlugin.Turbo.CourseMuuntStructs; +using Toolbox.Library; + +namespace FirstPlugin.MuuntEditor +{ + /// + /// Represets a path with multiple grouped points that connect to each other + /// + public class RenderablePath : IDrawableObject + { + public Color LineColor = Color.Green; + + public List PathGroups = new List(); + + public RenderablePath(List pathGroups) + { + PathGroups = pathGroups; + } + + public void Draw(Matrix4 mvp) + { + for (int i = 0; i < PathGroups.Count; i++) + { + foreach (var path in PathGroups[i].PathPoints) + { + var translate = new Vector3(path.Translate.X, path.Translate.Z, path.Translate.Y); + + if (path.IsSelected) + Render2D.DrawFilledCircle(new Vector2(translate.X, translate.Y), Color.Green, 30, 40, true); + else if (path.IsHovered) + Render2D.DrawFilledCircle(new Vector2(translate.X, translate.Y), Color.Yellow, 40, 40, true); + else + Render2D.DrawFilledCircle(new Vector2(translate.X, translate.Y), Color.Red, 30, 40, true); + + GL.LineWidth(2f); + foreach (var nextPt in path.NextPoints) + { + var nextTranslate = PathGroups[nextPt.PathID].PathPoints[nextPt.PtID].Translate; + + GL.Color3(LineColor); + GL.Begin(PrimitiveType.Lines); + GL.Vertex3(translate); + GL.Vertex3(nextTranslate.X, nextTranslate.Z, nextTranslate.Y); + GL.End(); + } + foreach (var prevPt in path.PrevPoints) + { + var prevTranslate = PathGroups[prevPt.PathID].PathPoints[prevPt.PtID].Translate; + + GL.Color3(LineColor); + GL.Begin(PrimitiveType.Lines); + GL.Vertex3(translate); + GL.Vertex3(prevTranslate.X, prevTranslate.Z, prevTranslate.Y); + GL.End(); + } + } + } + } + } +} diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/TurboMunntEditor.Designer.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/TurboMunntEditor.Designer.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/TurboMunntEditor.Designer.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/TurboMunntEditor.Designer.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/TurboMunntEditor.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/TurboMunntEditor.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/TurboMunntEditor.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/TurboMunntEditor.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/TurboMunntEditor.resx b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/TurboMunntEditor.resx similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/TurboMunntEditor.resx rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/TurboMunntEditor.resx diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Wrappers/PathCollectionNode.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Wrappers/PathCollectionNode.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Wrappers/PathCollectionNode.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Wrappers/PathCollectionNode.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Wrappers/PathGroupNode.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Wrappers/PathGroupNode.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Wrappers/PathGroupNode.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Wrappers/PathGroupNode.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Wrappers/PathPointNode.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Wrappers/PathPointNode.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Wrappers/PathPointNode.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Wrappers/PathPointNode.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Wrappers/ProbeLightingEntryWrapper.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Wrappers/ProbeLightingEntryWrapper.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Wrappers/ProbeLightingEntryWrapper.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Wrappers/ProbeLightingEntryWrapper.cs diff --git a/File_Format_Library/GUI/Byaml/CourseMuunt/Wrappers/ProbeLightingWrapper.cs b/File_Format_Library/GUI/Byaml/TurboCourseMuunt/Wrappers/ProbeLightingWrapper.cs similarity index 100% rename from File_Format_Library/GUI/Byaml/CourseMuunt/Wrappers/ProbeLightingWrapper.cs rename to File_Format_Library/GUI/Byaml/TurboCourseMuunt/Wrappers/ProbeLightingWrapper.cs diff --git a/Switch_Toolbox_Library/Forms/Custom/BarSlider/BarSlider.cs b/Switch_Toolbox_Library/Forms/Custom/BarSlider/BarSlider.cs index 90754139..40872c7e 100644 --- a/Switch_Toolbox_Library/Forms/Custom/BarSlider/BarSlider.cs +++ b/Switch_Toolbox_Library/Forms/Custom/BarSlider/BarSlider.cs @@ -1752,8 +1752,8 @@ namespace BarSlider if (TextEditorActive) return; - if (prevPos.X != 0 && prevPos.Y != 0) - Cursor.Position = prevPos; + // if (prevPos.X != 0 && prevPos.Y != 0) + // Cursor.Position = prevPos; // Cursor.Show(); base.OnKeyUp(e); diff --git a/Switch_Toolbox_Library/Forms/Custom/STComboBox.cs b/Switch_Toolbox_Library/Forms/Custom/STComboBox.cs index 7a133c8b..f8c6e9cf 100644 --- a/Switch_Toolbox_Library/Forms/Custom/STComboBox.cs +++ b/Switch_Toolbox_Library/Forms/Custom/STComboBox.cs @@ -57,6 +57,12 @@ namespace Toolbox.Library.Forms InitializeComponent(); } + public void LoadEnum(Type type) + { + DataBindings.Clear(); + DataSource = Enum.GetValues(type); + } + private bool IsTextReadOnly = true; public void SetAsReadOnly() diff --git a/Switch_Toolbox_Library/Forms/Editors/UV/UVEditorForm.cs b/Switch_Toolbox_Library/Forms/Editors/UV/UVEditorForm.cs index 53566029..5f120746 100644 --- a/Switch_Toolbox_Library/Forms/Editors/UV/UVEditorForm.cs +++ b/Switch_Toolbox_Library/Forms/Editors/UV/UVEditorForm.cs @@ -19,6 +19,8 @@ namespace Toolbox.Library.Forms public void LoadEditor(List Drawables) { + if (Drawables == null) return; + uvEditor1.Materials.Clear(); uvEditor1.Textures.Clear(); uvEditor1.Objects.Clear(); diff --git a/Switch_Toolbox_Library/OpenGL/IPickableObject.cs b/Switch_Toolbox_Library/OpenGL/IPickableObject.cs new file mode 100644 index 00000000..fde81b17 --- /dev/null +++ b/Switch_Toolbox_Library/OpenGL/IPickableObject.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Toolbox.Library +{ + public interface IPickable2DObject + { + bool IsHit(float X, float Y); + bool IsSelected { get; set; } + bool IsHovered { get; set; } + void PickTranslate(float X, float Y, float Z); + } +} diff --git a/Switch_Toolbox_Library/OpenGL/OpenGLHelper.cs b/Switch_Toolbox_Library/OpenGL/OpenGLHelper.cs index 9ab0dc71..d8bff0fd 100644 --- a/Switch_Toolbox_Library/OpenGL/OpenGLHelper.cs +++ b/Switch_Toolbox_Library/OpenGL/OpenGLHelper.cs @@ -11,7 +11,7 @@ namespace Toolbox.Library { public class OpenGLHelper { - public static Point convertScreenToWorldCoords(int x, int y) + public static Point convertScreenToWorldCoords(int x, int y, bool isTopDown = false) { int[] viewport = new int[4]; Matrix4 modelViewMatrix, projectionMatrix; @@ -21,11 +21,13 @@ namespace Toolbox.Library Vector2 mouse; mouse.X = x; mouse.Y = y; - Vector4 vector = UnProject(ref projectionMatrix, modelViewMatrix, new Size(viewport[2], viewport[3]), mouse); + Vector4 vector = UnProject(ref projectionMatrix, modelViewMatrix, new Size(viewport[2], viewport[3]), mouse, isTopDown); Point coords = new Point((int)vector.X, (int)vector.Y); + return coords; } - public static Vector4 UnProject(ref Matrix4 projection, Matrix4 view, Size viewport, Vector2 mouse) + + public static Vector4 UnProject(ref Matrix4 projection, Matrix4 view, Size viewport, Vector2 mouse, bool isTopDown) { Vector4 vec; @@ -34,6 +36,12 @@ namespace Toolbox.Library vec.Z = 0; vec.W = 1.0f; + if (isTopDown) + { + vec.Y = 0; + vec.Z = -(2.0f * mouse.Y / (float)viewport.Height - 1); + } + Matrix4 viewInv = Matrix4.Invert(view); Matrix4 projInv = Matrix4.Invert(projection); diff --git a/Switch_Toolbox_Library/OpenGL/Render2D.cs b/Switch_Toolbox_Library/OpenGL/Render2D.cs index 0a49a091..f86aebab 100644 --- a/Switch_Toolbox_Library/OpenGL/Render2D.cs +++ b/Switch_Toolbox_Library/OpenGL/Render2D.cs @@ -27,11 +27,34 @@ namespace Toolbox.Library GL.PopMatrix(); } - public static void DrawCircle(Vector2 Position, Color color) + public static void DrawFilledCircle(Vector2 Position, Color color, float radius = 300, byte transparency = 255, bool outline = false) { GL.PushMatrix(); GL.Translate(Position.X, Position.Y, 0); - GL.Scale(300,300,1); + GL.Scale(radius, radius, 1); + + GL.Color4(color.R, color.G, color.B, transparency); + GL.Begin(PrimitiveType.TriangleFan); + for (int i = 0; i <= 300; i++) + { + double angle = 2 * Math.PI * i / 300; + double x = Math.Cos(angle); + double y = Math.Sin(angle); + GL.Vertex2(x, y); + } + GL.End(); + + GL.PopMatrix(); + + if (outline) + DrawCircle(Position, color.Darken(20), radius); + } + + public static void DrawCircle(Vector2 Position, Color color, float radius = 300) + { + GL.PushMatrix(); + GL.Translate(Position.X, Position.Y, 0); + GL.Scale(radius, radius, 1); GL.Color4(color); GL.Begin(PrimitiveType.LineLoop); diff --git a/Switch_Toolbox_Library/OpenGL/STRectangle.cs b/Switch_Toolbox_Library/OpenGL/STRectangle.cs new file mode 100644 index 00000000..72e19c42 --- /dev/null +++ b/Switch_Toolbox_Library/OpenGL/STRectangle.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Toolbox.Library +{ + public class STRectangle + { + public int LeftPoint; + public int RightPoint; + public int TopPoint; + public int BottomPoint; + + public STRectangle(float posX, float posY, float width, float height) + { + LeftPoint = (int)(posX - (width / 2)); + RightPoint = (int)(posX + (width / 2)); + TopPoint = (int)(posY + (height / 2)); + BottomPoint = (int)(posY - (height / 2)); + } + + public STRectangle(int left, int right, int top, int bottom) + { + LeftPoint = left; + RightPoint = right; + TopPoint = top; + BottomPoint = bottom; + } + + public bool IsHit(int X, int Y) + { + bool isInBetweenX = (X > LeftPoint) && (X < RightPoint) || + (X < LeftPoint) && (X > RightPoint); + + bool isInBetweenY = (Y > BottomPoint) && (Y < TopPoint) || + (Y < BottomPoint) && (Y > TopPoint); + + if (isInBetweenX && isInBetweenY) + return true; + else + return false; + } + } +} diff --git a/Switch_Toolbox_Library/OpenGL/Viewport2D.cs b/Switch_Toolbox_Library/OpenGL/Viewport2D.cs index a9b7fa3c..3761b8e4 100644 --- a/Switch_Toolbox_Library/OpenGL/Viewport2D.cs +++ b/Switch_Toolbox_Library/OpenGL/Viewport2D.cs @@ -15,7 +15,7 @@ namespace Toolbox.Library.Forms { public class Viewport2D : UserControl { - public virtual bool UseOrtho { get; set; } = false; + public virtual bool UseOrtho { get; set; } = true; public virtual bool UseGrid { get; set; } = true; public Camera2D Camera = new Camera2D(); @@ -40,6 +40,8 @@ namespace Toolbox.Library.Forms private GLControl glControl1; private Color BackgroundColor = Color.FromArgb(40, 40, 40); + private List SelectedObjects = new List(); + public Viewport2D() { glControl1 = new GLControl(); @@ -109,6 +111,22 @@ namespace Toolbox.Library.Forms } } + public virtual List GetPickableObjects() + { + return new List(); + } + + private List SearchHit(float X, float Y) + { + List picks = new List(); + foreach (var pickObj in GetPickableObjects()) + { + if (pickObj.IsHit(X, Y)) + picks.Add(pickObj); + } + return picks; + } + private void SetupScene() { GL.Enable(EnableCap.Blend); @@ -125,6 +143,17 @@ namespace Toolbox.Library.Forms RenderSceme(); + if (showSelectionBox) + { + GL.Begin(PrimitiveType.LineLoop); + GL.Color4(Color.Red); + GL.Vertex2(SelectionBox.LeftPoint, SelectionBox.BottomPoint); + GL.Vertex2(SelectionBox.RightPoint, SelectionBox.BottomPoint); + GL.Vertex2(SelectionBox.RightPoint, SelectionBox.TopPoint); + GL.Vertex2(SelectionBox.LeftPoint, SelectionBox.TopPoint); + GL.End(); + } + if (UseOrtho) GL.PopMatrix(); @@ -132,13 +161,54 @@ namespace Toolbox.Library.Forms glControl1.SwapBuffers(); } + private STRectangle SelectionBox; + + private bool showSelectionBox = false; + + private void DrawSelectionBox(Point point1, Point point2) + { + SelectedObjects.Clear(); + + int left = point1.X; + int right = point2.X; + int top = point1.Y; + int bottom = point2.Y; + //Determine each point direction to see what is left/right/top/bottom + if (bottom > top) + { + top = point2.Y; + bottom = point1.Y; + } + if (left > right) + { + right = point1.X; + left = point2.X; + } + + showSelectionBox = true; + SelectionBox = new STRectangle(left, right, top, bottom); + + SetupScene(); + } + public virtual void RenderSceme() { } + private Point pickOriginMouse; private Point originMouse; private bool mouseCameraDown; + private bool isPicked; + private bool mouseDown = false; + + private Vector2 GetMouseCoords(Point screenMouse) + { + RenderEditor(); + var coords = OpenGLHelper.convertScreenToWorldCoords(screenMouse.X, screenMouse.Y); + GL.PopMatrix(); + return new Vector2(coords.X, coords.Y); + } private void glControl1_MouseDown(object sender, MouseEventArgs e) { @@ -149,6 +219,33 @@ namespace Toolbox.Library.Forms mouseCameraDown = true; glControl1.Invalidate(); } + else if (e.Button == MouseButtons.Left) + { + mouseDown = true; + + var mouseCoords = GetMouseCoords(e.Location); + + var picks = SearchHit(mouseCoords.X, mouseCoords.Y); + if (picks.Count > 0) + { + if (!SelectedObjects.Contains(picks[0])) + { + if (Control.ModifierKeys != Keys.Control) + UnselectAll(); + + SelectedObjects.Add(picks[0]); + + picks[0].IsSelected = true; + } + + isPicked = true; + } + else if (Control.ModifierKeys != Keys.Control) + UnselectAll(); + + pickOriginMouse = e.Location; + glControl1.Invalidate(); + } } private void glControl1_MouseUp(object sender, MouseEventArgs e) @@ -156,21 +253,64 @@ namespace Toolbox.Library.Forms if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Middle) { mouseCameraDown = false; + mouseDown = false; + isPicked = false; + showSelectionBox = false; + + glControl1.Invalidate(); } } + private void UnselectAll() + { + foreach (var pick in SelectedObjects) + pick.IsSelected = false; + + SelectedObjects.Clear(); + } + private void glControl1_MouseMove(object sender, MouseEventArgs e) { + var mouseCoords = GetMouseCoords(e.Location); + var picks = SearchHit(mouseCoords.X, mouseCoords.Y); + + if (picks.Count > 0) + { + if (!picks[0].IsSelected) + { + picks[0].IsHovered = true; + + glControl1.Invalidate(); + } + } + else + { + foreach (var obj in GetPickableObjects()) + obj.IsHovered = false; + + glControl1.Invalidate(); + } + if (mouseCameraDown) { var pos = new Vector2(e.Location.X - originMouse.X, e.Location.Y - originMouse.Y); Camera.Position.X += pos.X; - Camera.Position.Y += pos.Y; + Camera.Position.Y -= pos.Y; originMouse = e.Location; glControl1.Invalidate(); } + + if (mouseDown && !isPicked) + { + RenderEditor(); + var temp = e.Location; + var curPos = OpenGLHelper.convertScreenToWorldCoords(temp.X, temp.Y); + var prevPos = OpenGLHelper.convertScreenToWorldCoords(pickOriginMouse.X, pickOriginMouse.Y); + + DrawSelectionBox(prevPos, curPos); + } } private void glControl1_Resize(object sender, EventArgs e) diff --git a/Switch_Toolbox_Library/Toolbox_Library.csproj b/Switch_Toolbox_Library/Toolbox_Library.csproj index bce4ef82..89e16094 100644 --- a/Switch_Toolbox_Library/Toolbox_Library.csproj +++ b/Switch_Toolbox_Library/Toolbox_Library.csproj @@ -393,7 +393,9 @@ + + UserControl diff --git a/Toolbox/Gl_EditorFramework.dll b/Toolbox/Gl_EditorFramework.dll index 23740d72582aaa6d696eb8ed03ed79104a24f8ca..61e205a453c56536886f1aaf6684627764343f66 100644 GIT binary patch delta 6570 zcmajk3tW^{-Usmi|D2g&K-2+c=9vK%QIYThArdL3C|+7k*mV(j5Q1riw`bhT|LiYXH4?spgVHK zS_bqrM0_(a!wW+ZCOZ*Oz6ww~kwN+6R4ck7m2Dru-wLo)JRCR>=@-w#f%7Up9^9L| z+Oo_)0hppityZyScv1WmzXt*1o;E|Dr+DK35x+Y$4WYts*f}dc>-l!%0nfHk8!A#q zr`p(QvuFLJX_)Q_N{hyIo}{!a&*8Lgp~(mV3!f3KvCNrtv`^0gumH2qO7^szJix=! zV>~)07e%;Mt$n^FP$@=5f6;QPg$6vH(jxPh~hgF;kxw z{kD&45$U5uIll;CQ7JSF(R5;i#EJ3WPAtG8POPWr>ik2Vss)?nNgZPq zajy@I5tDy&=M7KV&d%buWjkNM0TnlQ+EJowMUV38Fe*{EN*tFSdrlm$92+E#F`w0n z&J_B9RKK$;Wka71)Fc}9g$}_4l}hAVH(_oXzhm)o}%NdxcWc{0HJKAZfbFDq|)&u0Xm}5uCTZ z=C}$&W>8iHo5RLAzJoHYW8F7fzK0qi(SHt9+7>x(K&rSai1!etv@yfKz<5n5!x93w zV6#>WafiDNbyB$iQjgB2l3onAQx-3k3*SeQ66a8s3-_9lcF$L;=cMHegxuf-bP)Fv zMfWXb#hY5!I#Cv%sWOn+Y^@VAtC7lq^thgm+Yp;YC39f3&>h$-RRg=j$C`eG+J%(W zz=PIfO+Uf%*GcXg*yx(kVNCDg#d_G3*y!!U7cq@pW2ZQ{Q`iPjITH}PNLy4L0J z#eVmoaFHr`wEbeg`w;tQQofPZ*$fXLsYwVAVVIP9vmZjHl-F&Y)WYfj%vH3`YtdY& zRtabcA&U7EUtXXk#4tsRmJr8msTy$fcp5oQenXX{x59+S-z2HQnDFZ+A(-*HR1LUk z>6tNfnJj9piFm_d!H!y|B9;l|OL^r${jgAr2I_|=l;l9IXe(6R(?I=koE8l<0M|*W z#T|eh6Zn40lVavuK86id8do7J;~Zr7S9@lyp}KKEX$Y=B!f9R0y@iLalQh z%n*$Cr7mH85JD@2)xK6%I9g%25~K&aS35$mpJr0X7Dp&Xtx=8U1#NMJVLv6&eYv9z zmN%)&5stBIeT~*SI%2gFggCc2BC%neYGrf87mm(Y@~+ZKp+_)&z0%iCbVC;`)U-#O zc67n04Js^q?5ZOMr)kk(9>rWGYh~yyM;z{z%7G(Y%+LcnmQlSNcqG~k@mMI850AIL z<>-m^T8YsJ2^jmH>S2VCI{^zd{~CAKk$`8l!q@{xBHA{pqCw1R^u`peeP}cKV20Kh zbQpbcyVm%ac1AKbYL&!wG6rDKCfSOZ!!E`^9NZ)u40hu)zvB>0`<>j=`_s66yRZ8^%Sg2DP#Lu{3cJkM zsd%jY8v8Stt3{1Ii?&@VqejPK*WzbVaiI9ITKsVL`M}p`uzeN|SF#?qrWvzwv{bJ3 zxOJ+~1fB8t%PANHTjs+4wmlu$SgXS){gxRyXzYg62 z9?UpEp%>_FT7fACmFT@MLDS!r4z*umFU8bDO7!-w!WvP9>J@i7WM6|b4lCVieaOBJ zZ)zn!{;7RECe~7x58c`$Y`_8`asK(>l5EgnyY>f-4Y>UX70s2mt1`5GN-8oIbq2pO z%#rd!FaIDc!^KUiHOjC^if+~omiMqmXAuds2dXw;kvF0!M0f@lSJ}z}J;JL1eGl&Mz@vhjAS;oej85 zN=^4^+*MzkJrc8QAF47)lX)4d>x%-k4xZ7XF7M$vt(f>fJ0D=977YN| z1ug2|#4c%3|7LczzOrN#nwY!uKj;kdt+|1vFr39|6$j>7hO@a!;++nG5p1&(h-=50 z%0AK(*N*dPc0#L*Kf*{h&TO0?)on!v1Is*J9kmso}tT{{!m6)n2TCb2OMs$}o5 z%P^TGotAe8bzupfQ6XJeudwj1w8ZTxrf8X4P7~{A-OIw*42C(ZXKD*8QqP3pZ_ z%UC}xT3AJ_PK&OAv0vkNPmH# zy92G(wd}5Ve56|kt=9EyIa8w5x`CBT>6;TXi-&UB8ODcx;4EW-QbpFep_M|db=FB_ z@3BywC5!Am)=_1U6!MXCBO7O?R@`q39&&DCB^KGJxK$l-Zf1#oKAmyyVC%%H79B$C z#P6IRFeAXHpPhSHmXsRWKGsisdZ4HAI`OQ!k7Y^GDnY1X7j#C?=2eV7XNZz+`HWx9 zq61Y$dc^;TO_9on^|5}gkJ&0E+01@+s!7dV`x!K+dinCAtYL$cWJxc3PRfgyyBaPp zdqJ1H+_jzSFk7iJ_W}_fVe53bK!l&NuXK2~M|W2pYt-4@9z9*hSZE9C(2KSfhU;?{ zE|m|q7VTX1Y^=@(cRh+b{ZP6i*7Y z)-HE-8?JAd%}}K7&$B3(Pdn@vSV))>&BaC5L5pVXTNW>+26Ks(>5RI+#?r-(OI=Wh z-?4fvdMmCoQ-rUFO>X=5Y)nTVci8`%y(B(4`ZnSlEL+MeCfIP@U~g(s_cz%pDe8W_ z>j!p1XVm>|wnQvBb%uuP4m+Slt^CNAM5&BgasR~nJwl{r(p-00p_Ern;;-zAc<}Z$ zbC2EAqI0^>a=WOEX6*qpb@yq9{UI9{`&&KWrBc*`_^Tt|pfj3Lbn~sh3mLD_A&r#r zeZR{%uhAJzBIg&is2LM){iy1Y>X~_p)_$?NEPSw(>fXX<{Vx^2`8>98XEnWc(D36O z@xNuw_!9A_Ltni>J}1GKWxAU4)lDjK1@k&3 zan)wJTJdde@wroVQRXsuwUp|@#ovA0mzBFhd5x6H+VQi!eAzx%IKL^SvIu@8$(MOu z9r#75OXx6Fhjikj`cQTWUlzlUEsm{K^63YYo z$%-Pp>UxydOQ~`9;Mx7vKxy3Z{0l7_c09kRMZ=EgZw*i-Y1r|6g_PQ#rRYiJs7|F|;w8K7%Z_=V2 zc{JbJq$>LuUam#^`g8oi5Y-Cp>*ILhA4uX6nVvZ&@N7x7BTwL4rD&q=yI$gdZ<1f= z%lv$k+JsKwY$!EDC3}QU<*l0ZMCf$hu}MQhXY!s+N)4UG2PsvCyo3wGf|42iG3rTn zqxo?^I@VQgcpblK(WP4a1LH8%iDNCC6~`lRT^v7!d*XN$0@pF9gD`PC23;$6Eyb5t z*;0y2+O7E{s{ebBz0QJFJiFMH!y;_E z{(5IP8#f^No$AxeKl>omRXi+*tqxu+y6}B%px?ub+S}QRwUw~@u WasNUFfuiKzzLh}*>;@La`uz{NUqST% delta 6705 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 E0~UY{z5oCK delta 22453 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 C7ZKC| diff --git a/Toolbox/Lib/Syroot.NintenTools.NSW.Bfres.dll b/Toolbox/Lib/Syroot.NintenTools.NSW.Bfres.dll index dd7a71628c88294d862d8a6e3d87a5784b1f279b..78e1fe6f44d7c066e4002255144412bf580f5ea8 100644 GIT binary patch delta 116 zcmZpe!`m>2cR~k?!T!8`jXkYBj9Yt{9{d-$c!_yJkJcy0)p5PsSWBFyY^`Bl;>403 zx%c*T6=&uEfzwZ&i%*nlyHC2cR~lt?2q5BH1@RiFmCN(dhlOBq3=feBw0(L;-I KyQd5Dc1{3_2sJDK diff --git a/Toolbox/Lib/Syroot.NintenTools.NSW.Bfres.pdb b/Toolbox/Lib/Syroot.NintenTools.NSW.Bfres.pdb index 63e8bf10498d367228f8a08098f2239656366a79..9e77bfc0d4812466c359ced5838e0298d8935648 100644 GIT binary patch delta 161 zcmZ28opsH0)(JHtr=L0(pD5LKpQN+APm1q$e0t>G+l>>pPGH=lBJ%Xk)lA*wYo9+j zxvezk5V`v4h^@i)1XadGvWz^_nVlIAi9F0XV7%v-x0SkvHg9y|FX$A%c MhtA~bao&u60CXQRxBvhE delta 161 zcmZ28opsH0)(JHten0-aSNJRHzeuMfj%T9Mq`eaBFEvisI)QPIiipL;$$w+EIX^xA z@(k0r`f9EvE=8={6I2-&$ue?HXLe>hB=Ufloq>;uft`VosWPHr5d#BP$J6OIof#t- ze@{1ZVbo=0+n(UUn8n5@IsLR3qY0zwG;c-)Mz`sT-i)dep}cGi1}q$+3?fhyq!}0( N96FPx$9XgQ0RU@7GKv5I