diff --git a/File_Format_Library/FileFormats/Shader/SHARC/SHARCFB.cs b/File_Format_Library/FileFormats/Shader/SHARC/SHARCFB.cs index accacea9..3876303b 100644 --- a/File_Format_Library/FileFormats/Shader/SHARC/SHARCFB.cs +++ b/File_Format_Library/FileFormats/Shader/SHARC/SHARCFB.cs @@ -78,6 +78,13 @@ namespace FirstPlugin if (header.sharcNX != null) { + foreach (var item in header.sharcNX.header.Variations) + { + if (item.Type == SHARCFBNX.ShaderVariation.ShaderType.Vertex) + Nodes[0].Nodes[0].Nodes.Add(item); + else + Nodes[0].Nodes[1].Nodes.Add(item); + } foreach (var item in header.sharcNX.header.ShaderPrograms) { Nodes[1].Nodes.Add(item); @@ -128,7 +135,7 @@ namespace FirstPlugin uint unk = reader.ReadUInt32(); uint NameLength = reader.ReadUInt32(); - if (NameLength == 4096) + if (NameLength == 4096 || NameLength == 8192) { IsNX = true; sharcNX = new SHARCFBNX(); diff --git a/File_Format_Library/FileFormats/Shader/SHARC/SHARCFBNX.cs b/File_Format_Library/FileFormats/Shader/SHARC/SHARCFBNX.cs index 4519957f..def683f4 100644 --- a/File_Format_Library/FileFormats/Shader/SHARC/SHARCFBNX.cs +++ b/File_Format_Library/FileFormats/Shader/SHARC/SHARCFBNX.cs @@ -8,6 +8,8 @@ using Toolbox.Library; using Toolbox.Library.Forms; using System.Windows.Forms; using FirstPlugin.Forms; +using static FirstPlugin.GMX.Header; +using static FirstPlugin.RARC_Parser; namespace FirstPlugin { @@ -18,6 +20,7 @@ namespace FirstPlugin public class Header { public List ShaderPrograms = new List(); + public List Variations = new List(); public void Read(FileReader reader) { @@ -50,29 +53,204 @@ namespace FirstPlugin var Position = reader.Position; //All offsets will be relative to this uint ShaderProgramArrayOffset = reader.ReadUInt32(); + uint VariationCount = reader.ReadUInt32(); + for (int i = 0; i < VariationCount; i++) + { + ShaderVariation var = new ShaderVariation(); + var.Read(reader); + Variations.Add(var); + } - - - reader.Seek(Position + ShaderProgramArrayOffset, System.IO.SeekOrigin.Begin); uint ProgramArraySize = reader.ReadUInt32(); uint ProgramCount = reader.ReadUInt32(); for (int i = 0; i < ProgramCount; i++) { - ShaderProgram program = new ShaderProgram(); + ShaderProgram program = new ShaderProgram(this); program.Read(reader); ShaderPrograms.Add(program); } } } + public static string ReadString(FileReader reader) + { + var offset = reader.ReadUInt64(); + using (reader.TemporarySeek(336 + (uint)offset, System.IO.SeekOrigin.Begin)) + { + return reader.ReadZeroTerminatedString(); + } + } + + public class ShaderVariation : TreeNodeCustom + { + public ulong BinaryDataOffset; + + public byte[] ShaderA; + + public ShaderType Type; + + public List Attributes = new List(); + public List Samplers = new List(); + + public List Buffers = new List(); + public List Uniforms = new List(); + public List UniformBlocks = new List(); + + 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); + } + + public void Read(FileReader reader) + { + var pos = reader.Position; + + uint SectionSize = reader.ReadUInt32(); + Type = (ShaderType)reader.ReadUInt32(); + reader.ReadUInt32(); //0 + + uint SectionSize2 = reader.ReadUInt32(); //next section size + + uint p = (uint)reader.Position; + + BinaryDataOffset = reader.ReadUInt64(); + uint ShaderASize = reader.ReadUInt32(); + uint ShaderAOffset = reader.ReadUInt32(); + reader.ReadUInt32(); //0 + uint numUniformBlocks = reader.ReadUInt32(); + var uniformBlockOffset = reader.ReadUInt64(); + + uint numBuffers = 0; + ulong bufferOffset = 0; + + //A dumb hack as version number isn't changed + bool isNewVersion = ShaderAOffset == 96 || uniformBlockOffset == 92; + + if (isNewVersion) + { + numBuffers = reader.ReadUInt32(); + bufferOffset = reader.ReadUInt64(); + } + + uint numAttributes = reader.ReadUInt32(); + var attributeOffset = reader.ReadUInt64(); + uint numUniforms = reader.ReadUInt32(); + var uniformOffset = reader.ReadUInt64(); + uint numSamplers = reader.ReadUInt32(); + var samplerOffset = reader.ReadUInt64(); + + reader.SeekBegin(p + uniformBlockOffset); + for (int i = 0; i < numUniformBlocks; i++) + { + UniformBlocks.Add(new SymbolUniformBlock() + { + Name = ReadString(reader), + Location = reader.ReadInt32(), + Size = reader.ReadUInt32(), + }); + } + + reader.SeekBegin(p + attributeOffset); + for (int i = 0; i < numAttributes; i++) + { + Attributes.Add(new Symbol() + { + Name = ReadString(reader), + Location = reader.ReadInt32(), + }); + } + + reader.SeekBegin(p + bufferOffset); + for (int i = 0; i < numBuffers; i++) + { + Buffers.Add(new Symbol() + { + Name = ReadString(reader), + Location = reader.ReadInt32(), + }); + } + + reader.SeekBegin(p + uniformOffset); + for (int i = 0; i < numUniforms; i++) + { + Uniforms.Add(new SymbolUniform() + { + Name = ReadString(reader), + Offset = reader.ReadUInt32(), + }); + } + + reader.SeekBegin(p + samplerOffset); + for (int i = 0; i < numSamplers; i++) + { + Samplers.Add(new Symbol() + { + Name = ReadString(reader), + Location = reader.ReadInt32(), + }); + } + + if (ShaderAOffset < SectionSize) + { + reader.SeekBegin(p + ShaderAOffset); + ShaderA = reader.ReadBytes((int)ShaderASize); + } + + reader.SeekBegin(pos + SectionSize); + } + + public enum ShaderType + { + Vertex, + Pixel, + } + } + + public class Symbol + { + public string Name; + public int Location; + } + + public class SymbolUniform + { + public string Name; + public uint Offset; + } + + public class SymbolUniformBlock + { + public string Name; + public int Location; + public uint Size; + } + public class ShaderProgram : TreeNodeCustom { public VariationMacroData variationMacroData; public VariationSymbolData variationSymbolData; public ShaderSymbolData UniformVariables; + public int BaseIndex; + + private Header Header; + + public ShaderProgram(Header header) + { + Header = header; + } + public override void OnClick(TreeView treeview) { ShaderEditor editor = (ShaderEditor)LibraryGUI.GetActiveContent(typeof(ShaderEditor)); @@ -93,8 +271,8 @@ namespace FirstPlugin uint SectionSize = reader.ReadUInt32(); uint NameLength = reader.ReadUInt32(); - uint ShaderType = reader.ReadUInt32(); - uint index = reader.ReadUInt32(); + uint sectionCount = reader.ReadUInt32(); //3 + BaseIndex = reader.ReadInt32(); Text = reader.ReadString((int)NameLength); @@ -102,12 +280,49 @@ namespace FirstPlugin variationSymbolData = new VariationSymbolData(); UniformVariables = new ShaderSymbolData(); - variationMacroData.Read(reader); variationSymbolData.Read(reader); + variationMacroData.Read(reader); UniformVariables.Read(reader); reader.Seek(SectionSize + pos, System.IO.SeekOrigin.Begin); } + + public ShaderVariation GetDefaultVertexVariation() + { + Dictionary settings = new Dictionary(); + foreach (var macro in variationSymbolData.symbols) + { + settings.Add(macro.Name, macro.Values.FirstOrDefault()); + } + return GetVariation(0, settings); + } + + public ShaderVariation GetDefaultPixelVariation() + { + Dictionary settings = new Dictionary(); + foreach (var macro in variationSymbolData.symbols) + { + settings.Add(macro.Name, macro.Values.FirstOrDefault()); + } + return GetVariation(1, settings); + } + + public ShaderVariation GetVariation(int type, Dictionary settings) + { + int index = GetVariationIndex(type, settings); + return Header.Variations[index]; + } + + public int GetVariationIndex(int type, Dictionary settings) + { + int index = 0; + foreach (var macro in variationSymbolData.symbols) + { + index *= macro.Values.Count; + index += macro.Values.IndexOf(settings[macro.Name]); + } + return BaseIndex + type + index * 2; + } } } } diff --git a/File_Format_Library/GUI/Editors/ShaderEditor.cs b/File_Format_Library/GUI/Editors/ShaderEditor.cs index 921e7b7f..01e587b2 100644 --- a/File_Format_Library/GUI/Editors/ShaderEditor.cs +++ b/File_Format_Library/GUI/Editors/ShaderEditor.cs @@ -30,6 +30,13 @@ namespace FirstPlugin.Forms LoadProgram(program); } + public void FillEditor(SHARCFBNX.ShaderVariation var) + { + string programXML = Sharc2XML.WriteProgram(var); + textEditor1.FillEditor(programXML); + textEditor1.IsXML = true; + } + public void FillEditor(SHARCFB.ShaderProgram program, SHARCFB.Header header) { LoadProgram(program); diff --git a/File_Format_Library/XML/Sharc2XML.cs b/File_Format_Library/XML/Sharc2XML.cs index 8797bbd1..e6d2c40a 100644 --- a/File_Format_Library/XML/Sharc2XML.cs +++ b/File_Format_Library/XML/Sharc2XML.cs @@ -34,6 +34,21 @@ namespace FirstPlugin doc.AppendChild(mainNode); } + public static string WriteProgram(SHARCFBNX.ShaderVariation program) + { + XmlDocument doc = new XmlDocument(); + XmlNode mainNode = doc.CreateElement("ShaderVariation"); + AddAttribute(doc, "Name", program.Text.Replace("\x00", ""), mainNode); + doc.AppendChild(mainNode); + + WriteVariationSymbols(doc, program.Uniforms, "Uniform_Variables", mainNode); + WriteVariationSymbols(doc, program.UniformBlocks, "Uniform_Blocks", mainNode); + WriteVariationSymbols(doc, program.Samplers, "Sampler_Variables", mainNode); + WriteVariationSymbols(doc, program.Attributes, "Attribute_Variables", mainNode); + + return DocumentToString(doc); + } + public static string WriteProgram(SHARC.ShaderProgram program) { XmlDocument doc = new XmlDocument(); @@ -66,6 +81,25 @@ namespace FirstPlugin WriteVariationSymbols(doc, program.variationSymbolData, "option_array", mainNode); WriteShaderSymbolData(doc, program.UniformVariables, "Uniform_Variables", mainNode); + XmlNode vertexNode = doc.CreateElement("VertexVariation"); + XmlNode pixelNode = doc.CreateElement("PixelVariation"); + mainNode.AppendChild(vertexNode); + mainNode.AppendChild(pixelNode); + + var var = program.GetDefaultVertexVariation(); + + WriteVariationSymbols(doc, var.Uniforms, "Uniform_Variables", vertexNode); + WriteVariationSymbols(doc, var.UniformBlocks, "Uniform_Blocks", vertexNode); + WriteVariationSymbols(doc, var.Samplers, "Sampler_Variables", vertexNode); + WriteVariationSymbols(doc, var.Attributes, "Attribute_Variables", vertexNode); + + var = program.GetDefaultPixelVariation(); + + WriteVariationSymbols(doc, var.Uniforms, "Uniform_Variables", pixelNode); + WriteVariationSymbols(doc, var.UniformBlocks, "Uniform_Blocks", pixelNode); + WriteVariationSymbols(doc, var.Samplers, "Sampler_Variables", pixelNode); + WriteVariationSymbols(doc, var.Attributes, "Attribute_Variables", pixelNode); + return DocumentToString(doc); } @@ -115,6 +149,47 @@ namespace FirstPlugin node.AppendChild(rootNode); } + private static void WriteVariationSymbols(XmlDocument doc, List symbols, string Name, XmlNode node) + { + XmlNode rootNode = doc.CreateElement(Name); + foreach (var symbol in symbols) + { + XmlNode childNode = doc.CreateElement("option"); + AddAttribute(doc, "name", symbol.Name.Replace("\x00", ""), childNode); + AddAttribute(doc, "location", symbol.Location.ToString(), childNode); + AddAttribute(doc, "size", symbol.Size.ToString(), childNode); + + rootNode.AppendChild(childNode); + } + node.AppendChild(rootNode); + } + + private static void WriteVariationSymbols(XmlDocument doc, List symbols, string Name, XmlNode node) + { + XmlNode rootNode = doc.CreateElement(Name); + foreach (var symbol in symbols) + { + XmlNode childNode = doc.CreateElement("option"); + AddAttribute(doc, "name", symbol.Name.Replace("\x00", ""), childNode); + AddAttribute(doc, "offset", symbol.Offset.ToString(), childNode); + rootNode.AppendChild(childNode); + } + node.AppendChild(rootNode); + } + + private static void WriteVariationSymbols(XmlDocument doc, List symbols, string Name, XmlNode node) + { + XmlNode rootNode = doc.CreateElement(Name); + foreach (var symbol in symbols) + { + XmlNode childNode = doc.CreateElement("option"); + AddAttribute(doc, "name", symbol.Name.Replace("\x00", ""), childNode); + AddAttribute(doc, "location", symbol.Location.ToString(), childNode); + rootNode.AppendChild(childNode); + } + node.AppendChild(rootNode); + } + private static void WriteShaderSymbolData(XmlDocument doc, ShaderSymbolData symbolData, string Name, XmlNode node) { XmlNode rootNode = doc.CreateElement(Name);