From 32fb5444e75441e9e17c9fdaf85d0c83d067c379 Mon Sep 17 00:00:00 2001 From: KillzXGaming Date: Tue, 10 Sep 2019 18:42:48 -0400 Subject: [PATCH] Add all the newest changes. Add support for bayonetta/astral chain dat. Add support for darc archives. Support previewing window panes for bflyt (1 frame atm with around kind) Add bflan reading. Saving needs more testing and will be enabled soon. Bflyt editor will keep the editor open within an archive when saved. A custom dialog will be added soon to customize saving parameters. Bflims will be loaded if in the same folder as the bflyt when opened. --- .../FileFormats/Archives/DARC.cs | 157 +++++ .../FileFormats/Archives/DAT_Bayonetta.cs | 132 ++++ .../FileFormats/Layout/BxlytToGL.cs | 245 +++++++- .../FileFormats/Layout/CAFE/BFLAN.cs | 573 +++++++++++++++++- .../FileFormats/Layout/CAFE/BFLYT.cs | 122 ++-- .../FileFormats/Layout/CAFE/BflytShader.cs | 4 + .../Layout/CAFE/Materials/TextureRef.cs | 1 - .../FileFormats/Layout/CTR/BCLYT.cs | 16 - .../CTR/{BrlytShader.cs => BclytShader.cs} | 9 +- .../FileFormats/Layout/Common.cs | 96 +++ .../FileFormats/Layout/Rev/BRLYT.cs | 16 - .../File_Format_Library.csproj | 13 +- File_Format_Library/GL/BFRES_Render.cs | 2 +- .../GUI/BFLYT/LayoutEditor.Designer.cs | 12 +- File_Format_Library/GUI/BFLYT/LayoutEditor.cs | 96 +-- .../GUI/BFLYT/LayoutHierarchy.cs | 81 +++ .../GUI/BFLYT/LayoutSaveDialog.Designer.cs | 191 ++++++ .../GUI/BFLYT/LayoutSaveDialog.cs | 21 + .../GUI/BFLYT/LayoutSaveDialog.resx | 120 ++++ .../GUI/BFLYT/LayoutTextureList.cs | 7 + File_Format_Library/GUI/BFLYT/LayoutViewer.cs | 71 +-- File_Format_Library/Main.cs | 8 +- .../Editors/Object Editor/ObjectEditorTree.cs | 7 +- Switch_Toolbox_Library/IO/FileReader.cs | 8 + Switch_Toolbox_Library/IO/STFileLoader.cs | 5 +- .../Interfaces/FileFormatting/IArchiveFile.cs | 19 +- .../FileFormatting/IFormEditorParameters.cs | 14 + Switch_Toolbox_Library/Toolbox_Library.csproj | 1 + Toolbox/Lib/KCLExt.dll | Bin 42496 -> 43008 bytes Toolbox/Shader/Layout/Bflyt.frag | 23 +- Toolbox/Shader/Layout/Bflyt.vert | 30 +- 31 files changed, 1871 insertions(+), 229 deletions(-) create mode 100644 File_Format_Library/FileFormats/Archives/DARC.cs create mode 100644 File_Format_Library/FileFormats/Archives/DAT_Bayonetta.cs rename File_Format_Library/FileFormats/Layout/CTR/{BrlytShader.cs => BclytShader.cs} (90%) create mode 100644 File_Format_Library/GUI/BFLYT/LayoutSaveDialog.Designer.cs create mode 100644 File_Format_Library/GUI/BFLYT/LayoutSaveDialog.cs create mode 100644 File_Format_Library/GUI/BFLYT/LayoutSaveDialog.resx create mode 100644 Switch_Toolbox_Library/Interfaces/FileFormatting/IFormEditorParameters.cs diff --git a/File_Format_Library/FileFormats/Archives/DARC.cs b/File_Format_Library/FileFormats/Archives/DARC.cs new file mode 100644 index 00000000..f6e8f76c --- /dev/null +++ b/File_Format_Library/FileFormats/Archives/DARC.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using Toolbox; +using System.Windows.Forms; +using Toolbox.Library; +using Toolbox.Library.IO; + +namespace FirstPlugin +{ + public class DARC : IArchiveFile, IFileFormat, ILeaveOpenOnLoad + { + public FileType FileType { get; set; } = FileType.Archive; + + public bool CanSave { get; set; } + public string[] Description { get; set; } = new string[] { "DARC" }; + public string[] Extension { get; set; } = new string[] { "*.arc", "*.darc" }; + public string FileName { get; set; } + public string FilePath { get; set; } + public IFileInfo IFileInfo { get; set; } + + public bool CanAddFiles { get; set; } + public bool CanRenameFiles { get; set; } + public bool CanReplaceFiles { get; set; } + public bool CanDeleteFiles { get; set; } + + public bool Identify(System.IO.Stream stream) + { + using (var reader = new Toolbox.Library.IO.FileReader(stream, true)) + { + return reader.CheckSignature(4, "darc"); + } + } + + public Type[] Types + { + get + { + List types = new List(); + return types.ToArray(); + } + } + + public List files = new List(); + + public IEnumerable Files => files; + + public void ClearFiles() { files.Clear(); } + + public uint Version; + public ushort Bom; + + public void Load(System.IO.Stream stream) + { + using (var reader = new FileReader(stream, true)) + { + reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; + reader.ReadSignature(4, "darc"); + Bom = reader.ReadUInt16(); + reader.CheckByteOrderMark(Bom); + ushort headerLength = reader.ReadUInt16(); + + Version = reader.ReadUInt32(); + uint FileSize = reader.ReadUInt32(); + uint FileTableOffset = reader.ReadUInt32(); + uint FileTableLength = reader.ReadUInt32(); + uint FileDataOffset = reader.ReadUInt32(); + + Console.WriteLine("Version " + Version); + Console.WriteLine("FileTableOffset " + FileTableOffset); + Console.WriteLine("FileTableLength " + FileTableLength); + Console.WriteLine("FileDataOffset " + FileDataOffset); + + uint endOfTable = FileDataOffset + FileTableLength; + + List entries = new List(); + reader.SeekBegin(FileTableOffset); + entries.Add(new NodeEntry(reader)); + for (int i = 0; i < entries[0].Size - 1; i++) + entries.Add(new NodeEntry(reader)); + + for (int i = 0; i < entries.Count; i++) + entries[i].Name = ReadCStringW(reader); + + for (int i = 0; i < entries.Count; i++) + { + string Name = entries[i].Name; + if (entries[i].IsFolder) + { + for (int s = 0; s < entries[i].Size; s++) + entries[i].FullName += $"{Name}/"; + } + else + entries[i].FullName = Name; + } + + for (int i = 0; i < entries.Count; i++) + { + if (!entries[i].IsFolder) + { + var file = new FileEntry(); + file.FileName = entries[i].FullName; + file.FileDataStream = new SubStream(reader.BaseStream, entries[i].Offset, entries[i].Size); + files.Add(file); + } + } + } + } + + public string ReadCStringW(FileReader reader) => string.Concat(Enumerable.Range(0, 999).Select(_ => (char)reader.ReadInt16()).TakeWhile(c => c != 0)); + + public void Unload() + { + + } + + public void Save(System.IO.Stream stream) + { + } + + public bool AddFile(ArchiveFileInfo archiveFileInfo) + { + return false; + } + + public bool DeleteFile(ArchiveFileInfo archiveFileInfo) + { + return false; + } + + public class NodeEntry + { + public uint NameOffset; + public uint Size; + public uint Offset; + + public bool IsFolder => (NameOffset >> 24) == 1; + + public string Name; + + public string FullName; + + public NodeEntry(FileReader reader) + { + NameOffset = reader.ReadUInt32(); + Offset = reader.ReadUInt32(); + Size = reader.ReadUInt32(); + } + } + + public class FileEntry : ArchiveFileInfo + { + } + } +} diff --git a/File_Format_Library/FileFormats/Archives/DAT_Bayonetta.cs b/File_Format_Library/FileFormats/Archives/DAT_Bayonetta.cs new file mode 100644 index 00000000..b62ccb90 --- /dev/null +++ b/File_Format_Library/FileFormats/Archives/DAT_Bayonetta.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Toolbox.Library; +using Toolbox.Library.IO; + +namespace FirstPlugin +{ + public class DAT_Bayonetta : IArchiveFile, IFileFormat, ILeaveOpenOnLoad + { + public FileType FileType { get; set; } = FileType.Archive; + + public bool CanSave { get; set; } + public string[] Description { get; set; } = new string[] { "Platinum Games Archive" }; + public string[] Extension { get; set; } = new string[] { "*.pkz" }; + public string FileName { get; set; } + public string FilePath { get; set; } + public IFileInfo IFileInfo { get; set; } + + public bool CanAddFiles { get; set; } + public bool CanRenameFiles { get; set; } + public bool CanReplaceFiles { get; set; } + public bool CanDeleteFiles { get; set; } + + public bool Identify(System.IO.Stream stream) + { + using (var reader = new Toolbox.Library.IO.FileReader(stream, true)) + { + return reader.CheckSignature(3, "DAT"); + } + } + + public Type[] Types + { + get + { + List types = new List(); + return types.ToArray(); + } + } + + public List files = new List(); + + public IEnumerable Files => files; + + public void ClearFiles() { files.Clear(); } + + private System.IO.Stream _stream; + public void Load(System.IO.Stream stream) + { + _stream = stream; + using (var reader = new FileReader(stream, true)) + { + reader.SetByteOrder(false); + uint magic = reader.ReadUInt32(); + uint fileCount = reader.ReadUInt32(); + uint offsetFileOffsetTbl= reader.ReadUInt32(); + uint offsetFileExtTbl = reader.ReadUInt32(); + uint offsetFileNameTbl = reader.ReadUInt32(); + uint offsetFileSizeTbl = reader.ReadUInt32(); + + reader.SeekBegin(offsetFileOffsetTbl); + var offsets = reader.ReadUInt32s((int)fileCount); + + reader.SeekBegin(offsetFileExtTbl); + string[] extensions = new string[fileCount]; + for (int i = 0; i < fileCount; i++) + extensions[i] = reader.ReadString(4, true); + + reader.SeekBegin(offsetFileNameTbl); + uint strSize = reader.ReadUInt32(); + + string[] names = new string[fileCount]; + for (int i = 0; i < fileCount; i++) + names[i] = reader.ReadString((int)strSize, true); + + reader.SeekBegin(offsetFileSizeTbl); + var sizes = reader.ReadUInt32s((int)fileCount); + + for (int i = 0; i < fileCount; i++) + { + var file = new FileEntry(); + file.FileName = $"{names[i]}"; + file.FileDataStream = new SubStream(reader.BaseStream, (long)offsets[i], (long)sizes[i]); + files.Add(file); + } + } + } + + public void Unload() + { + + } + + public void Save(System.IO.Stream stream) + { + } + + public bool AddFile(ArchiveFileInfo archiveFileInfo) + { + return false; + } + + public bool DeleteFile(ArchiveFileInfo archiveFileInfo) + { + return false; + } + + public class FileEntry : ArchiveFileInfo + { + public ulong fileSize; + public ulong fileOffset; + public ulong compressedSize; + + protected Stream stream; + public override Stream FileDataStream + { + get + { + if (compressedSize != fileSize) + return new MemoryStream(STLibraryCompression.ZSTD.Decompress(stream.ToBytes())); + else + return stream; + } + set + { + stream = value; + } + } + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BxlytToGL.cs b/File_Format_Library/FileFormats/Layout/BxlytToGL.cs index 56832531..add6e16d 100644 --- a/File_Format_Library/FileFormats/Layout/BxlytToGL.cs +++ b/File_Format_Library/FileFormats/Layout/BxlytToGL.cs @@ -193,6 +193,249 @@ namespace LayoutBXLYT BxlytToGL.DrawRectangle(pane.Rectangle, TexCoords, Colors, false, effectiveAlpha); } + public static void DrawWindowPane(BasePane pane, byte effectiveAlpha, Dictionary Textures) + { + uint sizeX = (uint)pane.Width; + uint sizeY = (uint)pane.Height; + + var window = (IWindowPane)pane; + switch (window.WindowKind) + { + case WindowKind.Around: + if (window.FrameCount == 1) //1 texture for all + { + var mat = window.WindowFrames[0].Material; + + if (mat.TextureMaps.Length == 0) + RenderWindowContent(pane, sizeX, sizeY, window.Content, effectiveAlpha, Textures); + else + { + var texture = mat.TextureMaps[0].Name; + if (!Textures.ContainsKey(texture)) + { + RenderWindowContent(pane, sizeX, sizeY, window.Content, effectiveAlpha, Textures); + break; + } + + var image = Textures[texture]; + + uint contentWidth = sizeX - (uint)window.FrameElementRight - (uint)window.FrameElementLeft; + uint contentHeight = sizeY - (uint)window.FrameElementTop - (uint)window.FrameElementBottm; + + RenderWindowContent(pane, + contentWidth, + contentHeight, + window.Content, effectiveAlpha, Textures); + + // _________ + //|______| | + //| | | | + //| |___|__| + //|__|______| + + + //Top Left + SetupShaders(mat, Textures); + mat.Shader.SetInt("flipTexture", (int)window.WindowFrames[0].TextureFlip); + + CustomRectangle rect; + + GL.PushMatrix(); + { + uint pieceWidth = sizeX - window.FrameElementRight; + uint pieceHeight = window.FrameElementTop; + int pieceX = (int)-(window.FrameElementRight / 2); + int pieceY = (int)((sizeY / 2) - (pieceHeight / 2)); + + GL.Translate(pieceX, pieceY, 0); + rect = pane.CreateRectangle(pieceWidth, pieceHeight); + GL.Begin(PrimitiveType.Quads); + GL.MultiTexCoord2(TextureUnit.Texture0, 0, 1); + GL.Vertex2(rect.LeftPoint, rect.BottomPoint); + GL.MultiTexCoord2(TextureUnit.Texture0, pieceWidth / window.FrameElementRight, 1); + GL.Vertex2(rect.RightPoint, rect.BottomPoint); + GL.MultiTexCoord2(TextureUnit.Texture0, pieceWidth / window.FrameElementRight, 0); + GL.Vertex2(rect.RightPoint, rect.TopPoint); + GL.MultiTexCoord2(TextureUnit.Texture0, 0, 0); + GL.Vertex2(rect.LeftPoint, rect.TopPoint); + GL.End(); + } + GL.PopMatrix(); + + //Top Right + GL.PushMatrix(); + { + uint pieceWidth = window.FrameElementRight; + uint pieceHeight = sizeY - window.FrameElementBottm; + int pieceX = (int)((contentWidth / 2) + (pieceWidth / 2)); + int pieceY = (int)(window.FrameElementBottm / 2); + + GL.Translate(pieceX, pieceY, 0); + rect = pane.CreateRectangle(pieceWidth, pieceHeight); + GL.Begin(PrimitiveType.Quads); + GL.MultiTexCoord2(TextureUnit.Texture0, 0, pieceHeight / window.FrameElementBottm); + GL.Vertex2(rect.LeftPoint, rect.BottomPoint); + GL.MultiTexCoord2(TextureUnit.Texture0, 1, pieceHeight / window.FrameElementBottm); + GL.Vertex2(rect.RightPoint, rect.BottomPoint); + GL.MultiTexCoord2(TextureUnit.Texture0, 0, 0); + GL.Vertex2(rect.RightPoint, rect.TopPoint); + GL.MultiTexCoord2(TextureUnit.Texture0, 1, 0); + GL.Vertex2(rect.LeftPoint, rect.TopPoint); + GL.End(); + } + GL.PopMatrix(); + + //Bottom Right + GL.PushMatrix(); + { + uint pieceWidth = window.FrameElementLeft; + uint pieceHeight = sizeY - window.FrameElementTop; + int pieceX = (int)-((contentWidth / 2) + (pieceWidth / 2)); + int pieceY = (int)-(window.FrameElementTop / 2); + + GL.Translate(pieceX, pieceY, 0); + rect = pane.CreateRectangle(pieceWidth, pieceHeight); + GL.Begin(PrimitiveType.Quads); + GL.MultiTexCoord2(TextureUnit.Texture0, 0, 0); + GL.Vertex2(rect.LeftPoint, rect.BottomPoint); + GL.MultiTexCoord2(TextureUnit.Texture0, 1, 0); + GL.Vertex2(rect.RightPoint, rect.BottomPoint); + GL.MultiTexCoord2(TextureUnit.Texture0, 1, pieceHeight / window.FrameElementTop); + GL.Vertex2(rect.RightPoint, rect.TopPoint); + GL.MultiTexCoord2(TextureUnit.Texture0, 0, pieceHeight / window.FrameElementTop); + GL.Vertex2(rect.LeftPoint, rect.TopPoint); + GL.End(); + } + GL.PopMatrix(); + + //Bottom Right + GL.PushMatrix(); + { + uint pieceWidth = sizeX - window.FrameElementLeft; + uint pieceHeight = window.FrameElementBottm; + int pieceX = (int)(window.FrameElementLeft / 2); + int pieceY = (int)(-(sizeY / 2) + (pieceHeight / 2)); + + GL.Translate(pieceX, pieceY, 0); + rect = pane.CreateRectangle(pieceWidth, pieceHeight); + GL.Begin(PrimitiveType.Quads); + GL.MultiTexCoord2(TextureUnit.Texture0, pieceWidth / window.FrameElementLeft, 1); + GL.Vertex2(rect.LeftPoint, rect.BottomPoint); + GL.MultiTexCoord2(TextureUnit.Texture0, 0, 1); + GL.Vertex2(rect.RightPoint, rect.BottomPoint); + GL.MultiTexCoord2(TextureUnit.Texture0, 0, 0); + GL.Vertex2(rect.RightPoint, rect.TopPoint); + GL.MultiTexCoord2(TextureUnit.Texture0, pieceWidth / window.FrameElementLeft, 0); + GL.Vertex2(rect.LeftPoint, rect.TopPoint); + GL.End(); + } + GL.PopMatrix(); + } + } + else if (window.FrameCount == 4) + { + + } + break; + case WindowKind.Horizontal: + break; + case WindowKind.HorizontalNoContent: + break; + } + + GL.UseProgram(0); + } + + enum FrameType + { + LeftTop, + Left, + LeftBottom, + Top, + Bottom, + RightTop, + Right, + RightBottom, + } + + private static Vector2 GetFramePosition(uint paneWidth, uint paneHeight, IWindowPane window, FrameType type) + { + + + Vector2 pos = new Vector2(); + switch (type) + { + case FrameType.LeftTop: + + break; + } + return pos; + } + + private static void SetupShaders(BxlytMaterial mat, Dictionary textures) + { + if (mat.Shader == null) + { + if (mat is Cafe.BFLYT.Material) + { + mat.Shader = new BflytShader((Cafe.BFLYT.Material)mat); + mat.Shader.Compile(); + } + } + + mat.Shader.Enable(); + if (mat is Cafe.BFLYT.Material) + ((BflytShader)mat.Shader).SetMaterials(textures); + } + + private static void RenderWindowContent(BasePane pane, uint sizeX, uint sizeY, BxlytWindowContent content, + byte effectiveAlpha, Dictionary Textures) + { + var mat = content.Material; + var rect = pane.CreateRectangle(sizeX, sizeY); + + SetupShaders(mat, Textures); + + Vector2[] texCoords = new Vector2[] { + new Vector2(1,1), + new Vector2(0,1), + new Vector2(0,0), + new Vector2(1,0) + }; + + Color[] colors = new Color[] { + content.ColorTopLeft.Color, + content.ColorTopRight.Color, + content.ColorBottomRight.Color, + content.ColorBottomLeft.Color, + }; + + if (content.TexCoords.Count > 0) + { + texCoords = new Vector2[] { + content.TexCoords[0].TopLeft.ToTKVector2(), + content.TexCoords[0].TopRight.ToTKVector2(), + content.TexCoords[0].BottomRight.ToTKVector2(), + content.TexCoords[0].BottomLeft.ToTKVector2(), + }; + } + + GL.Begin(PrimitiveType.Quads); + GL.Color4(colors[0]); + GL.MultiTexCoord2(TextureUnit.Texture0, texCoords[0].X, texCoords[0].Y); + GL.Vertex2(rect.LeftPoint, rect.BottomPoint); + GL.Color4(colors[1]); + GL.MultiTexCoord2(TextureUnit.Texture0, texCoords[1].X, texCoords[1].Y); + GL.Vertex2(rect.RightPoint, rect.BottomPoint); + GL.Color4(colors[2]); + GL.MultiTexCoord2(TextureUnit.Texture0, texCoords[2].X, texCoords[2].Y); + GL.Vertex2(rect.RightPoint, rect.TopPoint); + GL.Color4(colors[3]); + GL.MultiTexCoord2(TextureUnit.Texture0, texCoords[3].X, texCoords[3].Y); + GL.Vertex2(rect.LeftPoint, rect.TopPoint); + GL.End(); + } + public static bool BindGLTexture(BxlytTextureRef tex, STGenericTexture texture) { if (texture.RenderableTex == null || !texture.RenderableTex.GLInitialized) @@ -240,7 +483,7 @@ namespace LayoutBXLYT } public static void DrawRectangle(CustomRectangle rect, Vector2[] texCoords, - Color[] colors, bool useLines = true, byte alpha = 255) + Color[] colors, bool useLines = true, byte alpha = 255) { for (int i = 0; i < colors.Length; i++) { diff --git a/File_Format_Library/FileFormats/Layout/CAFE/BFLAN.cs b/File_Format_Library/FileFormats/Layout/CAFE/BFLAN.cs index f4da2eca..6cc589df 100644 --- a/File_Format_Library/FileFormats/Layout/CAFE/BFLAN.cs +++ b/File_Format_Library/FileFormats/Layout/CAFE/BFLAN.cs @@ -2,14 +2,15 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using System.Threading.Tasks; +using System.ComponentModel; using Toolbox; using System.Windows.Forms; using Toolbox.Library; +using Toolbox.Library.IO; namespace LayoutBXLYT { - public class BFLAN : IFileFormat + public class BFLAN : IEditorForm, IFileFormat { public FileType FileType { get; set; } = FileType.Layout; @@ -37,16 +38,582 @@ namespace LayoutBXLYT } } + Header header; + public void Load(System.IO.Stream stream) { + CanSave = false; + + header = new Header(); + header.Read(new FileReader(stream),this); } public void Unload() { } - public void Save(System.IO.Stream stream) + public void Save(System.IO.Stream stream) { + header.Write(new FileWriter(stream)); + } + + public LayoutEditor OpenForm() { + LayoutEditor editor = new LayoutEditor(); + editor.Dock = DockStyle.Fill; + editor.LoadBxlan(header); + return editor; + } + + public void FillEditor(Form control) + { + ((LayoutEditor)control).LoadBxlan(header); + } + + public class Header : BxlanHeader + { + private const string Magic = "FLAN"; + private ushort ByteOrderMark; + private ushort HeaderSize; + + //As of now this should be empty but just for future proofing + private List UnknownSections = new List(); + + public PAT1 AnimationTag; + public PAI1 AnimationInfo; + + public void Read(FileReader reader, BFLAN bflan) + { + AnimationTag = new PAT1(); + AnimationInfo = new PAI1(); + + reader.SetByteOrder(true); + reader.ReadSignature(4, Magic); + ByteOrderMark = reader.ReadUInt16(); + reader.CheckByteOrderMark(ByteOrderMark); + HeaderSize = reader.ReadUInt16(); + Version = reader.ReadUInt32(); + SetVersionInfo(); + uint FileSize = reader.ReadUInt32(); + ushort sectionCount = reader.ReadUInt16(); + reader.ReadUInt16(); //Padding + + FileInfo = bflan; + IsBigEndian = reader.ByteOrder == Syroot.BinaryData.ByteOrder.BigEndian; + + reader.SeekBegin(HeaderSize); + for (int i = 0; i < sectionCount; i++) + { + long pos = reader.Position; + string Signature = reader.ReadString(4, Encoding.ASCII); + uint SectionSize = reader.ReadUInt32(); + + SectionCommon section = new SectionCommon(Signature); + switch (Signature) + { + case "pat1": + AnimationTag = new PAT1(reader, this); + break; + case "pai1": + AnimationInfo = new PAI1(reader, this); + break; + default: + section.Data = reader.ReadBytes((int)SectionSize - 8); + UnknownSections.Add(section); + break; + } + + section.SectionSize = SectionSize; + reader.SeekBegin(pos + SectionSize); + } + } + + public void Write(FileWriter writer) + { + writer.SetByteOrder(true); + writer.WriteSignature(Magic); + writer.Write(ByteOrderMark); + writer.SetByteOrder(IsBigEndian); + writer.Write(HeaderSize); + writer.Write(Version); + writer.Write(uint.MaxValue); //Reserve space for file size later + writer.Write(ushort.MaxValue); //Reserve space for section count later + writer.Seek(2); //padding + + int sectionCount = 1; + + WriteSection(writer, "pat1", AnimationTag, () => AnimationTag.Write(writer, this)); + sectionCount++; + + WriteSection(writer, "pai1", AnimationInfo, () => AnimationInfo.Write(writer, this)); + sectionCount++; + + foreach (var section in UnknownSections) + { + WriteSection(writer, section.Signature, section, () => section.Write(writer, this)); + sectionCount++; + } + + //Write the total section count + using (writer.TemporarySeek(0x10, System.IO.SeekOrigin.Begin)) + { + writer.Write((ushort)sectionCount); + } + + //Write the total file size + using (writer.TemporarySeek(0x0C, System.IO.SeekOrigin.Begin)) + { + writer.Write((uint)writer.BaseStream.Length); + } + } + } + + public class PAT1 : SectionCommon + { + [DisplayName("Name"), CategoryAttribute("Animation")] + public string Name { get; set; } + + [DisplayName("Groups"), CategoryAttribute("Animation")] + public List Groups { get; set; } + + [DisplayName("Start"), CategoryAttribute("Frames")] + public ushort StartFrame { get; set; } + + [DisplayName("End"), CategoryAttribute("Frames")] + public ushort EndFrame { get; set; } + + [DisplayName("Animation Order"), CategoryAttribute("Parameters")] + public ushort AnimationOrder { get; set; } + + [DisplayName("Child Binding"), CategoryAttribute("Parameters")] + public bool ChildBinding { get; set; } + + private byte[] UnknownData; + + public PAT1() + { + AnimationOrder = 2; + Name = ""; + EndFrame = 0; + StartFrame = 0; + ChildBinding = false; + Groups = new List(); + } + + public PAT1(FileReader reader, Header header) + { + long startPos = reader.Position - 8; + + Groups = new List(); + + AnimationOrder = reader.ReadUInt16(); + ushort groupCount = reader.ReadUInt16(); + if (groupCount != 1) + throw new Exception("Unexpected group count! Expected 1!"); + uint animNameOffset = reader.ReadUInt32(); + uint groupNamesOffset = reader.ReadUInt32(); + StartFrame = reader.ReadUInt16(); + EndFrame = reader.ReadUInt16(); + ChildBinding = reader.ReadBoolean(); + UnknownData = reader.ReadBytes((int)(startPos + animNameOffset - reader.Position)); + + reader.SeekBegin(startPos + animNameOffset); + Name = reader.ReadZeroTerminatedString(); + + reader.SeekBegin(startPos + groupNamesOffset); + for (int i = 0; i < groupCount; i++) + Groups.Add(reader.ReadString(0x24, true)); + } + + public override void Write(FileWriter writer, LayoutHeader header) + { + long startPos = writer.Position - 8; + + writer.Write(AnimationOrder); + writer.Write((ushort)Groups.Count); + writer.Write(uint.MaxValue); //animNameOffset + writer.Write(uint.MaxValue); //groupNamesOffset + writer.Write(StartFrame); + writer.Write(EndFrame); + writer.Write(ChildBinding); + writer.Write(UnknownData); + + writer.WriteUint32Offset(4, startPos); + writer.WriteString(Name); + writer.Align(4); + + writer.WriteUint32Offset(8, startPos); + for (int i = 0; i < Groups.Count; i++) + writer.WriteString(Groups[i], 0x24); + } + } + + public class PAI1 : SectionCommon + { + public ushort FrameSize; + + private byte flags; + + public List Textures { get; set; } + + public List Entries = new List(); + + public PAI1() + { + Textures = new List(); + } + + public PAI1(FileReader reader, Header header) + { + long startPos = reader.Position - 8; + + Textures = new List(); + + FrameSize = reader.ReadUInt16(); + flags = reader.ReadByte(); + reader.ReadByte(); //padding + var numTextures = reader.ReadUInt16(); + var numEntries = reader.ReadUInt16(); + var entryOffsetTbl = reader.ReadUInt32(); + + var texOffsets = reader.ReadUInt32s(numTextures); + for (int i = 0; i < numTextures; i++) + { + reader.SeekBegin(startPos + texOffsets[i]); + Textures.Add(reader.ReadZeroTerminatedString()); + } + + reader.SeekBegin(startPos + entryOffsetTbl); + var entryOffsets = reader.ReadUInt32s(numEntries); + for (int i = 0; i < numEntries; i++) + { + reader.SeekBegin(startPos + entryOffsets[i]); + Entries.Add(new PaiEntry(reader, header)); + } + } + + public override void Write(FileWriter writer, LayoutHeader header) + { + long startPos = writer.Position; + + writer.Write(FrameSize); + writer.Write(flags); + writer.Write((byte)0); + writer.Write((ushort)Textures.Count); + writer.Write((ushort)Entries.Count); + + if (Textures.Count > 0) + { + writer.Write(new uint[Textures.Count]); + for (int i = 0; i < Textures.Count; i++) + { + writer.WriteUint32Offset(4 + (i * 4), startPos); + writer.WriteString(Textures[i]); + } + } + if (Entries.Count > 0) + { + writer.Write(new uint[Entries.Count]); + for (int i = 0; i < Textures.Count; i++) + { + writer.WriteUint32Offset(4 + (i * 4), startPos); + Entries[i].Write(writer, header); + } + } + } + } + + public class PaiEntry + { + [DisplayName("Name"), CategoryAttribute("Animation")] + public string Name { get; set; } + + [DisplayName("Target"), CategoryAttribute("Animation")] + public AnimationTarget Target { get; set; } + + public List Tags = new List(); + + public PaiEntry(FileReader reader, Header header) + { + long startPos = reader.Position; + + Name = reader.ReadString(28); + var numTags = reader.ReadByte(); + Target = reader.ReadEnum(false); + reader.ReadUInt16(); //padding + + var offsets = reader.ReadUInt32s(numTags); + for (int i = 0; i < numTags; i++) + { + reader.SeekBegin(startPos + offsets[i]); + Tags.Add(new PaiTag(reader, header)); + } + } + + public void Write(FileWriter writer, LayoutHeader header) + { + long startPos = writer.Position; + + writer.WriteString(Name, 28); + writer.Write((byte)Tags.Count); + writer.Write(Target, true); + writer.Write((byte)0); + if (Tags.Count > 0) + { + writer.Write(new uint[Tags.Count]); + for (int i = 0; i < Tags.Count; i++) + { + writer.WriteUint32Offset(4 + (i * 4), startPos); + Tags[i].Write(writer, header); + } + } + } + } + + public class PaiTag + { + public List Entries = new List(); + + private string Tag; + + public string Type + { + get { return TypeDefine.ContainsKey(Tag) ? TypeDefine[Tag] : Tag; } + } + + public Dictionary TypeDefine = new Dictionary() + { + {"FLPA","Pane" }, + {"FLTS","Pane Texture SRT" }, + {"FLVI","Pane Visibilty" }, + {"FLVC","Vertex Colors" }, + {"FLMC","Material Colors" }, + {"FLTP","Texture Pattern" }, + }; + + public PaiTag(FileReader reader, Header header) + { + long startPos = reader.Position; + + Tag = reader.ReadString(4, Encoding.ASCII); + var numEntries = reader.ReadByte(); + reader.Seek(3); + var offsets = reader.ReadUInt32s((int)numEntries); + for (int i = 0; i < numEntries; i++) + { + reader.SeekBegin(startPos + offsets[i]); + switch (Tag) + { + case "FLPA": + Entries.Add(new FLPATagEntry(reader, header)); + break; + case "FLTS": + Entries.Add(new FLTSTagEntry(reader, header)); + break; + case "FLVI": + Entries.Add(new FLVITagEntry(reader, header)); + break; + case "FLVC": + Entries.Add(new FLVCTagEntry(reader, header)); + break; + case "FLMC": + Entries.Add(new FLMCTagEntry(reader, header)); + break; + case "FLTP": + Entries.Add(new FLTPTagEntry(reader, header)); + break; + default: + Entries.Add(new PaiTagEntry(reader, header)); + break; + } + } + } + + public void Write(FileWriter writer, LayoutHeader header) + { + long startPos = writer.Position; + + writer.WriteSignature(Tag); + writer.Write((byte)Entries.Count); + writer.Seek(3); + writer.Write(new uint[Entries.Count]); + for (int i = 0; i < Entries.Count; i++) + { + writer.WriteUint32Offset(8 + (i * 4), startPos); + Entries[i].Write(writer, header); + } + } + } + + public class PaiTagEntry + { + [Browsable(false)] + public virtual string TargetName + { + get { return AnimationTarget.ToString(); } + } + + public byte AnimationTarget; + + [DisplayName("Index"), CategoryAttribute("Tag")] + public byte Index { get; private set; } + + [DisplayName("Data Type"), CategoryAttribute("Tag")] + public KeyType DataType { get; private set; } + + public byte Unknown; + + public List KeyFrames = new List(); + + public PaiTagEntry(FileReader reader, Header header) + { + long startPos = reader.Position; + Index = reader.ReadByte(); + AnimationTarget = reader.ReadByte(); + DataType = reader.ReadEnum(true); + Unknown = reader.ReadByte(); + var KeyFrameCount = reader.ReadUInt16(); + reader.ReadUInt16(); //Padding + uint keyFrameOffset = reader.ReadUInt32(); + + + reader.SeekBegin(startPos + keyFrameOffset); + for (int i = 0; i < KeyFrameCount; i++) + KeyFrames.Add(new KeyFrame(reader, DataType)); + } + + public void Write(FileWriter writer, LayoutHeader header) + { + long startPos = writer.Position; + + writer.Write(Index); + writer.Write(AnimationTarget); + writer.Write(DataType, true); + writer.Write(Unknown); + writer.Write((ushort)KeyFrames.Count); + writer.Write((ushort)0); //padding + writer.Write(0); //key offset + + if (KeyFrames.Count > 0) + { + writer.WriteUint32Offset(8, startPos); + for (int i = 0; i < KeyFrames.Count; i++) + KeyFrames[i].Write(writer, DataType); + } + } + } + + public class KeyFrame + { + [DisplayName("Blend"), CategoryAttribute("Key Frame")] + public float Blend { get; set; } + [DisplayName("Frame"), CategoryAttribute("Key Frame")] + public float Frame { get; set; } + [DisplayName("Value"), CategoryAttribute("Key Frame")] + public float Value { get; set; } + + public KeyFrame(FileReader reader, KeyType DataType) + { + Frame = reader.ReadSingle(); + switch (DataType) + { + case KeyType.Float: + Value = reader.ReadSingle(); + Blend = reader.ReadSingle(); + break; + case KeyType.Uin16: + Value = (float)reader.ReadInt16(); + Blend = (float)reader.ReadInt16(); + break; + } + } + + public void Write(FileWriter writer, KeyType DataType) + { + writer.Write(Frame); + switch (DataType) + { + case KeyType.Float: + writer.Write(Value); + writer.Write(Blend); + break; + case KeyType.Uin16: + writer.Write((ushort)Value); + writer.Write((ushort)Blend); + break; + } + } + } + + public class FLPATagEntry : PaiTagEntry + { + public override string TargetName => Target.ToString(); + [DisplayName("Target"), CategoryAttribute("Tag")] + public LPATarget Target + { + get { return (LPATarget)AnimationTarget; } + set { AnimationTarget = (byte)value; } + } + public FLPATagEntry(FileReader reader, Header header) : base(reader, header) { } + } + + public class FLTSTagEntry : PaiTagEntry + { + public override string TargetName => Target.ToString(); + [DisplayName("Target"), CategoryAttribute("Tag")] + public LTSTarget Target + { + get { return (LTSTarget)AnimationTarget; } + set { AnimationTarget = (byte)value; } + } + public FLTSTagEntry(FileReader reader, Header header) : base(reader, header) { } + } + + public class FLVITagEntry : PaiTagEntry + { + public override string TargetName => Target.ToString(); + [DisplayName("Target"), CategoryAttribute("Tag")] + public LVITarget Target + { + get { return (LVITarget)AnimationTarget; } + set { AnimationTarget = (byte)value; } + } + public FLVITagEntry(FileReader reader, Header header) : base(reader, header) { } + } + + public class FLVCTagEntry : PaiTagEntry + { + public override string TargetName => Target.ToString(); + [DisplayName("Target"), CategoryAttribute("Tag")] + public LVCTarget Target + { + get { return (LVCTarget)AnimationTarget; } + set { AnimationTarget = (byte)value; } + } + public FLVCTagEntry(FileReader reader, Header header) : base(reader, header) { } + } + + public class FLMCTagEntry : PaiTagEntry + { + public override string TargetName => Target.ToString(); + [DisplayName("Target"), CategoryAttribute("Tag")] + public LMCTarget Target + { + get { return (LMCTarget)AnimationTarget; } + set { AnimationTarget = (byte)value; } + } + public FLMCTagEntry(FileReader reader, Header header) : base(reader, header) { } + } + + public class FLTPTagEntry : PaiTagEntry + { + public override string TargetName => Target.ToString(); + [DisplayName("Target"), CategoryAttribute("Tag")] + public LTPTarget Target + { + get { return (LTPTarget)AnimationTarget; } + set { AnimationTarget = (byte)value; } + } + public FLTPTagEntry(FileReader reader, Header header) : base(reader, header) { } } } } diff --git a/File_Format_Library/FileFormats/Layout/CAFE/BFLYT.cs b/File_Format_Library/FileFormats/Layout/CAFE/BFLYT.cs index 277ed5a0..08b2ab05 100644 --- a/File_Format_Library/FileFormats/Layout/CAFE/BFLYT.cs +++ b/File_Format_Library/FileFormats/Layout/CAFE/BFLYT.cs @@ -199,6 +199,20 @@ namespace LayoutBXLYT.Cafe BFLIM test = new BFLIM(); Dictionary textures = new Dictionary(); + if (File.Exists(FilePath)) + { + string folder = Path.GetDirectoryName(FilePath); + foreach (var file in Directory.GetFiles(folder)) + { + if (Utils.GetExtension(file) == ".bflim") + { + BFLIM bflim = (BFLIM)STFileLoader.OpenFileFormat(file); + if (!textures.ContainsKey(bflim.FileName)) + textures.Add(bflim.FileName, bflim); + } + } + } + foreach (var archive in PluginRuntime.SarcArchives) { foreach (var file in archive.Files) @@ -516,9 +530,13 @@ namespace LayoutBXLYT.Cafe { Version = VersionMajor << 24 | VersionMinor << 16 | VersionMicro << 8 | VersionMicro2; - writer.SetByteOrder(IsBigEndian); + writer.SetByteOrder(true); writer.WriteSignature(Magic); - writer.Write(ByteOrderMark); + if (!IsBigEndian) + writer.Write((ushort)0xFFFE); + else + writer.Write((ushort)0xFEFF); + writer.SetByteOrder(IsBigEndian); writer.Write(HeaderSize); writer.Write(Version); writer.Write(uint.MaxValue); //Reserve space for file size later @@ -655,22 +673,6 @@ namespace LayoutBXLYT.Cafe } } - public class TexCoord - { - public Vector2F TopLeft { get; set; } - public Vector2F TopRight { get; set; } - public Vector2F BottomLeft { get; set; } - public Vector2F BottomRight { get; set; } - - public TexCoord() - { - TopLeft = new Vector2F(0, 0); - TopRight = new Vector2F(1, 0); - BottomLeft = new Vector2F(0, 1); - BottomRight = new Vector2F(1, 1); - } - } - public class TXT1 : PAN1 { public override string Signature { get; } = "txt1"; @@ -863,7 +865,7 @@ namespace LayoutBXLYT.Cafe }; } - public class WND1 : PAN1 + public class WND1 : PAN1, IWindowPane { public override string Signature { get; } = "wnd1"; @@ -875,44 +877,48 @@ namespace LayoutBXLYT.Cafe public bool UseOneMaterialForAll { get { return Convert.ToBoolean(_flag & 1); } + set { } } public bool UseVertexColorForAll { get { return Convert.ToBoolean((_flag >> 1) & 1); } + set { } } - public bool WindowKind + public WindowKind WindowKind { - get { return Convert.ToBoolean((_flag >> 2) & 3); } + get { return (WindowKind)((_flag >> 2) & 3); } + set { } } public bool NotDrawnContent { get { return Convert.ToBoolean((_flag >> 4) & 1); } + set { } } - public ushort StretchLeft; - public ushort StretchRight; - public ushort StretchTop; - public ushort StretchBottm; - public ushort FrameElementLeft; - public ushort FrameElementRight; - public ushort FrameElementTop; - public ushort FrameElementBottm; - public byte FrameCount; + public ushort StretchLeft { get; set; } + public ushort StretchRight { get; set; } + public ushort StretchTop { get; set; } + public ushort StretchBottm { get; set; } + public ushort FrameElementLeft { get; set; } + public ushort FrameElementRight { get; set; } + public ushort FrameElementTop { get; set; } + public ushort FrameElementBottm { get; set; } + public byte FrameCount { get; set; } private byte _flag; [TypeConverter(typeof(ExpandableObjectConverter))] - public WindowContent Content { get; set; } + public BxlytWindowContent Content { get; set; } [TypeConverter(typeof(ExpandableObjectConverter))] - public List WindowFrames { get; set; } + public List WindowFrames { get; set; } public WND1(FileReader reader, Header header) : base(reader) { - WindowFrames = new List(); + WindowFrames = new List(); long pos = reader.Position - 0x54; @@ -965,7 +971,7 @@ namespace LayoutBXLYT.Cafe writer.Write(0); writer.WriteUint32Offset(_ofsContentPos, pos); - Content.Write(writer); + ((WindowContent)Content).Write(writer); if (WindowFrames.Count > 0) { @@ -976,30 +982,15 @@ namespace LayoutBXLYT.Cafe for (int i = 0; i < WindowFrames.Count; i++) { writer.WriteUint32Offset(_ofsFramePos + (i * 4), pos); - WindowFrames[i].Write(writer); + ((WindowFrame)WindowFrames[i]).Write(writer); } } } - public class WindowContent + public class WindowContent : BxlytWindowContent { private Header LayoutFile; - public STColor8 ColorTopLeft { get; set; } - public STColor8 ColorTopRight { get; set; } - public STColor8 ColorBottomLeft { get; set; } - public STColor8 ColorBottomRight { get; set; } - - public ushort MaterialIndex { get; set; } - - public List TexCoords = new List(); - - [TypeConverter(typeof(ExpandableObjectConverter))] - public Material Material - { - get { return LayoutFile.MaterialList.Materials[MaterialIndex]; } - } - public WindowContent(FileReader reader, Header header) { LayoutFile = header; @@ -1020,6 +1011,8 @@ namespace LayoutBXLYT.Cafe BottomLeft = reader.ReadVec2SY(), BottomRight = reader.ReadVec2SY(), }); + + Material = LayoutFile.MaterialList.Materials[MaterialIndex]; } public void Write(FileWriter writer) @@ -1041,26 +1034,21 @@ namespace LayoutBXLYT.Cafe } } - public class WindowFrame + public class WindowFrame : BxlytWindowFrame { - public Material material { get; set; } - - public ushort MaterialIndex; - public byte TextureFlip; - public WindowFrame(FileReader reader, Header header) { MaterialIndex = reader.ReadUInt16(); - TextureFlip = reader.ReadByte(); + TextureFlip = (WindowFrameTexFlip)reader.ReadByte(); reader.ReadByte(); //padding - material = header.MaterialList.Materials[MaterialIndex]; + Material = header.MaterialList.Materials[MaterialIndex]; } public void Write(FileWriter writer) { writer.Write(MaterialIndex); - writer.Write(TextureFlip); + writer.Write(TextureFlip, false); writer.Write((byte)0); } } @@ -1236,16 +1224,19 @@ namespace LayoutBXLYT.Cafe { if (file.Contains(LayoutFile)) { - var openedFile = STFileLoader.OpenFileFormat(file); - if (openedFile is IArchiveFile) + if (Utils.GetExtension(file) == ".szs") { + var openedFile = STFileLoader.OpenFileFormat(file); + BFLYT bflyt = null; SearchArchive((IArchiveFile)openedFile, ref bflyt); if (bflyt != null) return bflyt; } - else if (openedFile is BFLYT) + else if (Utils.GetExtension(file) == ".bflyt") { + var openedFile = STFileLoader.OpenFileFormat(file); + openedFile.IFileInfo = new IFileInfo(); openedFile.IFileInfo.ArchiveParent = fileFormat.IFileInfo.ArchiveParent; return (BFLYT)openedFile; @@ -1846,9 +1837,6 @@ namespace LayoutBXLYT.Cafe [DisplayName("White Color"), CategoryAttribute("Color")] public STColor8 WhiteColor { get; set; } - [DisplayName("Texture Maps"), CategoryAttribute("Texture")] - public TextureRef[] TextureMaps { get; set; } - [DisplayName("Texture Transforms"), CategoryAttribute("Texture")] public TextureTransform[] TextureTransforms { get; set; } @@ -1981,7 +1969,7 @@ namespace LayoutBXLYT.Cafe } for (int i = 0; i < TextureMaps.Length; i++) - TextureMaps[i].Write(writer); + ((TextureRef)TextureMaps[i]).Write(writer); for (int i = 0; i < TextureTransforms.Length; i++) TextureTransforms[i].Write(writer); diff --git a/File_Format_Library/FileFormats/Layout/CAFE/BflytShader.cs b/File_Format_Library/FileFormats/Layout/CAFE/BflytShader.cs index 1340d8e4..4eb4c666 100644 --- a/File_Format_Library/FileFormats/Layout/CAFE/BflytShader.cs +++ b/File_Format_Library/FileFormats/Layout/CAFE/BflytShader.cs @@ -27,6 +27,7 @@ namespace LayoutBXLYT SetInt("debugShading", 0); SetInt("hasTexture0", 0); SetInt("numTextureMaps", 0); + SetInt("flipTexture", 0); SetVec2("uvScale0", new Vector2(1,1)); SetFloat("uvRotate0", 0); @@ -42,6 +43,9 @@ namespace LayoutBXLYT SetVec2("uvScale0", new Vector2(1, 1)); SetFloat("uvRotate0", 0); SetVec2("uvTranslate0", new Vector2(0, 0)); + SetInt("flipTexture", 0); + + Console.WriteLine("debugShading " + (int)Runtime.LayoutEditor.Shading); BindTextureUniforms(); diff --git a/File_Format_Library/FileFormats/Layout/CAFE/Materials/TextureRef.cs b/File_Format_Library/FileFormats/Layout/CAFE/Materials/TextureRef.cs index 4c825635..8225b314 100644 --- a/File_Format_Library/FileFormats/Layout/CAFE/Materials/TextureRef.cs +++ b/File_Format_Library/FileFormats/Layout/CAFE/Materials/TextureRef.cs @@ -4,7 +4,6 @@ namespace LayoutBXLYT.Cafe { public class TextureRef : BxlytTextureRef { - public short ID; byte flag1; byte flag2; diff --git a/File_Format_Library/FileFormats/Layout/CTR/BCLYT.cs b/File_Format_Library/FileFormats/Layout/CTR/BCLYT.cs index cef65729..5e191aee 100644 --- a/File_Format_Library/FileFormats/Layout/CTR/BCLYT.cs +++ b/File_Format_Library/FileFormats/Layout/CTR/BCLYT.cs @@ -382,22 +382,6 @@ namespace LayoutBXLYT } } - public class TexCoord - { - public Vector2F TopLeft { get; set; } - public Vector2F TopRight { get; set; } - public Vector2F BottomLeft { get; set; } - public Vector2F BottomRight { get; set; } - - public TexCoord() - { - TopLeft = new Vector2F(0, 0); - TopRight = new Vector2F(1, 0); - BottomLeft = new Vector2F(0, 1); - BottomRight = new Vector2F(1, 1); - } - } - public class TXT1 : PAN1 { public TXT1() : base() diff --git a/File_Format_Library/FileFormats/Layout/CTR/BrlytShader.cs b/File_Format_Library/FileFormats/Layout/CTR/BclytShader.cs similarity index 90% rename from File_Format_Library/FileFormats/Layout/CTR/BrlytShader.cs rename to File_Format_Library/FileFormats/Layout/CTR/BclytShader.cs index 5d5c445e..8cfcc68e 100644 --- a/File_Format_Library/FileFormats/Layout/CTR/BrlytShader.cs +++ b/File_Format_Library/FileFormats/Layout/CTR/BclytShader.cs @@ -38,6 +38,9 @@ namespace LayoutBXLYT SetColor("blackColor", Color.FromArgb(0, 0, 0, 0)); SetInt("debugShading", (int)Runtime.LayoutEditor.Shading); SetInt("numTextureMaps", material.TextureMaps.Count); + SetVec2("uvScale0", new Vector2(1, 1)); + SetFloat("uvRotate0", 0); + SetVec2("uvTranslate0", new Vector2(0, 0)); BindTextureUniforms(); @@ -64,9 +67,9 @@ namespace LayoutBXLYT if (transform.Scale.Y < 0) shiftY = 1; - SetVec2("uvScale0",new Vector2(transform.Scale.X, transform.Scale.Y)); - SetFloat("uvRotate0", transform.Rotate); - SetVec2("uvTranslate0",new Vector2(shiftX + transform.Translate.X, shiftY + transform.Translate.Y)); + //SetVec2("uvScale0",new Vector2(transform.Scale.X, transform.Scale.Y)); + // SetFloat("uvRotate0", transform.Rotate); + // SetVec2("uvTranslate0",new Vector2(shiftX + transform.Translate.X, shiftY + transform.Translate.Y)); } } diff --git a/File_Format_Library/FileFormats/Layout/Common.cs b/File_Format_Library/FileFormats/Layout/Common.cs index 6fa39546..5a76c5e7 100644 --- a/File_Format_Library/FileFormats/Layout/Common.cs +++ b/File_Format_Library/FileFormats/Layout/Common.cs @@ -95,6 +95,19 @@ namespace LayoutBXLYT rectangle = CreateRectangle(); } + public CustomRectangle CreateRectangle(uint width, uint height) + { + //Do origin transforms + var transformed = TransformOrientation((int)width, (int)height, originX, originY); + var parentTransform = ParentOriginTransform(transformed); + + return new CustomRectangle( + parentTransform.X, + parentTransform.Y, + parentTransform.Z, + parentTransform.W); + } + public CustomRectangle CreateRectangle() { //Do origin transforms @@ -225,6 +238,8 @@ namespace LayoutBXLYT public class BxlytTextureRef { + public short ID { get; set; } + public string Name { get; set; } public virtual WrapMode WrapModeU { get; set; } @@ -373,6 +388,84 @@ namespace LayoutBXLYT } + public enum WindowKind + { + Around = 0, + Horizontal = 1, + HorizontalNoContent = 2 + } + + public enum WindowFrameTexFlip : byte + { + None = 0, + FlipH = 1, + FlipV = 2, + Rotate90 = 3, + Rotate180 = 4, + Rotate270 = 5 + } + + public interface IWindowPane + { + bool UseOneMaterialForAll { get; set; } + bool UseVertexColorForAll { get; set; } + WindowKind WindowKind { get; set; } + bool NotDrawnContent { get; set; } + ushort StretchLeft { get; set; } + ushort StretchRight { get; set; } + ushort StretchTop { get; set; } + ushort StretchBottm { get; set; } + ushort FrameElementLeft { get; set; } + ushort FrameElementRight { get; set; } + ushort FrameElementTop { get; set; } + ushort FrameElementBottm { get; set; } + byte FrameCount { get; set; } + + BxlytWindowContent Content { get; set; } + + List WindowFrames { get; set; } + } + + public class BxlytWindowContent + { + public STColor8 ColorTopLeft { get; set; } + public STColor8 ColorTopRight { get; set; } + public STColor8 ColorBottomLeft { get; set; } + public STColor8 ColorBottomRight { get; set; } + + public ushort MaterialIndex { get; set; } + + [TypeConverter(typeof(ExpandableObjectConverter))] + public virtual BxlytMaterial Material { get; set; } + + public List TexCoords = new List(); + } + + public class BxlytWindowFrame + { + [TypeConverter(typeof(ExpandableObjectConverter))] + public BxlytMaterial Material { get; set; } + + public ushort MaterialIndex; + public WindowFrameTexFlip TextureFlip; + } + + public class TexCoord + { + public Vector2F TopLeft { get; set; } + public Vector2F TopRight { get; set; } + public Vector2F BottomLeft { get; set; } + public Vector2F BottomRight { get; set; } + + public TexCoord() + { + TopLeft = new Vector2F(0, 0); + TopRight = new Vector2F(1, 0); + BottomLeft = new Vector2F(0, 1); + BottomRight = new Vector2F(1, 1); + } + } + public class LayoutHeader : IDisposable { [Browsable(false)] @@ -479,6 +572,9 @@ namespace LayoutBXLYT [Browsable(false)] public virtual BxlytShader Shader { get; set; } + + [DisplayName("Texture Maps"), CategoryAttribute("Texture")] + public BxlytTextureRef[] TextureMaps { get; set; } } public class SectionCommon diff --git a/File_Format_Library/FileFormats/Layout/Rev/BRLYT.cs b/File_Format_Library/FileFormats/Layout/Rev/BRLYT.cs index a2efd956..7a048dac 100644 --- a/File_Format_Library/FileFormats/Layout/Rev/BRLYT.cs +++ b/File_Format_Library/FileFormats/Layout/Rev/BRLYT.cs @@ -385,22 +385,6 @@ namespace LayoutBXLYT } } - public class TexCoord - { - public Vector2F TopLeft { get; set; } - public Vector2F TopRight { get; set; } - public Vector2F BottomLeft { get; set; } - public Vector2F BottomRight { get; set; } - - public TexCoord() - { - TopLeft = new Vector2F(0, 0); - TopRight = new Vector2F(1, 0); - BottomLeft = new Vector2F(0, 1); - BottomRight = new Vector2F(1, 1); - } - } - public class TXT1 : PAN1 { public TXT1() : base() diff --git a/File_Format_Library/File_Format_Library.csproj b/File_Format_Library/File_Format_Library.csproj index 2275681e..4d3ac881 100644 --- a/File_Format_Library/File_Format_Library.csproj +++ b/File_Format_Library/File_Format_Library.csproj @@ -212,6 +212,8 @@ + + @@ -307,7 +309,7 @@ - + @@ -359,6 +361,12 @@ LayoutProperties.cs + + Form + + + LayoutSaveDialog.cs + Form @@ -1165,6 +1173,9 @@ LayoutProperties.cs + + LayoutSaveDialog.cs + LayoutTextDocked.cs diff --git a/File_Format_Library/GL/BFRES_Render.cs b/File_Format_Library/GL/BFRES_Render.cs index 686999a1..5f23ca97 100644 --- a/File_Format_Library/GL/BFRES_Render.cs +++ b/File_Format_Library/GL/BFRES_Render.cs @@ -899,7 +899,7 @@ namespace FirstPlugin { foreach (var tex in bntx.Textures) { - if (!tex.Value.RenderableTex.GLInitialized) + if (tex.Value.RenderableTex != null && !tex.Value.RenderableTex.GLInitialized) tex.Value.LoadOpenGLTexture(); } } diff --git a/File_Format_Library/GUI/BFLYT/LayoutEditor.Designer.cs b/File_Format_Library/GUI/BFLYT/LayoutEditor.Designer.cs index c77f8be6..e329e44d 100644 --- a/File_Format_Library/GUI/BFLYT/LayoutEditor.Designer.cs +++ b/File_Format_Library/GUI/BFLYT/LayoutEditor.Designer.cs @@ -48,6 +48,7 @@ this.textureListToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.textConverterToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.orthographicViewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.saveAnimationToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.backColorDisplay)).BeginInit(); this.stToolStrip1.SuspendLayout(); this.stMenuStrip1.SuspendLayout(); @@ -156,6 +157,7 @@ this.openToolStripMenuItem, this.clearWorkspaceToolStripMenuItem, this.saveToolStripMenuItem1, + this.saveAnimationToolStripMenuItem, this.saveToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); @@ -179,7 +181,7 @@ // this.saveToolStripMenuItem1.Name = "saveToolStripMenuItem1"; this.saveToolStripMenuItem1.Size = new System.Drawing.Size(180, 22); - this.saveToolStripMenuItem1.Text = "Save"; + this.saveToolStripMenuItem1.Text = "Save Layout"; this.saveToolStripMenuItem1.Click += new System.EventHandler(this.saveToolStripMenuItem1_Click); // // saveToolStripMenuItem @@ -227,6 +229,13 @@ this.orthographicViewToolStripMenuItem.Text = "Orthographic View"; this.orthographicViewToolStripMenuItem.Click += new System.EventHandler(this.orthographicViewToolStripMenuItem_Click); // + // saveAnimationToolStripMenuItem + // + this.saveAnimationToolStripMenuItem.Name = "saveAnimationToolStripMenuItem"; + this.saveAnimationToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.saveAnimationToolStripMenuItem.Text = "Save Animation"; + this.saveAnimationToolStripMenuItem.Click += new System.EventHandler(this.saveAnimationToolStripMenuItem_Click); + // // LayoutEditor // this.AllowDrop = true; @@ -277,5 +286,6 @@ private Toolbox.Library.Forms.STLabel stLabel1; private System.Windows.Forms.ToolStripMenuItem orthographicViewToolStripMenuItem; private System.Windows.Forms.ToolStripButton toolstripOrthoBtn; + private System.Windows.Forms.ToolStripMenuItem saveAnimationToolStripMenuItem; } } diff --git a/File_Format_Library/GUI/BFLYT/LayoutEditor.cs b/File_Format_Library/GUI/BFLYT/LayoutEditor.cs index 1c055c6a..687e3f47 100644 --- a/File_Format_Library/GUI/BFLYT/LayoutEditor.cs +++ b/File_Format_Library/GUI/BFLYT/LayoutEditor.cs @@ -19,13 +19,13 @@ namespace LayoutBXLYT { public partial class LayoutEditor : Form { - public static bool IsSaving = false; - private Dictionary Textures; public List LayoutFiles = new List(); + public List AnimationFiles = new List(); private BxlytHeader ActiveLayout; + private BxlanHeader ActiveAnimation; public enum DockLayout { @@ -38,8 +38,6 @@ namespace LayoutBXLYT public LayoutEditor() { - IsSaving = false; - InitializeComponent(); Textures = new Dictionary(); @@ -72,7 +70,7 @@ namespace LayoutBXLYT private LayoutPartsEditor LayoutPartsEditor; private bool isLoaded = false; - public void LoadBxlyt(BxlytHeader header, string fileName) + public void LoadBxlyt(BxlytHeader header) { LayoutFiles.Add(header); ActiveLayout = header; @@ -91,7 +89,18 @@ namespace LayoutBXLYT isLoaded = true; } - private void InitializeDockPanels() + public void LoadBxlan(BxlanHeader header) + { + AnimationFiles.Add(header); + ActiveAnimation = header; + + ShowAnimationHierarchy(); + ShowPropertiesPanel(); + + isLoaded = true; + } + + private void InitializeDockPanels(bool isAnimation = false) { ShowTextureList(); ShowPartsEditor(); @@ -152,7 +161,7 @@ namespace LayoutBXLYT if (LayoutProperties != null && (string)sender == "Select") { - ActiveViewport.SelectedPanes.Clear(); + ActiveViewport?.SelectedPanes.Clear(); if (e is TreeViewEventArgs) { var node = ((TreeViewEventArgs)e).Node; @@ -161,7 +170,7 @@ namespace LayoutBXLYT { var pane = node.Tag as BasePane; LayoutProperties.LoadProperties(pane, OnProperyChanged); - ActiveViewport.SelectedPanes.Add(pane); + ActiveViewport?.SelectedPanes.Add(pane); } else LayoutProperties.LoadProperties(node.Tag, OnProperyChanged); @@ -190,11 +199,6 @@ namespace LayoutBXLYT ToggleChildern(child, isChecked); } - public void LoadBflan() - { - - } - public void InitalizeEditors() { @@ -226,6 +230,14 @@ namespace LayoutBXLYT LayoutProperties.Show(dockPanel1, DockState.DockRight); } + public void ShowAnimationHierarchy() + { + LayoutHierarchy = new LayoutHierarchy(); + LayoutHierarchy.Text = "Animation Hierarchy"; + LayoutHierarchy.LoadAnimation(ActiveAnimation, ObjectSelected); + LayoutHierarchy.Show(dockPanel1, DockState.DockLeft); + } + private void ShowPaneHierarchy() { LayoutHierarchy = new LayoutHierarchy(); @@ -323,11 +335,11 @@ namespace LayoutBXLYT if (file == null) return; if (file is BFLYT) - LoadBxlyt(((BFLYT)file).header, file.FileName); + LoadBxlyt(((BFLYT)file).header); else if (file is BCLYT) - LoadBxlyt(((BCLYT)file).header, file.FileName); + LoadBxlyt(((BCLYT)file).header); else if (file is BRLYT) - LoadBxlyt(((BRLYT)file).header, file.FileName); + LoadBxlyt(((BRLYT)file).header); else if (file is IArchiveFile) { var layouts = SearchLayoutFiles((IArchiveFile)file); @@ -340,22 +352,22 @@ namespace LayoutBXLYT foreach (var layout in form.SelectedLayouts()) { if (layout is BFLYT) - LoadBxlyt(((BFLYT)layout).header, file.FileName); + LoadBxlyt(((BFLYT)layout).header); if (layout is BCLYT) - LoadBxlyt(((BCLYT)layout).header, file.FileName); + LoadBxlyt(((BCLYT)layout).header); if (layout is BRLYT) - LoadBxlyt(((BRLYT)layout).header, file.FileName); + LoadBxlyt(((BRLYT)layout).header); } } } else if (layouts.Count > 0) { if (layouts[0] is BFLYT) - LoadBxlyt(((BFLYT)layouts[0]).header, file.FileName); + LoadBxlyt(((BFLYT)layouts[0]).header); if (layouts[0] is BCLYT) - LoadBxlyt(((BCLYT)layouts[0]).header, file.FileName); + LoadBxlyt(((BCLYT)layouts[0]).header); if (layouts[0] is BRLYT) - LoadBxlyt(((BRLYT)layouts[0]).header, file.FileName); + LoadBxlyt(((BRLYT)layouts[0]).header); } } else if (file is BFLAN) @@ -492,23 +504,30 @@ namespace LayoutBXLYT } private void saveToolStripMenuItem1_Click(object sender, EventArgs e) { - SaveActiveFile(); + if (ActiveLayout != null) + SaveActiveFile(ActiveLayout.FileInfo); } - private void SaveActiveFile(bool ForceDialog = false) + private void saveAnimationToolStripMenuItem_Click(object sender, EventArgs e) { + if (ActiveAnimation != null) + SaveActiveFile(ActiveAnimation.FileInfo); + } + + private void SaveActiveFile(IFileFormat fileFormat, bool ForceDialog = false) { - if (ActiveLayout != null && ActiveLayout.FileInfo.CanSave) + if (fileFormat.CanSave) { - var fileFormat = ActiveLayout.FileInfo; - if (fileFormat.IFileInfo.ArchiveParent != null && !ForceDialog) + if (fileFormat.IFileInfo != null && + fileFormat.IFileInfo.ArchiveParent != null && !ForceDialog) { - this.DialogResult = DialogResult.OK; - IsSaving = true; - this.Close(); + if (fileFormat is IEditorFormParameters) + ((IEditorFormParameters)fileFormat).OnSave.Invoke(fileFormat, new EventArgs()); + + MessageBox.Show($"Saved {fileFormat.FileName} to archive!"); } else { - STFileSaver.SaveFileFormat(ActiveLayout.FileInfo, fileFormat.FilePath); + STFileSaver.SaveFileFormat(fileFormat, fileFormat.FilePath); } } } @@ -518,12 +537,18 @@ namespace LayoutBXLYT if (e.Control && e.Alt && e.KeyCode == Keys.S) // Ctrl + Alt + S Save As { e.SuppressKeyPress = true; - SaveActiveFile(true); + if (ActiveLayout != null) + SaveActiveFile(ActiveLayout.FileInfo, true); + if (ActiveAnimation != null) + SaveActiveFile(ActiveAnimation.FileInfo, true); } else if (e.Control && e.KeyCode == Keys.S) // Ctrl + S Save { e.SuppressKeyPress = true; - SaveActiveFile(false); + if (ActiveLayout != null) + SaveActiveFile(ActiveLayout.FileInfo, false); + if (ActiveAnimation != null) + SaveActiveFile(ActiveAnimation.FileInfo, false); } } @@ -565,7 +590,10 @@ namespace LayoutBXLYT } private void toolStripButton1_Click(object sender, EventArgs e) { - SaveActiveFile(false); + if (ActiveLayout != null) + SaveActiveFile(ActiveLayout.FileInfo, false); + if (ActiveAnimation != null) + SaveActiveFile(ActiveAnimation.FileInfo, false); } } } diff --git a/File_Format_Library/GUI/BFLYT/LayoutHierarchy.cs b/File_Format_Library/GUI/BFLYT/LayoutHierarchy.cs index 7b6268fd..5ee685b5 100644 --- a/File_Format_Library/GUI/BFLYT/LayoutHierarchy.cs +++ b/File_Format_Library/GUI/BFLYT/LayoutHierarchy.cs @@ -50,11 +50,14 @@ namespace LayoutBXLYT private bool isLoaded = false; private EventHandler OnProperySelected; + private BxlytHeader ActiveLayout; public void LoadLayout(BxlytHeader bxlyt, EventHandler onPropertySelected) { isLoaded = false; OnProperySelected = onPropertySelected; + ActiveLayout = bxlyt; + treeView1.BeginUpdate(); treeView1.Nodes.Clear(); @@ -71,12 +74,67 @@ namespace LayoutBXLYT isLoaded = true; } + public void LoadAnimation(BxlanHeader bxlan, EventHandler onPropertySelected) + { + isLoaded = false; + OnProperySelected = onPropertySelected; + + treeView1.BeginUpdate(); + treeView1.Nodes.Clear(); + LoadAnimations(bxlan,new TreeNode(bxlan.FileName) { Tag = bxlan }); + treeView1.EndUpdate(); + isLoaded = true; + } + public void Reset() { treeView1.Nodes.Clear(); isLoaded = false; } + private void LoadAnimations(BxlanHeader bxlan, TreeNode root) + { + treeView1.Nodes.Add(root); + if (bxlan is BFLAN.Header) + { + var header = bxlan as BFLAN.Header; + var pat1 = new TreeNode("Tag Info") { Tag = header.AnimationTag }; + var pai1 = new TreeNode("Animation Info") { Tag = header.AnimationInfo }; + + for (int i = 0; i < header.AnimationInfo.Entries.Count; i++) + LoadAnimationEntry(header.AnimationInfo.Entries[i], pai1); + + root.Nodes.Add(pat1); + root.Nodes.Add(pai1); + } + } + + private void LoadAnimationEntry(BFLAN.PaiEntry entry, TreeNode root) + { + var nodeEntry = new TreeNode(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] }; + nodeEntry.Nodes.Add(nodeTag); + for (int j = 0; j < entry.Tags[i].Entries.Count; j++) + LoadTagEntry(entry.Tags[i].Entries[j], nodeTag, j); + } + } + + private void LoadTagEntry(BFLAN.PaiTagEntry entry, TreeNode root, int index) + { + var nodeEntry = new TreeNode(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] }; + nodeEntry.Nodes.Add(keyNode); + } + } + private void LoadTextures(List textures) { TreeNode node = new TreeNode("Textures"); @@ -84,12 +142,35 @@ namespace LayoutBXLYT for (int i = 0; i < textures.Count; i++) { TreeNode matNode = new TreeNode(textures[i]); + matNode.Tag = i; + matNode.ContextMenuStrip = new ContextMenuStrip(); + var menu = new STToolStipMenuItem("Rename"); + menu.Click += RenameTextureAction; + matNode.ContextMenuStrip.Items.Add(menu); matNode.ImageKey = "texture"; matNode.SelectedImageKey = "texture"; node.Nodes.Add(matNode); } } + private void RenameTextureAction(object sender, EventArgs e) + { + var selectedNode = treeView1.SelectedNode; + if (selectedNode == null) return; + + int index = (int)selectedNode.Tag; + string activeTex = ActiveLayout.Textures[index]; + + RenameDialog dlg = new RenameDialog(); + dlg.SetString(activeTex); + + if (dlg.ShowDialog() == DialogResult.OK) + { + ActiveLayout.Textures[index] = dlg.textBox1.Text; + selectedNode.Text = dlg.textBox1.Text; + } + } + private void LoadFonts(List fonts) { TreeNode node = new TreeNode("Fonts"); diff --git a/File_Format_Library/GUI/BFLYT/LayoutSaveDialog.Designer.cs b/File_Format_Library/GUI/BFLYT/LayoutSaveDialog.Designer.cs new file mode 100644 index 00000000..fc6b8405 --- /dev/null +++ b/File_Format_Library/GUI/BFLYT/LayoutSaveDialog.Designer.cs @@ -0,0 +1,191 @@ +namespace FirstPlugin.Forms +{ + partial class LayoutSaveDialog + { + /// + /// 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() + { + System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("Animations"); + System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("Layouts"); + System.Windows.Forms.TreeNode treeNode3 = new System.Windows.Forms.TreeNode("Textures"); + System.Windows.Forms.TreeNode treeNode4 = new System.Windows.Forms.TreeNode("Fonts"); + System.Windows.Forms.TreeNode treeNode5 = new System.Windows.Forms.TreeNode("Shaders"); + this.stButton1 = new Toolbox.Library.Forms.STButton(); + this.treeView1 = new System.Windows.Forms.TreeView(); + this.radioButton1 = new System.Windows.Forms.RadioButton(); + this.radioButton2 = new System.Windows.Forms.RadioButton(); + this.radioButton3 = new System.Windows.Forms.RadioButton(); + this.radioButton4 = new System.Windows.Forms.RadioButton(); + this.radioButton5 = new System.Windows.Forms.RadioButton(); + this.radioButton6 = new System.Windows.Forms.RadioButton(); + this.contentContainer.SuspendLayout(); + this.SuspendLayout(); + // + // contentContainer + // + this.contentContainer.Controls.Add(this.radioButton6); + this.contentContainer.Controls.Add(this.radioButton5); + this.contentContainer.Controls.Add(this.radioButton4); + this.contentContainer.Controls.Add(this.radioButton3); + this.contentContainer.Controls.Add(this.radioButton2); + this.contentContainer.Controls.Add(this.radioButton1); + this.contentContainer.Controls.Add(this.treeView1); + this.contentContainer.Controls.Add(this.stButton1); + this.contentContainer.Size = new System.Drawing.Size(389, 337); + this.contentContainer.Controls.SetChildIndex(this.stButton1, 0); + this.contentContainer.Controls.SetChildIndex(this.treeView1, 0); + this.contentContainer.Controls.SetChildIndex(this.radioButton1, 0); + this.contentContainer.Controls.SetChildIndex(this.radioButton2, 0); + this.contentContainer.Controls.SetChildIndex(this.radioButton3, 0); + this.contentContainer.Controls.SetChildIndex(this.radioButton4, 0); + this.contentContainer.Controls.SetChildIndex(this.radioButton5, 0); + this.contentContainer.Controls.SetChildIndex(this.radioButton6, 0); + // + // stButton1 + // + this.stButton1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.stButton1.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.stButton1.Location = new System.Drawing.Point(305, 305); + this.stButton1.Name = "stButton1"; + this.stButton1.Size = new System.Drawing.Size(75, 23); + this.stButton1.TabIndex = 0; + this.stButton1.Text = "Save"; + this.stButton1.UseVisualStyleBackColor = false; + // + // treeView1 + // + this.treeView1.Location = new System.Drawing.Point(3, 31); + this.treeView1.Name = "treeView1"; + treeNode1.Name = "Node5"; + treeNode1.Text = "Animations"; + treeNode2.Name = "Node6"; + treeNode2.Text = "Layouts"; + treeNode3.Name = "Node7"; + treeNode3.Text = "Textures"; + treeNode4.Name = "Node8"; + treeNode4.Text = "Fonts"; + treeNode5.Name = "Node9"; + treeNode5.Text = "Shaders"; + this.treeView1.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { + treeNode1, + treeNode2, + treeNode3, + treeNode4, + treeNode5}); + this.treeView1.Size = new System.Drawing.Size(248, 271); + this.treeView1.TabIndex = 1; + // + // radioButton1 + // + this.radioButton1.AutoSize = true; + this.radioButton1.Location = new System.Drawing.Point(257, 37); + this.radioButton1.Name = "radioButton1"; + this.radioButton1.Size = new System.Drawing.Size(105, 17); + this.radioButton1.TabIndex = 2; + this.radioButton1.TabStop = true; + this.radioButton1.Text = "Save To Archive"; + this.radioButton1.UseVisualStyleBackColor = true; + // + // radioButton2 + // + this.radioButton2.AutoSize = true; + this.radioButton2.Location = new System.Drawing.Point(257, 60); + this.radioButton2.Name = "radioButton2"; + this.radioButton2.Size = new System.Drawing.Size(129, 17); + this.radioButton2.TabIndex = 3; + this.radioButton2.TabStop = true; + this.radioButton2.Text = "Save As New Archive"; + this.radioButton2.UseVisualStyleBackColor = true; + // + // radioButton3 + // + this.radioButton3.AutoSize = true; + this.radioButton3.Location = new System.Drawing.Point(257, 83); + this.radioButton3.Name = "radioButton3"; + this.radioButton3.Size = new System.Drawing.Size(119, 17); + this.radioButton3.TabIndex = 4; + this.radioButton3.TabStop = true; + this.radioButton3.Text = "Save To File/Folder"; + this.radioButton3.UseVisualStyleBackColor = true; + // + // radioButton4 + // + this.radioButton4.AutoSize = true; + this.radioButton4.Location = new System.Drawing.Point(257, 203); + this.radioButton4.Name = "radioButton4"; + this.radioButton4.Size = new System.Drawing.Size(90, 17); + this.radioButton4.TabIndex = 5; + this.radioButton4.TabStop = true; + this.radioButton4.Text = "Save As XML"; + this.radioButton4.UseVisualStyleBackColor = true; + // + // radioButton5 + // + this.radioButton5.AutoSize = true; + this.radioButton5.Location = new System.Drawing.Point(257, 226); + this.radioButton5.Name = "radioButton5"; + this.radioButton5.Size = new System.Drawing.Size(97, 17); + this.radioButton5.TabIndex = 6; + this.radioButton5.TabStop = true; + this.radioButton5.Text = "Save As YAML"; + this.radioButton5.UseVisualStyleBackColor = true; + // + // radioButton6 + // + this.radioButton6.AutoSize = true; + this.radioButton6.Location = new System.Drawing.Point(257, 180); + this.radioButton6.Name = "radioButton6"; + this.radioButton6.Size = new System.Drawing.Size(97, 17); + this.radioButton6.TabIndex = 11; + this.radioButton6.TabStop = true; + this.radioButton6.Text = "Save As Binary"; + this.radioButton6.UseVisualStyleBackColor = true; + // + // LayoutSaveDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(395, 342); + this.Name = "LayoutSaveDialog"; + this.Text = "Layout Save Dialog"; + this.contentContainer.ResumeLayout(false); + this.contentContainer.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private Toolbox.Library.Forms.STButton stButton1; + private System.Windows.Forms.TreeView treeView1; + private System.Windows.Forms.RadioButton radioButton1; + private System.Windows.Forms.RadioButton radioButton2; + private System.Windows.Forms.RadioButton radioButton3; + private System.Windows.Forms.RadioButton radioButton4; + private System.Windows.Forms.RadioButton radioButton5; + private System.Windows.Forms.RadioButton radioButton6; + } +} \ No newline at end of file diff --git a/File_Format_Library/GUI/BFLYT/LayoutSaveDialog.cs b/File_Format_Library/GUI/BFLYT/LayoutSaveDialog.cs new file mode 100644 index 00000000..bd79e108 --- /dev/null +++ b/File_Format_Library/GUI/BFLYT/LayoutSaveDialog.cs @@ -0,0 +1,21 @@ +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 FirstPlugin.Forms +{ + public partial class LayoutSaveDialog : STForm + { + public LayoutSaveDialog() + { + InitializeComponent(); + } + } +} diff --git a/File_Format_Library/GUI/BFLYT/LayoutSaveDialog.resx b/File_Format_Library/GUI/BFLYT/LayoutSaveDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/File_Format_Library/GUI/BFLYT/LayoutSaveDialog.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/LayoutTextureList.cs b/File_Format_Library/GUI/BFLYT/LayoutTextureList.cs index 19507fb4..3b44efaa 100644 --- a/File_Format_Library/GUI/BFLYT/LayoutTextureList.cs +++ b/File_Format_Library/GUI/BFLYT/LayoutTextureList.cs @@ -85,6 +85,13 @@ namespace LayoutBXLYT { if (textureList.ContainsKey(texture)) { + if (header is BCLYT.Header) + { + //Skip certain formats like bcn ones + if (STGenericTexture.IsCompressed(textureList[texture].Format)) + continue; + } + LoadTextureIcon(index, textureList[texture]); } index++; diff --git a/File_Format_Library/GUI/BFLYT/LayoutViewer.cs b/File_Format_Library/GUI/BFLYT/LayoutViewer.cs index d9669d1a..6a5a95b8 100644 --- a/File_Format_Library/GUI/BFLYT/LayoutViewer.cs +++ b/File_Format_Library/GUI/BFLYT/LayoutViewer.cs @@ -62,11 +62,8 @@ namespace LayoutBXLYT protected override void OnFormClosing(FormClosingEventArgs e) { - if (LayoutEditor.IsSaving) - { - base.OnFormClosing(e); - return; - } + base.OnFormClosing(e); + return; var result = MessageBox.Show("Are you sure you want to close this file? You will lose any unsaved progress!", "Layout Editor", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result != DialogResult.Yes) @@ -206,10 +203,10 @@ namespace LayoutBXLYT { if (pane is BFLYT.PIC1 || pane is BCLYT.PIC1 || pane is BRLYT.PIC1) BxlytToGL.DrawPictureBox(pane, effectiveAlpha, Textures); + else if (pane is IWindowPane) + BxlytToGL.DrawWindowPane(pane, effectiveAlpha, Textures); else if (pane is BFLYT.BND1 || pane is BCLYT.BND1 || pane is BRLYT.BND1) BxlytToGL.DrawBoundryPane(pane, effectiveAlpha, SelectedPanes); - else if (pane is BFLYT.WND1) - DrawWindowPane((BFLYT.WND1)pane, effectiveAlpha); else if (pane is BFLYT.PRT1) DrawPartsPane((BFLYT.PRT1)pane, effectiveAlpha, parentAlphaInfluence); else @@ -298,66 +295,6 @@ namespace LayoutBXLYT } } - private void DrawWindowPane(BFLYT.WND1 pane, byte effectiveAlpha) - { - Vector2[] TexCoords = new Vector2[] { - new Vector2(1,1), - new Vector2(0,1), - new Vector2(0,0), - new Vector2(1,0) - }; - - Color[] Colors = new Color[] { - pane.Content.ColorTopLeft.Color, - pane.Content.ColorTopRight.Color, - pane.Content.ColorBottomRight.Color, - pane.Content.ColorBottomLeft.Color, - }; - - - float frameLeft = 0; - float frameTop = 0; - float frameRight = 0; - float frameBottom = 0; - if (pane.FrameCount == 1) - { - } - else if (pane.FrameCount == 4) - { - - } - else if (pane.FrameCount == 8) - { - - } - - var mat = pane.Content.Material; - if (mat.Shader == null) - { - mat.Shader = new BflytShader(mat); - mat.Shader.Compile(); - } - - mat.Shader.Enable(); - ((BflytShader)mat.Shader).SetMaterials(Textures); - if (pane.Content.TexCoords.Count > 0) - { - TexCoords = new Vector2[] { - pane.Content.TexCoords[0].TopLeft.ToTKVector2(), - pane.Content.TexCoords[0].TopRight.ToTKVector2(), - pane.Content.TexCoords[0].BottomRight.ToTKVector2(), - pane.Content.TexCoords[0].BottomLeft.ToTKVector2(), - }; - } - - BxlytToGL.DrawRectangle(pane.Rectangle, TexCoords, Colors, false, effectiveAlpha); - - mat.Shader.Disable(); - - GL.BindTexture(TextureTarget.Texture2D, 0); - GL.PopAttrib(); - } - private void DrawPicturePane(BCLYT.PIC1 pane, byte effectiveAlpha) { Vector2[] TexCoords = new Vector2[] { diff --git a/File_Format_Library/Main.cs b/File_Format_Library/Main.cs index 518e991e..a11d4ac4 100644 --- a/File_Format_Library/Main.cs +++ b/File_Format_Library/Main.cs @@ -318,8 +318,6 @@ namespace FirstPlugin Formats.Add(typeof(NSP)); Formats.Add(typeof(BNSH)); Formats.Add(typeof(BFSHA)); - Formats.Add(typeof(BFLIM)); - Formats.Add(typeof(BCLIM)); Formats.Add(typeof(BFSTM)); Formats.Add(typeof(BCSTM)); Formats.Add(typeof(BRSTM)); @@ -382,6 +380,11 @@ namespace FirstPlugin Formats.Add(typeof(DKCTF.PAK)); Formats.Add(typeof(WTB)); Formats.Add(typeof(PKZ)); + Formats.Add(typeof(DARC)); + Formats.Add(typeof(BFLIM)); + Formats.Add(typeof(BCLIM)); + Formats.Add(typeof(LayoutBXLYT.BFLAN)); + Formats.Add(typeof(DAT_Bayonetta)); // Formats.Add(typeof(MSBP)); // Formats.Add(typeof(BFGRP)); @@ -390,7 +393,6 @@ namespace FirstPlugin if (Runtime.DEVELOPER_DEBUG_MODE) { Formats.Add(typeof(XCI)); - Formats.Add(typeof(LayoutBXLYT.BFLAN)); Formats.Add(typeof(XLINK)); Formats.Add(typeof(BFSAR)); Formats.Add(typeof(GFA)); diff --git a/Switch_Toolbox_Library/Forms/Editors/Object Editor/ObjectEditorTree.cs b/Switch_Toolbox_Library/Forms/Editors/Object Editor/ObjectEditorTree.cs index c67aa50c..ff5f7fa2 100644 --- a/Switch_Toolbox_Library/Forms/Editors/Object Editor/ObjectEditorTree.cs +++ b/Switch_Toolbox_Library/Forms/Editors/Object Editor/ObjectEditorTree.cs @@ -292,7 +292,12 @@ namespace Toolbox.Library.Forms foreach (var node in TreeViewExtensions.Collect(treeViewCustom1.Nodes)) { - if (node is IFileFormat) + if (node is ArchiveRootNodeWrapper) + { + var file = ((ArchiveRootNodeWrapper)node).ArchiveFile; + ((IFileFormat)file).Unload(); + } + else if (node is IFileFormat) { ((IFileFormat)node).Unload(); } diff --git a/Switch_Toolbox_Library/IO/FileReader.cs b/Switch_Toolbox_Library/IO/FileReader.cs index a28d3a37..92330ce1 100644 --- a/Switch_Toolbox_Library/IO/FileReader.cs +++ b/Switch_Toolbox_Library/IO/FileReader.cs @@ -142,6 +142,14 @@ namespace Toolbox.Library.IO return ReadString(BinaryStringFormat.ZeroTerminated, encoding ?? Encoding); } + public string[] ReadZeroTerminatedStrings(uint count, Encoding encoding = null) + { + string[] str = new string[count]; + for (int i = 0; i < count; i++) + str[i] = ReadString(BinaryStringFormat.ZeroTerminated, encoding ?? Encoding); + return str; + } + public string ReadUTF16String() { List chars = new List(); diff --git a/Switch_Toolbox_Library/IO/STFileLoader.cs b/Switch_Toolbox_Library/IO/STFileLoader.cs index ec3daf2e..46a8bd2f 100644 --- a/Switch_Toolbox_Library/IO/STFileLoader.cs +++ b/Switch_Toolbox_Library/IO/STFileLoader.cs @@ -224,10 +224,7 @@ namespace Toolbox.Library.IO if (Magic == "Yaz0") { - if (data != null) - data = EveryFileExplorer.YAZ0.Decompress(data); - else - data = EveryFileExplorer.YAZ0.Decompress(FileName); + data = EveryFileExplorer.YAZ0.Decompress(stream.ToArray()); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, CompressionType.Yaz0, DecompressedFileSize, CompressedFileSize); diff --git a/Switch_Toolbox_Library/Interfaces/FileFormatting/IArchiveFile.cs b/Switch_Toolbox_Library/Interfaces/FileFormatting/IArchiveFile.cs index 09578b42..f3ea33ef 100644 --- a/Switch_Toolbox_Library/Interfaces/FileFormatting/IArchiveFile.cs +++ b/Switch_Toolbox_Library/Interfaces/FileFormatting/IArchiveFile.cs @@ -949,11 +949,28 @@ namespace Toolbox.Library { activeForm = GetEditorForm(fileFormat); activeForm.Text = (((IFileFormat)fileFormat).FileName); - activeForm.FormClosed += OnFormClosed; + if (fileFormat is IEditorFormParameters) + { + ((IEditorFormParameters)fileFormat).OnSave += OnFormSaved; + } activeForm.Show(); } } + private void OnFormSaved(object sender, EventArgs args) + { + if (ArchiveFileInfo.FileFormat == null) return; + + Console.WriteLine("OnFormSaved"); + if (ArchiveFileInfo.FileFormat.CanSave) + { + Console.WriteLine("SaveFileFormat"); + + ArchiveFileInfo.SaveFileFormat(); + UpdateEditor(); + } + } + private void OnFormClosed(object sender, EventArgs args) { if (ArchiveFileInfo.FileFormat == null) return; diff --git a/Switch_Toolbox_Library/Interfaces/FileFormatting/IFormEditorParameters.cs b/Switch_Toolbox_Library/Interfaces/FileFormatting/IFormEditorParameters.cs new file mode 100644 index 00000000..82690bb7 --- /dev/null +++ b/Switch_Toolbox_Library/Interfaces/FileFormatting/IFormEditorParameters.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Toolbox.Library +{ + public interface IEditorFormParameters + { + bool KeepOpen { get; } + EventHandler OnSave { get; set; } + } +} diff --git a/Switch_Toolbox_Library/Toolbox_Library.csproj b/Switch_Toolbox_Library/Toolbox_Library.csproj index 0350a625..4d5a458d 100644 --- a/Switch_Toolbox_Library/Toolbox_Library.csproj +++ b/Switch_Toolbox_Library/Toolbox_Library.csproj @@ -301,6 +301,7 @@ + diff --git a/Toolbox/Lib/KCLExt.dll b/Toolbox/Lib/KCLExt.dll index 2b619d3f3adb3f130cdb0544ea2abd2cd799f2fd..fc86b4fd8a6eea07249f731d7688f3c2ba7e3312 100644 GIT binary patch delta 15151 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 0) { if (hasTexture0 == 1) - textureMap0 = texture2D(textures0, gl_TexCoord[0].st);; + textureMap0 = texture2D(textures0, gl_TexCoord[0].st); } + if (debugShading == 0) { - vec4 colorFrag = gl_Color * textureMap0; - vec4 colorBlend = colorFrag * whiteColor; - gl_FragColor = colorBlend; + vec4 colorBlend = textureMap0 * whiteColor; + vec3 blackBlend = (vec3(1) - textureMap0.rgb) + blackColor.rgb; + gl_FragColor = gl_Color * colorBlend; } - if (debugShading == 1) + else if (debugShading == 5) gl_FragColor = vec4(textureMap0.rgb, 1); - if (debugShading == 2) + else if (debugShading == 1) + gl_FragColor = gl_Color; + else if (debugShading == 2) gl_FragColor = whiteColor; - if (debugShading == 3) + else if (debugShading == 3) gl_FragColor = blackColor; - if (debugShading == 4) + else if (debugShading == 4) gl_FragColor = texture2D(uvTestPattern, gl_TexCoord[0].st); } \ No newline at end of file diff --git a/Toolbox/Shader/Layout/Bflyt.vert b/Toolbox/Shader/Layout/Bflyt.vert index 68a2cca4..63b55b42 100644 --- a/Toolbox/Shader/Layout/Bflyt.vert +++ b/Toolbox/Shader/Layout/Bflyt.vert @@ -1,11 +1,39 @@ uniform vec2 uvScale0; uniform vec2 uvRotate0; uniform vec2 uvTranslate0; +uniform int flipTexture; + +vec2 rotateUV(vec2 uv, float rotation) +{ + float mid = 0.5; + return vec2( + cos(rotation) * (uv.x - mid) + sin(rotation) * (uv.y - mid) + mid, + cos(rotation) * (uv.y - mid) - sin(rotation) * (uv.x - mid) + mid + ); +} + +vec2 SetFlip(vec2 tex) +{ + vec2 outTexCoord = tex; + + if (flipTexture == 1) //FlipH + return vec2(-1, 1) * tex + vec2(1, 0); + else if (flipTexture == 2) //FlipV + return vec2(1, -1) * tex + vec2(0, 1); + else if (flipTexture == 3) //Rotate90 + return rotateUV(tex, 90.0); + else if (flipTexture == 4) //Rotate180 + return rotateUV(tex, 180.0); + else if (flipTexture == 5) //Rotate270 + return rotateUV(tex, 270.0); + + return outTexCoord; +} void main() { gl_FrontColor = gl_Color; vec2 texCoord0 = uvScale0 * gl_MultiTexCoord0.xy + uvTranslate0; - gl_TexCoord[0].st = texCoord0; + gl_TexCoord[0].st = SetFlip(texCoord0); gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } \ No newline at end of file