Add latest files

Start on base for BLO. These will probably not be usable for awhile and is wip.. Currently aiming to support more varied layouts so this can help improve the code base.
Add BRFNT and BCFNT support. All merged as BXFNT class.
Fix bflim 3ds with LA4 textures.
Fix loading/saving part panes with property user data.
Fix texture coordinates to default centered UVs for layout panes with no textures.
Cleanup some files and directories.
This commit is contained in:
KillzXGaming 2020-02-14 18:25:08 -05:00
parent ba43fa5633
commit af8a8f17f6
55 changed files with 3667 additions and 1719 deletions

File diff suppressed because it is too large Load diff

View file

@ -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;
}
}
}

View file

@ -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<BffntEditor>, 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<Type> types = new List<Type>();
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;
}
}
}

View file

@ -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))

View file

@ -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;
}
}
}

View file

@ -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<CMAP> 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<Mapping>(true);
Padding = reader.ReadUInt16();
}
else
{
CodeBegin = reader.ReadUInt16();
CodeEnd = reader.ReadUInt16();
MappingMethod = reader.ReadEnum<Mapping>(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<short> table = new List<short>();
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;
}
}
}

View file

@ -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<CharacterWidthEntry> WidthEntries = new List<CharacterWidthEntry>();
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<CWDH> 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; }
}
}

View file

@ -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<char, int> CodeMapDictionary = new Dictionary<char, int>();
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<CWDH> CharacterWidths { get; set; }
public List<CMAP> 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<CWDH>();
CodeMaps = new List<CMAP>();
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<FontType>(true);
LineFeed = reader.ReadByte();
AlterCharIndex = reader.ReadUInt16();
DefaultLeftWidth = reader.ReadByte();
DefaultGlyphWidth = reader.ReadByte();
DefaultCharWidth = reader.ReadByte();
CharEncoding = reader.ReadEnum<CharacterCode>(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<FontType>(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<CharacterCode>(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!");
}
}
}

View file

@ -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();
}
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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<STGenericTexture> textures = new List<STGenericTexture>();
public List<STGenericTexture> 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<byte[]> SheetDataList = new List<byte[]>();
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];
}
}
}

View file

@ -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<LayoutEditor>
{
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<Type> types = new List<Type>();
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)
{
}
}
}

View file

@ -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,
}
}
}

View file

@ -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)
{
}
}
}

View file

@ -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
{
}
}

View file

@ -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<BxlytWindowFrame> 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<BxlytWindowFrame>();
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,
};
}
}
}

View file

@ -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<Material> ReadMaterials(
FileReader reader, BLOHeader header)
{
List<Material> materials = new List<Material>();
ushort count = reader.ReadUInt16();
reader.ReadUInt16(); //0xFF
uint materialDataOffset = reader.ReadUInt32();
for (int i = 0; i < count; i++)
materials.Add(new Material());
return materials;
}
}
}

View file

@ -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)
{
}
}
}

View file

@ -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)
{
}
}
}

View file

@ -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<string> Read(FileReader reader, BLOHeader header)
{
List<string> values = new List<string>();
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<string> 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);
}
}
}
}

View file

@ -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
{
}
}

View file

@ -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
{
}
}

View file

@ -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<string, BloResource.bloResourceType> Resources =
new Dictionary<string, BloResource.bloResourceType>();
private List<string> textureList = new List<string>();
private List<string> fontList = new List<string>();
private List<BxlytMaterial> materialList = new List<BxlytMaterial>();
public override List<string> Textures
{
get { return textureList; }
}
public override List<string> Fonts
{
get { return fontList; }
}
public override List<BxlytMaterial> Materials
{
get { return materialList; }
}
public override Dictionary<string, STGenericTexture> GetTextures {
get {
Dictionary<string, STGenericTexture> textures = new Dictionary<string, STGenericTexture>();
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)
{
}
}
}

View file

@ -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,
}
}
}

View file

@ -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<string, STGenericTexture> 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);
}
}
}
}

View file

@ -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);
}
}
}

View file

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

View file

@ -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<string, STGenericTexture> 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);
}
}
}
}

View file

@ -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;
@ -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,

View file

@ -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)
{

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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

View file

@ -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)
{

View file

@ -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)

View file

@ -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;
}
}
}
}

View file

@ -11,7 +11,7 @@ using Toolbox.Library.IO;
namespace FirstPlugin
{
public class MSBT : IEditor<MSBTEditor>, IFileFormat
public class MSBT : IEditor<MSBTEditor>, 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));
}
}
@ -532,8 +583,6 @@ namespace FirstPlugin
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);
}
}

View file

@ -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,

View file

@ -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)

View file

@ -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; } }

View file

@ -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;
}
}

View file

@ -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)
{

View file

@ -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)
{
}

View file

@ -293,6 +293,7 @@ namespace LayoutBXLYT
{
AnimationPanel?.Reset();
foreach (ListViewItem item in LayoutAnimList.GetSelectedAnimations)
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)
{

View file

@ -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,6 +163,7 @@ namespace FirstPlugin.Forms
form.editorBase.Text = Text;
form.editorBase.Dock = DockStyle.Fill;
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)

View file

@ -0,0 +1,45 @@
namespace FirstPlugin.GUI.BFFNT
{
partial class CharacterSelector
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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
}
}

View file

@ -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();
}
}
}

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -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));

View file

@ -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();

View file

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