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];