Skip to content

Instantly share code, notes, and snippets.

@shadowninja108
Last active February 7, 2025 09:22
Show Gist options
  • Save shadowninja108/301d3698caa1405a84cd6690f522e2ca to your computer and use it in GitHub Desktop.
Save shadowninja108/301d3698caa1405a84cd6690f522e2ca to your computer and use it in GitHub Desktop.
Toolbox hacked together a bit to support Switch SHARCFBs better. Note that I include the 0x30 byte header that Ryujinx.ShaderTools assumes is stripped (as other tools do attempt to strip it). You can adjust ShaderTools to support this by changing the first argument to `Translator.CreateContext` in Program.cs to 0x30 (or tweak `GetData` in this g…
diff --git a/File_Format_Library/FileFormats/Shader/SHARC/SHARCFBNX.cs b/File_Format_Library/FileFormats/Shader/SHARC/SHARCFBNX.cs
index def683f4..39af78ac 100644
--- a/File_Format_Library/FileFormats/Shader/SHARC/SHARCFBNX.cs
+++ b/File_Format_Library/FileFormats/Shader/SHARC/SHARCFBNX.cs
@@ -21,6 +21,9 @@ namespace FirstPlugin
{
public List<ShaderProgram> ShaderPrograms = new List<ShaderProgram>();
public List<ShaderVariation> Variations = new List<ShaderVariation>();
+ public byte[] BinaryArray;
+ public uint BinaryArraySize;
+ public uint BinaryArrayOffset;
public void Read(FileReader reader)
{
@@ -32,17 +35,19 @@ namespace FirstPlugin
uint FileSize = reader.ReadUInt32();
uint ByteOrderMark = reader.ReadUInt32();
- if (ByteOrderMark == 1)
+ if ((ByteOrderMark & 1)== 1)
reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
else
reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
uint unk = reader.ReadUInt32();
uint Alignment = reader.ReadUInt32();
- uint BinaryArraySize = reader.ReadUInt32();
- uint BinaryArrayOffset = reader.ReadUInt32();
-
+ BinaryArraySize = reader.ReadUInt32();
+ BinaryArrayOffset = reader.ReadUInt32();
+ reader.SeekBegin(BinaryArrayOffset);
+ BinaryArray = new byte[BinaryArraySize];
+ reader.Read(BinaryArray, 0, BinaryArray.Length);
reader.Seek(336, System.IO.SeekOrigin.Begin); //String table always at 336
@@ -57,7 +62,7 @@ namespace FirstPlugin
for (int i = 0; i < VariationCount; i++)
{
ShaderVariation var = new ShaderVariation();
- var.Read(reader);
+ var.Read(this, reader);
Variations.Add(var);
}
@@ -98,6 +103,8 @@ namespace FirstPlugin
public List<SymbolUniform> Uniforms = new List<SymbolUniform>();
public List<SymbolUniformBlock> UniformBlocks = new List<SymbolUniformBlock>();
+ public Header Header;
+
public override void OnClick(TreeView treeview)
{
ShaderEditor editor = (ShaderEditor)LibraryGUI.GetActiveContent(typeof(ShaderEditor));
@@ -112,11 +119,40 @@ namespace FirstPlugin
editor.FillEditor(this);
}
- public void Read(FileReader reader)
+ /* TODO: this is stupid as fuck */
+ public byte[] GetData()
+ {
+ var all = Header.BinaryArray;
+ for (var pos = (long) BinaryDataOffset + 0x100; pos < all.Length; pos += 0x100)
+ {
+ var b1 = all[pos+0];
+ var b2 = all[pos+1];
+ var b3 = all[pos+2];
+ var b4 = all[pos+3];
+
+ if(
+ b1 != 0x78 ||
+ b2 != 0x56 ||
+ b3 != 0x34 ||
+ b4 != 0x12
+ )
+ continue;
+
+ return all.Slice((uint)BinaryDataOffset, (uint)(pos - (long)BinaryDataOffset)).ToArray();
+ }
+
+ return all.Slice((uint)BinaryDataOffset, (uint)(all.LongLength - (long)BinaryDataOffset));
+ }
+
+ public void Read(Header header, FileReader reader)
{
+
+ Header = header;
var pos = reader.Position;
uint SectionSize = reader.ReadUInt32();
+
+
Type = (ShaderType)reader.ReadUInt32();
reader.ReadUInt32(); //0
@@ -126,8 +162,7 @@ namespace FirstPlugin
BinaryDataOffset = reader.ReadUInt64();
uint ShaderASize = reader.ReadUInt32();
- uint ShaderAOffset = reader.ReadUInt32();
- reader.ReadUInt32(); //0
+ ulong ShaderAOffset = reader.ReadUInt64();
uint numUniformBlocks = reader.ReadUInt32();
var uniformBlockOffset = reader.ReadUInt64();
@@ -214,6 +249,8 @@ namespace FirstPlugin
{
Vertex,
Pixel,
+ Geometry,
+ Compute
}
}
@@ -241,6 +278,7 @@ namespace FirstPlugin
public VariationMacroData variationMacroData;
public VariationSymbolData variationSymbolData;
public ShaderSymbolData UniformVariables;
+ public uint ShaderBitfield;
public int BaseIndex;
@@ -271,7 +309,7 @@ namespace FirstPlugin
uint SectionSize = reader.ReadUInt32();
uint NameLength = reader.ReadUInt32();
- uint sectionCount = reader.ReadUInt32(); //3
+ ShaderBitfield = reader.ReadUInt32();
BaseIndex = reader.ReadInt32();
Text = reader.ReadString((int)NameLength);
@@ -289,31 +327,43 @@ namespace FirstPlugin
public ShaderVariation GetDefaultVertexVariation()
{
- Dictionary<string, string> settings = new Dictionary<string, string>();
- foreach (var macro in variationSymbolData.symbols)
- {
- settings.Add(macro.Name, macro.Values.FirstOrDefault());
- }
- return GetVariation(0, settings);
+ return GetVariation(ShaderVariation.ShaderType.Vertex, GetDefaultSettings());
}
-
public ShaderVariation GetDefaultPixelVariation()
+ {
+ return GetVariation(ShaderVariation.ShaderType.Pixel, GetDefaultSettings());
+ }
+ public ShaderVariation GetDefaultGeometryVariation()
+ {
+ return GetVariation(ShaderVariation.ShaderType.Geometry, GetDefaultSettings());
+ }
+
+ public Dictionary<string, string> GetDefaultSettings()
{
Dictionary<string, string> settings = new Dictionary<string, string>();
foreach (var macro in variationSymbolData.symbols)
{
settings.Add(macro.Name, macro.Values.FirstOrDefault());
}
- return GetVariation(1, settings);
+
+ return settings;
+ }
+
+ public bool HasShader(ShaderVariation.ShaderType type)
+ {
+ var mask = 1u << (int)type;
+ return (ShaderBitfield & mask) != 0;
}
- public ShaderVariation GetVariation(int type, Dictionary<string, string> settings)
+ public ShaderVariation GetVariation(ShaderVariation.ShaderType type, Dictionary<string, string> settings)
{
+ if (!HasShader(type))
+ return null;
int index = GetVariationIndex(type, settings);
return Header.Variations[index];
}
- public int GetVariationIndex(int type, Dictionary<string, string> settings)
+ public int GetVariationIndex(ShaderVariation.ShaderType type, Dictionary<string, string> settings)
{
int index = 0;
foreach (var macro in variationSymbolData.symbols)
@@ -321,7 +371,7 @@ namespace FirstPlugin
index *= macro.Values.Count;
index += macro.Values.IndexOf(settings[macro.Name]);
}
- return BaseIndex + type + index * 2;
+ return BaseIndex + ((int)type)+ index * 2;
}
}
}
diff --git a/File_Format_Library/GUI/Editors/ShaderEditor.cs b/File_Format_Library/GUI/Editors/ShaderEditor.cs
index 01e587b2..82bc4e3e 100644
--- a/File_Format_Library/GUI/Editors/ShaderEditor.cs
+++ b/File_Format_Library/GUI/Editors/ShaderEditor.cs
@@ -62,6 +62,42 @@ namespace FirstPlugin.Forms
string programXML = Sharc2XML.WriteProgram(program);
textEditor1.FillEditor(programXML);
textEditor1.IsXML = true;
+
+ hexVertexData.OnControlClosing();
+ hexTextData.FillEditor("");
+ hexPixelData.OnControlClosing();
+ pixelTextData.FillEditor("");
+ hexGeomData.OnControlClosing();
+ geomTextData.FillEditor("");
+
+ var vertex = program.GetDefaultVertexVariation();
+ var fragment = program.GetDefaultPixelVariation();
+ var geometry = program.GetDefaultGeometryVariation();
+
+ if(vertex != null)
+ {
+ var d = vertex.GetData();
+ hexVertexData.LoadData(d);
+ hexTextData.FillEditor(
+ NSWShaderDecompile.DecompileShader(NSWShaderDecompile.NswShaderType.Vertex, d)
+ );
+ }
+ if (fragment != null)
+ {
+ var d = fragment.GetData();
+ hexPixelData.LoadData(d);
+ pixelTextData.FillEditor(
+ NSWShaderDecompile.DecompileShader(NSWShaderDecompile.NswShaderType.Fragment, d)
+ );
+ }
+ if (geometry != null)
+ {
+ var d = geometry.GetData();
+ hexGeomData.LoadData(d);
+ geomTextData.FillEditor(
+ NSWShaderDecompile.DecompileShader(NSWShaderDecompile.NswShaderType.Geometry, d)
+ );
+ }
}
private void LoadProgram(SHARCFB.ShaderProgram program)
diff --git a/File_Format_Library/XML/Sharc2XML.cs b/File_Format_Library/XML/Sharc2XML.cs
index e6d2c40a..2ce1a932 100644
--- a/File_Format_Library/XML/Sharc2XML.cs
+++ b/File_Format_Library/XML/Sharc2XML.cs
@@ -83,22 +83,38 @@ namespace FirstPlugin
XmlNode vertexNode = doc.CreateElement("VertexVariation");
XmlNode pixelNode = doc.CreateElement("PixelVariation");
+ XmlNode geomNode = doc.CreateElement("GeomVariation");
mainNode.AppendChild(vertexNode);
mainNode.AppendChild(pixelNode);
+ mainNode.AppendChild(geomNode);
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);
+ if (var != null)
+ {
+ 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();
+ if (var != null)
+ {
+ 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);
+ }
- 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);
+ var = program.GetDefaultGeometryVariation();
+ if (var != null)
+ {
+ WriteVariationSymbols(doc, var.Uniforms, "Uniform_Variables", geomNode);
+ WriteVariationSymbols(doc, var.UniformBlocks, "Uniform_Blocks", geomNode);
+ WriteVariationSymbols(doc, var.Samplers, "Sampler_Variables", geomNode);
+ WriteVariationSymbols(doc, var.Attributes, "Attribute_Variables", geomNode);
+ }
return DocumentToString(doc);
}
diff --git a/Switch_Toolbox_Library/Forms/Editors/HexEditor/HexEditor.Designer.cs b/Switch_Toolbox_Library/Forms/Editors/HexEditor/HexEditor.Designer.cs
index 135b37f1..93bfeb09 100644
--- a/Switch_Toolbox_Library/Forms/Editors/HexEditor/HexEditor.Designer.cs
+++ b/Switch_Toolbox_Library/Forms/Editors/HexEditor/HexEditor.Designer.cs
@@ -30,6 +30,8 @@
{
this.hexBox1 = new Be.Windows.Forms.HexBox();
this.stContextMenuStrip1 = new Toolbox.Library.Forms.STMenuStrip();
+ this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.fixedBytesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -37,7 +39,7 @@
this.stContextMenuStrip1.SuspendLayout();
this.SuspendLayout();
//
- // hexBox1
+ // saveBox
//
this.hexBox1.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.hexBox1.ColumnInfoVisible = true;
@@ -55,7 +57,9 @@
//
// stContextMenuStrip1
//
+ this.stContextMenuStrip1.HighlightSelectedTab = false;
this.stContextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.fileToolStripMenuItem,
this.viewToolStripMenuItem,
this.editToolStripMenuItem});
this.stContextMenuStrip1.Location = new System.Drawing.Point(0, 0);
@@ -64,6 +68,21 @@
this.stContextMenuStrip1.TabIndex = 1;
this.stContextMenuStrip1.Text = "stContextMenuStrip1";
//
+ // fileToolStripMenuItem
+ //
+ this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.saveToolStripMenuItem});
+ this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
+ this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
+ this.fileToolStripMenuItem.Text = "File";
+ //
+ // saveToolStripMenuItem
+ //
+ this.saveToolStripMenuItem.Name = "saveToolStripMenuItem";
+ this.saveToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+ this.saveToolStripMenuItem.Text = "Save";
+ this.saveToolStripMenuItem.Click += new System.EventHandler(this.saveToolStripMenuItem_Click);
+ //
// viewToolStripMenuItem
//
this.viewToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
@@ -118,5 +137,7 @@
private System.Windows.Forms.ToolStripMenuItem findToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem viewToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem fixedBytesToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem;
}
}
diff --git a/Switch_Toolbox_Library/Forms/Editors/HexEditor/HexEditor.cs b/Switch_Toolbox_Library/Forms/Editors/HexEditor/HexEditor.cs
index f5d166f3..5f51a90a 100644
--- a/Switch_Toolbox_Library/Forms/Editors/HexEditor/HexEditor.cs
+++ b/Switch_Toolbox_Library/Forms/Editors/HexEditor/HexEditor.cs
@@ -103,5 +103,16 @@ namespace Toolbox.Library.Forms
hexBox1.UseFixedBytesPerLine = fixedBytesToolStripMenuItem.Checked;
hexBox1.Refresh();
}
+
+ private void saveToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ SaveFileDialog sfd = new SaveFileDialog();
+ sfd.DefaultExt = "bin";
+
+ if (sfd.ShowDialog() == DialogResult.OK)
+ {
+ System.IO.File.WriteAllBytes(sfd.FileName, ((DynamicByteProvider)hexBox1.ByteProvider).Bytes.ToArray());
+ }
+ }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment