using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using FirstPlugin.Forms; using System.Windows.Forms; using Toolbox.Library; using Toolbox.Library.IO; using Toolbox.Library.Forms; namespace FirstPlugin { public class SHARCFB : TreeNodeFile, IFileFormat { public FileType FileType { get; set; } = FileType.Shader; public bool CanSave { get; set; } public string[] Description { get; set; } = new string[] { "Binary Shader Archive" }; public string[] Extension { get; set; } = new string[] { "*.sharcfb" }; public string FileName { get; set; } public string FilePath { get; set; } public IFileInfo IFileInfo { get; set; } public bool Identify(System.IO.Stream stream) { using (var reader = new Toolbox.Library.IO.FileReader(stream, true)) { return reader.CheckSignature(4, "BAHS"); } } public Type[] Types { get { List types = new List(); return types.ToArray(); } } public Header header; public void Load(System.IO.Stream stream) { header = new Header(); header.Read(new FileReader(stream)); this.Text = header.Name; Nodes.Add("BinaryData"); Nodes.Add("ShaderPrograms"); Nodes[0].Nodes.Add("Vertex Shaders"); Nodes[0].Nodes.Add("Fragment Shaders"); Nodes[0].Nodes.Add("Geometry Shaders"); int v = 0; int p = 0; int g = 0; foreach (BinaryData item in header.BinaryDatas) { if (item.Type == BinaryData.ShaderType.GX2VertexShader) { item.Text += $"Binary [{v++}]"; Nodes[0].Nodes[0].Nodes.Add(item); } if (item.Type == BinaryData.ShaderType.GX2PixelShader) { item.Text += $"Binary [{p++}]"; Nodes[0].Nodes[1].Nodes.Add(item); } if (item.Type == BinaryData.ShaderType.GX2GeometryShader) { item.Text += $"Binary [{g++}]"; Nodes[0].Nodes[2].Nodes.Add(item); } } if (header.sharcNX != null) { foreach (var item in header.sharcNX.header.ShaderPrograms) { Nodes[1].Nodes.Add(item); } } else { foreach (ShaderProgram item in header.ShaderPrograms) { Nodes[1].Nodes.Add(item); } } } public void Unload() { } public void Save(System.IO.Stream stream) { } //Docs https://github.com/Kinnay/Wii-U-File-Formats/wiki/SHARCFB-File-Format public class Header { public string Name; public uint Version; public List BinaryDatas = new List(); public List ShaderPrograms = new List(); public bool IsNX = false; public SHARCFBNX sharcNX; public void Read(FileReader reader) { reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; reader.ReadSignature(4, "BAHS"); uint Version = reader.ReadUInt32(); uint FileSize = reader.ReadUInt32(); uint ByteOrderMark = reader.ReadUInt32(); if (ByteOrderMark == 1) reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; else reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian; uint unk = reader.ReadUInt32(); uint NameLength = reader.ReadUInt32(); if (NameLength == 4096) { IsNX = true; sharcNX = new SHARCFBNX(); sharcNX.header = new SHARCFBNX.Header(); sharcNX.header.Read(reader); return; } Name = reader.ReadString((int)NameLength); var pos = reader.Position; uint BinarySectionSize = reader.ReadUInt32(); uint BinaryFileCount = reader.ReadUInt32(); for (int i = 0; i < BinaryFileCount; i++) { BinaryData binary = new BinaryData(); binary.Read(reader); BinaryDatas.Add(binary); } reader.Seek(BinarySectionSize + pos, System.IO.SeekOrigin.Begin); pos = reader.Position; uint ProgramSectionSize = reader.ReadUInt32(); uint ProgramCount = reader.ReadUInt32(); for (int i = 0; i < ProgramCount; i++) { ShaderProgram program = new ShaderProgram(); program.Read(reader); ShaderPrograms.Add(program); } } public void Write(FileWriter reader) { } } public class ShaderProgram : TreeNodeCustom { public enum ShaderType { GX2VertexShader = 0x1, GX2PixelShader = 0x2, GX2ComputeShader = 0x3, GX2GeometryShader = 0x4, } public ShaderType Type; public VariationMacroData variationMacroData; public VariationSymbolData variationSymbolData; public ShaderSymbolData UniformVariables; public ShaderSymbolData UniformBlocks; public ShaderSymbolData SamplerVariables; public ShaderSymbolData AttributeVariables; public override void OnClick(TreeView treeview) { ShaderEditor editor = (ShaderEditor)LibraryGUI.GetActiveContent(typeof(ShaderEditor)); if (editor == null) { editor = new ShaderEditor(); LibraryGUI.LoadEditor(editor); } editor.Text = Text; editor.Dock = DockStyle.Fill; editor.FillEditor(this, ((SHARCFB)Parent.Parent).header); } public void Read(FileReader reader) { var pos = reader.Position; uint SectionSize = reader.ReadUInt32(); uint NameLength = reader.ReadUInt32(); Type = reader.ReadEnum(false); uint index = reader.ReadUInt32(); Text = reader.ReadString((int)NameLength); variationMacroData = new VariationMacroData(); variationSymbolData = new VariationSymbolData(); UniformVariables = new ShaderSymbolData(); UniformBlocks = new ShaderSymbolData(); SamplerVariables = new ShaderSymbolData(); AttributeVariables = new ShaderSymbolData(); variationMacroData.Read(reader); variationSymbolData.Read(reader); UniformVariables.Read(reader); UniformBlocks.Read(reader); SamplerVariables.Read(reader); AttributeVariables.Read(reader); reader.Seek(SectionSize + pos, System.IO.SeekOrigin.Begin); } } public class BinaryData : TreeNodeCustom { public enum ShaderType { GX2VertexShader, GX2PixelShader, GX2GeometryShader, } public ShaderType Type; public byte[] Data; public override void OnClick(TreeView treeview) { HexEditor editor = (HexEditor)LibraryGUI.GetActiveContent(typeof(HexEditor)); if (editor == null) { editor = new HexEditor(); LibraryGUI.LoadEditor(editor); } editor.Text = Text; editor.Dock = DockStyle.Fill; editor.LoadData(Data); } private void ExportShader(object sender, EventArgs args) { SaveFileDialog sfd = new SaveFileDialog(); sfd.DefaultExt = "bin"; sfd.FileName = "shader"; sfd.Filter = "Supported Formats|*.bin;"; if (sfd.ShowDialog() == DialogResult.OK) { System.IO.File.WriteAllBytes(sfd.FileName, Data); } } public void Read(FileReader reader) { var pos = reader.Position; uint SectionSize = reader.ReadUInt32(); Type = reader.ReadEnum(true); uint Offset = reader.ReadUInt32(); uint BinarySize = reader.ReadUInt32(); Data = reader.ReadBytes((int)BinarySize); reader.Seek(SectionSize + pos, System.IO.SeekOrigin.Begin); ContextMenu = new ContextMenu(); ContextMenu.MenuItems.Add(new MenuItem("Export Shader", ExportShader)); } public void Write(FileWriter reader) { } } } public class VariationMacroData { public List macros = new List(); public void Read(FileReader reader, uint Version = 12) { var SectionPos = reader.Position; uint SectionSize = reader.ReadUInt32(); uint SectionCount = reader.ReadUInt32(); for (int i = 0; i < SectionCount; i++) { VariationMacro variation = new VariationMacro(); variation.Read(reader, Version); macros.Add(variation); } reader.Seek(SectionPos + SectionSize, System.IO.SeekOrigin.Begin); } } public class VariationMacro { public string Name { get; set; } public string Value { get; set; } public void Read(FileReader reader, uint Version) { var pos = reader.Position; uint SectionSize = reader.ReadUInt32(); uint NameLength = reader.ReadUInt32(); uint ValueLength = reader.ReadUInt32(); Name = reader.ReadString((int)NameLength); Value = reader.ReadString((int)ValueLength); Console.WriteLine("VariationMacro ------------------"); Console.WriteLine(Name); Console.WriteLine(Value); Console.WriteLine("------------------"); reader.Seek(pos + SectionSize, System.IO.SeekOrigin.Begin); } } public class VariationSymbolData { public List symbols = new List(); public void Read(FileReader reader) { var SectionPos = reader.Position; uint SectionSize = reader.ReadUInt32(); uint SectionCount = reader.ReadUInt32(); for (int i = 0; i < SectionCount; i++) { VariationSymbol symbol = new VariationSymbol(); symbol.Read(reader); symbols.Add(symbol); } reader.Seek(SectionPos + SectionSize, System.IO.SeekOrigin.Begin); } } public class VariationSymbol { public string Name { get; set; } public string DefaultValue { get; set; } public string SymbolName { get; set; } public void Read(FileReader reader) { var pos = reader.Position; uint SectionSize = reader.ReadUInt32(); uint macroNameLength = reader.ReadUInt32(); uint defaultValueLength = reader.ReadUInt32(); uint symbolNameLength = reader.ReadUInt32(); Name = reader.ReadString((int)macroNameLength); DefaultValue = reader.ReadString((int)defaultValueLength); SymbolName = reader.ReadString((int)symbolNameLength); Console.WriteLine("VariationSymbol ------------------"); Console.WriteLine(Name); Console.WriteLine(DefaultValue); Console.WriteLine(SymbolName); Console.WriteLine("------------------"); reader.Seek(pos + SectionSize, System.IO.SeekOrigin.Begin); } } public class ShaderSymbolData { public List symbols = new List(); public void Read(FileReader reader, uint Version = 12, bool SkipReading = false) { var SectionPos = reader.Position; uint SectionSize = reader.ReadUInt32(); uint SectionCount = reader.ReadUInt32(); if (!SkipReading) { for (int i = 0; i < SectionCount; i++) { ShaderSymbol symbol = new ShaderSymbol(); symbol.Read(reader, Version); symbols.Add(symbol); } } reader.Seek(SectionPos + SectionSize, System.IO.SeekOrigin.Begin); } } public class ShaderSymbol { public string Name { get; set; } public byte[] DefaultValue { get; set; } public string SymbolName { get; set; } public byte[] flags; public string flagData { get; set; } public List sharcNXValues = new List(); public string DefaultValueString { get { return DefaultValueToString(); } } private string DefaultValueToString() { if (DefaultValue != null) { using (var reader = new FileReader(DefaultValue)) { if (DefaultValue.Length == 32) { float[] values = reader.ReadSingles(4); return $"{values[0]},{values[1]},{values[2]},{values[3]}" + $"{values[4]},{values[5]},{values[6]},{values[7]}"; } if (DefaultValue.Length == 16) { float[] values = reader.ReadSingles(4); return $"{values[0]},{values[1]},{values[2]},{values[3]}"; } if (DefaultValue.Length == 12) { float[] values = reader.ReadSingles(3); return $"{values[0]},{values[1]},{values[2]}"; } if (DefaultValue.Length == 8) { float[] values = reader.ReadSingles(3); return $"{values[0]},{values[1]}"; } if (DefaultValue.Length == 4) { float[] values = reader.ReadSingles(3); return $"{values[0]}}}"; } return reader.ReadString(DefaultValue.Length); } } else { return ""; } } public void Read(FileReader reader, uint Version) { var pos = reader.Position; uint SectionSize = reader.ReadUInt32(); if (Version >= 13) { uint shaderVariableSize = reader.ReadUInt32(); uint variationNameLength = reader.ReadUInt32(); Name = reader.ReadString((int)variationNameLength); uint ValueSectionSize = reader.ReadUInt32(); uint ValueCount = reader.ReadUInt32(); for (int i = 0; i < ValueCount; i++) { SharcNXValue value = new SharcNXValue(); value.Read(reader); sharcNXValues.Add(value); } } else { uint shaderVariableSize = reader.ReadUInt32(); uint variationNameLength = reader.ReadUInt32(); uint symbolNameLength = reader.ReadUInt32(); uint defaultValueLength = reader.ReadUInt32(); uint variationCount = reader.ReadUInt32(); Name = reader.ReadString((int)variationNameLength); SymbolName = reader.ReadString((int)symbolNameLength); DefaultValue = reader.ReadBytes((int)defaultValueLength); Console.WriteLine("----------------SHADER SYMBOL -----------"); Console.WriteLine(SectionSize); Console.WriteLine(Name); Console.WriteLine(SymbolName); Console.WriteLine(DefaultValue); Console.WriteLine("-----------------------------------------"); flags = new byte[variationCount]; for (int i = 0; i < variationCount; i++) { // flags[i] = reader.ReadByte(); // flagData += " " + flags[i]; } } reader.Seek(pos + SectionSize, System.IO.SeekOrigin.Begin); } public class SharcNXValue { public string Name { get; set; } public void Read(FileReader reader) { var pos = reader.Position; uint dataSize = reader.ReadUInt32(); uint unk = reader.ReadUInt32(); uint stringLength = reader.ReadUInt32(); Name = reader.ReadString((int)stringLength); reader.Seek(pos + dataSize, System.IO.SeekOrigin.Begin); } } } }