From af8a8f17f6f5464427e519e3a64071f45003b8b7 Mon Sep 17 00:00:00 2001 From: KillzXGaming Date: Fri, 14 Feb 2020 18:25:08 -0500 Subject: [PATCH] Add latest files Start on base for BLO. These will probably not be usable for awhile and is wip.. Currently aiming to support more varied layouts so this can help improve the code base. Add BRFNT and BCFNT support. All merged as BXFNT class. Fix bflim 3ds with LA4 textures. Fix loading/saving part panes with property user data. Fix texture coordinates to default centered UVs for layout panes with no textures. Cleanup some files and directories. --- File_Format_Library/FileFormats/Font/BFFNT.cs | 1398 ----------------- File_Format_Library/FileFormats/Font/BXFNT.cs | 26 - .../FileFormats/Font/BXFNT/BXFNT.cs | 501 ++++++ .../Font/{ => BXFNT}/BffntCharSet2Xlor.cs | 2 +- .../Font/BXFNT/BxfntYamlConverter.cs | 118 ++ .../FileFormats/Font/BXFNT/CMAP.cs | 288 ++++ .../FileFormats/Font/BXFNT/CWDH.cs | 100 ++ .../FileFormats/Font/BXFNT/FINF.cs | 223 +++ .../Font/BXFNT/FontKerningTable.cs | 68 + .../Font/BXFNT/Images/CtrImageBlock.cs | 114 ++ .../Font/BXFNT/Images/Gx2ImageBlock.cs | 277 ++++ .../Font/BXFNT/Images/RevImageBlock.cs | 112 ++ .../FileFormats/Font/BXFNT/TGLP.cs | 160 ++ .../FileFormats/Layout/BLO/BL0.cs | 79 + .../FileFormats/Layout/BLO/BLO1/PAN1.cs | 98 ++ .../FileFormats/Layout/BLO/BLO1/PIC1.cs | 71 + .../FileFormats/Layout/BLO/BLO1/TBX1.cs | 12 + .../FileFormats/Layout/BLO/BLO1/WIN1.cs | 157 ++ .../FileFormats/Layout/BLO/BLO2/MAT1.cs | 27 + .../FileFormats/Layout/BLO/BLO2/PAN2.cs | 42 + .../FileFormats/Layout/BLO/BLO2/PIC2.cs | 74 + .../FileFormats/Layout/BLO/BLO2/StringList.cs | 50 + .../FileFormats/Layout/BLO/BLO2/TBX2.cs | 12 + .../FileFormats/Layout/BLO/BLO2/WIN2.cs | 12 + .../FileFormats/Layout/BLO/BLOHeader.cs | 209 +++ .../FileFormats/Layout/BLO/BloResource.cs | 43 + .../FileFormats/Layout/BLO/BloShader.cs | 100 ++ .../FileFormats/Layout/BLO/INF1.cs | 41 + .../FileFormats/Layout/BLO/Material.cs | 20 + .../FileFormats/Layout/BxlytShader.cs | 115 ++ .../FileFormats/Layout/BxlytToGL.cs | 91 +- .../FileFormats/Layout/CAFE/BflytShader.cs | 55 +- .../FileFormats/Layout/CAFE/Panes/PRT1.cs | 8 + .../FileFormats/Layout/CAFE/Panes/TXT1.cs | 3 +- .../FileFormats/Layout/CTR/BclytShader.cs | 82 +- .../FileFormats/Layout/Common.cs | 18 +- .../FileFormats/Layout/Rev/BrlytShader.cs | 54 - .../FileFormats/Layout/ShaderLoader.cs | 10 + .../FileFormats/Message/MSBT.cs | 169 +- .../FileFormats/Texture/BFLIM.cs | 14 +- .../FileFormats/Texture/BNTX.cs | 10 +- .../FileFormats/Texture/BTI.cs | 2 +- .../PaneMatTextureMapsEditor.Designer.cs | 39 +- .../Materials/PaneMatTextureMapsEditor.cs | 3 + .../Editor/TextEditor/NewTextboxDialog.cs | 4 +- File_Format_Library/GUI/BFLYT/LayoutEditor.cs | 9 +- .../{BFFNT => BXFNT}/BffntEditor.Designer.cs | 0 .../GUI/{BFFNT => BXFNT}/BffntEditor.cs | 22 +- .../GUI/{BFFNT => BXFNT}/BffntEditor.resx | 0 .../GUI/BXFNT/CharacterSelector.Designer.cs | 45 + .../GUI/BXFNT/CharacterSelector.cs | 20 + .../GUI/BXFNT/CharacterSelector.resx | 120 ++ File_Format_Library/Main.cs | 5 +- .../Imaging/BitmapExtension.cs | 31 + .../Gamecube/Decode_Gamecube.cs | 23 + 55 files changed, 3667 insertions(+), 1719 deletions(-) delete mode 100644 File_Format_Library/FileFormats/Font/BFFNT.cs delete mode 100644 File_Format_Library/FileFormats/Font/BXFNT.cs create mode 100644 File_Format_Library/FileFormats/Font/BXFNT/BXFNT.cs rename File_Format_Library/FileFormats/Font/{ => BXFNT}/BffntCharSet2Xlor.cs (98%) create mode 100644 File_Format_Library/FileFormats/Font/BXFNT/BxfntYamlConverter.cs create mode 100644 File_Format_Library/FileFormats/Font/BXFNT/CMAP.cs create mode 100644 File_Format_Library/FileFormats/Font/BXFNT/CWDH.cs create mode 100644 File_Format_Library/FileFormats/Font/BXFNT/FINF.cs create mode 100644 File_Format_Library/FileFormats/Font/BXFNT/FontKerningTable.cs create mode 100644 File_Format_Library/FileFormats/Font/BXFNT/Images/CtrImageBlock.cs create mode 100644 File_Format_Library/FileFormats/Font/BXFNT/Images/Gx2ImageBlock.cs create mode 100644 File_Format_Library/FileFormats/Font/BXFNT/Images/RevImageBlock.cs create mode 100644 File_Format_Library/FileFormats/Font/BXFNT/TGLP.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BL0.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BLO1/PAN1.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BLO1/PIC1.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BLO1/TBX1.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BLO1/WIN1.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BLO2/MAT1.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BLO2/PAN2.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BLO2/PIC2.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BLO2/StringList.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BLO2/TBX2.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BLO2/WIN2.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BLOHeader.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BloResource.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/BloShader.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/INF1.cs create mode 100644 File_Format_Library/FileFormats/Layout/BLO/Material.cs rename File_Format_Library/GUI/{BFFNT => BXFNT}/BffntEditor.Designer.cs (100%) rename File_Format_Library/GUI/{BFFNT => BXFNT}/BffntEditor.cs (96%) rename File_Format_Library/GUI/{BFFNT => BXFNT}/BffntEditor.resx (100%) create mode 100644 File_Format_Library/GUI/BXFNT/CharacterSelector.Designer.cs create mode 100644 File_Format_Library/GUI/BXFNT/CharacterSelector.cs create mode 100644 File_Format_Library/GUI/BXFNT/CharacterSelector.resx diff --git a/File_Format_Library/FileFormats/Font/BFFNT.cs b/File_Format_Library/FileFormats/Font/BFFNT.cs deleted file mode 100644 index 1df5f912..00000000 --- a/File_Format_Library/FileFormats/Font/BFFNT.cs +++ /dev/null @@ -1,1398 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Runtime.InteropServices; -using System.Windows.Forms; -using Toolbox.Library; -using System.IO; -using Toolbox.Library.IO; -using Toolbox.Library.Forms; -using System.Drawing; -using FirstPlugin.Forms; -using LibEveryFileExplorer.GFX; -using System.Drawing.Imaging; - -namespace FirstPlugin -{ - public class BFFNT : BXFNT, IFileFormat, IEditor, IConvertableTextFormat - { - public FileType FileType { get; set; } = FileType.Font; - - public bool CanSave { get; set; } - public string[] Description { get; set; } = new string[] { "Cafe Font" }; - public string[] Extension { get; set; } = new string[] { "*.bffnt" }; - public string FileName { get; set; } - public string FilePath { get; set; } - public IFileInfo IFileInfo { get; set; } - - public bool Identify(Stream stream) - { - using (var reader = new FileReader(stream, true)) - { - return reader.CheckSignature(4, "FFNT"); - } - } - - public Type[] Types - { - get - { - List types = new List(); - return types.ToArray(); - } - } - - public FFNT bffnt; - - public BffntEditor OpenForm() - { - BffntEditor form = new BffntEditor(); - form.Text = "BFFNT Editor"; - form.Dock = DockStyle.Fill; - return form; - } - - public void FillEditor(UserControl control) - { - ((BffntEditor)control).LoadFontFile(this); - } - - - #region Text Converter Interface - public TextFileType TextFileType => TextFileType.Xml; - public bool CanConvertBack => false; - - public string ConvertToString() - { - return BffntCharSet2Xlor.ToXlor(this); - } - - public void ConvertFromString(string text) - { - } - - #endregion - - public void Load(System.IO.Stream stream) - { - PluginRuntime.BxfntFiles.Add(this); - - CanSave = true; - - bffnt = new FFNT(); - bffnt.Read(new FileReader(stream)); - - TGLP tglp = bffnt.FontSection.TextureGlyph; - - if (tglp.SheetDataList.Count > 0) - { - var bntx = STFileLoader.OpenFileFormat( - new MemoryStream(Utils.CombineByteArray(tglp.SheetDataList.ToArray())), "Sheet_0"); - if (bntx != null) - { - tglp.BinaryTextureFile = (BNTX)bntx; - } - else - { - for (int s = 0; s < tglp.SheetDataList.Count; s++) - { - var surface = new Gx2ImageBlock(); - surface.Text = $"Sheet_{s}"; - surface.Load(tglp, s); - tglp.Gx2Textures.Add(surface); - } - } - } - - int i = 0; - foreach (byte[] texture in tglp.SheetDataList) - { - // BNTX file = (BNTX)STFileLoader.OpenFileFormat("Sheet" + i++, texture); - // Nodes.Add(file); - } - } - - public override string Name { get { return FileName; } } - - public override BitmapFont GetBitmapFont(bool UseChannelComp = false) - { - return bffnt.GetBitmapFont(UseChannelComp); - } - - public override Bitmap GetBitmap(string text, bool reversewh, LayoutBXLYT.BasePane pane) - { - return bffnt.GetBitmap(text, reversewh, pane); - } - - public void Unload() - { - PluginRuntime.BxfntFiles.Remove(this); - } - - public void Save(System.IO.Stream stream) - { - bffnt.Write(new FileWriter(stream)); - } - - - public class SheetEntry : TreeNodeCustom - { - public SheetEntry() - { - ImageKey = "fileBlank"; - SelectedImageKey = "fileBlank"; - - ContextMenu = new ContextMenu(); - MenuItem export = new MenuItem("Export"); - ContextMenu.MenuItems.Add(export); - export.Click += Export; - - } - public byte[] data; - - public override void OnClick(TreeView treeview) - { - - } - - private void Export(object sender, EventArgs args) - { - SaveFileDialog sfd = new SaveFileDialog(); - sfd.FileName = Text; - sfd.DefaultExt = "bntx"; - sfd.Filter = "Supported Formats|*.bntx;|" + - "All files(*.*)|*.*"; - - - if (sfd.ShowDialog() == DialogResult.OK) - { - File.WriteAllBytes(sfd.FileName, data); - } - } - } - } - - public class FFNT - { - public ushort BOM; - public ushort HeaderSize; - public uint Version { get; set; } - - public FINF FontSection { get; set; } - public FontKerningTable KerningTable { get; set; } - - public List Blocks = new List(); - - public PlatformType Platform { get; set; } = PlatformType.Cafe; - - public enum PlatformType - { - Cafe, - NX, - Ctr - } - - public void Read(FileReader reader) - { - reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; - - string Signature = reader.ReadString(4, Encoding.ASCII); - if (Signature != "FFNT" && Signature != "CFNT") - throw new Exception($"Invalid signature {Signature}! Expected FFNT or CFNT."); - - BOM = reader.ReadUInt16(); - reader.CheckByteOrderMark(BOM); - HeaderSize = reader.ReadUInt16(); - Version = reader.ReadUInt32(); - uint FileSize = reader.ReadUInt16(); - ushort BlockCount = reader.ReadUInt16(); - ushort Padding = reader.ReadUInt16(); - - if (reader.ByteOrder == Syroot.BinaryData.ByteOrder.LittleEndian) - { - if (Version > 0x3000000 || Version > 0x00000103) - Platform = PlatformType.NX; - else - Platform = PlatformType.Ctr; - } - else - Platform = PlatformType.Cafe; - - if (Signature == "CFNT") - Platform = PlatformType.Ctr; - - reader.Seek(HeaderSize, SeekOrigin.Begin); - FontSection = new FINF(); - FontSection.Read(reader, this); - Blocks.Add(FontSection); - - //Check for any unread blocks - reader.Seek(HeaderSize, SeekOrigin.Begin); - while (!reader.EndOfStream) - { - long BlockStart = reader.Position; - - string BlockSignature = reader.ReadString(4, Encoding.ASCII); - uint BlockSize = reader.ReadUInt32(); - - switch (BlockSignature) - { - case "FFNT": - case "FFNA": - case "FCPX": - case "CWDH": - case "CGLP": - case "CMAP": - case "TGLP": - case "FINF": - break; - case "KRNG": - KerningTable = new FontKerningTable(); - KerningTable.Read(reader, this); - break; - case "GLGR": - case "HTGL": - break; - default: - throw new Exception("Unknown block found! " + BlockSignature); - } - - reader.SeekBegin(BlockStart + BlockSize); - } - } - - internal int BlockCounter = 0; - public void Write(FileWriter writer) - { - writer.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; - - BlockCounter = 1; - - writer.WriteSignature("FFNT"); - writer.Write(BOM); - writer.CheckByteOrderMark(BOM); - writer.Write(HeaderSize); - writer.Write(Version); - long _ofsFileSize = writer.Position; - writer.Write(uint.MaxValue); - long _ofsBlockNum = writer.Position; - writer.Write((ushort)0); //BlockCount - writer.Write((ushort)0); - - writer.SeekBegin(HeaderSize); - FontSection.Write(writer, this); - - //Save Block Count - using (writer.TemporarySeek(_ofsBlockNum, SeekOrigin.Begin)) - { - writer.Write((ushort)(BlockCounter + 1)); - } - - //Save File size - using (writer.TemporarySeek(_ofsFileSize, SeekOrigin.Begin)) - { - writer.Write((uint)(writer.BaseStream.Length)); - } - } - - private string CheckSignature(FileReader reader) - { - string Signature = reader.ReadString(4, Encoding.ASCII); - reader.Seek(-4, SeekOrigin.Current); - return Signature; - } - - private BitmapFont bitmapFont; - public Bitmap GetBitmap(string text, bool reversewh, LayoutBXLYT.BasePane pane) - { - var FontInfo = FontSection; - var TextureGlyph = FontInfo.TextureGlyph; - - var textPane = (LayoutBXLYT.ITextPane)pane; - - int fontWidth = (int)textPane.FontSize.X; - int fontHeight = (int)textPane.FontSize.Y; - if (textPane.FontSize.X > 2) - { - fontWidth = (int)textPane.FontSize.X - 2; - fontHeight = (int)textPane.FontSize.Y - 2; - } - - float XScale = (fontWidth / TextureGlyph.CellWidth); - float YScale = (fontHeight / TextureGlyph.CellWidth); - float height = (TextureGlyph.SheetHeight - 2) / TextureGlyph.LinesCount; - - /* int pos = 0; - for (int i = 0; i < text.Length; i++) - { - char character = text[i]; - - int charWidth = (int)FontInfo.DefaultCharWidth; - int glyphWidth = (int)FontInfo.DefaultGlyphWidth; - int leftWidth = (int)FontInfo.DefaultLeftWidth; - - if (FontInfo.CodeMapDictionary.ContainsKey(character)) - { - var idx = FontInfo.CodeMapDictionary[character]; - if (idx == 0xFFFF) continue; - var charWidthInfo = GetCharWidthInfoByIndex(FontInfo, (ushort)idx); - - charWidth = charWidthInfo.CharWidth; - glyphWidth = charWidthInfo.GlyphWidth; - leftWidth = charWidthInfo.Left; - } - - - /* Bitmap b = new Bitmap(width, height); - using (Graphics g = Graphics.FromImage(b)) - { - g.DrawImage(); - } - }*/ - - if (bitmapFont == null) - bitmapFont = GetBitmapFont(true); - - return bitmapFont.PrintToBitmap(text, new BitmapFont.FontRenderSettings() - { - TopColor = textPane.FontTopColor.Color, - BottomColor = textPane.FontBottomColor.Color, - CharSpacing = (int)textPane.CharacterSpace, - XScale = (textPane.FontSize.X / TextureGlyph.CellWidth), - YScale = (textPane.FontSize.Y / TextureGlyph.CellHeight), - LineSpacing = (int)textPane.LineSpace, - }); - } - - public BitmapFont GetBitmapFont(bool UseChannelComp = false) - { - var FontInfo = FontSection; - var TextureGlyph = FontInfo.TextureGlyph; - - BitmapFont f = new BitmapFont(); - f.LineHeight = FontInfo.LineFeed; - Bitmap[] Chars = new Bitmap[TextureGlyph.LinesCount * TextureGlyph.RowCount * TextureGlyph.SheetCount]; - - float realcellwidth = TextureGlyph.CellWidth + 1; - float realcellheight = TextureGlyph.CellHeight + 1; - - int j = 0; - for (int sheet = 0; sheet < TextureGlyph.SheetCount; sheet++) - { - Bitmap SheetBM = TextureGlyph.GetImageSheet(sheet).GetBitmap(); - - if (UseChannelComp) - SheetBM = TextureGlyph.GetImageSheet(sheet).GetComponentBitmap(SheetBM, true); - - SheetBM.RotateFlip(RotateFlipType.RotateNoneFlipY); - BitmapData bd = SheetBM.LockBits(new Rectangle(0, 0, SheetBM.Width, SheetBM.Height), - ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); - - for (int y = 0; y < TextureGlyph.LinesCount; y++) - { - for (int x = 0; x < TextureGlyph.RowCount; x++) - { - Bitmap b = new Bitmap(TextureGlyph.CellWidth, TextureGlyph.CellHeight); - BitmapData bd2 = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), - ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); - - for (int y2 = 0; y2 < TextureGlyph.CellHeight; y2++) - { - for (int x2 = 0; x2 < TextureGlyph.CellWidth; x2++) - { - Marshal.WriteInt32(bd2.Scan0, y2 * bd2.Stride + x2 * 4, - Marshal.ReadInt32(bd.Scan0, (int)(y * realcellheight + y2 + 1) * - bd.Stride + (int)(x * realcellwidth + x2 + 1) * 4)); - } - } - b.UnlockBits(bd2); - Chars[j++] = b; - } - } - SheetBM.UnlockBits(bd); - } - - foreach (var charMap in FontInfo.CodeMapDictionary) - { - var idx = charMap.Value; - if (idx == 0xFFFF) continue; - var info = GetCharWidthInfoByIndex(FontInfo, (ushort)idx); - - f.Characters.Add(charMap.Key, new BitmapFont.Character(Chars[idx], info.Left, info.GlyphWidth, info.CharWidth)); - } - - return f; - } - - private CharacterWidthEntry GetCharWidthInfoByIndex(FINF fontInfo, UInt16 Index) - { - foreach (var v in fontInfo.CharacterWidths) - { - if (Index < v.StartIndex || Index > v.EndIndex) continue; - return v.WidthEntries[Index - v.StartIndex]; - } - return null; - } - } - - //Kerning Table - //https://github.com/dnasdw/3dsfont/blob/4ead538d225d5d05929dce9d736bec91a6158052/src/bffnt/ResourceFormat.h - public class FontKerningTable - { - private byte[] Data; - - public KerningFirstTable FirstTable { get; set; } - - public void Read(FileReader reader, FFNT Header) - { - if (Header.Platform == FFNT.PlatformType.NX) - { - ushort FirstWordCount = reader.ReadUInt16(); - ushort padding = reader.ReadUInt16(); - - FirstTable = new KerningFirstTable(); - FirstTable.Read(reader, Header); - } - } - } - - public class KerningFirstTable - { - public uint FirstWordCount { get; set; } - public uint Offset { get; set; } - - public void Read(FileReader reader, FFNT Header) - { - if (Header.Platform == FFNT.PlatformType.NX) - { - uint FirstWordCount = reader.ReadUInt16(); - uint Offset = reader.ReadUInt16(); - } - } - } - - public enum Gx2ImageFormats - { - RGBA8_UNORM, - RGB8_UNORM, - RGB5A1_UNORM, - RGB565_UNORM, - RGBA4_UNORM, - LA8_UNORM, - LA4_UNORM, - A4_UNORM, - A8_UNORM, - BC1_UNORM, - BC2_UNORM, - BC3_UNORM, - BC4_UNORM, - BC5_UNORM, - RGBA8_SRGB, - BC1_SRGB, - BC2_SRGB, - BC3_SRGB, - } - - public class Gx2ImageBlock : STGenericTexture - { - public TGLP TextureTGLP; - - public int SheetIndex = 0; - - public void Load(TGLP texture, int Index) - { - CanReplace = true; - - SheetIndex = Index; - TextureTGLP = texture; - Height = TextureTGLP.SheetHeight; - Width = TextureTGLP.SheetWidth; - var BFNTFormat = (Gx2ImageFormats)TextureTGLP.Format; - Format = ConvertToGeneric(BFNTFormat); - if (Format == TEX_FORMAT.BC4_UNORM) - { - AlphaChannel = STChannelType.Red; - } - - ImageKey = "Texture"; - SelectedImageKey = "Texture"; - } - - public override bool CanEdit { get; set; } = true; - public override string ExportFilter => FileFilters.GTX; - public override string ReplaceFilter => FileFilters.GTX; - - public override void Replace(string FileName) - { - Bfres.Structs.FTEX ftex = new Bfres.Structs.FTEX(); - ftex.ReplaceTexture(FileName, Format, 1, 0, SupportedFormats, true, true, false); - if (ftex.texture != null) - { - TextureTGLP.Format = (ushort)ConvertToGx2(ftex.Format); - TextureTGLP.SheetHeight = (ushort)ftex.texture.Height; - TextureTGLP.SheetWidth = (ushort)ftex.texture.Width; - TextureTGLP.SheetDataList[SheetIndex] = ftex.texture.Data; - Format = ftex.Format; - Width = ftex.texture.Width; - Height = ftex.texture.Height; - - UpdateEditor(); - } - } - - public override TEX_FORMAT[] SupportedFormats - { - get - { - return new TEX_FORMAT[] { - TEX_FORMAT.R8_UNORM, - TEX_FORMAT.BC1_UNORM_SRGB, - TEX_FORMAT.BC1_UNORM, - TEX_FORMAT.BC2_UNORM, - TEX_FORMAT.BC2_UNORM_SRGB, - TEX_FORMAT.BC3_UNORM, - TEX_FORMAT.BC3_UNORM_SRGB, - TEX_FORMAT.BC4_UNORM, - TEX_FORMAT.BC5_UNORM, - TEX_FORMAT.R8G8_UNORM, - TEX_FORMAT.B5G6R5_UNORM, - TEX_FORMAT.B5G5R5A1_UNORM, - TEX_FORMAT.R8G8B8A8_UNORM_SRGB, - TEX_FORMAT.R8G8B8A8_UNORM, - }; - } - } - - public TEX_FORMAT ConvertToGeneric(Gx2ImageFormats Format) - { - switch (Format) - { - case Gx2ImageFormats.A8_UNORM: return TEX_FORMAT.R8_UNORM; - case Gx2ImageFormats.BC1_SRGB: return TEX_FORMAT.BC1_UNORM_SRGB; - case Gx2ImageFormats.BC1_UNORM: return TEX_FORMAT.BC1_UNORM; - case Gx2ImageFormats.BC2_UNORM: return TEX_FORMAT.BC2_UNORM; - case Gx2ImageFormats.BC2_SRGB: return TEX_FORMAT.BC2_UNORM_SRGB; - case Gx2ImageFormats.BC3_UNORM: return TEX_FORMAT.BC3_UNORM; - case Gx2ImageFormats.BC3_SRGB: return TEX_FORMAT.BC3_UNORM_SRGB; - case Gx2ImageFormats.BC4_UNORM: return TEX_FORMAT.BC4_UNORM; - case Gx2ImageFormats.BC5_UNORM: return TEX_FORMAT.BC5_UNORM; - case Gx2ImageFormats.LA4_UNORM: return TEX_FORMAT.R4G4_UNORM; - case Gx2ImageFormats.LA8_UNORM: return TEX_FORMAT.R8G8_UNORM; - case Gx2ImageFormats.RGB565_UNORM: return TEX_FORMAT.B5G6R5_UNORM; - case Gx2ImageFormats.RGB5A1_UNORM: return TEX_FORMAT.B5G5R5A1_UNORM; - case Gx2ImageFormats.RGB8_UNORM: return TEX_FORMAT.R8G8_UNORM; - case Gx2ImageFormats.RGBA8_SRGB: return TEX_FORMAT.R8G8B8A8_UNORM_SRGB; - case Gx2ImageFormats.RGBA8_UNORM: return TEX_FORMAT.R8G8B8A8_UNORM; - default: - throw new NotImplementedException("Unsupported format " + Format); - } - } - - public Gx2ImageFormats ConvertToGx2(TEX_FORMAT Format) - { - switch (Format) - { - case TEX_FORMAT.R8_UNORM: return Gx2ImageFormats.A8_UNORM; - case TEX_FORMAT.BC1_UNORM_SRGB: return Gx2ImageFormats.BC1_SRGB; - case TEX_FORMAT.BC1_UNORM: return Gx2ImageFormats.BC1_UNORM; - case TEX_FORMAT.BC2_UNORM_SRGB: return Gx2ImageFormats.BC2_SRGB; - case TEX_FORMAT.BC2_UNORM: return Gx2ImageFormats.BC2_UNORM; - case TEX_FORMAT.BC3_UNORM_SRGB: return Gx2ImageFormats.BC3_SRGB; - case TEX_FORMAT.BC3_UNORM: return Gx2ImageFormats.BC3_UNORM; - case TEX_FORMAT.BC4_UNORM: return Gx2ImageFormats.BC4_UNORM; - case TEX_FORMAT.BC5_UNORM: return Gx2ImageFormats.BC5_UNORM; - case TEX_FORMAT.R4G4_UNORM: return Gx2ImageFormats.LA4_UNORM; - case TEX_FORMAT.R8G8_UNORM: return Gx2ImageFormats.RGB8_UNORM; - case TEX_FORMAT.B5G6R5_UNORM: return Gx2ImageFormats.RGB565_UNORM; - case TEX_FORMAT.B5G5R5A1_UNORM: return Gx2ImageFormats.RGB5A1_UNORM; - case TEX_FORMAT.R8G8B8A8_UNORM_SRGB: return Gx2ImageFormats.RGBA8_SRGB; - case TEX_FORMAT.R8G8B8A8_UNORM: return Gx2ImageFormats.RGBA8_UNORM; - default: - throw new NotImplementedException("Unsupported format " + Format); - } - } - - public override void SetImageData(Bitmap bitmap, int ArrayLevel) - { - if (bitmap == null) - return; //Image is likely disposed and not needed to be applied - - uint Gx2Format = (uint)Bfres.Structs.FTEX.ConvertToGx2Format(Format); - Width = (uint)bitmap.Width; - Height = (uint)bitmap.Height; - - MipCount = 1; - uint[] MipOffsets = new uint[MipCount]; - - try - { - //Create image block from bitmap first - var data = GenerateMipsAndCompress(bitmap, MipCount, Format); - - //Swizzle and create surface - var surface = GX2.CreateGx2Texture(data, Text, - (uint)4, - (uint)0, - (uint)Width, - (uint)Height, - (uint)1, - (uint)Gx2Format, - (uint)SwizzlePattern, - (uint)1, - (uint)MipCount - ); - - TextureTGLP.Format = (ushort)ConvertToGx2(Format); - TextureTGLP.SheetHeight = (ushort)surface.height; - TextureTGLP.SheetWidth = (ushort)surface.width; - TextureTGLP.SheetDataList[SheetIndex] = surface.data; - - IsEdited = true; - UpdateEditor(); - } - catch (Exception ex) - { - STErrorDialog.Show("Failed to swizzle and compress image " + Text, "Error", ex.ToString()); - } - } - - private const uint SwizzleBase = 0x00000000; - - private uint swizzle; - private uint Swizzle - { - get - { - swizzle = SwizzleBase; - swizzle |= (uint)(SheetIndex * 2) << 8; - return swizzle; - } - } - - private uint SwizzlePattern - { - get - { - return (uint)(SheetIndex * 2); - } - } - - public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0, int DepthLevel = 0) - { - uint bpp = GetBytesPerPixel(Format); - - GX2.GX2Surface surf = new GX2.GX2Surface(); - surf.bpp = bpp; - surf.height = Height; - surf.width = Width; - surf.aa = (uint)GX2.GX2AAMode.GX2_AA_MODE_1X; - surf.alignment = 0; - surf.depth = 1; - surf.dim = (uint)GX2.GX2SurfaceDimension.DIM_2D; - surf.format = (uint)Bfres.Structs.FTEX.ConvertToGx2Format(Format); - surf.use = (uint)GX2.GX2SurfaceUse.USE_COLOR_BUFFER; - surf.pitch = 0; - surf.data = TextureTGLP.SheetDataList[SheetIndex]; - surf.numMips = 1; - surf.mipOffset = new uint[0]; - surf.mipData = null; - surf.tileMode = (uint)GX2.GX2TileMode.MODE_2D_TILED_THIN1; - surf.swizzle = Swizzle; - surf.numArray = 1; - - return GX2.Decode(surf, ArrayLevel, MipLevel); - } - - public override void OnClick(TreeView treeview) - { - UpdateEditor(); - } - - private void UpdateEditor() - { - ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase)); - if (editor == null) - { - editor = new ImageEditorBase(); - editor.Dock = DockStyle.Fill; - LibraryGUI.LoadEditor(editor); - } - - Properties prop = new Properties(); - prop.Width = Width; - prop.Height = Height; - prop.Depth = Depth; - prop.MipCount = MipCount; - prop.ArrayCount = ArrayCount; - prop.ImageSize = (uint)TextureTGLP.SheetDataList[SheetIndex].Length; - prop.Format = Format; - prop.Swizzle = Swizzle; - - - editor.Text = Text; - editor.LoadProperties(prop); - editor.LoadImage(this); - } - } - - public class BFFNT_Block - { - - } - - public class FINF : BFFNT_Block - { - public Dictionary CodeMapDictionary = new Dictionary(); - - public uint Size; - public FontType Type { get; set; } - public byte Width { get; set; } - public byte Height { get; set; } - public byte Ascent { get; set; } - public ushort LineFeed { get; set; } - public ushort AlterCharIndex { get; set; } - public byte DefaultLeftWidth { get; set; } - public byte DefaultGlyphWidth { get; set; } - public byte DefaultCharWidth { get; set; } - public CharacterCode CharEncoding { get; set; } - public TGLP TextureGlyph; - public CMAP CodeMap; - public CWDH CharacterWidth; - - public List CharacterWidths { get; set; } - public List CodeMaps { get; set; } - - public enum FontType : byte - { - Glyph = 1, - Texture = 2, - PackedTexture = 3, - } - - public enum CharacterCode : byte - { - Unicode = 1, - ShiftJIS = 2, - CP1252 = 3, - } - - public void Read(FileReader reader, FFNT Header) - { - CharacterWidths = new List(); - CodeMaps = new List(); - - string Signature = reader.ReadString(4, Encoding.ASCII); - if (Signature != "FINF") - throw new Exception($"Invalid signature {Signature}! Expected FINF."); - Size = reader.ReadUInt32(); - - if (Header.Platform == FFNT.PlatformType.Ctr) - { - Type = reader.ReadEnum(true); - LineFeed = reader.ReadUInt16(); - AlterCharIndex = reader.ReadUInt16(); - DefaultLeftWidth = reader.ReadByte(); - DefaultGlyphWidth = reader.ReadByte(); - DefaultCharWidth = reader.ReadByte(); - CharEncoding = reader.ReadEnum(true); - uint tglpOffset = reader.ReadUInt32(); - uint cwdhOffset = reader.ReadUInt32(); - uint cmapOffset = reader.ReadUInt32(); - - Height = reader.ReadByte(); - Width = reader.ReadByte(); - Ascent = reader.ReadByte(); - reader.ReadByte(); //Padding - - - //Add counter for TGLP - //Note the other counters are inside sections due to recusive setup - Header.BlockCounter += 1; - - TextureGlyph = new TGLP(); - using (reader.TemporarySeek(tglpOffset - 8, SeekOrigin.Begin)) - TextureGlyph.Read(reader); - - CharacterWidth = new CWDH(); - CharacterWidths.Add(CharacterWidth); - using (reader.TemporarySeek(cwdhOffset - 8, SeekOrigin.Begin)) - CharacterWidth.Read(reader, Header, CharacterWidths); - - CodeMap = new CMAP(); - CodeMaps.Add(CodeMap); - using (reader.TemporarySeek(cmapOffset - 8, SeekOrigin.Begin)) - CodeMap.Read(reader, Header, CodeMaps); - - } - else - { - - Type = reader.ReadEnum(true); - Height = reader.ReadByte(); - Width = reader.ReadByte(); - Ascent = reader.ReadByte(); - LineFeed = reader.ReadUInt16(); - AlterCharIndex = reader.ReadUInt16(); - DefaultLeftWidth = reader.ReadByte(); - DefaultGlyphWidth = reader.ReadByte(); - DefaultCharWidth = reader.ReadByte(); - CharEncoding = reader.ReadEnum(true); - uint tglpOffset = reader.ReadUInt32(); - uint cwdhOffset = reader.ReadUInt32(); - uint cmapOffset = reader.ReadUInt32(); - - //Add counter for TGLP - //Note the other counters are inside sections due to recusive setup - Header.BlockCounter += 1; - - TextureGlyph = new TGLP(); - using (reader.TemporarySeek(tglpOffset - 8, SeekOrigin.Begin)) - TextureGlyph.Read(reader); - - CharacterWidth = new CWDH(); - CharacterWidths.Add(CharacterWidth); - using (reader.TemporarySeek(cwdhOffset - 8, SeekOrigin.Begin)) - CharacterWidth.Read(reader, Header, CharacterWidths); - - CodeMap = new CMAP(); - CodeMaps.Add(CodeMap); - using (reader.TemporarySeek(cmapOffset - 8, SeekOrigin.Begin)) - CodeMap.Read(reader, Header, CodeMaps); - - } - } - - public void Write(FileWriter writer, FFNT header) - { - long pos = writer.Position; - - writer.WriteSignature("FINF"); - writer.Write(uint.MaxValue); - writer.Write(Type, true); - writer.Write(Height); - writer.Write(Width); - writer.Write(Ascent); - writer.Write(LineFeed); - writer.Write(AlterCharIndex); - writer.Write(DefaultLeftWidth); - writer.Write(DefaultGlyphWidth); - writer.Write(DefaultCharWidth); - writer.Write(CharEncoding, true); - - long _ofsTGLP = writer.Position; - writer.Write(uint.MaxValue); - long _ofsCWDH = writer.Position; - writer.Write(uint.MaxValue); - long _ofsCMAP = writer.Position; - writer.Write(uint.MaxValue); - - - //Save section size - long endPos = writer.Position; - using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin)) - { - writer.Write((uint)(endPos - pos)); - } - - //Save Texture Glyph - writer.WriteUint32Offset(_ofsTGLP, -8); - TextureGlyph.Write(writer, header); - - //Save Character Widths - writer.WriteUint32Offset(_ofsCWDH, -8); - CharacterWidth.Write(writer, header); - - //Save Code Maps - writer.WriteUint32Offset(_ofsCMAP, -8); - CodeMap.Write(writer, header); - } - - public CWDH GetCharacterWidth(int index) - { - if (index == -1) - return null; - - for (int i = 0; i < CharacterWidths.Count; i++) - { - if (CharacterWidths[i].StartIndex <= index && CharacterWidths[i].EndIndex >= index) - { - int CharaIndex = index - CharacterWidths[i].StartIndex; - return CharacterWidths[CharaIndex]; - } - } - - throw new Exception("Failed to get valid character index!"); - } - } - public class TGLP - { - public BNTX BinaryTextureFile; - public List Gx2Textures = new List(); - - public uint SectionSize; - public byte CellWidth { get; set; } - public byte CellHeight { get; set; } - public byte MaxCharWidth { get; set; } - public byte SheetCount { get; private set; } - public uint SheetSize { get; set; } - public ushort BaseLinePos { get; set; } - public ushort Format { get; set; } - public ushort RowCount { get; set; } - public ushort LinesCount { get; set; } - public ushort SheetWidth { get; set; } - public ushort SheetHeight { get; set; } - public List SheetDataList = new List(); - - public void Read(FileReader reader) - { - string Signature = reader.ReadString(4, Encoding.ASCII); - if (Signature != "TGLP") - throw new Exception($"Invalid signature {Signature}! Expected TGLP."); - SectionSize = reader.ReadUInt32(); - CellWidth = reader.ReadByte(); - CellHeight = reader.ReadByte(); - SheetCount = reader.ReadByte(); - MaxCharWidth = reader.ReadByte(); - SheetSize = reader.ReadUInt32(); - BaseLinePos = reader.ReadUInt16(); - Format = reader.ReadUInt16(); - RowCount = reader.ReadUInt16(); - LinesCount = reader.ReadUInt16(); - SheetWidth = reader.ReadUInt16(); - SheetHeight = reader.ReadUInt16(); - uint sheetOffset = reader.ReadUInt32(); - - using (reader.TemporarySeek(sheetOffset, SeekOrigin.Begin)) - { - for (int i = 0; i < SheetCount; i++) - { - SheetDataList.Add(reader.ReadBytes((int)SheetSize)); - } - } - } - - public void Write(FileWriter writer, FFNT Header) - { - long pos = writer.Position; - - if (BinaryTextureFile != null) - { - var mem = new System.IO.MemoryStream(); - BinaryTextureFile.Save(mem); - SheetDataList[0] = mem.ToArray(); - } - - writer.WriteSignature("TGLP"); - writer.Write(uint.MaxValue); - writer.Write(CellWidth); - writer.Write(CellHeight); - writer.Write((byte)SheetDataList.Count); - writer.Write(MaxCharWidth); - writer.Write(SheetDataList[0].Length); - writer.Write(BaseLinePos); - writer.Write(Format); - writer.Write(RowCount); - writer.Write(LinesCount); - writer.Write(SheetWidth); - writer.Write(SheetHeight); - long _ofsSheetBlocks = writer.Position; - writer.Write(uint.MaxValue); - - if (Header.Platform == FFNT.PlatformType.NX) - writer.Align(4096); - else - writer.Align(8192); - - long DataPosition = writer.Position; - using (writer.TemporarySeek(_ofsSheetBlocks, SeekOrigin.Begin)) - { - writer.Write((uint)DataPosition); - } - - for (int i = 0; i < SheetDataList.Count; i++) - { - writer.Write(SheetDataList[i]); - } - - - long SectionEndPosition = writer.Position; - //End of section. Set the size - using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin)) - { - writer.Write((uint)(SectionEndPosition - pos)); - } - } - - public STGenericTexture[] GetImageSheets() - { - STGenericTexture[] textures = new STGenericTexture[SheetCount]; - for (int i = 0; i < SheetCount; i++) - textures[i] = GetImageSheet(i); - return textures; - } - - public STGenericTexture GetImageSheet(int Index) - { - if (BinaryTextureFile != null) //BNTX uses only one image with multiple arrays - return BinaryTextureFile.Textures.ElementAt(0).Value; - else - return Gx2Textures[Index]; - } - } - - public interface CharMapping { } - - public class CMAPIndexTable : CharMapping - { - public short[] Table { get; set; } - } - - public class CMAPDirect : CharMapping - { - public ushort Offset { get; set; } - } - - public class CMAPScanMapping : CharMapping - { - public uint[] Codes { get; set; } - public short[] Indexes { get; set; } - } - - public class CMAP - { - public uint SectionSize; - - public char CharacterCodeBegin { get; set; } - public char CharacterCodeEnd { get; set; } - - public Mapping MappingMethod { get; set; } - - private ushort Padding; - - public CharMapping MappingData; - - public enum Mapping : ushort - { - Direct, - Table, - Scan, - } - - public ushort GetIndexFromCode(ushort code) - { - if (code < CharacterCodeBegin || code > CharacterCodeEnd) return 0xFFFF; - - switch (MappingMethod) - { - case Mapping.Direct: - return (UInt16)(code - CharacterCodeBegin + ((CMAPDirect)MappingData).Offset); - case Mapping.Table: - return (ushort)((CMAPIndexTable)MappingData).Table[code - CharacterCodeBegin]; - case Mapping.Scan: - if (!((CMAPScanMapping)MappingData).Codes.Contains(code)) return 0xFFFF; - else - { - var codes = ((CMAPScanMapping)MappingData).Codes; - var index = Array.FindIndex(codes, map => map == code); - - return (ushort)((CMAPScanMapping)MappingData).Indexes[index]; - } - } - - return 0xFFFF; - } - - public CMAP NextCodeMapSection { get; set; } - - public void Read(FileReader reader, FFNT header, List CodeMaps) - { - uint CodeBegin = 0; - uint CodeEnd = 0; - - long pos = reader.Position; - - reader.ReadSignature(4, "CMAP"); - SectionSize = reader.ReadUInt32(); - if (header.Platform == FFNT.PlatformType.NX) - { - CodeBegin = reader.ReadUInt32(); - CodeEnd = reader.ReadUInt32(); - MappingMethod = reader.ReadEnum(true); - Padding = reader.ReadUInt16(); - } - else - { - CodeBegin = reader.ReadUInt16(); - CodeEnd = reader.ReadUInt16(); - MappingMethod = reader.ReadEnum(true); - Padding = reader.ReadUInt16(); - } - - CharacterCodeBegin = (char)CodeBegin; - CharacterCodeEnd = (char)CodeEnd; - - uint NextMapOffset = reader.ReadUInt32(); - - //Mapping methods from - https://github.com/IcySon55/Kuriimu/blob/f670c2719affc1eaef8b4c40e40985881247acc7/src/Cetera/Font/BFFNT.cs#L211 - switch (MappingMethod) - { - case Mapping.Direct: - var charOffset = reader.ReadUInt16(); - for (char i = CharacterCodeBegin; i <= CharacterCodeEnd; i++) - { - int idx = i - CharacterCodeBegin + charOffset; - header.FontSection.CodeMapDictionary[i] = idx < ushort.MaxValue ? idx : 0; - } - - MappingData = new CMAPDirect(); - ((CMAPDirect)MappingData).Offset = charOffset; - break; - case Mapping.Table: - List table = new List(); - for (char i = CharacterCodeBegin; i <= CharacterCodeEnd; i++) - { - short idx = reader.ReadInt16(); - if (idx != -1) header.FontSection.CodeMapDictionary[i] = idx; - - table.Add(idx); - } - - MappingData = new CMAPIndexTable(); - ((CMAPIndexTable)MappingData).Table = table.ToArray(); - break; - case Mapping.Scan: - var CharEntryCount = reader.ReadUInt16(); - - if (header.Platform == FFNT.PlatformType.NX) - reader.ReadUInt16(); //Padding - - uint[] codes = new uint[CharEntryCount]; - short[] indexes = new short[CharEntryCount]; - - for (int i = 0; i < CharEntryCount; i++) - { - if (header.Platform == FFNT.PlatformType.NX) - { - uint charCode = reader.ReadUInt32(); - short index = reader.ReadInt16(); - short padding = reader.ReadInt16(); - if (index != -1) header.FontSection.CodeMapDictionary[(char)charCode] = index; - - codes[i] = charCode; - indexes[i] = index; - } - else - { - ushort charCode = reader.ReadUInt16(); - short index = reader.ReadInt16(); - if (index != -1) header.FontSection.CodeMapDictionary[(char)charCode] = index; - - codes[i] = charCode; - indexes[i] = index; - } - } - - MappingData = new CMAPScanMapping(); - ((CMAPScanMapping)MappingData).Codes = codes; - ((CMAPScanMapping)MappingData).Indexes = indexes; - break; - } - - if (NextMapOffset != 0) - { - reader.SeekBegin(NextMapOffset - 8); - NextCodeMapSection = new CMAP(); - NextCodeMapSection.Read(reader, header, CodeMaps); - CodeMaps.Add(NextCodeMapSection); - } - else - reader.SeekBegin(pos + SectionSize); - } - - public void Write(FileWriter writer, FFNT Header) - { - Header.BlockCounter += 1; - - long pos = writer.Position; - - writer.WriteSignature("CMAP"); - writer.Write(uint.MaxValue); //Section Size - if (Header.Platform == FFNT.PlatformType.NX) - { - writer.Write((uint)CharacterCodeBegin); - writer.Write((uint)CharacterCodeEnd); - } - else - { - writer.Write((ushort)CharacterCodeBegin); - writer.Write((ushort)CharacterCodeEnd); - } - - writer.Write(MappingMethod, true); - writer.Seek(2); - - long DataPos = writer.Position; - writer.Write(0); //Next Section Offset - - //Write the data - switch (MappingMethod) - { - case Mapping.Direct: - writer.Write(((CMAPDirect)MappingData).Offset); - break; - case Mapping.Table: - for (int i = 0; i < ((CMAPIndexTable)MappingData).Table.Length; i++) - { - writer.Write(((CMAPIndexTable)MappingData).Table[i]); - } - break; - case Mapping.Scan: - writer.Write((ushort)((CMAPScanMapping)MappingData).Codes.Length); - if (Header.Platform == FFNT.PlatformType.NX) - writer.Seek(2); //Padding - - for (int i = 0; i < ((CMAPScanMapping)MappingData).Codes.Length; i++) - { - if (Header.Platform == FFNT.PlatformType.NX) - { - writer.Write((uint)((CMAPScanMapping)MappingData).Codes[i]); - writer.Write(((CMAPScanMapping)MappingData).Indexes[i]); - writer.Write((ushort)0); //Padding - } - else - { - writer.Write((ushort)((CMAPScanMapping)MappingData).Codes[i]); - writer.Write(((CMAPScanMapping)MappingData).Indexes[i]); - } - } - break; - } - writer.Align(4); //Padding - - - //Save section size - long endPos = writer.Position; - using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin)) - { - writer.Write((uint)(endPos - pos)); - } - - if (NextCodeMapSection != null) - { - writer.WriteUint32Offset(DataPos, -8); - NextCodeMapSection.Write(writer, Header); - } - } - - //From https://github.com/dnasdw/3dsfont/blob/79e6f4ab6676d82fdcd6c0f79d9b0d7a343f82b5/src/bcfnt2charset/bcfnt2charset.cpp#L3 - //Todo add the rest of the encoding types - public char CodeToU16Code(FINF.CharacterCode characterCode, ushort code) - { - if (code < 0x20) - { - return (char)0; - } - - switch (characterCode) - { - case FINF.CharacterCode.Unicode: - return (char)code; - } - - return (char)code; - } - } - - public class CWDH - { - public ushort StartIndex { get; set; } - public ushort EndIndex { get; set; } - - public List WidthEntries = new List(); - - public CWDH NextWidthSection { get; set; } - - public ushort EntryCount - { - get { return (ushort)(EndIndex - StartIndex + 1); } - } - - public uint SectionSize; - - public void Read(FileReader reader, FFNT header, List CharacterWidths) - { - long pos = reader.Position; - - reader.ReadSignature(4, "CWDH"); - SectionSize = reader.ReadUInt32(); - StartIndex = reader.ReadUInt16(); - EndIndex = reader.ReadUInt16(); - uint NextWidthSectionOffset = reader.ReadUInt32(); - - for (ushort i = StartIndex; i <= EndIndex; i++) - { - var entry = new CharacterWidthEntry(); - entry.Left = reader.ReadSByte(); - entry.GlyphWidth = reader.ReadByte(); - entry.CharWidth = reader.ReadByte(); - WidthEntries.Add(entry); - } - - if (NextWidthSectionOffset != 0) - { - reader.SeekBegin((int)NextWidthSectionOffset - 8); - NextWidthSection = new CWDH(); - NextWidthSection.Read(reader, header, CharacterWidths); - CharacterWidths.Add(NextWidthSection); - } - else - reader.SeekBegin(pos + SectionSize); - } - - public void Write(FileWriter writer, FFNT Header) - { - Header.BlockCounter += 1; - - long pos = writer.Position; - - writer.WriteSignature("CWDH"); - writer.Write(uint.MaxValue); //Section Size - writer.Write(StartIndex); - writer.Write(EndIndex); - - long DataPos = writer.Position; - writer.Write(0); //NextOffset - - for (int i = 0; i < WidthEntries.Count; i++) - { - writer.Write(WidthEntries[i].Left); - writer.Write(WidthEntries[i].GlyphWidth); - writer.Write(WidthEntries[i].CharWidth); - } - - writer.Align(4); - - if (NextWidthSection != null) - { - writer.WriteUint32Offset(DataPos, -8); - NextWidthSection.Write(writer, Header); - } - - //Save section size - long endPos = writer.Position; - using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin)) - { - writer.Write((uint)(endPos - pos)); - } - } - } - - public class CharacterWidthEntry - { - public sbyte Left { get; set; } - public byte GlyphWidth { get; set; } - public byte CharWidth { get; set; } - } -} diff --git a/File_Format_Library/FileFormats/Font/BXFNT.cs b/File_Format_Library/FileFormats/Font/BXFNT.cs deleted file mode 100644 index 5cf6c667..00000000 --- a/File_Format_Library/FileFormats/Font/BXFNT.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Drawing; -using Toolbox.Library; -using LibEveryFileExplorer.GFX; - -namespace FirstPlugin -{ - public class BXFNT - { - public virtual string Name { get; set; } - - public virtual Bitmap GetBitmap(string text, bool reversewh, LayoutBXLYT.BasePane pane) - { - return new Bitmap(32,32); - } - - public virtual BitmapFont GetBitmapFont(bool UseChannelComp = false) - { - return null; - } - } -} diff --git a/File_Format_Library/FileFormats/Font/BXFNT/BXFNT.cs b/File_Format_Library/FileFormats/Font/BXFNT/BXFNT.cs new file mode 100644 index 00000000..0d43b09c --- /dev/null +++ b/File_Format_Library/FileFormats/Font/BXFNT/BXFNT.cs @@ -0,0 +1,501 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using Toolbox.Library; +using System.IO; +using Toolbox.Library.IO; +using Toolbox.Library.Forms; +using System.Drawing; +using FirstPlugin.Forms; +using LibEveryFileExplorer.GFX; +using System.Drawing.Imaging; + +namespace FirstPlugin +{ + public class BXFNT : IFileFormat, IEditor, IConvertableTextFormat + { + public FileType FileType { get; set; } = FileType.Font; + + public bool CanSave { get; set; } + public string[] Description { get; set; } = new string[] { "Cafe Font", "CTR Font", "Revolution Font" }; + public string[] Extension { get; set; } = new string[] { "*.bffnt", "*.bcfnt", "*.brfnt", }; + public string FileName { get; set; } + public string FilePath { get; set; } + public IFileInfo IFileInfo { get; set; } + + public bool Identify(Stream stream) + { + using (var reader = new FileReader(stream, true)) + { + return reader.CheckSignature(4, "FFNT") || + reader.CheckSignature(4, "CFNT") || + reader.CheckSignature(4, "RFNT"); + } + } + + public Type[] Types + { + get + { + List types = new List(); + return types.ToArray(); + } + } + + public FFNT bffnt; + + public BffntEditor OpenForm() + { + BffntEditor form = new BffntEditor(); + form.Text = "Font Editor"; + form.Dock = DockStyle.Fill; + return form; + } + + public void FillEditor(UserControl control) + { + ((BffntEditor)control).LoadFontFile(this); + } + + + #region Text Converter Interface + public TextFileType TextFileType => TextFileType.Yaml; + public bool CanConvertBack => false; + + public string ConvertToString() + { + return BxfntYamlConverter.ToYaml(bffnt); + } + + public void ConvertFromString(string text) + { + } + + #endregion + + public void Load(System.IO.Stream stream) + { + PluginRuntime.BxfntFiles.Add(this); + + CanSave = true; + + bffnt = new FFNT(); + bffnt.Read(new FileReader(stream)); + + TGLP tglp = bffnt.FontSection.TextureGlyph; + + if (tglp.SheetDataList.Count > 0) + { + if (bffnt.Platform == FFNT.PlatformType.NX) + { + var bntx = STFileLoader.OpenFileFormat( + new MemoryStream(Utils.CombineByteArray(tglp.SheetDataList.ToArray())), "Sheet_0"); + if (bntx != null) + { + tglp.BinaryTextureFile = (BNTX)bntx; + } + } + else if (bffnt.Platform == FFNT.PlatformType.Cafe) + { + for (int s = 0; s < tglp.SheetDataList.Count; s++) { + var surface = new Gx2ImageBlock(); + surface.Text = $"Sheet_{s}"; + surface.Load(tglp, s); + tglp.Textures.Add(surface); + } + } + else if (bffnt.Platform == FFNT.PlatformType.Ctr) + { + for (int s = 0; s < tglp.SheetDataList.Count; s++) + { + var surface = new CtrImageBlock(); + surface.Text = $"Sheet_{s}"; + surface.Load(tglp, s); + surface.GetBitmap().Save($"Image{s}.png"); + tglp.Textures.Add(surface); + } + } + else + { + for (int s = 0; s < tglp.SheetDataList.Count; s++) + { + var surface = new RevImageBlock(); + surface.Text = $"Sheet_{s}"; + surface.Load(tglp, s); + surface.GetBitmap().Save($"Image{s}.png"); + tglp.Textures.Add(surface); + } + } + } + + int i = 0; + foreach (byte[] texture in tglp.SheetDataList) + { + // BNTX file = (BNTX)STFileLoader.OpenFileFormat("Sheet" + i++, texture); + // Nodes.Add(file); + } + } + + public string Name { get { return FileName; } } + + public BitmapFont GetBitmapFont(bool UseChannelComp = false) + { + return bffnt.GetBitmapFont(UseChannelComp); + } + + public Bitmap GetBitmap(string text, bool reversewh, LayoutBXLYT.BasePane pane) + { + return bffnt.GetBitmap(text, reversewh, pane); + } + + public void Unload() + { + PluginRuntime.BxfntFiles.Remove(this); + } + + public void Save(System.IO.Stream stream) + { + bffnt.Write(new FileWriter(stream)); + } + + + public class SheetEntry : TreeNodeCustom + { + public SheetEntry() + { + ImageKey = "fileBlank"; + SelectedImageKey = "fileBlank"; + + ContextMenu = new ContextMenu(); + MenuItem export = new MenuItem("Export"); + ContextMenu.MenuItems.Add(export); + export.Click += Export; + + } + public byte[] data; + + public override void OnClick(TreeView treeview) + { + + } + + private void Export(object sender, EventArgs args) + { + SaveFileDialog sfd = new SaveFileDialog(); + sfd.FileName = Text; + sfd.DefaultExt = "bntx"; + sfd.Filter = "Supported Formats|*.bntx;|" + + "All files(*.*)|*.*"; + + + if (sfd.ShowDialog() == DialogResult.OK) + { + File.WriteAllBytes(sfd.FileName, data); + } + } + } + } + + public class FFNT + { + public string Signature; + + public ushort BOM; + public ushort HeaderSize; + public uint Version { get; set; } + + public FINF FontSection { get; set; } + public FontKerningTable KerningTable { get; set; } + + public PlatformType Platform { get; set; } = PlatformType.Cafe; + + public enum PlatformType + { + Wii, + Ctr, + Cafe, + NX, + } + + public void Read(FileReader reader) + { + reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; + + Signature = reader.ReadString(4, Encoding.ASCII); + if (Signature != "FFNT" && Signature != "CFNT" && Signature != "RFNT") + throw new Exception($"Invalid signature {Signature}! Expected FFNT or CFNT or RFNT."); + + BOM = reader.ReadUInt16(); + reader.CheckByteOrderMark(BOM); + + //Parse header first and check the version + //Brfnt uses a slightly different header structure + if (Signature == "RFNT") { + Version = reader.ReadUInt16(); + uint FileSize = reader.ReadUInt32(); + HeaderSize = reader.ReadUInt16(); + ushort BlockCount = reader.ReadUInt16(); + } + else + { + HeaderSize = reader.ReadUInt16(); + Version = reader.ReadUInt32(); + uint FileSize = reader.ReadUInt16(); + ushort BlockCount = reader.ReadUInt16(); + ushort Padding = reader.ReadUInt16(); + } + + //Check platform based on version, magic, and endianness + if (reader.ByteOrder == Syroot.BinaryData.ByteOrder.LittleEndian) + { + if (Version >= 0x04010000) + Platform = PlatformType.NX; + else + Platform = PlatformType.Ctr; + } + else + Platform = PlatformType.Cafe; + + if (Signature == "CFNT") + Platform = PlatformType.Ctr; + if (Signature == "RFNT") + Platform = PlatformType.Wii; + + Console.WriteLine($"Platform {Platform}"); + + reader.Seek(HeaderSize, SeekOrigin.Begin); + FontSection = new FINF(); + FontSection.Read(reader, this); + + //Check for any unread blocks + reader.Seek(HeaderSize, SeekOrigin.Begin); + while (!reader.EndOfStream) + { + long BlockStart = reader.Position; + + string BlockSignature = reader.ReadString(4, Encoding.ASCII); + uint BlockSize = reader.ReadUInt32(); + + switch (BlockSignature) + { + case "FFNT": + case "FFNA": + case "FCPX": + case "CWDH": + case "CGLP": + case "CMAP": + case "TGLP": + case "FINF": + break; + case "KRNG": + KerningTable = new FontKerningTable(); + KerningTable.Read(reader, this, BlockSize); + break; + case "GLGR": + case "HTGL": + break; + default: + throw new Exception("Unknown block found! " + BlockSignature); + } + + reader.SeekBegin(BlockStart + BlockSize); + } + } + + internal int BlockCounter = 0; + public void Write(FileWriter writer) + { + writer.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; + + BlockCounter = 1; + + writer.WriteSignature(Signature); + writer.Write(BOM); + writer.CheckByteOrderMark(BOM); + + long _ofsFileSize; + long _ofsBlockNum; + if (Platform == PlatformType.Wii) + { + writer.Write((ushort)Version); + _ofsFileSize = writer.Position; + writer.Write(uint.MaxValue); + writer.Write(HeaderSize); + _ofsBlockNum = writer.Position; + writer.Write((ushort)0); //BlockCount + } + else + { + writer.Write(HeaderSize); + writer.Write(Version); + _ofsFileSize = writer.Position; + writer.Write(uint.MaxValue); + _ofsBlockNum = writer.Position; + writer.Write((ushort)0); //BlockCount + writer.Write((ushort)0); + } + + writer.SeekBegin(HeaderSize); + FontSection.Write(writer, this); + if (KerningTable != null) { + BlockCounter++; + KerningTable.Write(writer, this); + } + + //Save Block Count + using (writer.TemporarySeek(_ofsBlockNum, SeekOrigin.Begin)) + { + writer.Write((ushort)(BlockCounter + 1)); + } + + //Save File size + using (writer.TemporarySeek(_ofsFileSize, SeekOrigin.Begin)) + { + writer.Write((uint)(writer.BaseStream.Length)); + } + } + + private string CheckSignature(FileReader reader) + { + string Signature = reader.ReadString(4, Encoding.ASCII); + reader.Seek(-4, SeekOrigin.Current); + return Signature; + } + + private BitmapFont bitmapFont; + public Bitmap GetBitmap(string text, bool reversewh, LayoutBXLYT.BasePane pane) + { + var FontInfo = FontSection; + var TextureGlyph = FontInfo.TextureGlyph; + + var textPane = (LayoutBXLYT.ITextPane)pane; + + int fontWidth = (int)textPane.FontSize.X; + int fontHeight = (int)textPane.FontSize.Y; + if (textPane.FontSize.X > 2) + { + fontWidth = (int)textPane.FontSize.X - 2; + fontHeight = (int)textPane.FontSize.Y - 2; + } + + float XScale = (fontWidth / TextureGlyph.CellWidth); + float YScale = (fontHeight / TextureGlyph.CellWidth); + float height = (TextureGlyph.SheetHeight - 2) / TextureGlyph.LinesCount; + + /* int pos = 0; + for (int i = 0; i < text.Length; i++) + { + char character = text[i]; + + int charWidth = (int)FontInfo.DefaultCharWidth; + int glyphWidth = (int)FontInfo.DefaultGlyphWidth; + int leftWidth = (int)FontInfo.DefaultLeftWidth; + + if (FontInfo.CodeMapDictionary.ContainsKey(character)) + { + var idx = FontInfo.CodeMapDictionary[character]; + if (idx == 0xFFFF) continue; + var charWidthInfo = GetCharWidthInfoByIndex(FontInfo, (ushort)idx); + + charWidth = charWidthInfo.CharWidth; + glyphWidth = charWidthInfo.GlyphWidth; + leftWidth = charWidthInfo.Left; + } + + + /* Bitmap b = new Bitmap(width, height); + using (Graphics g = Graphics.FromImage(b)) + { + g.DrawImage(); + } + }*/ + + if (bitmapFont == null) + bitmapFont = GetBitmapFont(true); + + return bitmapFont.PrintToBitmap(text, new BitmapFont.FontRenderSettings() + { + TopColor = textPane.FontTopColor.Color, + BottomColor = textPane.FontBottomColor.Color, + CharSpacing = (int)textPane.CharacterSpace, + XScale = (textPane.FontSize.X / TextureGlyph.CellWidth), + YScale = (textPane.FontSize.Y / TextureGlyph.CellHeight), + LineSpacing = (int)textPane.LineSpace, + }); + } + + public BitmapFont GetBitmapFont(bool UseChannelComp = false) + { + var FontInfo = FontSection; + var TextureGlyph = FontInfo.TextureGlyph; + + BitmapFont f = new BitmapFont(); + f.LineHeight = FontInfo.LineFeed; + Bitmap[] Chars = new Bitmap[TextureGlyph.LinesCount * TextureGlyph.RowCount * TextureGlyph.SheetCount]; + + float realcellwidth = TextureGlyph.CellWidth + 1; + float realcellheight = TextureGlyph.CellHeight + 1; + + int j = 0; + for (int sheet = 0; sheet < TextureGlyph.SheetCount; sheet++) + { + Bitmap SheetBM = TextureGlyph.GetImageSheet(sheet).GetBitmap(); + + if (UseChannelComp) + SheetBM = TextureGlyph.GetImageSheet(sheet).GetComponentBitmap(SheetBM, true); + + if (Platform >= PlatformType.Cafe) + SheetBM.RotateFlip(RotateFlipType.RotateNoneFlipY); + BitmapData bd = SheetBM.LockBits(new Rectangle(0, 0, SheetBM.Width, SheetBM.Height), + ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + + for (int y = 0; y < TextureGlyph.LinesCount; y++) + { + for (int x = 0; x < TextureGlyph.RowCount; x++) + { + Bitmap b = new Bitmap(TextureGlyph.CellWidth, TextureGlyph.CellHeight); + BitmapData bd2 = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), + ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + + for (int y2 = 0; y2 < TextureGlyph.CellHeight; y2++) + { + for (int x2 = 0; x2 < TextureGlyph.CellWidth; x2++) + { + Marshal.WriteInt32(bd2.Scan0, y2 * bd2.Stride + x2 * 4, + Marshal.ReadInt32(bd.Scan0, (int)(y * realcellheight + y2 + 1) * + bd.Stride + (int)(x * realcellwidth + x2 + 1) * 4)); + } + } + b.UnlockBits(bd2); + Chars[j++] = b; + } + } + SheetBM.UnlockBits(bd); + } + + foreach (var charMap in FontInfo.CodeMapDictionary) + { + var idx = charMap.Value; + if (idx == 0xFFFF) continue; + var info = GetCharWidthInfoByIndex(FontInfo, (ushort)idx); + + f.Characters.Add(charMap.Key, new BitmapFont.Character(Chars[idx], info.Left, info.GlyphWidth, info.CharWidth)); + } + + return f; + } + + private CharacterWidthEntry GetCharWidthInfoByIndex(FINF fontInfo, UInt16 Index) + { + foreach (var v in fontInfo.CharacterWidths) + { + if (Index < v.StartIndex || Index > v.EndIndex) continue; + return v.WidthEntries[Index - v.StartIndex]; + } + return null; + } + } +} diff --git a/File_Format_Library/FileFormats/Font/BffntCharSet2Xlor.cs b/File_Format_Library/FileFormats/Font/BXFNT/BffntCharSet2Xlor.cs similarity index 98% rename from File_Format_Library/FileFormats/Font/BffntCharSet2Xlor.cs rename to File_Format_Library/FileFormats/Font/BXFNT/BffntCharSet2Xlor.cs index e7ab345e..34c85f7a 100644 --- a/File_Format_Library/FileFormats/Font/BffntCharSet2Xlor.cs +++ b/File_Format_Library/FileFormats/Font/BXFNT/BffntCharSet2Xlor.cs @@ -9,7 +9,7 @@ namespace FirstPlugin { public class BffntCharSet2Xlor { - public static string ToXlor(BFFNT bffnt) + public static string ToXlor(BXFNT bffnt) { StringBuilder sb = new StringBuilder(); using (var texWriter = new StringWriter(sb)) diff --git a/File_Format_Library/FileFormats/Font/BXFNT/BxfntYamlConverter.cs b/File_Format_Library/FileFormats/Font/BXFNT/BxfntYamlConverter.cs new file mode 100644 index 00000000..ba856092 --- /dev/null +++ b/File_Format_Library/FileFormats/Font/BXFNT/BxfntYamlConverter.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using SharpYaml.Serialization; + +namespace FirstPlugin +{ + public class BxfntYamlConverter + { + public static string ToYaml(FFNT header) + { + YamlMappingNode mapping = new YamlMappingNode(); + mapping.Add("Platform", header.Platform.ToString()); + mapping.Add("Version", header.Version.ToString("X")); + mapping.Add("FontInfo", SaveFontInfo(header.FontSection)); + mapping.Add("KerningTable", SaveKerningTable(header.KerningTable)); + + var doc = new YamlDocument(mapping); + + YamlStream stream = new YamlStream(doc); + var buffer = new StringBuilder(); + using (var writer = new StringWriter(buffer)) { + stream.Save(writer, true); + return writer.ToString(); + } + } + + private static YamlMappingNode SaveFontInfo(FINF fontInfo) + { + YamlMappingNode mapping = new YamlMappingNode(); + mapping.Add("Type", fontInfo.Type.ToString()); + mapping.Add("Font_Width", fontInfo.Width.ToString()); + mapping.Add("Font_Height", fontInfo.Height.ToString()); + mapping.Add("Line_Feed", fontInfo.LineFeed.ToString()); + mapping.Add("Ascent", fontInfo.Ascent.ToString()); + mapping.Add("AlterCharIndex", fontInfo.AlterCharIndex.ToString()); + mapping.Add("DefaultCharWidth", fontInfo.DefaultCharWidth.ToString()); + mapping.Add("DefaultGlyphWidth", fontInfo.DefaultGlyphWidth.ToString()); + mapping.Add("DefaultLeftWidth", fontInfo.DefaultLeftWidth.ToString()); + mapping.Add("Texture_Glyph", SaveTextureGlyph(fontInfo.TextureGlyph)); + mapping.Add("Characters", SaveCharacterMaps(fontInfo)); + mapping.Add("Character Widths", SaveCharacterWidths(fontInfo)); + return mapping; + } + + private static YamlMappingNode SaveTextureGlyph(TGLP texInfo) + { + YamlMappingNode mapping = new YamlMappingNode(); + mapping.Add("Cell_Height", texInfo.CellHeight.ToString()); + mapping.Add("Cell_Width", texInfo.CellWidth.ToString()); + mapping.Add("Format", texInfo.Format.ToString()); + mapping.Add("BaseLinePos", texInfo.BaseLinePos.ToString()); + mapping.Add("MaxCharWidth", texInfo.MaxCharWidth.ToString()); + mapping.Add("Sheet_Height", texInfo.SheetHeight.ToString()); + mapping.Add("Sheet_Width", texInfo.SheetWidth.ToString()); + mapping.Add("RowCount", texInfo.RowCount.ToString()); + mapping.Add("LinesCount", texInfo.LinesCount.ToString()); + return mapping; + } + + private static YamlSequenceNode SaveCharacterMaps(FINF fontInfo) + { + YamlSequenceNode node = new YamlSequenceNode(); + // node.Style = SharpYaml.YamlStyle.Flow; + foreach (var character in fontInfo.CodeMapDictionary.Keys) + { + YamlMappingNode mapping = new YamlMappingNode(); + mapping.Add($"0x{((ushort)character).ToString("X4")}", character.ToString()); + node.Add(mapping); + } + + return node; + } + + private static YamlSequenceNode SaveCharacterWidths(FINF fontInfo) + { + YamlSequenceNode node = new YamlSequenceNode(); + foreach (var character in fontInfo.CodeMapDictionary) + { + YamlMappingNode mapping = new YamlMappingNode(); + mapping.Style = SharpYaml.YamlStyle.Flow; + if (character.Value != -1) { + var width = fontInfo.GetCharacterWidth(character.Value); + mapping.Add($"0x{((ushort)character.Key).ToString("X4")}", SaveCharacterWidth(width)); + } + node.Add(mapping); + } + return node; + } + + private static YamlSequenceNode SaveCharacterWidth(CharacterWidthEntry table) + { + YamlSequenceNode node = new YamlSequenceNode(); + node.Style = SharpYaml.YamlStyle.Flow; + node.Add(NewMappingNode("CharWidth", table.CharWidth.ToString())); + node.Add(NewMappingNode("GlyphWidth", table.GlyphWidth.ToString())); + node.Add(NewMappingNode("Left", table.Left.ToString())); + return node; + } + + private static YamlMappingNode NewMappingNode(string key, string value) + { + return new YamlMappingNode(new YamlScalarNode(key), new YamlScalarNode(value)); + } + + private static YamlMappingNode SaveKerningTable(FontKerningTable table) + { + YamlMappingNode mapping = new YamlMappingNode(); + if (table == null) + return mapping; + + + return mapping; + } + } +} diff --git a/File_Format_Library/FileFormats/Font/BXFNT/CMAP.cs b/File_Format_Library/FileFormats/Font/BXFNT/CMAP.cs new file mode 100644 index 00000000..d545f4a3 --- /dev/null +++ b/File_Format_Library/FileFormats/Font/BXFNT/CMAP.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Threading.Tasks; +using Toolbox.Library.IO; + +namespace FirstPlugin +{ + public interface CharMapping { } + + public class CMAPIndexTable : CharMapping + { + public short[] Table { get; set; } + } + + public class CMAPDirect : CharMapping + { + public ushort Offset { get; set; } + } + + public class CMAPScanMapping : CharMapping + { + public uint[] Codes { get; set; } + public short[] Indexes { get; set; } + } + + public class CMAP + { + public uint SectionSize; + + public char CharacterCodeBegin { get; set; } + public char CharacterCodeEnd { get; set; } + + public Mapping MappingMethod { get; set; } + + private ushort Padding; + + public CharMapping MappingData; + + public enum Mapping : ushort + { + Direct, + Table, + Scan, + } + + public ushort GetIndexFromCode(ushort code) + { + if (code < CharacterCodeBegin || code > CharacterCodeEnd) return 0xFFFF; + + switch (MappingMethod) + { + case Mapping.Direct: + return (UInt16)(code - CharacterCodeBegin + ((CMAPDirect)MappingData).Offset); + case Mapping.Table: + return (ushort)((CMAPIndexTable)MappingData).Table[code - CharacterCodeBegin]; + case Mapping.Scan: + if (!((CMAPScanMapping)MappingData).Codes.Contains(code)) return 0xFFFF; + else + { + var codes = ((CMAPScanMapping)MappingData).Codes; + var index = Array.FindIndex(codes, map => map == code); + + return (ushort)((CMAPScanMapping)MappingData).Indexes[index]; + } + } + + return 0xFFFF; + } + + public CMAP NextCodeMapSection { get; set; } + + public static void GenerateCMAP(FileReader reader, FFNT header) + { + var fontSection = header.FontSection; + var cmap = new CMAP(); + + + + fontSection.CodeMap = cmap; + } + + public void Read(FileReader reader, FFNT header, List CodeMaps) + { + uint CodeBegin = 0; + uint CodeEnd = 0; + + long pos = reader.Position; + + reader.ReadSignature(4, "CMAP"); + SectionSize = reader.ReadUInt32(); + if (header.Platform == FFNT.PlatformType.NX) + { + CodeBegin = reader.ReadUInt32(); + CodeEnd = reader.ReadUInt32(); + MappingMethod = reader.ReadEnum(true); + Padding = reader.ReadUInt16(); + } + else + { + CodeBegin = reader.ReadUInt16(); + CodeEnd = reader.ReadUInt16(); + MappingMethod = reader.ReadEnum(true); + Padding = reader.ReadUInt16(); + } + + CharacterCodeBegin = (char)CodeBegin; + CharacterCodeEnd = (char)CodeEnd; + + uint NextMapOffset = reader.ReadUInt32(); + + //Mapping methods from + https://github.com/IcySon55/Kuriimu/blob/f670c2719affc1eaef8b4c40e40985881247acc7/src/Cetera/Font/BFFNT.cs#L211 + switch (MappingMethod) + { + case Mapping.Direct: + var charOffset = reader.ReadUInt16(); + for (char i = CharacterCodeBegin; i <= CharacterCodeEnd; i++) + { + int idx = i - CharacterCodeBegin + charOffset; + header.FontSection.CodeMapDictionary[i] = idx < ushort.MaxValue ? idx : 0; + + Console.WriteLine($"direct {i} {idx}"); + } + + MappingData = new CMAPDirect(); + ((CMAPDirect)MappingData).Offset = charOffset; + break; + case Mapping.Table: + List table = new List(); + for (char i = CharacterCodeBegin; i <= CharacterCodeEnd; i++) + { + short idx = reader.ReadInt16(); + if (idx != -1) header.FontSection.CodeMapDictionary[i] = idx; + + Console.WriteLine($"direct {i} {idx}"); + + table.Add(idx); + } + + MappingData = new CMAPIndexTable(); + ((CMAPIndexTable)MappingData).Table = table.ToArray(); + break; + case Mapping.Scan: + var CharEntryCount = reader.ReadUInt16(); + + if (header.Platform == FFNT.PlatformType.NX) + reader.ReadUInt16(); //Padding + + uint[] codes = new uint[CharEntryCount]; + short[] indexes = new short[CharEntryCount]; + + for (int i = 0; i < CharEntryCount; i++) + { + if (header.Platform == FFNT.PlatformType.NX) + { + uint charCode = reader.ReadUInt32(); + short index = reader.ReadInt16(); + short padding = reader.ReadInt16(); + if (index != -1) header.FontSection.CodeMapDictionary[(char)charCode] = index; + + codes[i] = charCode; + indexes[i] = index; + } + else + { + ushort charCode = reader.ReadUInt16(); + short index = reader.ReadInt16(); + if (index != -1) header.FontSection.CodeMapDictionary[(char)charCode] = index; + + Console.WriteLine($"scan {i} {(char)charCode} {index}"); + + codes[i] = charCode; + indexes[i] = index; + } + } + + MappingData = new CMAPScanMapping(); + ((CMAPScanMapping)MappingData).Codes = codes; + ((CMAPScanMapping)MappingData).Indexes = indexes; + break; + } + + if (NextMapOffset != 0) + { + reader.SeekBegin(NextMapOffset - 8); + NextCodeMapSection = new CMAP(); + NextCodeMapSection.Read(reader, header, CodeMaps); + CodeMaps.Add(NextCodeMapSection); + } + else + reader.SeekBegin(pos + SectionSize); + } + + public void Write(FileWriter writer, FFNT Header) + { + Header.BlockCounter += 1; + + long pos = writer.Position; + + writer.WriteSignature("CMAP"); + writer.Write(uint.MaxValue); //Section Size + if (Header.Platform == FFNT.PlatformType.NX) + { + writer.Write((uint)CharacterCodeBegin); + writer.Write((uint)CharacterCodeEnd); + } + else + { + writer.Write((ushort)CharacterCodeBegin); + writer.Write((ushort)CharacterCodeEnd); + } + + writer.Write(MappingMethod, true); + writer.Seek(2); + + long DataPos = writer.Position; + writer.Write(0); //Next Section Offset + + //Write the data + switch (MappingMethod) + { + case Mapping.Direct: + writer.Write(((CMAPDirect)MappingData).Offset); + break; + case Mapping.Table: + for (int i = 0; i < ((CMAPIndexTable)MappingData).Table.Length; i++) + { + writer.Write(((CMAPIndexTable)MappingData).Table[i]); + } + break; + case Mapping.Scan: + writer.Write((ushort)((CMAPScanMapping)MappingData).Codes.Length); + if (Header.Platform == FFNT.PlatformType.NX) + writer.Seek(2); //Padding + + for (int i = 0; i < ((CMAPScanMapping)MappingData).Codes.Length; i++) + { + if (Header.Platform == FFNT.PlatformType.NX) + { + writer.Write((uint)((CMAPScanMapping)MappingData).Codes[i]); + writer.Write(((CMAPScanMapping)MappingData).Indexes[i]); + writer.Write((ushort)0); //Padding + } + else + { + writer.Write((ushort)((CMAPScanMapping)MappingData).Codes[i]); + writer.Write(((CMAPScanMapping)MappingData).Indexes[i]); + } + } + break; + } + writer.AlignBytes(4); //Padding + + //Save section size + long endPos = writer.Position; + using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin)) + { + writer.Write((uint)(endPos - pos)); + } + + if (NextCodeMapSection != null) + { + writer.WriteUint32Offset(DataPos, -8); + NextCodeMapSection.Write(writer, Header); + } + } + + //From https://github.com/dnasdw/3dsfont/blob/79e6f4ab6676d82fdcd6c0f79d9b0d7a343f82b5/src/bcfnt2charset/bcfnt2charset.cpp#L3 + //Todo add the rest of the encoding types + public char CodeToU16Code(FINF.CharacterCode characterCode, ushort code) + { + if (code < 0x20) + { + return (char)0; + } + + switch (characterCode) + { + case FINF.CharacterCode.Unicode: + return (char)code; + } + + return (char)code; + } + } +} diff --git a/File_Format_Library/FileFormats/Font/BXFNT/CWDH.cs b/File_Format_Library/FileFormats/Font/BXFNT/CWDH.cs new file mode 100644 index 00000000..88385cb2 --- /dev/null +++ b/File_Format_Library/FileFormats/Font/BXFNT/CWDH.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; + +namespace FirstPlugin +{ + public class CWDH + { + public ushort StartIndex { get; set; } + public ushort EndIndex { get; set; } + + public List WidthEntries = new List(); + + public CWDH NextWidthSection { get; set; } + + public ushort EntryCount + { + get { return (ushort)(EndIndex - StartIndex + 1); } + } + + public uint SectionSize; + + public void Read(FileReader reader, FFNT header, List CharacterWidths) + { + long pos = reader.Position; + + reader.ReadSignature(4, "CWDH"); + SectionSize = reader.ReadUInt32(); + StartIndex = reader.ReadUInt16(); + EndIndex = reader.ReadUInt16(); + uint NextWidthSectionOffset = reader.ReadUInt32(); + + for (ushort i = StartIndex; i <= EndIndex; i++) + { + var entry = new CharacterWidthEntry(); + entry.Left = reader.ReadSByte(); + entry.GlyphWidth = reader.ReadByte(); + entry.CharWidth = reader.ReadByte(); + WidthEntries.Add(entry); + } + + if (NextWidthSectionOffset != 0) + { + reader.SeekBegin((int)NextWidthSectionOffset - 8); + NextWidthSection = new CWDH(); + NextWidthSection.Read(reader, header, CharacterWidths); + CharacterWidths.Add(NextWidthSection); + } + else + reader.SeekBegin(pos + SectionSize); + } + + public void Write(FileWriter writer, FFNT Header) + { + Header.BlockCounter += 1; + + long pos = writer.Position; + + writer.WriteSignature("CWDH"); + writer.Write(uint.MaxValue); //Section Size + writer.Write(StartIndex); + writer.Write(EndIndex); + + long DataPos = writer.Position; + writer.Write(0); //NextOffset + + for (int i = 0; i < WidthEntries.Count; i++) + { + writer.Write(WidthEntries[i].Left); + writer.Write(WidthEntries[i].GlyphWidth); + writer.Write(WidthEntries[i].CharWidth); + } + + writer.Align(4); + + if (NextWidthSection != null) + { + writer.WriteUint32Offset(DataPos, -8); + NextWidthSection.Write(writer, Header); + } + + //Save section size + long endPos = writer.Position; + using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin)) + { + writer.Write((uint)(endPos - pos)); + } + } + } + + public class CharacterWidthEntry + { + public sbyte Left { get; set; } + public byte GlyphWidth { get; set; } + public byte CharWidth { get; set; } + } +} diff --git a/File_Format_Library/FileFormats/Font/BXFNT/FINF.cs b/File_Format_Library/FileFormats/Font/BXFNT/FINF.cs new file mode 100644 index 00000000..32f04e66 --- /dev/null +++ b/File_Format_Library/FileFormats/Font/BXFNT/FINF.cs @@ -0,0 +1,223 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using Toolbox.Library; +using Toolbox.Library.IO; + +namespace FirstPlugin +{ + public class FINF + { + public Dictionary CodeMapDictionary = new Dictionary(); + + public uint Size; + public FontType Type { get; set; } + public byte Width { get; set; } + public byte Height { get; set; } + public byte Ascent { get; set; } + public ushort LineFeed { get; set; } + public ushort AlterCharIndex { get; set; } + public byte DefaultLeftWidth { get; set; } + public byte DefaultGlyphWidth { get; set; } + public byte DefaultCharWidth { get; set; } + public CharacterCode CharEncoding { get; set; } + public TGLP TextureGlyph; + public CMAP CodeMap; + public CWDH CharacterWidth; + + public List CharacterWidths { get; set; } + public List CodeMaps { get; set; } + + public enum FontType : byte + { + Glyph = 1, + Texture = 2, + PackedTexture = 3, + } + + public enum CharacterCode : byte + { + UTF8 = 0, + Unicode = 1, + ShiftJIS = 2, + CP1252 = 3, + } + + public void Read(FileReader reader, FFNT header) + { + CharacterWidths = new List(); + CodeMaps = new List(); + + string Signature = reader.ReadString(4, Encoding.ASCII); + if (Signature != "FINF") + throw new Exception($"Invalid signature {Signature}! Expected FINF."); + Size = reader.ReadUInt32(); + + if (header.Platform <= FFNT.PlatformType.Ctr && header.Version < 0x04000000) + { + Type = reader.ReadEnum(true); + LineFeed = reader.ReadByte(); + AlterCharIndex = reader.ReadUInt16(); + DefaultLeftWidth = reader.ReadByte(); + DefaultGlyphWidth = reader.ReadByte(); + DefaultCharWidth = reader.ReadByte(); + CharEncoding = reader.ReadEnum(true); + uint tglpOffset = reader.ReadUInt32(); + uint cwdhOffset = reader.ReadUInt32(); + uint cmapOffset = reader.ReadUInt32(); + + Height = reader.ReadByte(); + Width = reader.ReadByte(); + Ascent = reader.ReadByte(); + reader.ReadByte(); //Padding + + //Add counter for TGLP + //Note the other counters are inside sections due to recusive setup + header.BlockCounter += 1; + + TextureGlyph = new TGLP(); + using (reader.TemporarySeek(tglpOffset - 8, SeekOrigin.Begin)) + TextureGlyph.Read(reader, header); + + CharacterWidth = new CWDH(); + CharacterWidths.Add(CharacterWidth); + using (reader.TemporarySeek(cwdhOffset - 8, SeekOrigin.Begin)) + CharacterWidth.Read(reader, header, CharacterWidths); + + CodeMap = new CMAP(); + CodeMaps.Add(CodeMap); + using (reader.TemporarySeek(cmapOffset - 8, SeekOrigin.Begin)) + CodeMap.Read(reader, header, CodeMaps); + + } + else + { + + Type = reader.ReadEnum(true); + Height = reader.ReadByte(); + Width = reader.ReadByte(); + Ascent = reader.ReadByte(); + LineFeed = reader.ReadUInt16(); + AlterCharIndex = reader.ReadUInt16(); + DefaultLeftWidth = reader.ReadByte(); + DefaultGlyphWidth = reader.ReadByte(); + DefaultCharWidth = reader.ReadByte(); + CharEncoding = reader.ReadEnum(true); + uint tglpOffset = reader.ReadUInt32(); + uint cwdhOffset = reader.ReadUInt32(); + uint cmapOffset = reader.ReadUInt32(); + + //Add counter for TGLP + //Note the other counters are inside sections due to recusive setup + header.BlockCounter += 1; + + TextureGlyph = new TGLP(); + using (reader.TemporarySeek(tglpOffset - 8, SeekOrigin.Begin)) + TextureGlyph.Read(reader, header); + + CharacterWidth = new CWDH(); + CharacterWidths.Add(CharacterWidth); + using (reader.TemporarySeek(cwdhOffset - 8, SeekOrigin.Begin)) + CharacterWidth.Read(reader, header, CharacterWidths); + + CodeMap = new CMAP(); + CodeMaps.Add(CodeMap); + using (reader.TemporarySeek(cmapOffset - 8, SeekOrigin.Begin)) + CodeMap.Read(reader, header, CodeMaps); + + } + } + + public void Write(FileWriter writer, FFNT header) + { + long pos = writer.Position; + + writer.WriteSignature("FINF"); + writer.Write(uint.MaxValue); + + long _ofsTGLP = 0; + long _ofsCWDH = 0; + long _ofsCMAP = 0; + if (header.Platform <= FFNT.PlatformType.Ctr && header.Version < 0x04000000) + { + writer.Write(Type, true); + writer.Write((byte)LineFeed); + writer.Write(AlterCharIndex); + writer.Write(DefaultLeftWidth); + writer.Write(DefaultGlyphWidth); + writer.Write(DefaultCharWidth); + writer.Write(CharEncoding, true); + + _ofsTGLP = writer.Position; + writer.Write(uint.MaxValue); + _ofsCWDH = writer.Position; + writer.Write(uint.MaxValue); + _ofsCMAP = writer.Position; + writer.Write(uint.MaxValue); + + writer.Write(Height); + writer.Write(Width); + writer.Write(Ascent); + writer.Write((byte)0); + } + else + { + writer.Write(Type, true); + writer.Write(Height); + writer.Write(Width); + writer.Write(Ascent); + writer.Write(LineFeed); + writer.Write(AlterCharIndex); + writer.Write(DefaultLeftWidth); + writer.Write(DefaultGlyphWidth); + writer.Write(DefaultCharWidth); + writer.Write(CharEncoding, true); + _ofsTGLP = writer.Position; + writer.Write(uint.MaxValue); + _ofsCWDH = writer.Position; + writer.Write(uint.MaxValue); + _ofsCMAP = writer.Position; + writer.Write(uint.MaxValue); + } + + + //Save section size + long endPos = writer.Position; + using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin)) + { + writer.Write((uint)(endPos - pos)); + } + + //Save Texture Glyph + writer.WriteUint32Offset(_ofsTGLP, -8); + TextureGlyph.Write(writer, header); + + //Save Character Widths + writer.WriteUint32Offset(_ofsCWDH, -8); + CharacterWidth.Write(writer, header); + + //Save Code Maps + writer.WriteUint32Offset(_ofsCMAP, -8); + CodeMap.Write(writer, header); + } + + public CharacterWidthEntry GetCharacterWidth(int index) + { + if (index == -1) + return null; + + for (int i = 0; i < CharacterWidths.Count; i++) + { + if (CharacterWidths[i].StartIndex <= index && CharacterWidths[i].EndIndex >= index) + { + int CharaIndex = index - CharacterWidths[i].StartIndex; + return CharacterWidths[i].WidthEntries[CharaIndex]; + } + } + + throw new Exception("Failed to get valid character index!"); + } + } +} diff --git a/File_Format_Library/FileFormats/Font/BXFNT/FontKerningTable.cs b/File_Format_Library/FileFormats/Font/BXFNT/FontKerningTable.cs new file mode 100644 index 00000000..ceba6aec --- /dev/null +++ b/File_Format_Library/FileFormats/Font/BXFNT/FontKerningTable.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; + +namespace FirstPlugin +{ + //Kerning Table + //https://github.com/dnasdw/3dsfont/blob/4ead538d225d5d05929dce9d736bec91a6158052/src/bffnt/ResourceFormat.h + public class FontKerningTable + { + private byte[] Data; + + public KerningFirstTable FirstTable { get; set; } + + public void Read(FileReader reader, FFNT Header, uint size) + { + Data = reader.ReadBytes((int)(size - 8)); + + /* if (Header.Platform == FFNT.PlatformType.NX) + { + ushort FirstWordCount = reader.ReadUInt16(); + ushort padding = reader.ReadUInt16(); + + FirstTable = new KerningFirstTable(); + FirstTable.Read(reader, Header); + } + else + { + ushort FirstWordCount = reader.ReadUInt16(); + + FirstTable = new KerningFirstTable(); + FirstTable.Read(reader, Header); + }*/ + } + + public void Write(FileWriter writer, FFNT Header) + { + long pos = writer.Position; + writer.WriteSignature("KRNG"); + writer.Write(uint.MaxValue); + writer.Write(Data); + writer.WriteSectionSizeU32(pos + 4, pos, writer.Position); + } + } + + public class KerningFirstTable + { + public uint FirstWordCount { get; set; } + public uint Offset { get; set; } + + public void Read(FileReader reader, FFNT Header) + { + if (Header.Platform == FFNT.PlatformType.NX) + { + uint FirstWordCount = reader.ReadUInt32(); + uint Offset = reader.ReadUInt32(); + } + else + { + uint FirstWordCount = reader.ReadUInt16(); + uint Offset = reader.ReadUInt16(); + } + } + } +} diff --git a/File_Format_Library/FileFormats/Font/BXFNT/Images/CtrImageBlock.cs b/File_Format_Library/FileFormats/Font/BXFNT/Images/CtrImageBlock.cs new file mode 100644 index 00000000..4e12d367 --- /dev/null +++ b/File_Format_Library/FileFormats/Font/BXFNT/Images/CtrImageBlock.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using Toolbox.Library; +using System.Windows.Forms; +using Toolbox.Library.Forms; + +namespace FirstPlugin +{ + public class CtrImageBlock : STGenericTexture + { + public TGLP TextureTGLP; + + public int SheetIndex = 0; + + public void Load(TGLP texture, int Index) + { + CanReplace = true; + + SheetIndex = Index; + TextureTGLP = texture; + Height = TextureTGLP.SheetHeight; + Width = TextureTGLP.SheetWidth; + var BFNTFormat = (CTR_3DS.PICASurfaceFormat)TextureTGLP.Format; + Format = CTR_3DS.ConvertPICAToGenericFormat(BFNTFormat); + + if (Format == TEX_FORMAT.A4) { + RedChannel = STChannelType.Alpha; + GreenChannel = STChannelType.Alpha; + BlueChannel = STChannelType.Alpha; + AlphaChannel = STChannelType.Alpha; + } + + PlatformSwizzle = PlatformSwizzle.Platform_3DS; + + ImageKey = "Texture"; + SelectedImageKey = "Texture"; + } + + public override bool CanEdit { get; set; } = true; + public override string ExportFilter => FileFilters.GTX; + public override string ReplaceFilter => FileFilters.GTX; + + public override void Replace(string FileName) + { + + } + + public override TEX_FORMAT[] SupportedFormats + { + get + { + return new TEX_FORMAT[] { + TEX_FORMAT.R8_UNORM, + TEX_FORMAT.BC1_UNORM_SRGB, + TEX_FORMAT.BC1_UNORM, + TEX_FORMAT.BC2_UNORM, + TEX_FORMAT.BC2_UNORM_SRGB, + TEX_FORMAT.BC3_UNORM, + TEX_FORMAT.BC3_UNORM_SRGB, + TEX_FORMAT.BC4_UNORM, + TEX_FORMAT.BC5_UNORM, + TEX_FORMAT.R8G8_UNORM, + TEX_FORMAT.B5G6R5_UNORM, + TEX_FORMAT.B5G5R5A1_UNORM, + TEX_FORMAT.R8G8B8A8_UNORM_SRGB, + TEX_FORMAT.R8G8B8A8_UNORM, + }; + } + } + + public override void SetImageData(Bitmap bitmap, int ArrayLevel) + { + + } + + public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0, int DepthLevel = 0) + { + return TextureTGLP.SheetDataList[SheetIndex]; + } + + public override void OnClick(TreeView treeview) + { + UpdateEditor(); + } + + private void UpdateEditor() + { + ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase)); + if (editor == null) + { + editor = new ImageEditorBase(); + editor.Dock = DockStyle.Fill; + LibraryGUI.LoadEditor(editor); + } + + Properties prop = new Properties(); + prop.Width = Width; + prop.Height = Height; + prop.Depth = Depth; + prop.MipCount = MipCount; + prop.ArrayCount = ArrayCount; + prop.ImageSize = (uint)TextureTGLP.SheetDataList[SheetIndex].Length; + prop.Format = Format; + + editor.Text = Text; + editor.LoadProperties(prop); + editor.LoadImage(this); + } + } + +} diff --git a/File_Format_Library/FileFormats/Font/BXFNT/Images/Gx2ImageBlock.cs b/File_Format_Library/FileFormats/Font/BXFNT/Images/Gx2ImageBlock.cs new file mode 100644 index 00000000..20e0e0e6 --- /dev/null +++ b/File_Format_Library/FileFormats/Font/BXFNT/Images/Gx2ImageBlock.cs @@ -0,0 +1,277 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using Toolbox.Library; +using System.Windows.Forms; +using Toolbox.Library.Forms; + +namespace FirstPlugin +{ + public class Gx2ImageBlock : STGenericTexture + { + public TGLP TextureTGLP; + + public int SheetIndex = 0; + + public void Load(TGLP texture, int Index) + { + CanReplace = true; + + SheetIndex = Index; + TextureTGLP = texture; + Height = TextureTGLP.SheetHeight; + Width = TextureTGLP.SheetWidth; + var BFNTFormat = (Gx2ImageFormats)TextureTGLP.Format; + Format = ConvertToGeneric(BFNTFormat); + if (Format == TEX_FORMAT.BC4_UNORM) + { + AlphaChannel = STChannelType.Red; + } + + ImageKey = "Texture"; + SelectedImageKey = "Texture"; + } + + + public enum Gx2ImageFormats + { + RGBA8_UNORM, + RGB8_UNORM, + RGB5A1_UNORM, + RGB565_UNORM, + RGBA4_UNORM, + LA8_UNORM, + LA4_UNORM, + A4_UNORM, + A8_UNORM, + BC1_UNORM, + BC2_UNORM, + BC3_UNORM, + BC4_UNORM, + BC5_UNORM, + RGBA8_SRGB, + BC1_SRGB, + BC2_SRGB, + BC3_SRGB, + } + + public override bool CanEdit { get; set; } = true; + public override string ExportFilter => FileFilters.GTX; + public override string ReplaceFilter => FileFilters.GTX; + + public override void Replace(string FileName) + { + Bfres.Structs.FTEX ftex = new Bfres.Structs.FTEX(); + ftex.ReplaceTexture(FileName, Format, 1, 0, SupportedFormats, true, true, false); + if (ftex.texture != null) + { + TextureTGLP.Format = (ushort)ConvertToGx2(ftex.Format); + TextureTGLP.SheetHeight = (ushort)ftex.texture.Height; + TextureTGLP.SheetWidth = (ushort)ftex.texture.Width; + TextureTGLP.SheetDataList[SheetIndex] = ftex.texture.Data; + Format = ftex.Format; + Width = ftex.texture.Width; + Height = ftex.texture.Height; + + UpdateEditor(); + } + } + + public override TEX_FORMAT[] SupportedFormats + { + get + { + return new TEX_FORMAT[] { + TEX_FORMAT.R8_UNORM, + TEX_FORMAT.BC1_UNORM_SRGB, + TEX_FORMAT.BC1_UNORM, + TEX_FORMAT.BC2_UNORM, + TEX_FORMAT.BC2_UNORM_SRGB, + TEX_FORMAT.BC3_UNORM, + TEX_FORMAT.BC3_UNORM_SRGB, + TEX_FORMAT.BC4_UNORM, + TEX_FORMAT.BC5_UNORM, + TEX_FORMAT.R8G8_UNORM, + TEX_FORMAT.B5G6R5_UNORM, + TEX_FORMAT.B5G5R5A1_UNORM, + TEX_FORMAT.R8G8B8A8_UNORM_SRGB, + TEX_FORMAT.R8G8B8A8_UNORM, + }; + } + } + + public TEX_FORMAT ConvertToGeneric(Gx2ImageFormats Format) + { + switch (Format) + { + case Gx2ImageFormats.A8_UNORM: return TEX_FORMAT.R8_UNORM; + case Gx2ImageFormats.BC1_SRGB: return TEX_FORMAT.BC1_UNORM_SRGB; + case Gx2ImageFormats.BC1_UNORM: return TEX_FORMAT.BC1_UNORM; + case Gx2ImageFormats.BC2_UNORM: return TEX_FORMAT.BC2_UNORM; + case Gx2ImageFormats.BC2_SRGB: return TEX_FORMAT.BC2_UNORM_SRGB; + case Gx2ImageFormats.BC3_UNORM: return TEX_FORMAT.BC3_UNORM; + case Gx2ImageFormats.BC3_SRGB: return TEX_FORMAT.BC3_UNORM_SRGB; + case Gx2ImageFormats.BC4_UNORM: return TEX_FORMAT.BC4_UNORM; + case Gx2ImageFormats.BC5_UNORM: return TEX_FORMAT.BC5_UNORM; + case Gx2ImageFormats.LA4_UNORM: return TEX_FORMAT.R4G4_UNORM; + case Gx2ImageFormats.LA8_UNORM: return TEX_FORMAT.R8G8_UNORM; + case Gx2ImageFormats.RGB565_UNORM: return TEX_FORMAT.B5G6R5_UNORM; + case Gx2ImageFormats.RGB5A1_UNORM: return TEX_FORMAT.B5G5R5A1_UNORM; + case Gx2ImageFormats.RGB8_UNORM: return TEX_FORMAT.R8G8_UNORM; + case Gx2ImageFormats.RGBA8_SRGB: return TEX_FORMAT.R8G8B8A8_UNORM_SRGB; + case Gx2ImageFormats.RGBA8_UNORM: return TEX_FORMAT.R8G8B8A8_UNORM; + default: + throw new NotImplementedException("Unsupported format " + Format); + } + } + + public Gx2ImageFormats ConvertToGx2(TEX_FORMAT Format) + { + switch (Format) + { + case TEX_FORMAT.R8_UNORM: return Gx2ImageFormats.A8_UNORM; + case TEX_FORMAT.BC1_UNORM_SRGB: return Gx2ImageFormats.BC1_SRGB; + case TEX_FORMAT.BC1_UNORM: return Gx2ImageFormats.BC1_UNORM; + case TEX_FORMAT.BC2_UNORM_SRGB: return Gx2ImageFormats.BC2_SRGB; + case TEX_FORMAT.BC2_UNORM: return Gx2ImageFormats.BC2_UNORM; + case TEX_FORMAT.BC3_UNORM_SRGB: return Gx2ImageFormats.BC3_SRGB; + case TEX_FORMAT.BC3_UNORM: return Gx2ImageFormats.BC3_UNORM; + case TEX_FORMAT.BC4_UNORM: return Gx2ImageFormats.BC4_UNORM; + case TEX_FORMAT.BC5_UNORM: return Gx2ImageFormats.BC5_UNORM; + case TEX_FORMAT.R4G4_UNORM: return Gx2ImageFormats.LA4_UNORM; + case TEX_FORMAT.R8G8_UNORM: return Gx2ImageFormats.RGB8_UNORM; + case TEX_FORMAT.B5G6R5_UNORM: return Gx2ImageFormats.RGB565_UNORM; + case TEX_FORMAT.B5G5R5A1_UNORM: return Gx2ImageFormats.RGB5A1_UNORM; + case TEX_FORMAT.R8G8B8A8_UNORM_SRGB: return Gx2ImageFormats.RGBA8_SRGB; + case TEX_FORMAT.R8G8B8A8_UNORM: return Gx2ImageFormats.RGBA8_UNORM; + default: + throw new NotImplementedException("Unsupported format " + Format); + } + } + + public override void SetImageData(Bitmap bitmap, int ArrayLevel) + { + if (bitmap == null) + return; //Image is likely disposed and not needed to be applied + + uint Gx2Format = (uint)Bfres.Structs.FTEX.ConvertToGx2Format(Format); + Width = (uint)bitmap.Width; + Height = (uint)bitmap.Height; + + MipCount = 1; + uint[] MipOffsets = new uint[MipCount]; + + try + { + //Create image block from bitmap first + var data = GenerateMipsAndCompress(bitmap, MipCount, Format); + + //Swizzle and create surface + var surface = GX2.CreateGx2Texture(data, Text, + (uint)4, + (uint)0, + (uint)Width, + (uint)Height, + (uint)1, + (uint)Gx2Format, + (uint)SwizzlePattern, + (uint)1, + (uint)MipCount + ); + + TextureTGLP.Format = (ushort)ConvertToGx2(Format); + TextureTGLP.SheetHeight = (ushort)surface.height; + TextureTGLP.SheetWidth = (ushort)surface.width; + TextureTGLP.SheetDataList[SheetIndex] = surface.data; + + IsEdited = true; + UpdateEditor(); + } + catch (Exception ex) + { + STErrorDialog.Show("Failed to swizzle and compress image " + Text, "Error", ex.ToString()); + } + } + + private const uint SwizzleBase = 0x00000000; + + private uint swizzle; + private uint Swizzle + { + get + { + swizzle = SwizzleBase; + swizzle |= (uint)(SheetIndex * 2) << 8; + return swizzle; + } + } + + private uint SwizzlePattern + { + get + { + return (uint)(SheetIndex * 2); + } + } + + public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0, int DepthLevel = 0) + { + uint bpp = GetBytesPerPixel(Format); + + GX2.GX2Surface surf = new GX2.GX2Surface(); + surf.bpp = bpp; + surf.height = Height; + surf.width = Width; + surf.aa = (uint)GX2.GX2AAMode.GX2_AA_MODE_1X; + surf.alignment = 0; + surf.depth = 1; + surf.dim = (uint)GX2.GX2SurfaceDimension.DIM_2D; + surf.format = (uint)Bfres.Structs.FTEX.ConvertToGx2Format(Format); + surf.use = (uint)GX2.GX2SurfaceUse.USE_COLOR_BUFFER; + surf.pitch = 0; + surf.data = TextureTGLP.SheetDataList[SheetIndex]; + surf.numMips = 1; + surf.mipOffset = new uint[0]; + surf.mipData = null; + surf.tileMode = (uint)GX2.GX2TileMode.MODE_2D_TILED_THIN1; + surf.swizzle = Swizzle; + surf.numArray = 1; + + return GX2.Decode(surf, ArrayLevel, MipLevel); + } + + public override void OnClick(TreeView treeview) + { + UpdateEditor(); + } + + private void UpdateEditor() + { + ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase)); + if (editor == null) + { + editor = new ImageEditorBase(); + editor.Dock = DockStyle.Fill; + LibraryGUI.LoadEditor(editor); + } + + Properties prop = new Properties(); + prop.Width = Width; + prop.Height = Height; + prop.Depth = Depth; + prop.MipCount = MipCount; + prop.ArrayCount = ArrayCount; + prop.ImageSize = (uint)TextureTGLP.SheetDataList[SheetIndex].Length; + prop.Format = Format; + prop.Swizzle = Swizzle; + + + editor.Text = Text; + editor.LoadProperties(prop); + editor.LoadImage(this); + } + } + +} diff --git a/File_Format_Library/FileFormats/Font/BXFNT/Images/RevImageBlock.cs b/File_Format_Library/FileFormats/Font/BXFNT/Images/RevImageBlock.cs new file mode 100644 index 00000000..718f9067 --- /dev/null +++ b/File_Format_Library/FileFormats/Font/BXFNT/Images/RevImageBlock.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using Toolbox.Library; +using System.Windows.Forms; +using Toolbox.Library.Forms; + +namespace FirstPlugin +{ + public class RevImageBlock : STGenericTexture + { + public TGLP TextureTGLP; + + public int SheetIndex = 0; + + public void Load(TGLP texture, int Index) + { + CanReplace = true; + + SheetIndex = Index; + TextureTGLP = texture; + Height = TextureTGLP.SheetHeight; + Width = TextureTGLP.SheetWidth; + var BFNTFormat = (Decode_Gamecube.TextureFormats)TextureTGLP.Format; + Format = Decode_Gamecube.ToGenericFormat(BFNTFormat); + + if (Format == TEX_FORMAT.A4) + { + AlphaChannel = STChannelType.Red; + } + + PlatformSwizzle = PlatformSwizzle.Platform_Gamecube; + + ImageKey = "Texture"; + SelectedImageKey = "Texture"; + } + + public override bool CanEdit { get; set; } = true; + public override string ExportFilter => FileFilters.GTX; + public override string ReplaceFilter => FileFilters.GTX; + + public override void Replace(string FileName) + { + + } + + public override TEX_FORMAT[] SupportedFormats + { + get + { + return new TEX_FORMAT[] { + TEX_FORMAT.R8_UNORM, + TEX_FORMAT.BC1_UNORM_SRGB, + TEX_FORMAT.BC1_UNORM, + TEX_FORMAT.BC2_UNORM, + TEX_FORMAT.BC2_UNORM_SRGB, + TEX_FORMAT.BC3_UNORM, + TEX_FORMAT.BC3_UNORM_SRGB, + TEX_FORMAT.BC4_UNORM, + TEX_FORMAT.BC5_UNORM, + TEX_FORMAT.R8G8_UNORM, + TEX_FORMAT.B5G6R5_UNORM, + TEX_FORMAT.B5G5R5A1_UNORM, + TEX_FORMAT.R8G8B8A8_UNORM_SRGB, + TEX_FORMAT.R8G8B8A8_UNORM, + }; + } + } + + public override void SetImageData(Bitmap bitmap, int ArrayLevel) + { + + } + + public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0, int DepthLevel = 0) + { + return TextureTGLP.SheetDataList[SheetIndex]; + } + + public override void OnClick(TreeView treeview) + { + UpdateEditor(); + } + + private void UpdateEditor() + { + ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase)); + if (editor == null) + { + editor = new ImageEditorBase(); + editor.Dock = DockStyle.Fill; + LibraryGUI.LoadEditor(editor); + } + + Properties prop = new Properties(); + prop.Width = Width; + prop.Height = Height; + prop.Depth = Depth; + prop.MipCount = MipCount; + prop.ArrayCount = ArrayCount; + prop.ImageSize = (uint)TextureTGLP.SheetDataList[SheetIndex].Length; + prop.Format = Format; + + editor.Text = Text; + editor.LoadProperties(prop); + editor.LoadImage(this); + } + } + +} diff --git a/File_Format_Library/FileFormats/Font/BXFNT/TGLP.cs b/File_Format_Library/FileFormats/Font/BXFNT/TGLP.cs new file mode 100644 index 00000000..3954a053 --- /dev/null +++ b/File_Format_Library/FileFormats/Font/BXFNT/TGLP.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using Toolbox.Library; +using Toolbox.Library.IO; + +namespace FirstPlugin +{ + public class TGLP + { + public BNTX BinaryTextureFile; + + private List textures = new List(); + public List Textures + { + get { return textures; } + set { textures = value; } + } + + public uint SectionSize; + public byte CellWidth { get; set; } + public byte CellHeight { get; set; } + public byte MaxCharWidth { get; set; } + public byte SheetCount { get; private set; } + public uint SheetSize { get; set; } + public ushort BaseLinePos { get; set; } + public ushort Format { get; set; } + public ushort RowCount { get; set; } + public ushort LinesCount { get; set; } + public ushort SheetWidth { get; set; } + public ushort SheetHeight { get; set; } + public List SheetDataList = new List(); + + public void Read(FileReader reader, FFNT header) + { + string Signature = reader.ReadString(4, Encoding.ASCII); + if (Signature != "TGLP") + throw new Exception($"Invalid signature {Signature}! Expected TGLP."); + SectionSize = reader.ReadUInt32(); + CellWidth = reader.ReadByte(); + CellHeight = reader.ReadByte(); + if (header.Platform <= FFNT.PlatformType.Ctr && header.Version < 0x04000000) + { + BaseLinePos = reader.ReadByte(); + MaxCharWidth = reader.ReadByte(); + SheetSize = reader.ReadUInt32(); + SheetCount = (byte)reader.ReadUInt16(); + } + else + { + SheetCount = reader.ReadByte(); + MaxCharWidth = reader.ReadByte(); + SheetSize = reader.ReadUInt32(); + BaseLinePos = reader.ReadUInt16(); + } + + Format = reader.ReadUInt16(); + RowCount = reader.ReadUInt16(); + LinesCount = reader.ReadUInt16(); + SheetWidth = reader.ReadUInt16(); + SheetHeight = reader.ReadUInt16(); + + uint sheetOffset = reader.ReadUInt32(); + using (reader.TemporarySeek(sheetOffset, SeekOrigin.Begin)) + { + for (int i = 0; i < SheetCount; i++) + { + SheetDataList.Add(reader.ReadBytes((int)SheetSize)); + if (SheetDataList[i].Length != SheetSize) + throw new Exception("SheetSize mis match!"); + } + } + } + + public void Write(FileWriter writer, FFNT header) + { + long pos = writer.Position; + + if (BinaryTextureFile != null) + { + var mem = new System.IO.MemoryStream(); + BinaryTextureFile.Save(mem); + SheetDataList[0] = mem.ToArray(); + } + + writer.WriteSignature("TGLP"); + writer.Write(uint.MaxValue); + writer.Write(CellWidth); + writer.Write(CellHeight); + if (header.Platform <= FFNT.PlatformType.Ctr && header.Version < 0x04000000) + { + writer.Write((byte)BaseLinePos); + writer.Write(MaxCharWidth); + writer.Write(SheetDataList[0].Length); + writer.Write((ushort)SheetDataList.Count); + } + else + { + writer.Write((byte)SheetDataList.Count); + writer.Write(MaxCharWidth); + writer.Write(SheetDataList[0].Length); + writer.Write(BaseLinePos); + } + + writer.Write(Format); + writer.Write(RowCount); + writer.Write(LinesCount); + writer.Write(SheetWidth); + writer.Write(SheetHeight); + long _ofsSheetBlocks = writer.Position; + writer.Write(uint.MaxValue); + + if (header.Platform == FFNT.PlatformType.NX) + writer.Align(4096); + else if (header.Platform == FFNT.PlatformType.Cafe) + writer.Align(8192); + else if (header.Platform == FFNT.PlatformType.Ctr) + writer.Align(64); + else + writer.Align(32); + + long DataPosition = writer.Position; + using (writer.TemporarySeek(_ofsSheetBlocks, SeekOrigin.Begin)) + { + writer.Write((uint)DataPosition); + } + + for (int i = 0; i < SheetDataList.Count; i++) + { + writer.Write(SheetDataList[i]); + } + + + long SectionEndPosition = writer.Position; + //End of section. Set the size + using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin)) + { + writer.Write((uint)(SectionEndPosition - pos)); + } + } + + public STGenericTexture[] GetImageSheets() + { + STGenericTexture[] textures = new STGenericTexture[SheetCount]; + for (int i = 0; i < SheetCount; i++) + textures[i] = GetImageSheet(i); + return textures; + } + + public STGenericTexture GetImageSheet(int Index) + { + if (BinaryTextureFile != null) //BNTX uses only one image with multiple arrays + return BinaryTextureFile.Textures.ElementAt(0).Value; + else + return Textures[Index]; + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BL0.cs b/File_Format_Library/FileFormats/Layout/BLO/BL0.cs new file mode 100644 index 00000000..52be7058 --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BL0.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox; +using System.Windows.Forms; +using Toolbox.Library; +using Toolbox.Library.IO; +using LayoutBXLYT.GCBLO; + +namespace LayoutBXLYT +{ + public class BLO : IFileFormat, IEditorForm + { + public FileType FileType { get; set; } = FileType.Archive; + + public bool CanSave { get; set; } + public string[] Description { get; set; } = new string[] { "GC Layout File" }; + public string[] Extension { get; set; } = new string[] { "*.bl0" }; + 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, "SCRN"); + } + } + + public Type[] Types + { + get + { + List types = new List(); + return types.ToArray(); + } + } + + public LayoutEditor OpenForm() + { + LayoutEditor editor = new LayoutEditor(); + editor.Dock = DockStyle.Fill; + editor.LoadBxlyt(Header); + return editor; + } + + public void FillEditor(Form control) + { + ((LayoutEditor)control).LoadBxlyt(Header); + } + + public BLOHeader Header; + + public void Load(System.IO.Stream stream) + { + using (var reader = new FileReader(stream)) { + Header = new BLOHeader(); + Header.Read(reader, this); + } + } + + public void Unload() + { + + } + + public void Save(System.IO.Stream stream) + { + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BLO1/PAN1.cs b/File_Format_Library/FileFormats/Layout/BLO/BLO1/PAN1.cs new file mode 100644 index 00000000..176d298f --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BLO1/PAN1.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; +using Syroot.Maths; + +namespace LayoutBXLYT.GCBLO +{ + public class PAN1 : BasePane + { + public float Left { get; set; } + public float Top { get; set; } + + public short Angle { get; set; } = 0; + + public AnchorType Anchor { get; set; } = AnchorType.TopLeft; + + public PAN1() : base() + { + } + + public PAN1(FileReader reader, BLOHeader header) : base() + { + byte paramCount = reader.ReadByte(); + Visible = reader.ReadBoolean(); + reader.ReadUInt16(); + Name = reader.ReadString(4, true); + + Left = reader.ReadUInt16(); + Top = reader.ReadUInt16(); + Width = reader.ReadUInt16(); + Height = reader.ReadInt16(); + + paramCount -= 6; + if (paramCount > 0) { + Angle = reader.ReadInt16(); + --paramCount; + } + if (paramCount > 0) { + Anchor = (AnchorType)reader.ReadByte(); + --paramCount; + } + if (paramCount > 0) { + Alpha = reader.ReadByte(); + --paramCount; + } + if (paramCount > 0) { + InfluenceAlpha = reader.ReadBoolean(); + --paramCount; + } + Alpha = 255; + + Translate = GetPosition(); + Scale = new Vector2F(1, 1); + Rotate = new Vector3F(0,0,0); + } + + public Vector3F GetPosition() + { + float X = 0, Y = 0; + switch ((byte)Anchor % 3) + { + case 0: X = 0; break; + case 1: X = Left / 2; break; + case 2: X = Left; break; + } + switch ((byte)Anchor / 3) + { + case 0: Y = 0; break; + case 1: Y = Top / 2; break; + case 2: Y = Top; break; + } + return new Vector3F(X,Y,0); + } + + public virtual void Write(FileWriter writer) + { + + } + + public enum AnchorType + { + TopLeft, + TopMiddle, + TopRight, + + CenterLeft, + CenterMiddle, + CenterRight, + + BottomLeft, + BottomMiddle, + BottomRight, + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BLO1/PIC1.cs b/File_Format_Library/FileFormats/Layout/BLO/BLO1/PIC1.cs new file mode 100644 index 00000000..66563302 --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BLO1/PIC1.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; +using Toolbox.Library; +using Syroot.BinaryData; + +namespace LayoutBXLYT.GCBLO +{ + public class PIC1 : PAN1, IPicturePane + { + public TexCoord[] TexCoords { get; set; } + public STColor8 ColorTopLeft { get; set; } = STColor8.White; + public STColor8 ColorTopRight { get; set; } = STColor8.White; + public STColor8 ColorBottomLeft { get; set; } = STColor8.White; + public STColor8 ColorBottomRight { get; set; } = STColor8.White; + + public string TextureName { get; set; } = ""; + public string PaletteName { get; set; } = ""; + public byte Binding { get; set; } + + public BxlytMaterial Material { get; set; } + + public void CopyMaterial() { + Material = (BxlytMaterial)Material.Clone(); + } + + public ushort MaterialIndex { get; set; } + + public PIC1(FileReader reader, BLOHeader header) : base(reader, header) + { + byte numParams = reader.ReadByte(); + if (numParams > 0) { + TextureName = BloResource.Read(reader, header); + numParams--; + } + if (numParams > 0) { + PaletteName = BloResource.Read(reader, header); + numParams--; + } + if (numParams > 0) { + Binding = reader.ReadByte(); + numParams--; + } + + Material = new Material(); + + if (TextureName == string.Empty) + Material.TextureMaps = new BxlytTextureRef[0]; + else + { + Material.TextureMaps = new BxlytTextureRef[1]; + Material.TextureMaps[0] = new BxlytTextureRef() + { + Name = TextureName, + }; + } + + + TexCoords = new TexCoord[1]; + TexCoords[0] = new TexCoord(); + } + + public void Write(FileWriter writer) + { + + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BLO1/TBX1.cs b/File_Format_Library/FileFormats/Layout/BLO/BLO1/TBX1.cs new file mode 100644 index 00000000..fcc0bb50 --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BLO1/TBX1.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LayoutBXLYT.GCBLO +{ + class TBX1 + { + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BLO1/WIN1.cs b/File_Format_Library/FileFormats/Layout/BLO/BLO1/WIN1.cs new file mode 100644 index 00000000..6fd7f22c --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BLO1/WIN1.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; +using Toolbox.Library; +using Syroot.BinaryData; + +namespace LayoutBXLYT.GCBLO +{ + public class WIN1 : PAN1, IWindowPane + { + public BxlytHeader layoutHeader; + + public bool UseOneMaterialForAll + { + get { return Convert.ToBoolean(_flag & 1); } + set { } + } + + public bool UseVertexColorForAll + { + get { return Convert.ToBoolean((_flag >> 1) & 1); } + set { } + } + + public WindowKind WindowKind { get; set; } + + public bool NotDrawnContent + { + get { return (_flag & 8) == 16; } + set { } + } + + 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; } + private byte _flag; + + private byte frameCount; + public byte FrameCount + { + get { return frameCount; } + set + { + frameCount = value; + } + } + + public System.Drawing.Color[] GetVertexColors() + { + return new System.Drawing.Color[4] + { + Content.ColorTopLeft.Color, + Content.ColorTopRight.Color, + Content.ColorBottomLeft.Color, + Content.ColorBottomRight.Color, + }; + } + + public void ReloadFrames() + { + SetFrames(layoutHeader); + } + + public void SetFrames(BxlytHeader header) + { + + } + + public void CopyWindows() + { + Content = (BxlytWindowContent)Content.Clone(); + for (int f = 0; f < WindowFrames.Count; f++) + WindowFrames[f] = (BxlytWindowFrame)WindowFrames[f].Clone(); + } + + public BxlytWindowContent Content { get; set; } + + public List WindowFrames { get; set; } + + public string PaletteName { get; set; } + + public WIN1(FileReader reader, BLOHeader header) : base(reader, header) + { + byte numParams = reader.ReadByte(); + short transX = reader.ReadInt16(); + short transY = reader.ReadInt16(); + Width = reader.ReadInt16(); + Height = reader.ReadInt16(); + + Translate = GetPosition() + new Syroot.Maths.Vector3F(transX, transY, 0); + + Content = new BxlytWindowContent(header); + Content.Material = new Material(); + Content.Material.TextureMaps = new BxlytTextureRef[0]; + + Console.WriteLine($"numParams {numParams}"); + FrameCount = 4; + WindowKind = WindowKind.Around; + + numParams -= 5; + if (numParams > 0) { + WindowFrames = new List(); + for (int i = 0; i < 4; i++) + { + string texName = BloResource.Read(reader, header); + Console.WriteLine($"texName {texName}"); + + var frame = new WindowFrame(texName); + WindowFrames.Add(frame); + } + } + + /* if (numParams > 0) { + PaletteName = BloResource.Read(reader, header); + numParams--; + } + + PaletteName = BloResource.Read(reader, header); + byte src = reader.ReadByte(); + + for (int i = 0; i < 4; i++) + { + var mirror = (byte)((src >> (6 - (i * 2))) & 0x3); + if (mirror == 1) + WindowFrames[i].TextureFlip = WindowFrameTexFlip.FlipV; + }*/ + } + + public void Write(FileWriter writer) + { + + } + } + + public class WindowFrame : BxlytWindowFrame + { + public STColor8 Color { get; set; } + + public WindowFrame(string name) + { + Material = new Material(); + Material.TextureMaps = new BxlytTextureRef[1]; + Material.TextureMaps[0] = new BxlytTextureRef() + { + Name = name, + }; + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BLO2/MAT1.cs b/File_Format_Library/FileFormats/Layout/BLO/BLO2/MAT1.cs new file mode 100644 index 00000000..c73297b4 --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BLO2/MAT1.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; + +namespace LayoutBXLYT.GCBLO +{ + public static class MAT1 + { + public static List ReadMaterials( + FileReader reader, BLOHeader header) + { + List materials = new List(); + + ushort count = reader.ReadUInt16(); + reader.ReadUInt16(); //0xFF + uint materialDataOffset = reader.ReadUInt32(); + + for (int i = 0; i < count; i++) + materials.Add(new Material()); + + return materials; + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BLO2/PAN2.cs b/File_Format_Library/FileFormats/Layout/BLO/BLO2/PAN2.cs new file mode 100644 index 00000000..49708cbe --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BLO2/PAN2.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; +using Syroot.Maths; + +namespace LayoutBXLYT.GCBLO +{ + public class PAN2 : PAN1 + { + public PAN2(FileReader reader, BLOHeader header) : base() + { + long pos = reader.Position; + + ushort sectionSize = reader.ReadUInt16(); + ushort unk = reader.ReadUInt16(); + uint unk2 = reader.ReadUInt32(); + uint unk3 = reader.ReadUInt32(); + Name = reader.ReadString(0x0C, true); + + Width = reader.ReadSingle(); + Height = reader.ReadSingle(); + Left = reader.ReadSingle(); + Top = reader.ReadSingle(); + + Translate = GetPosition(); + Scale = new Vector2F(1, 1); + Rotate = new Vector3F(0, 0, 0); + Alpha = 255; + Visible = true; + + reader.SeekBegin(pos + sectionSize); + } + + public override void Write(FileWriter writer) + { + + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BLO2/PIC2.cs b/File_Format_Library/FileFormats/Layout/BLO/BLO2/PIC2.cs new file mode 100644 index 00000000..36ea4bc3 --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BLO2/PIC2.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; +using Toolbox.Library; +using Syroot.Maths; + +namespace LayoutBXLYT.GCBLO +{ + public class PIC2 : PAN2, IPicturePane + { + public TexCoord[] TexCoords { get; set; } + public STColor8 ColorTopLeft { get; set; } = STColor8.White; + public STColor8 ColorTopRight { get; set; } = STColor8.White; + public STColor8 ColorBottomLeft { get; set; } = STColor8.White; + public STColor8 ColorBottomRight { get; set; } = STColor8.White; + + public string TextureName { get; set; } = ""; + public string PaletteName { get; set; } = ""; + public byte Binding { get; set; } + + public BxlytMaterial Material { get; set; } + + public void CopyMaterial() + { + Material = (BxlytMaterial)Material.Clone(); + } + + public ushort MaterialIndex { get; set; } + + public PIC2(FileReader reader, BLOHeader header) : base(reader, header) { + TexCoords = new TexCoord[1]; + TexCoords[0] = new TexCoord(); + + ushort sectionSize = reader.ReadUInt16(); + Console.WriteLine($"PIC2 {sectionSize}"); + MaterialIndex = reader.ReadUInt16(); + Material = header.Materials[MaterialIndex]; + uint unk = reader.ReadUInt32(); + //These increase for each material + ushort index1 = reader.ReadUInt16(); + ushort index2 = reader.ReadUInt16(); + ushort index3 = reader.ReadUInt16(); + ushort index4 = reader.ReadUInt16(); + + //I think these are texture coordinates + TexCoords[0].TopLeft = new Vector2F( + reader.ReadInt16() / 256f, + reader.ReadInt16() / 256f); + TexCoords[0].TopRight = new Vector2F( + reader.ReadInt16() / 256f, + reader.ReadInt16() / 256f); + TexCoords[0].BottomLeft = new Vector2F( + reader.ReadInt16() / 256f, + reader.ReadInt16() / 256f); + TexCoords[0].BottomRight = new Vector2F( + reader.ReadInt16() / 256f, + reader.ReadInt16() / 256f); + + ColorTopLeft = STColor8.FromBytes(reader.ReadBytes(4)); + ColorTopRight = STColor8.FromBytes(reader.ReadBytes(4)); + ColorBottomLeft = STColor8.FromBytes(reader.ReadBytes(4)); + ColorBottomRight = STColor8.FromBytes(reader.ReadBytes(4)); + + } + + public override void Write(FileWriter writer) + { + + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BLO2/StringList.cs b/File_Format_Library/FileFormats/Layout/BLO/BLO2/StringList.cs new file mode 100644 index 00000000..f3a5e7d0 --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BLO2/StringList.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; + +namespace LayoutBXLYT.GCBLO +{ + public class StringList + { + public static List Read(FileReader reader, BLOHeader header) + { + List values = new List(); + + ushort count = reader.ReadUInt16(); + if (count == 0) return values; + + ushort unk = reader.ReadUInt16(); //0xFFFF + uint headerSize = reader.ReadUInt32(); //0x10 + + long startpos = reader.Position; + + ushort count2 = reader.ReadUInt16(); //Same as count + ushort[] offsets = reader.ReadUInt16s((int)count); + for (int i = 0; i < count; i++) + { + reader.SeekBegin(startpos + offsets[i]); + values.Add(BloResource.Read(reader, header)); + } + return values; + } + + public static void Write(List values, FileWriter writer, BLOHeader header) + { + writer.Write(values.Count); + writer.Write((ushort)0xFFFF); + writer.Write((ushort)0x10); + + long startpos = writer.Position; + writer.Write(values.Count); + writer.Write(new ushort[values.Count]); + for (int i = 0; i < values.Count; i++) + { + writer.WriteUint16Offset(startpos + (i * 4), startpos); + BloResource.Write(writer, values[i], header); + } + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BLO2/TBX2.cs b/File_Format_Library/FileFormats/Layout/BLO/BLO2/TBX2.cs new file mode 100644 index 00000000..91785e7b --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BLO2/TBX2.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FirstPlugin.FileFormats.Layout.BLO.BLO2 +{ + class TBX2 + { + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BLO2/WIN2.cs b/File_Format_Library/FileFormats/Layout/BLO/BLO2/WIN2.cs new file mode 100644 index 00000000..e5779005 --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BLO2/WIN2.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FirstPlugin.FileFormats.Layout.BLO.BLO2 +{ + class WIN2 + { + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BLOHeader.cs b/File_Format_Library/FileFormats/Layout/BLO/BLOHeader.cs new file mode 100644 index 00000000..c1718135 --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BLOHeader.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; +using Toolbox.Library; +using FirstPlugin; + +namespace LayoutBXLYT.GCBLO +{ + public class BLOHeader : BxlytHeader + { + public Dictionary Resources = + new Dictionary(); + + private List textureList = new List(); + private List fontList = new List(); + private List materialList = new List(); + + public override List Textures + { + get { return textureList; } + } + + public override List Fonts + { + get { return fontList; } + } + + public override List Materials + { + get { return materialList; } + } + + public override Dictionary GetTextures { + get { + Dictionary textures = new Dictionary(); + + var archive = this.FileInfo.IFileInfo.ArchiveParent; + foreach (var tex in Textures) + { + if (archive != null) + { + foreach (var file in archive.Files) + { + string name = System.IO.Path.GetFileName(file.FileName); + + Console.WriteLine($"{name} {tex} {tex.Contains(name)}"); + if (tex.Contains(name)) + { + var fileFormat = file.OpenFile(); + if (fileFormat is BTI) { + textures.Add(tex, (BTI)fileFormat); + } + } + } + } + } + return textures; + } + } + + public INF1 LayoutInfo; + + public void Read(FileReader reader, BLO bloFile) + { + FileInfo = bloFile; + + reader.SetByteOrder(true); + reader.ReadSignature(4, "SCRN"); + string version = reader.ReadString(4, Encoding.ASCII); + switch (version) + { + case "blo0": Version = 0; break; + case "blo1": Version = 1; break; + case "blo2": Version = 2; break; + default: + throw new Exception("Unknown blo version! " + version); + } + uint fileSize = reader.ReadUInt32(); + uint numSections = reader.ReadUInt32(); + reader.Seek(0x10); //padding + + bool setRoot = false; + bool setGroupRoot = false; + + BasePane currentPane = null; + BasePane parentPane = null; + this.RootGroup = new GroupPane(); + for (int i = 0; i < numSections; i++) + { + long pos = reader.Position; + + string Signature = reader.ReadString(4, Encoding.ASCII); + uint SectionSize = reader.ReadUInt32(); + switch (Signature) + { + case "INF1": + LayoutInfo = new INF1(reader, this); + break; + case "TEX1": + textureList = StringList.Read(reader, this); + break; + case "FNT1": + fontList = StringList.Read(reader, this); + break; + case "MAT1": + var mats = MAT1.ReadMaterials(reader, this); + foreach (var mat in mats) + materialList.Add(mat); + break; + case "PAN1": + { + var panel = new PAN1(reader, this); + AddPaneToTable(panel); + if (!setRoot) + { + RootPane = panel; + setRoot = true; + } + + SetPane(panel, parentPane); + currentPane = panel; + } + break; + case "PAN2": + { + var panel = new PAN2(reader, this); + AddPaneToTable(panel); + if (!setRoot) + { + RootPane = panel; + setRoot = true; + } + SetPane(panel, parentPane); + currentPane = panel; + } + break; + case "PIC1": + { + var picturePanel = new PIC1(reader, this); + AddPaneToTable(picturePanel); + + if (picturePanel.TextureName != string.Empty && + !textureList.Contains(picturePanel.TextureName)) + { + textureList.Add(picturePanel.TextureName); + } + + SetPane(picturePanel, parentPane); + currentPane = picturePanel; + break; + } + case "PIC2": + { + reader.ReadUInt32(); //pan1 magic + reader.ReadUInt32(); //pan1 size + var picturePanel = new PIC2(reader, this); + AddPaneToTable(picturePanel); + + SetPane(picturePanel, parentPane); + currentPane = picturePanel; + break; + } + case "WIN1": + var windowPane = new WIN1(reader, this); + AddPaneToTable(windowPane); + + SetPane(windowPane, parentPane); + currentPane = windowPane; + break; + case "BGN1": + if (currentPane != null) + parentPane = currentPane; + break; + case "END1": + if (parentPane != null) + currentPane = parentPane; + parentPane = currentPane.Parent; + break; + case "EXT1": + // reader.ReadUInt32(); + // reader.Align(0x20); + break; + default: + Console.WriteLine("Unknown section!" + Signature); + break; + } + + reader.SeekBegin(pos + SectionSize); + } + } + + private void SetPane(BasePane pane, BasePane parentPane) + { + if (parentPane != null) + { + parentPane.Childern.Add(pane); + pane.Parent = parentPane; + } + } + + public void Write(FileWriter writer) + { + + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BloResource.cs b/File_Format_Library/FileFormats/Layout/BLO/BloResource.cs new file mode 100644 index 00000000..5ee32101 --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BloResource.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; + +namespace LayoutBXLYT.GCBLO +{ + public class BloResource + { + public static string Read(FileReader reader, BLOHeader header) + { + var type = (bloResourceType)reader.ReadByte(); + byte length = reader.ReadByte(); + string name = reader.ReadString(length, true); + Console.WriteLine($"{type} {length} {name}"); + + if (!header.Resources.ContainsKey(name)) + header.Resources.Add(name, type); + return name; + } + + public static void Write(FileWriter writer, string value, BLOHeader header) + { + if (header.Resources.ContainsKey(value)) + writer.Write((byte)header.Resources[value]); + else + writer.Write((byte)bloResourceType.LocalArchive); + + writer.Write((byte)value.Length); + writer.WriteString(value); + } + + public enum bloResourceType + { + None, + LocalDirectory, + LocalArchive, + Global, + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/BloShader.cs b/File_Format_Library/FileFormats/Layout/BLO/BloShader.cs new file mode 100644 index 00000000..56a0b8eb --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/BloShader.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using Toolbox.Library; +using OpenTK; +using OpenTK.Graphics.OpenGL; + +namespace LayoutBXLYT +{ + public class BloShader : BxlytShader + { + public BloShader() : base() { + LoadShaders(); + } + + public override void OnCompiled() + { + SetColor("whiteColor", Color.FromArgb(255, 255, 255, 255)); + SetColor("blackColor", Color.FromArgb(0, 0, 0, 0)); + SetInt("debugShading", 0); + SetInt("hasTexture0", 0); + SetInt("numTextureMaps", 0); + SetInt("flipTexture", 0); + SetInt("textures0", 0); + SetInt("textures1", 0); + SetInt("textures2", 0); + SetBool("AlphaInterpolation", false); + var rotationMatrix = Matrix4.Identity; + SetMatrix("rotationMatrix", ref rotationMatrix); + SetInt("numTevStages", 0); + + SetVec2("uvScale0", new Vector2(1, 1)); + SetFloat("uvRotate0", 0); + SetVec2("uvTranslate0", new Vector2(0, 0)); + SetVec4("IndirectMat0", new Vector4(1, 1, 0, 0)); + SetVec4("IndirectMat1", new Vector4(1, 1, 0, 0)); + SetInt($"texCoords0GenType", 0); + SetInt($"texCoords0Source", 0); + } + + public static void SetMaterials(BxlytShader shader, GCBLO.Material material, + BasePane pane, Dictionary textures) + { + var rotationMatrix = pane.GetRotationMatrix(); + shader.SetMatrix("rotationMatrix", ref rotationMatrix); + + STColor8 WhiteColor = material.WhiteColor; + STColor8 BlackColor = material.BlackColor; + + shader.SetColor("whiteColor", WhiteColor.Color); + shader.SetColor("blackColor", BlackColor.Color); + shader.SetInt("debugShading", (int)Runtime.LayoutEditor.Shading); + shader.SetInt("numTextureMaps", material.TextureMaps.Length); + shader.SetVec2("uvScale0", new Vector2(1, 1)); + shader.SetFloat("uvRotate0", 0); + shader.SetVec2("uvTranslate0", new Vector2(0, 0)); + shader.SetInt("flipTexture", 0); + shader.SetInt("numTevStages", 0); + shader.SetBool("AlphaInterpolation", material.AlphaInterpolation); + shader.SetVec4("IndirectMat0", new Vector4(1, 1, 0, 0)); + shader.SetVec4("IndirectMat1", new Vector4(1, 1, 0, 0)); + shader.SetInt("tevTexMode", 0); + shader.SetInt($"texCoords0GenType", 0); + shader.SetInt($"texCoords0Source", 0); + + LoadTextureUniforms(shader, material, textures); + LoadDefaultBlending(); + } + + public override string VertexShader + { + get + { + string path = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Layout", "Bflyt.vert"); + string legacyPath = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Layout", "Legacy", "Bflyt.vert"); + + if (LayoutEditor.UseLegacyGL) + return System.IO.File.ReadAllText(legacyPath); + else + return System.IO.File.ReadAllText(path); + } + } + + public override string FragmentShader + { + get + { + string path = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Layout", "Bflyt.frag"); + string legacyPath = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Layout", "Legacy", "Bflyt.frag"); + + if (LayoutEditor.UseLegacyGL) + return System.IO.File.ReadAllText(legacyPath); + else + return System.IO.File.ReadAllText(path); + } + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/INF1.cs b/File_Format_Library/FileFormats/Layout/BLO/INF1.cs new file mode 100644 index 00000000..fa11a47c --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/INF1.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; +using Toolbox.Library; + +namespace LayoutBXLYT.GCBLO +{ + public class INF1 : LayoutInfo + { + public uint Unknown { get; set; } + + public STColor8 TintColor { get; set; } + + public INF1() + { + Unknown = 0; + Width = 0; + Height = 0; + TintColor = STColor8.White; + } + + public INF1(FileReader reader, BLOHeader header) + { + Unknown = reader.ReadUInt32(); + Width = reader.ReadUInt16(); + Height = reader.ReadInt16(); + TintColor = reader.ReadColor8RGBA(); + } + + public void Write(FileWriter writer) + { + writer.Write(Unknown); + writer.Write((ushort)Width); + writer.Write((ushort)Height); + writer.Write(TintColor); + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BLO/Material.cs b/File_Format_Library/FileFormats/Layout/BLO/Material.cs new file mode 100644 index 00000000..cb953e5c --- /dev/null +++ b/File_Format_Library/FileFormats/Layout/BLO/Material.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library; + +namespace LayoutBXLYT.GCBLO +{ + public class Material : BxlytMaterial + { + public Material() + { + WhiteColor = STColor8.White; + BlackColor = STColor8.Black; + TevStages = new BxlytTevStage[0]; + TextureMaps = new BxlytTextureRef[0]; + } + } +} diff --git a/File_Format_Library/FileFormats/Layout/BxlytShader.cs b/File_Format_Library/FileFormats/Layout/BxlytShader.cs index 5001f5fb..48de2075 100644 --- a/File_Format_Library/FileFormats/Layout/BxlytShader.cs +++ b/File_Format_Library/FileFormats/Layout/BxlytShader.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using OpenTK.Graphics.OpenGL; using OpenTK; +using Toolbox.Library; namespace LayoutBXLYT { @@ -234,5 +235,119 @@ namespace LayoutBXLYT GL.DeleteShader(fragmentShader); return program; } + + public static void LoadDefaultBlending() + { + GL.Enable(EnableCap.Blend); + GL.Enable(EnableCap.AlphaTest); + GL.AlphaFunc(AlphaFunction.Always, 0f); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + GL.BlendEquation(BlendEquationMode.FuncAdd); + GL.Disable(EnableCap.ColorLogicOp); + GL.LogicOp(LogicOp.Noop); + } + + public static void LoadTextureUniforms(BxlytShader shader, BxlytMaterial material, + Dictionary textures) + { + shader.SetInt("hasTexture0", 0); + shader.SetInt("hasTexture1", 0); + shader.SetInt("hasTexture2", 0); + shader.SetInt("textures0", 0); + shader.SetInt("textures1", 0); + shader.SetInt("textures2", 0); + + BindTextureUniforms(shader, material); + + if (material.TextureMaps.Length > 0 || Runtime.LayoutEditor.Shading == Runtime.LayoutEditor.DebugShading.UVTestPattern) + GL.Enable(EnableCap.Texture2D); + + for (int i = 0; i < 3; i++) + { + //Default UVs as centered + var matTranslate = Matrix4.CreateTranslation(0 / 1 - 0.5f, 0 / 1 - 0.5f, 0); + shader.SetMatrix(String.Format("textureTransforms[{0}]", i), ref matTranslate); + } + + int id = 1; + for (int i = 0; i < material.TextureMaps.Length; i++) + { + string TexName = material.TextureMaps[i].Name; + + if (material.animController.TexturePatterns.ContainsKey((LTPTarget)i)) + TexName = material.animController.TexturePatterns[(LTPTarget)i]; + + if (textures.ContainsKey(TexName)) + { + GL.ActiveTexture(TextureUnit.Texture0 + id); + shader.SetInt($"textures{i}", id); + bool isBinded = BxlytToGL.BindGLTexture(material.TextureMaps[i], textures[TexName]); + if (isBinded) + shader.SetInt($"hasTexture{i}", 1); + + var scale = new Syroot.Maths.Vector2F(1, 1); + float rotate = 0; + var translate = new Syroot.Maths.Vector2F(0, 0); + + int index = i; + + if (material.TextureTransforms.Length > index) + { + var transform = material.TextureTransforms[index]; + scale = transform.Scale; + rotate = transform.Rotate; + translate = transform.Translate; + + foreach (var animItem in material.animController.TextureSRTS) + { + switch (animItem.Key) + { + case LTSTarget.ScaleS: scale.X = animItem.Value; break; + case LTSTarget.ScaleT: scale.Y = animItem.Value; break; + case LTSTarget.Rotate: rotate = animItem.Value; break; + case LTSTarget.TranslateS: translate.X = animItem.Value; break; + case LTSTarget.TranslateT: translate.Y = animItem.Value; break; + } + } + } + + + var matScale = Matrix4.CreateScale(scale.X, scale.Y, 1.0f); + var matRotate = Matrix4.CreateFromAxisAngle(new Vector3(0, 0, 1), MathHelper.DegreesToRadians(rotate)); + var matTranslate = Matrix4.CreateTranslation( + translate.X / scale.X - 0.5f, + translate.Y / scale.Y - 0.5f, 0); + + Matrix4 matTransform = matRotate * matTranslate * matScale; + shader.SetMatrix(String.Format("textureTransforms[{0}]", i), ref matTransform); + + id++; + } + } + } + + private static void BindTextureUniforms(BxlytShader shader, BxlytMaterial material) + { + //Do uv test pattern + GL.ActiveTexture(TextureUnit.Texture10); + GL.Uniform1(GL.GetUniformLocation(shader.program, "uvTestPattern"), 10); + GL.BindTexture(TextureTarget.Texture2D, RenderTools.uvTestPattern.RenderableTex.TexID); + + if (material.TextureMaps.Length > 0) + { + var tex = material.TextureMaps[0]; + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, BxlytToGL.ConvertTextureWrap(tex.WrapModeU)); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, BxlytToGL.ConvertTextureWrap(tex.WrapModeV)); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, BxlytToGL.ConvertMagFilterMode(tex.MaxFilterMode)); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, BxlytToGL.ConvertMinFilterMode(tex.MinFilterMode)); + } + else + { + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureParameterName.ClampToEdge); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureParameterName.ClampToEdge); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); + } + } } } diff --git a/File_Format_Library/FileFormats/Layout/BxlytToGL.cs b/File_Format_Library/FileFormats/Layout/BxlytToGL.cs index c9f84303..435d2b3c 100644 --- a/File_Format_Library/FileFormats/Layout/BxlytToGL.cs +++ b/File_Format_Library/FileFormats/Layout/BxlytToGL.cs @@ -169,6 +169,84 @@ namespace LayoutBXLYT GL.Disable(EnableCap.Texture2D); // ShaderLoader.RevShader.Disable(); } + else if (pane is GCBLO.PIC1) + { + var pic1Pane = pane as GCBLO.PIC1; + + ShaderLoader.BLOShader.Enable(); + BloShader.SetMaterials(ShaderLoader.BLOShader, (GCBLO.Material)pic1Pane.Material, pane, Textures); + + Color[] Colors = new Color[] { + pic1Pane.ColorBottomLeft.Color, + pic1Pane.ColorBottomRight.Color, + pic1Pane.ColorTopRight.Color, + pic1Pane.ColorTopLeft.Color, + }; + + if (pic1Pane.TexCoords.Length > 0) + { + TexCoords = new Vector2[] { + pic1Pane.TexCoords[0].BottomLeft.ToTKVector2(), + pic1Pane.TexCoords[0].BottomRight.ToTKVector2(), + pic1Pane.TexCoords[0].TopRight.ToTKVector2(), + pic1Pane.TexCoords[0].TopLeft.ToTKVector2(), + }; + } + + DrawRectangle(pane, gameWindow, pane.Rectangle, TexCoords, Colors, false, effectiveAlpha, isSelected); + ShaderLoader.BLOShader.Disable(); + } + else if (pane is GCBLO.PIC2) + { + var pic1Pane = pane as GCBLO.PIC2; + + ShaderLoader.BLOShader.Enable(); + BloShader.SetMaterials(ShaderLoader.BLOShader, (GCBLO.Material)pic1Pane.Material, pane, Textures); + + Color[] Colors = new Color[] { + pic1Pane.ColorBottomLeft.Color, + pic1Pane.ColorBottomRight.Color, + pic1Pane.ColorTopRight.Color, + pic1Pane.ColorTopLeft.Color, + }; + + if (pic1Pane.TexCoords.Length > 0) + { + TexCoords = new Vector2[] { + pic1Pane.TexCoords[0].BottomLeft.ToTKVector2(), + pic1Pane.TexCoords[0].BottomRight.ToTKVector2(), + pic1Pane.TexCoords[0].TopRight.ToTKVector2(), + pic1Pane.TexCoords[0].TopLeft.ToTKVector2(), + }; + } + + DrawRectangle(pane, gameWindow, pane.Rectangle, TexCoords, Colors, false, effectiveAlpha, isSelected); + ShaderLoader.BLOShader.Disable(); + } + else + { + var pic1Pane = pane as IPicturePane; + + Color[] Colors = new Color[] { + pic1Pane.ColorBottomLeft.Color, + pic1Pane.ColorBottomRight.Color, + pic1Pane.ColorTopRight.Color, + pic1Pane.ColorTopLeft.Color, + }; + + if (pic1Pane.TexCoords.Length > 0) + { + TexCoords = new Vector2[] { + pic1Pane.TexCoords[0].BottomLeft.ToTKVector2(), + pic1Pane.TexCoords[0].BottomRight.ToTKVector2(), + pic1Pane.TexCoords[0].TopRight.ToTKVector2(), + pic1Pane.TexCoords[0].TopLeft.ToTKVector2(), + }; + } + + DrawRectangle(pane, gameWindow, pane.Rectangle, TexCoords, Colors, false, effectiveAlpha, isSelected); + + } // GL.BindTexture(TextureTarget.Texture2D, 0); // GL.Disable(EnableCap.Texture2D); @@ -228,8 +306,8 @@ namespace LayoutBXLYT GL.LogicOp(logicOp); for (int i = 0; i < 3; i++) { - Matrix4 matTransform = Matrix4.Identity; - mat.Shader.SetMatrix4(String.Format("textureTransforms[{0}]", i), ref matTransform); + var matTranslate = Matrix4.CreateTranslation(0 / 1 - 0.5f, 0 / 1 - 0.5f, 0); + mat.Shader.SetMatrix4(String.Format("textureTransforms[{0}]", i), ref matTranslate); } mat.Shader.Enable(); @@ -576,6 +654,8 @@ namespace LayoutBXLYT shader = ShaderLoader.CtrShader; if (pane is Revolution.PAN1) shader = ShaderLoader.RevShader; + if (pane is GCBLO.PAN1) + shader = ShaderLoader.BLOShader; var window = (IWindowPane)pane; @@ -1120,7 +1200,7 @@ namespace LayoutBXLYT { if (mat is Revolution.Material) ((Revolution.Material)mat).Shader.SetInt("flipTexture", (int)flip); - else + else shader.SetInt("flipTexture", (int)flip); } @@ -1252,6 +1332,11 @@ namespace LayoutBXLYT ShaderLoader.CtrShader.Enable(); BclytShader.SetMaterials(ShaderLoader.CtrShader, (CTR.Material)mat, pane, textures); } + else if (mat is GCBLO.Material) + { + ShaderLoader.BLOShader.Enable(); + BloShader.SetMaterials(ShaderLoader.CtrShader, (GCBLO.Material)mat, pane, textures); + } } private static void RenderWindowContent(BasePane pane, uint sizeX, uint sizeY, BxlytWindowContent content, diff --git a/File_Format_Library/FileFormats/Layout/CAFE/BflytShader.cs b/File_Format_Library/FileFormats/Layout/CAFE/BflytShader.cs index b95d0360..fcfcc57d 100644 --- a/File_Format_Library/FileFormats/Layout/CAFE/BflytShader.cs +++ b/File_Format_Library/FileFormats/Layout/CAFE/BflytShader.cs @@ -130,59 +130,8 @@ namespace LayoutBXLYT shader.SetInt($"tevStage{i}A", (int)material.TevStages[i].AlphaMode); } - for (int i = 0; i < 3; i++) { - Matrix4 matTransform = Matrix4.Identity; - shader.SetMatrix(String.Format("textureTransforms[{0}]", i), ref matTransform); - } - - for (int i = 0; i < material.TextureMaps.Length; i++) - { - var scale = new Syroot.Maths.Vector2F(1, 1); - float rotate = 0; - var translate = new Syroot.Maths.Vector2F(0, 0); - - int index = i; - // if (material.TexCoordGens?.Length > i) - // index = (int)material.TexCoordGens[i].Source / 3 - 10; - - if (material.TextureTransforms.Length > index) - { - var transform = material.TextureTransforms[index]; - scale = transform.Scale; - rotate = transform.Rotate; - translate = transform.Translate; - - foreach (var animItem in material.animController.TextureSRTS) - { - switch (animItem.Key) - { - case LTSTarget.ScaleS: scale.X = animItem.Value; break; - case LTSTarget.ScaleT: scale.Y = animItem.Value; break; - case LTSTarget.Rotate: rotate = animItem.Value; break; - case LTSTarget.TranslateS: translate.X = animItem.Value; break; - case LTSTarget.TranslateT: translate.Y = animItem.Value; break; - } - } - } - - var matScale = Matrix4.CreateScale(scale.X, scale.Y, 1.0f); - var matRotate = Matrix4.CreateFromAxisAngle(new Vector3(0, 0, 1), MathHelper.DegreesToRadians(rotate)); - var matTranslate = Matrix4.CreateTranslation( - translate.X / scale.X - 0.5f, - translate.Y / scale.Y - 0.5f, 0); - - Matrix4 matTransform = matRotate * matTranslate * matScale; - shader.SetMatrix(String.Format("textureTransforms[{0}]", i), ref matTransform); - } - - - GL.Enable(EnableCap.Blend); - GL.Enable(EnableCap.AlphaTest); - GL.AlphaFunc(AlphaFunction.Always, 0f); - GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); - GL.BlendEquation(BlendEquationMode.FuncAdd); - GL.Disable(EnableCap.ColorLogicOp); - GL.LogicOp(LogicOp.Noop); + LoadTextureUniforms(shader, material, textures); + LoadDefaultBlending(); if (material.BlendMode != null && material.EnableBlend) { diff --git a/File_Format_Library/FileFormats/Layout/CAFE/Panes/PRT1.cs b/File_Format_Library/FileFormats/Layout/CAFE/Panes/PRT1.cs index 707d2ed0..ba6a7beb 100644 --- a/File_Format_Library/FileFormats/Layout/CAFE/Panes/PRT1.cs +++ b/File_Format_Library/FileFormats/Layout/CAFE/Panes/PRT1.cs @@ -336,6 +336,9 @@ namespace LayoutBXLYT.Cafe if (userDataOffset != 0) { reader.SeekBegin(StartPosition + userDataOffset); + reader.ReadUInt32();//magic + reader.ReadUInt32();//section size + UserData = new USD1(reader, header); } if (panelInfoOffset != 0) @@ -376,7 +379,12 @@ namespace LayoutBXLYT.Cafe if (UserData != null) { writer.WriteUint32Offset(_ofsPos + 4, startPos); + long pos = writer.Position; + writer.WriteSignature("usd1"); + writer.Write(uint.MaxValue); UserData.Write(writer, header); + writer.Align(4); + writer.WriteSectionSizeU32(pos + 4, pos, writer.Position); } } diff --git a/File_Format_Library/FileFormats/Layout/CAFE/Panes/TXT1.cs b/File_Format_Library/FileFormats/Layout/CAFE/Panes/TXT1.cs index 5eb48c85..767e58cb 100644 --- a/File_Format_Library/FileFormats/Layout/CAFE/Panes/TXT1.cs +++ b/File_Format_Library/FileFormats/Layout/CAFE/Panes/TXT1.cs @@ -252,6 +252,8 @@ namespace LayoutBXLYT.Cafe long startPos = reader.Position - 84; + Console.WriteLine($"{Name}"); + TextLength = reader.ReadUInt16(); MaxTextLength = reader.ReadUInt16(); MaterialIndex = reader.ReadUInt16(); @@ -302,7 +304,6 @@ namespace LayoutBXLYT.Cafe TextBoxName = reader.ReadZeroTerminatedString(); } - if (header.VersionMajor > 2 && PerCharTransformEnabled) { reader.SeekBegin(startPos + perCharTransformOffset); diff --git a/File_Format_Library/FileFormats/Layout/CTR/BclytShader.cs b/File_Format_Library/FileFormats/Layout/CTR/BclytShader.cs index 62958f4e..5f4ef6bd 100644 --- a/File_Format_Library/FileFormats/Layout/CTR/BclytShader.cs +++ b/File_Format_Library/FileFormats/Layout/CTR/BclytShader.cs @@ -60,86 +60,8 @@ namespace LayoutBXLYT shader.SetInt($"texCoords0GenType", 0); shader.SetInt($"texCoords0Source", 0); - BindTextureUniforms(shader, material); - - int id = 1; - for (int i = 0; i < material.TextureMaps.Length; i++) - { - string TexName = material.TextureMaps[i].Name; - if (material.animController.TexturePatterns.ContainsKey((LTPTarget)i)) - TexName = material.animController.TexturePatterns[(LTPTarget)i]; - - shader.SetInt($"hasTexture{i}", 0); - if (textures.ContainsKey(TexName)) - { - GL.ActiveTexture(TextureUnit.Texture0 + id); - shader.SetInt($"textures{i}", id); - bool binded = BxlytToGL.BindGLTexture(material.TextureMaps[i], textures[TexName]); - shader.SetInt($"hasTexture{i}", binded ? 1 : 0); - id++; - } - } - - for (int i = 0; i < 3; i++) { - Matrix4 matTransform = Matrix4.Identity; - shader.SetMatrix(String.Format("textureTransforms[{0}]", i), ref matTransform); - } - - for (int i = 0; i < material.TextureMaps.Length; i++) { - var scale = new Syroot.Maths.Vector2F(1, 1); - float rotate = 0; - var translate = new Syroot.Maths.Vector2F(0, 0); - - int index = i; - // if (material.TexCoordGens?.Length > i) - // index = (int)material.TexCoordGens[i].Source / 3 - 10; - - if (material.TextureTransforms.Length > index) - { - var transform = material.TextureTransforms[index]; - scale = transform.Scale; - rotate = transform.Rotate; - translate = transform.Translate; - - foreach (var animItem in material.animController.TextureSRTS) - { - switch (animItem.Key) - { - case LTSTarget.ScaleS: scale.X = animItem.Value; break; - case LTSTarget.ScaleT: scale.Y = animItem.Value; break; - case LTSTarget.Rotate: rotate = animItem.Value; break; - case LTSTarget.TranslateS: translate.X = animItem.Value; break; - case LTSTarget.TranslateT: translate.Y = animItem.Value; break; - } - } - } - - var matScale = Matrix4.CreateScale(scale.X, scale.Y, 1.0f); - var matRotate = Matrix4.CreateFromAxisAngle(new Vector3(0, 0, 1), MathHelper.DegreesToRadians(rotate)); - var matTranslate = Matrix4.CreateTranslation( - translate.X / scale.X - 0.5f, - translate.Y / scale.Y - 0.5f, 0); - - Matrix4 matTransform = matRotate * matTranslate * matScale; - shader.SetMatrix(String.Format("textureTransforms[{0}]", i), ref matTransform); - } - } - - private static void BindTextureUniforms(BxlytShader shader, BxlytMaterial material) - { - //Do uv test pattern - GL.ActiveTexture(TextureUnit.Texture10); - GL.Uniform1(GL.GetUniformLocation(shader.program, "uvTestPattern"), 10); - GL.BindTexture(TextureTarget.Texture2D, RenderTools.uvTestPattern.RenderableTex.TexID); - - if (material.TextureMaps.Length > 0) - { - var tex = material.TextureMaps[0]; - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, BxlytToGL.ConvertTextureWrap(tex.WrapModeU)); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, BxlytToGL.ConvertTextureWrap(tex.WrapModeV)); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, BxlytToGL.ConvertMagFilterMode(tex.MaxFilterMode)); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, BxlytToGL.ConvertMinFilterMode(tex.MinFilterMode)); - } + LoadTextureUniforms(shader, material, textures); + LoadDefaultBlending(); } public override string VertexShader diff --git a/File_Format_Library/FileFormats/Layout/Common.cs b/File_Format_Library/FileFormats/Layout/Common.cs index 5ea26090..b9c05e3c 100644 --- a/File_Format_Library/FileFormats/Layout/Common.cs +++ b/File_Format_Library/FileFormats/Layout/Common.cs @@ -334,7 +334,7 @@ namespace LayoutBXLYT [Browsable(false)] [YamlIgnore] - public CustomRectangle Rectangle + public virtual CustomRectangle Rectangle { get { @@ -1405,6 +1405,15 @@ namespace LayoutBXLYT return this.MemberwiseClone(); } + public BxlytWindowContent(BxlytHeader header) { + LayoutFile = header; + ColorTopLeft = STColor8.White; + ColorTopRight = STColor8.White; + ColorBottomLeft = STColor8.White; + ColorBottomRight = STColor8.White; + TexCoords.Add(new TexCoord()); + } + public BxlytWindowContent(BxlytHeader header, string name) { LayoutFile = header; @@ -1476,6 +1485,11 @@ namespace LayoutBXLYT return this.MemberwiseClone(); } + public BxlytWindowFrame() + { + + } + public BxlytWindowFrame(BxlytHeader header, string materialName) { TextureFlip = WindowFrameTexFlip.None; @@ -2548,6 +2562,8 @@ namespace LayoutBXLYT public OpenTK.Vector2 BottomLeftPoint; public OpenTK.Vector2 BottomRightPoint; + public CustomRectangle() { } + public CustomRectangle(OpenTK.Vector2 topLeft, OpenTK.Vector2 topRight, OpenTK.Vector2 bottomLeft, OpenTK.Vector2 bottomRight) { diff --git a/File_Format_Library/FileFormats/Layout/Rev/BrlytShader.cs b/File_Format_Library/FileFormats/Layout/Rev/BrlytShader.cs index 2af6c526..cbfbf9ad 100644 --- a/File_Format_Library/FileFormats/Layout/Rev/BrlytShader.cs +++ b/File_Format_Library/FileFormats/Layout/Rev/BrlytShader.cs @@ -108,60 +108,6 @@ namespace LayoutBXLYT shader.SetInt("tevTexMode", 0); shader.SetInt($"texCoords0GenType", 0); shader.SetInt($"texCoords0Source", 0); - - BindTextureUniforms(shader, material); - - int id = 1; - for (int i = 0; i < material.TextureMaps.Length; i++) - { - string TexName = material.TextureMaps[i].Name; - - if (material.animController.TexturePatterns.ContainsKey((LTPTarget)i)) - TexName = material.animController.TexturePatterns[(LTPTarget)i]; - - if (textures.ContainsKey(TexName)) - { - GL.ActiveTexture(TextureUnit.Texture0 + id); - shader.SetInt($"textures{i}", id); - bool isBinded = BxlytToGL.BindGLTexture(material.TextureMaps[i], textures[TexName]); - if (isBinded) - shader.SetInt($"hasTexture{i}", 1); - - id++; - } - } - - if (material.TextureTransforms.Length > 0) - { - var transform = material.TextureTransforms[0]; - var scale = transform.Scale; - var rotate = transform.Rotate; - var translate = transform.Translate; - - foreach (var animItem in material.animController.TextureSRTS) - { - switch (animItem.Key) - { - case LTSTarget.ScaleS: scale.X = animItem.Value; break; - case LTSTarget.ScaleT: scale.Y = animItem.Value; break; - case LTSTarget.Rotate: rotate = animItem.Value; break; - case LTSTarget.TranslateS: translate.X = animItem.Value; break; - case LTSTarget.TranslateT: translate.Y = animItem.Value; break; - } - } - - shader.SetVec2("uvScale0", new Vector2(scale.X, scale.Y)); - shader.SetFloat("uvRotate0", rotate); - shader.SetVec2("uvTranslate0", new Vector2(translate.X, translate.Y)); - } - - GL.Enable(EnableCap.Blend); - GL.Enable(EnableCap.AlphaTest); - GL.AlphaFunc(AlphaFunction.Always, 0f); - GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); - GL.BlendEquation(BlendEquationMode.FuncAdd); - GL.Disable(EnableCap.ColorLogicOp); - GL.LogicOp(LogicOp.Noop); } private static void BindTextureUniforms(BxlytShader shader, BxlytMaterial material) diff --git a/File_Format_Library/FileFormats/Layout/ShaderLoader.cs b/File_Format_Library/FileFormats/Layout/ShaderLoader.cs index 9cb27db6..3210195a 100644 --- a/File_Format_Library/FileFormats/Layout/ShaderLoader.cs +++ b/File_Format_Library/FileFormats/Layout/ShaderLoader.cs @@ -11,6 +11,7 @@ namespace LayoutBXLYT private static BflytShader cafeShader; private static BrlytShader revShader; private static BclytShader ctrShader; + private static BloShader bloShader; public static BflytShader CafeShader { @@ -39,5 +40,14 @@ namespace LayoutBXLYT return ctrShader; } } + public static BloShader BLOShader + { + get + { + if (bloShader == null) + bloShader = new BloShader(); + return bloShader; + } + } } } diff --git a/File_Format_Library/FileFormats/Message/MSBT.cs b/File_Format_Library/FileFormats/Message/MSBT.cs index f93047fd..828b10ee 100644 --- a/File_Format_Library/FileFormats/Message/MSBT.cs +++ b/File_Format_Library/FileFormats/Message/MSBT.cs @@ -11,7 +11,7 @@ using Toolbox.Library.IO; namespace FirstPlugin { - public class MSBT : IEditor, IFileFormat + public class MSBT : IEditor, IFileFormat, IConvertableTextFormat { public FileType FileType { get; set; } = FileType.Message; @@ -39,6 +39,21 @@ namespace FirstPlugin } } + + #region Text Converter Interface + public TextFileType TextFileType => TextFileType.Xml; + public bool CanConvertBack => false; + + public string ConvertToString() { + return MSYT.ToYaml(this); + } + + public void ConvertFromString(string text) + { + } + + #endregion + public MSBTEditor OpenForm() { MSBTEditor editor = new MSBTEditor(); @@ -56,7 +71,7 @@ namespace FirstPlugin public void Load(System.IO.Stream stream) { - CanSave = false; + CanSave = true; header = new Header(); header.Read(new FileReader(stream)); @@ -113,7 +128,13 @@ namespace FirstPlugin uint FileSize = reader.ReadUInt32(); Reserved = reader.ReadBytes(10); - StringEncoding = (encoding == 0x01 ? Encoding.BigEndianUnicode : Encoding.UTF8); + + if (encoding == 0x00) + StringEncoding = Encoding.UTF8; + else if (reader.IsBigEndian) + StringEncoding = Encoding.BigEndianUnicode; + else + StringEncoding = Encoding.Unicode; for (int i = 0; i < SectionCount; i++) { @@ -151,18 +172,13 @@ namespace FirstPlugin MSBTEntry entry = new MSBTEntry(); entry.Signature = Signature; entry.Padding = reader.ReadBytes(8); - entry.EntryCount = reader.ReadUInt32(); entry.Data = reader.ReadBytes((int)SectionSize); entries.Add(entry); break; } reader.SeekBegin(pos + SectionSize + 0x10); - - while (reader.BaseStream.Position % 16 != 0 && reader.BaseStream.Position != reader.BaseStream.Length) - { - reader.ReadByte(); - } + reader.Align(16); } //Setup labels to text properly @@ -202,6 +218,16 @@ namespace FirstPlugin writer.Write((uint)writer.BaseStream.Length); } } + + public override string ToString() + { + var builder = new StringBuilder(); + using (var textWriter = new StringWriter(builder)) + { + textWriter.Write($""); + } + return builder.ToString(); + } } public class LabelGroup @@ -236,13 +262,15 @@ namespace FirstPlugin { private uint _index; - public StringEntry(byte[] data) - { + public StringEntry(byte[] data) { Data = data; } - public StringEntry(string text, Encoding encoding) - { + public StringEntry(byte[] data, Encoding encoding) { + Data = data; + } + + public StringEntry(string text, Encoding encoding) { Data = encoding.GetBytes(text); } @@ -264,6 +292,35 @@ namespace FirstPlugin { return encoding.GetString(Data); } + + public byte[] ToBytes(Encoding encoding, bool isBigEndian) + { + return Data; + + var mem = new MemoryStream(); + var text = GetText(encoding); + using (var writer = new FileWriter(mem, encoding)) { + writer.SetByteOrder(isBigEndian); + for (int i = 0; i < text.Length; i++) + { + var c = text[i]; + writer.Write(c); + if (c == 0xE) + { + writer.Write((short)text[++i]); + writer.Write((short)text[++i]); + int count = text[++i]; + writer.Write((short)count); + for (var j = 0; j < count; j++) + { + writer.Write((byte)text[++i]); + } + } + } + writer.Write('\0'); + } + return mem.ToArray(); + } } public class TXT2 : MSBTEntry @@ -274,29 +331,33 @@ namespace FirstPlugin public override void Read(FileReader reader, Header header) { + reader.Seek(-4); + uint sectionSize = reader.ReadUInt32(); + Padding = reader.ReadBytes(8); - long Position = reader.Position; + long pos = reader.Position; EntryCount = reader.ReadUInt32(); Offsets = reader.ReadUInt32s((int)EntryCount); for (int i = 0; i < EntryCount; i++) { - reader.SeekBegin(Offsets[i] + Position); - ReadMessageString(reader, header, (uint)i); + //Get the start and end position + uint startPos = Offsets[i] + (uint)pos; + uint endPos = i + 1 < EntryCount ? (uint)pos + Offsets[i + 1] : + (uint)pos + sectionSize; + + reader.SeekBegin(startPos); + ReadMessageString(reader, header, (uint)i, endPos - startPos); } } - private void ReadMessageString(FileReader reader, Header header, uint index) + private void ReadMessageString(FileReader reader, Header header, uint index, uint size) { - string text = ""; - if (header.StringEncoding == Encoding.BigEndianUnicode) - text = reader.ReadUTF16String(); - else - text = reader.ReadZeroTerminatedString(header.StringEncoding); + byte[] textData = reader.ReadBytes((int)size); - TextData.Add(new StringEntry(text, header.StringEncoding) { Index = index, }); - OriginalTextData.Add(new StringEntry(text, header.StringEncoding) { Index = index, }); + TextData.Add(new StringEntry(textData, header.StringEncoding) { Index = index, }); + OriginalTextData.Add(new StringEntry(textData, header.StringEncoding) { Index = index, }); } public override void Write(FileWriter writer, Header header) @@ -307,19 +368,9 @@ namespace FirstPlugin writer.Write(TextData.Count); writer.Write(new uint[TextData.Count]); - for (int i = 0; i < EntryCount; i++) - { + for (int i = 0; i < EntryCount; i++) { writer.WriteUint32Offset(pos + 4 + (i * 4), pos); - if (header.StringEncoding == Encoding.UTF8) - writer.WriteString(TextData[i].ToString(), Encoding.UTF8); - else - { - for (int j = 0; j < TextData[i].ToString().Length; j+= 2) - { - writer.Write(TextData[i].ToString()[j + 1]); - writer.Write(TextData[i].ToString()[j]); - } - } + writer.Write(TextData[i].ToBytes(header.StringEncoding, header.IsBigEndian)); } } @@ -527,13 +578,11 @@ namespace FirstPlugin for (int i = 0; i < group.NumberOfLabels; i++) { LabelEntry entry = new LabelEntry(); - entry.Length = reader.ReadByte(); + entry.Length = reader.ReadByte(); entry.Name = reader.ReadString((int)entry.Length); entry.Index = reader.ReadUInt32(); entry.Checksum = (uint)Groups.IndexOf(group); Labels.Add(entry); - - Console.WriteLine("label entry " + entry.Name); } } @@ -542,11 +591,26 @@ namespace FirstPlugin public override void Write(FileWriter writer, Header header) { - writer.Write(Padding); + writer.Seek(8); - for (int i = 0; i < Groups.Count; i++) - { + long pos = writer.Position; + writer.Write(Groups.Count); + for (int i = 0; i < Groups.Count; i++) { + writer.Write(Groups[i].NumberOfLabels); + writer.Write(uint.MaxValue); + } + int index = 0; + for (int g = 0; g < Groups.Count; g++) { + writer.WriteUint32Offset(pos + 8 + (g * 8), pos); + for (int i = 0; i < Groups[g].NumberOfLabels; i++) + { + writer.Write((byte)Labels[index].Name.Length); + writer.WriteString(Labels[index].Name, Labels[index].Length); + writer.Write(Labels[index].Index); + + index++; + } } } } @@ -557,23 +621,11 @@ namespace FirstPlugin writer.WriteSignature(magic); writer.Write(uint.MaxValue); section.Write(writer, header); - long endPos = writer.Position - 16; - WritePadding(writer); + long endPos = writer.Position; - using (writer.TemporarySeek(startPos + 4, System.IO.SeekOrigin.Begin)) - { - writer.Write((uint)(endPos - startPos)); - } - } - - private static void WritePadding(FileWriter writer) - { - long alignedBytes = writer.BaseStream.Position % 16; - if (alignedBytes > 0) - { - for (int i = 0; i < 16 - alignedBytes; i++) - writer.Write((byte)0xAB); - } + writer.AlignBytes(16, 0xAB); + //Skip 20 bytes from the header + writer.WriteSectionSizeU32(startPos + 4, startPos + 0x10, endPos); } public class MSBTEntry @@ -590,7 +642,6 @@ namespace FirstPlugin public virtual void Write(FileWriter writer, Header header) { writer.Write(Padding); - writer.Write(EntryCount); writer.Write(Data); } } diff --git a/File_Format_Library/FileFormats/Texture/BFLIM.cs b/File_Format_Library/FileFormats/Texture/BFLIM.cs index 9354a8ca..a3ed371f 100644 --- a/File_Format_Library/FileFormats/Texture/BFLIM.cs +++ b/File_Format_Library/FileFormats/Texture/BFLIM.cs @@ -160,7 +160,7 @@ namespace FirstPlugin OpenFileDialog ofd = new OpenFileDialog(); ofd.Multiselect = true; - ofd.Filter = Utils.GetAllFilters(new Type[] { typeof(BFLIM), typeof(BFFNT), typeof(BFRES), typeof(PTCL), typeof(SARC) }); + ofd.Filter = Utils.GetAllFilters(new Type[] { typeof(BFLIM), typeof(BXFNT), typeof(BFRES), typeof(PTCL), typeof(SARC) }); if (ofd.ShowDialog() == DialogResult.OK) { @@ -169,7 +169,7 @@ namespace FirstPlugin { foreach (string file in ofd.FileNames) { - var FileFormat = STFileLoader.OpenFileFormat(file, new Type[] { typeof(BFLIM), typeof(PTCL), typeof(BFRES), typeof(BFFNT), typeof(SARC) }); + var FileFormat = STFileLoader.OpenFileFormat(file, new Type[] { typeof(BFLIM), typeof(PTCL), typeof(BFRES), typeof(BXFNT), typeof(SARC) }); if (FileFormat == null) continue; @@ -202,16 +202,16 @@ namespace FirstPlugin foreach (var file in ((SARC)FileFormat).Files) { - var archiveFile = STFileLoader.OpenFileFormat(file.FileName, new Type[] { typeof(BFLIM), typeof(BFFNT), typeof(PTCL), typeof(BFRES), typeof(SARC) }, file.FileData); + var archiveFile = STFileLoader.OpenFileFormat(file.FileName, new Type[] { typeof(BFLIM), typeof(BXFNT), typeof(PTCL), typeof(BFRES), typeof(SARC) }, file.FileData); if (archiveFile == null) continue; SearchBinary(archiveFile, ArchiveFilePath, Extension); } } - if (FileFormat is BFFNT) + if (FileFormat is BXFNT) { - foreach (STGenericTexture texture in ((BFFNT)FileFormat).bffnt.FontSection.TextureGlyph.Gx2Textures) + foreach (STGenericTexture texture in ((BXFNT)FileFormat).bffnt.FontSection.TextureGlyph.Textures) texture.Export(Path.Combine(Folder, $"{texture.Text}{Extension}")); } if (FileFormat is BFRES) @@ -488,7 +488,7 @@ namespace FirstPlugin { [0] = TEX_FORMAT.L8, [1] = TEX_FORMAT.A8_UNORM, - [2] = TEX_FORMAT.A4, + [2] = TEX_FORMAT.LA4, [3] = TEX_FORMAT.LA8, [4] = TEX_FORMAT.HIL08, [5] = TEX_FORMAT.B5G6R5_UNORM, @@ -512,7 +512,7 @@ namespace FirstPlugin { [0] = TEX_FORMAT.L8, [1] = TEX_FORMAT.A8_UNORM, - [2] = TEX_FORMAT.A4, + [2] = TEX_FORMAT.LA4, [3] = TEX_FORMAT.LA8, [4] = TEX_FORMAT.R8G8_UNORM, //HILO8 [5] = TEX_FORMAT.B5G6R5_UNORM, diff --git a/File_Format_Library/FileFormats/Texture/BNTX.cs b/File_Format_Library/FileFormats/Texture/BNTX.cs index e05ad998..8b5f4761 100644 --- a/File_Format_Library/FileFormats/Texture/BNTX.cs +++ b/File_Format_Library/FileFormats/Texture/BNTX.cs @@ -190,7 +190,7 @@ namespace FirstPlugin OpenFileDialog ofd = new OpenFileDialog(); ofd.Multiselect = true; - ofd.Filter = Utils.GetAllFilters(new Type[] { typeof(BNTX), typeof(BFFNT), typeof(BFRES), typeof(PTCL), typeof(SARC) }); + ofd.Filter = Utils.GetAllFilters(new Type[] { typeof(BNTX), typeof(BXFNT), typeof(BFRES), typeof(PTCL), typeof(SARC) }); if (ofd.ShowDialog() == DialogResult.OK) { @@ -199,7 +199,7 @@ namespace FirstPlugin { foreach (string file in ofd.FileNames) { - var FileFormat = STFileLoader.OpenFileFormat(file, new Type[] { typeof(BNTX), typeof(BFFNT), typeof(BFRES), typeof(PTCL), typeof(SARC) }); + var FileFormat = STFileLoader.OpenFileFormat(file, new Type[] { typeof(BNTX), typeof(BXFNT), typeof(BFRES), typeof(PTCL), typeof(SARC) }); if (FileFormat == null) continue; @@ -230,7 +230,7 @@ namespace FirstPlugin foreach (var file in ((SARC)FileFormat).Files) { - var archiveFile = STFileLoader.OpenFileFormat(file.FileName, new Type[] { typeof(BNTX), typeof(BFFNT), typeof(BFRES), typeof(PTCL), typeof(SARC) }, file.FileData); + var archiveFile = STFileLoader.OpenFileFormat(file.FileName, new Type[] { typeof(BNTX), typeof(BXFNT), typeof(BFRES), typeof(PTCL), typeof(SARC) }, file.FileData); if (archiveFile == null) continue; @@ -264,9 +264,9 @@ namespace FirstPlugin bntx.Unload(); } } - if (FileFormat is BFFNT) + if (FileFormat is BXFNT) { - var bntx = ((BFFNT)FileFormat).bffnt.FontSection.TextureGlyph.BinaryTextureFile; + var bntx = ((BXFNT)FileFormat).bffnt.FontSection.TextureGlyph.BinaryTextureFile; if (bntx != null) { foreach (var texture in bntx.Textures.Values) diff --git a/File_Format_Library/FileFormats/Texture/BTI.cs b/File_Format_Library/FileFormats/Texture/BTI.cs index 3e4e9ced..29aef17a 100644 --- a/File_Format_Library/FileFormats/Texture/BTI.cs +++ b/File_Format_Library/FileFormats/Texture/BTI.cs @@ -8,7 +8,7 @@ using System.Runtime.InteropServices; namespace FirstPlugin { - class BTI : STGenericTexture, IFileFormat, ISingleTextureIconLoader + public class BTI : STGenericTexture, IFileFormat, ISingleTextureIconLoader { public STGenericTexture IconTexture { get { return this; } } diff --git a/File_Format_Library/GUI/BFLYT/Editor/Materials/PaneMatTextureMapsEditor.Designer.cs b/File_Format_Library/GUI/BFLYT/Editor/Materials/PaneMatTextureMapsEditor.Designer.cs index 43ff7915..165cc71c 100644 --- a/File_Format_Library/GUI/BFLYT/Editor/Materials/PaneMatTextureMapsEditor.Designer.cs +++ b/File_Format_Library/GUI/BFLYT/Editor/Materials/PaneMatTextureMapsEditor.Designer.cs @@ -58,6 +58,8 @@ this.stLabel5 = new Toolbox.Library.Forms.STLabel(); this.scaleYUD = new BarSlider.BarSlider(); this.scaleXUD = new BarSlider.BarSlider(); + this.stLabel8 = new Toolbox.Library.Forms.STLabel(); + this.textureNameTB = new Toolbox.Library.Forms.STTextBox(); ((System.ComponentModel.ISupportInitialize)(this.stPanel1)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.stPanel2)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.stPanel3)).BeginInit(); @@ -214,6 +216,8 @@ // stDropDownPanel2 // this.stDropDownPanel2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.stDropDownPanel2.Controls.Add(this.textureNameTB); + this.stDropDownPanel2.Controls.Add(this.stLabel8); this.stDropDownPanel2.Controls.Add(this.shrinkCB); this.stDropDownPanel2.Controls.Add(this.stLabel3); this.stDropDownPanel2.Controls.Add(this.expandCB); @@ -243,7 +247,7 @@ this.shrinkCB.ButtonColor = System.Drawing.Color.Empty; this.shrinkCB.FormattingEnabled = true; this.shrinkCB.IsReadOnly = false; - this.shrinkCB.Location = new System.Drawing.Point(263, 131); + this.shrinkCB.Location = new System.Drawing.Point(263, 152); this.shrinkCB.Name = "shrinkCB"; this.shrinkCB.Size = new System.Drawing.Size(142, 21); this.shrinkCB.TabIndex = 14; @@ -252,7 +256,7 @@ // stLabel3 // this.stLabel3.AutoSize = true; - this.stLabel3.Location = new System.Drawing.Point(183, 134); + this.stLabel3.Location = new System.Drawing.Point(183, 155); this.stLabel3.Name = "stLabel3"; this.stLabel3.Size = new System.Drawing.Size(65, 13); this.stLabel3.TabIndex = 13; @@ -265,7 +269,7 @@ this.expandCB.ButtonColor = System.Drawing.Color.Empty; this.expandCB.FormattingEnabled = true; this.expandCB.IsReadOnly = false; - this.expandCB.Location = new System.Drawing.Point(263, 104); + this.expandCB.Location = new System.Drawing.Point(263, 125); this.expandCB.Name = "expandCB"; this.expandCB.Size = new System.Drawing.Size(142, 21); this.expandCB.TabIndex = 12; @@ -274,7 +278,7 @@ // stLabel4 // this.stLabel4.AutoSize = true; - this.stLabel4.Location = new System.Drawing.Point(183, 107); + this.stLabel4.Location = new System.Drawing.Point(183, 128); this.stLabel4.Name = "stLabel4"; this.stLabel4.Size = new System.Drawing.Size(71, 13); this.stLabel4.TabIndex = 11; @@ -287,7 +291,7 @@ this.wrapModeVCB.ButtonColor = System.Drawing.Color.Empty; this.wrapModeVCB.FormattingEnabled = true; this.wrapModeVCB.IsReadOnly = false; - this.wrapModeVCB.Location = new System.Drawing.Point(263, 66); + this.wrapModeVCB.Location = new System.Drawing.Point(263, 87); this.wrapModeVCB.Name = "wrapModeVCB"; this.wrapModeVCB.Size = new System.Drawing.Size(142, 21); this.wrapModeVCB.TabIndex = 10; @@ -296,7 +300,7 @@ // stLabel2 // this.stLabel2.AutoSize = true; - this.stLabel2.Location = new System.Drawing.Point(183, 69); + this.stLabel2.Location = new System.Drawing.Point(183, 90); this.stLabel2.Name = "stLabel2"; this.stLabel2.Size = new System.Drawing.Size(76, 13); this.stLabel2.TabIndex = 9; @@ -309,7 +313,7 @@ this.wrapModeUCB.ButtonColor = System.Drawing.Color.Empty; this.wrapModeUCB.FormattingEnabled = true; this.wrapModeUCB.IsReadOnly = false; - this.wrapModeUCB.Location = new System.Drawing.Point(263, 39); + this.wrapModeUCB.Location = new System.Drawing.Point(263, 60); this.wrapModeUCB.Name = "wrapModeUCB"; this.wrapModeUCB.Size = new System.Drawing.Size(142, 21); this.wrapModeUCB.TabIndex = 8; @@ -318,7 +322,7 @@ // stLabel1 // this.stLabel1.AutoSize = true; - this.stLabel1.Location = new System.Drawing.Point(183, 42); + this.stLabel1.Location = new System.Drawing.Point(183, 63); this.stLabel1.Name = "stLabel1"; this.stLabel1.Size = new System.Drawing.Size(77, 13); this.stLabel1.TabIndex = 7; @@ -590,6 +594,23 @@ this.scaleXUD.Value = 30F; this.scaleXUD.ValueChanged += new System.EventHandler(this.transformUV_ValueChanged); // + // stLabel8 + // + this.stLabel8.AutoSize = true; + this.stLabel8.Location = new System.Drawing.Point(183, 30); + this.stLabel8.Name = "stLabel8"; + this.stLabel8.Size = new System.Drawing.Size(38, 13); + this.stLabel8.TabIndex = 15; + this.stLabel8.Text = "Name:"; + // + // textureNameTB + // + this.textureNameTB.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.textureNameTB.Location = new System.Drawing.Point(263, 28); + this.textureNameTB.Name = "textureNameTB"; + this.textureNameTB.Size = new System.Drawing.Size(142, 20); + this.textureNameTB.TabIndex = 16; + // // PaneMatTextureMapsEditor // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -643,5 +664,7 @@ private Toolbox.Library.Forms.STLabel stLabel5; private BarSlider.BarSlider scaleYUD; private BarSlider.BarSlider scaleXUD; + private Toolbox.Library.Forms.STTextBox textureNameTB; + private Toolbox.Library.Forms.STLabel stLabel8; } } diff --git a/File_Format_Library/GUI/BFLYT/Editor/Materials/PaneMatTextureMapsEditor.cs b/File_Format_Library/GUI/BFLYT/Editor/Materials/PaneMatTextureMapsEditor.cs index 50a75a52..8bebebd7 100644 --- a/File_Format_Library/GUI/BFLYT/Editor/Materials/PaneMatTextureMapsEditor.cs +++ b/File_Format_Library/GUI/BFLYT/Editor/Materials/PaneMatTextureMapsEditor.cs @@ -56,6 +56,7 @@ namespace LayoutBXLYT ResetImagePanels(); Images.Clear(); + textureNameTB.Text = ""; for (int i = 0; i < ActiveMaterial.TextureMaps?.Length; i++) { @@ -93,6 +94,7 @@ namespace LayoutBXLYT } else { + textureNameTB.Text = ""; editBtn.Enabled = true; removebtn.Enabled = true; addbtn.Enabled = true; @@ -165,6 +167,7 @@ namespace LayoutBXLYT wrapModeVCB.SelectedItem = texMap.WrapModeV; expandCB.SelectedItem = texMap.MaxFilterMode; shrinkCB.SelectedItem = texMap.MinFilterMode; + textureNameTB.Text = texMap.Name; if (ActiveMaterial.TextureTransforms?.Length > SelectedIndex) { diff --git a/File_Format_Library/GUI/BFLYT/Editor/TextEditor/NewTextboxDialog.cs b/File_Format_Library/GUI/BFLYT/Editor/TextEditor/NewTextboxDialog.cs index 83a5a609..446d2f39 100644 --- a/File_Format_Library/GUI/BFLYT/Editor/TextEditor/NewTextboxDialog.cs +++ b/File_Format_Library/GUI/BFLYT/Editor/TextEditor/NewTextboxDialog.cs @@ -49,7 +49,7 @@ namespace LayoutBXLYT { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = Utils.GetAllFilters(new Type[] - { typeof(BFFNT), typeof(BFTTF) }); + { typeof(BXFNT), typeof(BXFNT) }); if (ofd.ShowDialog() == DialogResult.OK) { @@ -58,7 +58,7 @@ namespace LayoutBXLYT btnOk.Enabled = true; var file = STFileLoader.OpenFileFormat(ofd.FileName); - if (file is BFFNT) + if (file is BXFNT) { } diff --git a/File_Format_Library/GUI/BFLYT/LayoutEditor.cs b/File_Format_Library/GUI/BFLYT/LayoutEditor.cs index 9f5951dc..8972ad8c 100644 --- a/File_Format_Library/GUI/BFLYT/LayoutEditor.cs +++ b/File_Format_Library/GUI/BFLYT/LayoutEditor.cs @@ -293,7 +293,8 @@ namespace LayoutBXLYT { AnimationPanel?.Reset(); foreach (ListViewItem item in LayoutAnimList.GetSelectedAnimations) - UpdateAnimationPlayer((BxlanHeader)item.Tag); + if (item.Tag is BxlanHeader) + UpdateAnimationPlayer((BxlanHeader)item.Tag); } } } @@ -704,10 +705,8 @@ namespace LayoutBXLYT LoadBxlyt(((BRLYT)layouts[0]).header); } } - else if (file is BFLAN) - LoadBxlan(((BFLAN)file).BxlanHeader); - else if (file is BRLAN) - LoadBxlan(((BRLAN)file).BxlanHeader); + else if (file is BXLAN) + LoadBxlan(((BXLAN)file).BxlanHeader); else if (file is BNTX) { diff --git a/File_Format_Library/GUI/BFFNT/BffntEditor.Designer.cs b/File_Format_Library/GUI/BXFNT/BffntEditor.Designer.cs similarity index 100% rename from File_Format_Library/GUI/BFFNT/BffntEditor.Designer.cs rename to File_Format_Library/GUI/BXFNT/BffntEditor.Designer.cs diff --git a/File_Format_Library/GUI/BFFNT/BffntEditor.cs b/File_Format_Library/GUI/BXFNT/BffntEditor.cs similarity index 96% rename from File_Format_Library/GUI/BFFNT/BffntEditor.cs rename to File_Format_Library/GUI/BXFNT/BffntEditor.cs index 675f706c..f48c62f2 100644 --- a/File_Format_Library/GUI/BFFNT/BffntEditor.cs +++ b/File_Format_Library/GUI/BXFNT/BffntEditor.cs @@ -10,6 +10,7 @@ using System.Windows.Forms; using Toolbox.Library.Forms; using Toolbox.Library; using LibEveryFileExplorer.GFX; +using Toolbox.Library.IO; namespace FirstPlugin.Forms { @@ -34,9 +35,9 @@ namespace FirstPlugin.Forms private BitmapFont bitmapFont; private FFNT ActiveFile; - private BFFNT FileFormat; + private BXFNT FileFormat; - public void LoadFontFile(BFFNT fontFile) + public void LoadFontFile(BXFNT fontFile) { FileFormat = fontFile; ActiveFile = fontFile.bffnt; @@ -129,18 +130,12 @@ namespace FirstPlugin.Forms bool IsBntx = ActiveFile.FontSection.TextureGlyph.BinaryTextureFile != null; if (IsBntx) - { - PanelImage = image.GetBitmap(ImageIndex); - } + PanelImage = image.GetComponentBitmap(image.GetBitmap(ImageIndex)); else - { - PanelImage = image.GetBitmap(); - } + PanelImage = image.GetComponentBitmap(image.GetBitmap()); - if (PanelImage != null) - { + if (PanelImage != null && ActiveFile.Platform >= FFNT.PlatformType.Cafe) PanelImage.RotateFlip(RotateFlipType.RotateNoneFlipY); - } FillCells(); @@ -168,7 +163,8 @@ namespace FirstPlugin.Forms form.editorBase.Text = Text; form.editorBase.Dock = DockStyle.Fill; - image.Parameters.FlipY = true; + if (ActiveFile.Platform >= FFNT.PlatformType.Cafe) + image.Parameters.FlipY = true; if (IsBntx) { @@ -331,6 +327,8 @@ namespace FirstPlugin.Forms return; Graphics graphics = e.Graphics; + + graphics.Clear(Color.FromArgb(30,30,30)); graphics.DrawImage(PanelImage, 0.0f, 0.0f); if (ActiveFile == null) diff --git a/File_Format_Library/GUI/BFFNT/BffntEditor.resx b/File_Format_Library/GUI/BXFNT/BffntEditor.resx similarity index 100% rename from File_Format_Library/GUI/BFFNT/BffntEditor.resx rename to File_Format_Library/GUI/BXFNT/BffntEditor.resx diff --git a/File_Format_Library/GUI/BXFNT/CharacterSelector.Designer.cs b/File_Format_Library/GUI/BXFNT/CharacterSelector.Designer.cs new file mode 100644 index 00000000..f915c2f7 --- /dev/null +++ b/File_Format_Library/GUI/BXFNT/CharacterSelector.Designer.cs @@ -0,0 +1,45 @@ +namespace FirstPlugin.GUI.BFFNT +{ + partial class CharacterSelector + { + /// + /// 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 Component 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(); + // + // CharacterSelector + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Name = "CharacterSelector"; + this.Size = new System.Drawing.Size(483, 275); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/File_Format_Library/GUI/BXFNT/CharacterSelector.cs b/File_Format_Library/GUI/BXFNT/CharacterSelector.cs new file mode 100644 index 00000000..d547b0b2 --- /dev/null +++ b/File_Format_Library/GUI/BXFNT/CharacterSelector.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace FirstPlugin.GUI.BFFNT +{ + public partial class CharacterSelector : UserControl + { + public CharacterSelector() + { + InitializeComponent(); + } + } +} diff --git a/File_Format_Library/GUI/BXFNT/CharacterSelector.resx b/File_Format_Library/GUI/BXFNT/CharacterSelector.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/File_Format_Library/GUI/BXFNT/CharacterSelector.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/Main.cs b/File_Format_Library/Main.cs index 4affd2d0..3a95164d 100644 --- a/File_Format_Library/Main.cs +++ b/File_Format_Library/Main.cs @@ -349,7 +349,7 @@ namespace FirstPlugin Formats.Add(typeof(BEA)); Formats.Add(typeof(BYAML)); Formats.Add(typeof(XTX)); - Formats.Add(typeof(BFFNT)); + Formats.Add(typeof(BXFNT)); Formats.Add(typeof(MSBT)); Formats.Add(typeof(BARS)); Formats.Add(typeof(GFPAK)); @@ -451,8 +451,7 @@ namespace FirstPlugin Formats.Add(typeof(WTA)); Formats.Add(typeof(BinGzArchive)); Formats.Add(typeof(BNR)); - - + // Formats.Add(typeof(LayoutBXLYT.BLO)); // Formats.Add(typeof(MSBP)); // Formats.Add(typeof(BFGRP)); diff --git a/Switch_Toolbox_Library/Imaging/BitmapExtension.cs b/Switch_Toolbox_Library/Imaging/BitmapExtension.cs index eb9e8f4f..d5c61858 100644 --- a/Switch_Toolbox_Library/Imaging/BitmapExtension.cs +++ b/Switch_Toolbox_Library/Imaging/BitmapExtension.cs @@ -730,6 +730,37 @@ namespace Toolbox.Library } } + public static Bitmap AdjustBrightness(Image image, float level) + { + ImageAttributes attributes = new ImageAttributes(); + + ColorMatrix cm = new ColorMatrix(new float[][] + { + new float[] { level, 0, 0, 0, 0}, + new float[] {0, level, 0, 0, 0}, + new float[] {0, 0, level, 0, 0}, + new float[] {0, 0, 0, 1, 0}, + new float[] {0, 0, 0, 0, 1}, + }); + attributes.SetColorMatrix(cm); + + Point[] points = + { + new Point(0, 0), + new Point(image.Width, 0), + new Point(0, image.Height), + }; + Rectangle rect = new Rectangle(0, 0, image.Width, image.Height); + + Bitmap bm = new Bitmap(image.Width, image.Height); + using (Graphics gr = Graphics.FromImage(bm)) + { + gr.DrawImage(image, points, rect, + GraphicsUnit.Pixel, attributes); + } + return bm; + } + public static Bitmap AdjustGamma(Image image, float gamma) { ImageAttributes attributes = new ImageAttributes(); diff --git a/Switch_Toolbox_Library/Texture Decoding/Gamecube/Decode_Gamecube.cs b/Switch_Toolbox_Library/Texture Decoding/Gamecube/Decode_Gamecube.cs index ffa7f7e4..826718a4 100644 --- a/Switch_Toolbox_Library/Texture Decoding/Gamecube/Decode_Gamecube.cs +++ b/Switch_Toolbox_Library/Texture Decoding/Gamecube/Decode_Gamecube.cs @@ -802,6 +802,29 @@ namespace Toolbox.Library return decodedData; } + public static byte[] DecodeC14X2(FileReader stream, uint width, uint height) + { + byte[] decodedData = new byte[width * height * 2]; + uint numBlocksW = width / 4; //4 pixel block width + uint numBlocksH = height / 4; //4 pixel block height + + for (int yBlock = 0; yBlock < numBlocksH; yBlock++) { + for (int xBlock = 0; xBlock < numBlocksW; xBlock++) { + for (int pY = 0; pY < 4; pY++) { + for (int pX = 0; pX < 4; pX++) + { + if ((xBlock * 4 + pX >= width) || (yBlock * 4 + pY >= height)) + continue; + + ushort value = stream.ReadUInt16(); + } + } + } + } + + return decodedData; + } + private static byte[] DecodeRgb5A3(FileReader stream, uint width, uint height) { byte[] decodedData = new byte[width * height * 4];