CodeWalker/CodeWalker.Core/GameFiles/FileTypes/FxcFile.cs
2022-05-20 17:52:51 +10:00

1897 lines
63 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TC = System.ComponentModel.TypeConverterAttribute;
using EXP = System.ComponentModel.ExpandableObjectConverter;
using System.Xml;
//GTAV FXC file reader by dexyfex.
// use this however you want. some credit would be nice.
namespace CodeWalker.GameFiles
{
[TC(typeof(EXP))] public class FxcFile : PackedFile
{
public string Name { get; set; }
public RpfFileEntry FileEntry { get; set; }
public uint Hash { get; set; }
public VertexType VertexType { get; set; }
public FxcPresetParam[] PresetParams { get; set; }
public FxcShaderGroup[] ShaderGroups { get; set; }
public FxcCBuffer[] CBuffers1 { get; set; }
public FxcVariable[] Variables1 { get; set; }
public FxcCBuffer[] CBuffers2 { get; set; }
public FxcVariable[] Variables2 { get; set; }
public FxcTechnique[] Techniques { get; set; }
public FxcShader[] Shaders { get; set; }
public FxcShader[] VertexShaders { get; set; }
public FxcShader[] PixelShaders { get; set; }
public FxcShader[] ComputeShaders { get; set; }
public FxcShader[] DomainShaders { get; set; }
public FxcShader[] GeometryShaders { get; set; }
public FxcShader[] HullShaders { get; set; }
public Dictionary<uint, FxcCBuffer> CBufferDict { get; set; }
public FxcVariable[] GlobalVariables { get; set; }
public void Load(byte[] data, RpfFileEntry entry)
{
FileEntry = entry;
Name = entry.Name;
Hash = entry.ShortNameHash;
MemoryStream ms = new MemoryStream(data);
BinaryReader br = new BinaryReader(ms);
uint magic_rgxe = br.ReadUInt32();
if (magic_rgxe != 1702389618) //"rgxe"
{
return;
}
VertexType = (VertexType)br.ReadUInt32();
byte ppCount = br.ReadByte();
if (ppCount > 0)
{
var pparams = new List<FxcPresetParam>();
for (int i = 0; i < ppCount; i++)
{
FxcPresetParam pparam = new FxcPresetParam();
pparam.Read(br);
pparams.Add(pparam);
}
PresetParams = pparams.ToArray();
}
var groups = new List<FxcShaderGroup>();
var shaders = new List<FxcShader>();
for (int i = 0; i < 6; i++)
{
FxcShaderGroup group = new FxcShaderGroup();
group.Read(br, i);
groups.Add(group);
if (group.Shaders != null)
{
shaders.AddRange(group.Shaders);
}
}
ShaderGroups = groups.ToArray();
Shaders = shaders.ToArray();
VertexShaders = groups[0].Shaders;
PixelShaders = groups[1].Shaders;
ComputeShaders = groups[2].Shaders;
DomainShaders = groups[3].Shaders;
GeometryShaders = groups[4].Shaders;
HullShaders = groups[5].Shaders;
List<FxcVariable> globalVars = new List<FxcVariable>();
CBufferDict = new Dictionary<uint, FxcCBuffer>();
byte cbCount1 = br.ReadByte();
if (cbCount1 > 0)
{
var cbuffers1 = new List<FxcCBuffer>();
for (int i = 0; i < cbCount1; i++) //cbuffers? includes?
{
FxcCBuffer cbuf = new FxcCBuffer();
cbuf.Read(br);
cbuffers1.Add(cbuf);
CBufferDict[cbuf.NameHash] = cbuf;
}
CBuffers1 = cbuffers1.ToArray();
}
byte varCount1 = br.ReadByte();
if (varCount1 > 0)
{
var vars1 = new List<FxcVariable>(); //cbuffer contents/vars
for (int i = 0; i < varCount1; i++)
{
FxcVariable vari = new FxcVariable();
vari.Read(br);
vars1.Add(vari);
if (CBufferDict.TryGetValue(vari.CBufferName, out var cbtmp))
{
cbtmp.AddVariable(vari);
}
else
{
globalVars.Add(vari);
}
}
Variables1 = vars1.ToArray();
}
byte cbCount2 = br.ReadByte(); //0,1, +?
if (cbCount2 > 0)
{
var cbuffers2 = new List<FxcCBuffer>(); //more cbuffers..
for (int i = 0; i < cbCount2; i++)
{
FxcCBuffer cbuf = new FxcCBuffer();
cbuf.Read(br);
cbuffers2.Add(cbuf);
CBufferDict[cbuf.NameHash] = cbuf;
}
CBuffers2 = cbuffers2.ToArray();
}
byte varCount2 = br.ReadByte();
if (varCount2 > 0)
{
var vars2 = new List<FxcVariable>();
for (int i = 0; i < varCount2; i++) //textures/samplers
{
FxcVariable vari = new FxcVariable();
vari.Read(br);
vars2.Add(vari);
if (CBufferDict.TryGetValue(vari.CBufferName, out var cbtmp))
{
cbtmp.AddVariable(vari);
}
else
{
globalVars.Add(vari);
}
}
Variables2 = vars2.ToArray();
}
byte techCount = br.ReadByte();
if (techCount > 0)
{
var techniques = new List<FxcTechnique>();
for (int i = 0; i < techCount; i++)
{
FxcTechnique tech = new FxcTechnique();
tech.Read(br);
tech.GetNamesFromIndices(this);
techniques.Add(tech);
}
Techniques = techniques.ToArray();
}
foreach (var cbuf in CBufferDict.Values)
{
cbuf.ConsolidateVariables();
}
GlobalVariables = globalVars.ToArray();
if (ms.Position != ms.Length)
{ }//no hit
ms.Dispose();
}
public byte[] Save()
{
var s = new MemoryStream();
var w = new BinaryWriter(s);
w.Write((uint)1702389618); //"rgxe"
w.Write((uint)VertexType);
var ppCount = (byte)(PresetParams?.Length ?? 0);
w.Write(ppCount);
for (int i = 0; i < ppCount; i++)
{
PresetParams[i].Write(w);
}
ShaderGroups[0].Shaders = VertexShaders;
ShaderGroups[1].Shaders = PixelShaders;
ShaderGroups[2].Shaders = ComputeShaders;
ShaderGroups[3].Shaders = DomainShaders;
ShaderGroups[4].Shaders = GeometryShaders;
ShaderGroups[5].Shaders = HullShaders;
for (int i = 0; i < 6; i++)
{
var group = ShaderGroups[i];
group.Write(w, i);
}
var cbCount1 = (byte)(CBuffers1?.Length ?? 0);
w.Write(cbCount1);
for (int i = 0; i < cbCount1; i++)
{
CBuffers1[i].Write(w);
}
var varCount1 = (byte)(Variables1?.Length ?? 0);
w.Write(varCount1);
for (int i = 0; i < varCount1; i++)
{
Variables1[i].Write(w);
}
var cbCount2 = (byte)(CBuffers2?.Length ?? 0);
w.Write(cbCount2);
for (int i = 0; i < cbCount2; i++)
{
CBuffers2[i].Write(w);
}
var varCount2 = (byte)(Variables2?.Length ?? 0);
w.Write(varCount2);
for (int i = 0; i < varCount2; i++)
{
Variables2[i].Write(w);
}
var techCount = (byte)(Techniques?.Length ?? 0);
w.Write(techCount);
for (int i = 0; i < techCount; i++)
{
Techniques[i].Write(w);
}
var buf = new byte[s.Length];
s.Position = 0;
s.Read(buf, 0, buf.Length);
return buf;
}
public void WriteXml(StringBuilder sb, int indent, string csofolder)
{
if ((ShaderGroups == null) || (ShaderGroups.Length < 6)) return;
FxcXml.StringTag(sb, indent, "VertexType", VertexType.ToString());
if (PresetParams != null)
{
FxcXml.WriteItemArray(sb, PresetParams, indent, "PresetParams");
}
var ci = indent + 1;
var gi = ci + 1;
FxcXml.OpenTag(sb, indent, "Shaders");
for (int i = 0; i < 6; i++)
{
var group = ShaderGroups[i];
var typen = group.Type.ToString() + "s";
var tagn = typen;
if (group.OffsetBy1)
{
tagn += " OffsetBy1=\"" + group.OffsetBy1.ToString() + "\"";
}
if ((group.Shaders?.Length ?? 0) > 0)
{
FxcXml.OpenTag(sb, ci, tagn);
group.WriteXml(sb, gi, csofolder);
FxcXml.CloseTag(sb, ci, typen);
}
else //if (group.OffsetBy1)
{
FxcXml.SelfClosingTag(sb, ci, tagn);
}
}
FxcXml.CloseTag(sb, indent, "Shaders");
if (CBuffers1 != null)
{
FxcXml.WriteItemArray(sb, CBuffers1, indent, "CBuffers1");
}
if (Variables1 != null)
{
FxcXml.WriteItemArray(sb, Variables1, indent, "Variables1");
}
if (CBuffers2 != null)
{
FxcXml.WriteItemArray(sb, CBuffers2, indent, "CBuffers2");
}
if (Variables2 != null)
{
FxcXml.WriteItemArray(sb, Variables2, indent, "Variables2");
}
if (Techniques != null)
{
FxcXml.WriteItemArray(sb, Techniques, indent, "Techniques");
}
}
public void ReadXml(XmlNode node, string csofolder)
{
VertexType = Xml.GetChildEnumInnerText<VertexType>(node, "VertexType");
PresetParams = XmlMeta.ReadItemArray<FxcPresetParam>(node, "PresetParams");
var snode = node.SelectSingleNode("Shaders");
if (snode != null)
{
var shaders = new List<FxcShader>();
FxcShaderGroup getShaderGroup(FxcShaderType type)
{
var gname = type.ToString() + "s";
var gnode = snode.SelectSingleNode(gname);
if (gnode == null) return null;
var group = new FxcShaderGroup();
group.Type = type;
group.OffsetBy1 = Xml.GetBoolAttribute(gnode, "OffsetBy1");
group.ReadXml(gnode, csofolder);
return group;
}
var groups = new FxcShaderGroup[6];
for (int i = 0; i < 6; i++)
{
var group = getShaderGroup((FxcShaderType)i);
groups[i] = group;
if (group.Shaders != null)
{
shaders.AddRange(group.Shaders);
}
}
ShaderGroups = groups;
Shaders = shaders.ToArray();
VertexShaders = groups[0].Shaders;
PixelShaders = groups[1].Shaders;
ComputeShaders = groups[2].Shaders;
DomainShaders = groups[3].Shaders;
GeometryShaders = groups[4].Shaders;
HullShaders = groups[5].Shaders;
}
CBuffers1 = XmlMeta.ReadItemArray<FxcCBuffer>(node, "CBuffers1");
Variables1 = XmlMeta.ReadItemArray<FxcVariable>(node, "Variables1");
CBuffers2 = XmlMeta.ReadItemArray<FxcCBuffer>(node, "CBuffers2");
Variables2 = XmlMeta.ReadItemArray<FxcVariable>(node, "Variables2");
Techniques = XmlMeta.ReadItemArray<FxcTechnique>(node, "Techniques");
if (Techniques != null)
{
foreach (var t in Techniques)
{
t.GetIndicesFromNames(this);
}
}
}
public string GetMetaString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("Name: " + Name);
sb.AppendLine("Hash: " + Hash.ToString());
sb.AppendLine("Vertex type: " + ((uint)VertexType).ToString());
sb.AppendLine();
if (PresetParams != null)
{
sb.AppendLine("Header");
foreach (var ext in PresetParams)
{
sb.AppendLine(" " + ext.ToString());
}
sb.AppendLine();
}
if (ShaderGroups != null)
{
sb.AppendLine("Sections");
foreach (var chunk in ShaderGroups)
{
sb.AppendLine(" " + chunk.ToString());
}
sb.AppendLine();
}
if (Shaders != null)
{
sb.AppendLine("Shaders (" + Shaders.Length.ToString() + ")");
foreach (var shader in Shaders)
{
sb.AppendLine(" " + shader.Name);
if ((shader.Variables != null) && (shader.Variables.Length > 0))
{
sb.AppendLine(" (Params)");
foreach (var parm in shader.Variables)
{
sb.AppendLine(" " + parm);
}
}
if ((shader.Buffers != null) && (shader.Buffers.Length > 0))
{
sb.AppendLine(" (Buffers)");
foreach (var ext in shader.Buffers)
{
sb.AppendLine(" " + ext.ToString());
}
}
}
sb.AppendLine();
}
if (CBuffers1 != null)
{
sb.AppendLine("CBuffers 1 (" + CBuffers1.Length.ToString() + ")");
foreach (var p in CBuffers1)
{
sb.AppendLine(" " + p.ToString());
}
sb.AppendLine();
}
if (Variables1 != null)
{
sb.AppendLine("Variables 1 (" + Variables1.Length.ToString() + ")");
foreach (var p in Variables1)
{
sb.AppendLine(" " + p.ToString());
if ((p.Params != null) && (p.Params.Length > 0))
{
sb.AppendLine(" (Params)");
foreach (var c in p.Params)
{
sb.AppendLine(" " + c.ToString());
}
}
if ((p.ValuesF != null) && (p.ValuesF.Length > 0))
{
sb.AppendLine(" (Values)");
foreach (var d in p.ValuesF)
{
sb.AppendLine(" " + d.ToString());
}
}
}
sb.AppendLine();
}
if (CBuffers2 != null)
{
sb.AppendLine("CBuffers 2 (" + CBuffers2.Length.ToString() + ")");
foreach (var p in CBuffers2)
{
sb.AppendLine(" " + p.ToString());
}
sb.AppendLine();
}
if (Variables2 != null)
{
sb.AppendLine("Variables 2 (" + Variables2.Length.ToString() + ")");
foreach (var p in Variables2)
{
sb.AppendLine(" " + p.ToString());
if ((p.Params != null) && (p.Params.Length > 0))
{
sb.AppendLine(" (Params)");
foreach (var c in p.Params)
{
sb.AppendLine(" " + c.ToString());
}
}
if ((p.ValuesF != null) && (p.ValuesF.Length > 0))
{
sb.AppendLine(" (Values)");
foreach (var d in p.ValuesF)
{
sb.AppendLine(" " + d.ToString());
}
}
}
sb.AppendLine();
}
if (Techniques != null)
{
sb.AppendLine("Techniques (" + Techniques.Length.ToString() + ")");
foreach (var t in Techniques)
{
sb.AppendLine(" " + t.Name);
if ((t.PassCount > 0) && (t.Passes != null))
{
sb.AppendLine(" (Passes)");
foreach (var p in t.Passes)
{
sb.AppendLine(" " + p.ToString());
if ((p.ParamCount > 0) && (p.Params != null))
{
//sb.AppendLine(" Params");
foreach (var v in p.Params)
{
sb.AppendLine(" " + v.ToString());
}
}
}
}
}
sb.AppendLine();
}
return sb.ToString();
}
public FxcShader GetVS(int id)
{
int i = id - 1;
if ((i < 0) || (VertexShaders == null) || (i >= VertexShaders.Length))
{
return null;
}
return VertexShaders[i];
}
public FxcShader GetPS(int id)
{
int i = id - 1;
if ((i < 0) || (PixelShaders == null) || (i >= PixelShaders.Length))
{
return null;
}
return PixelShaders[i];
}
public FxcShader GetCS(int id)
{
int i = id - 1;
if ((i < 0) || (ComputeShaders == null) || (i >= ComputeShaders.Length))
{
return null;
}
return ComputeShaders[i];
}
public FxcShader GetDS(int id)
{
int i = id - 1;
if ((i < 0) || (DomainShaders == null) || (i >= DomainShaders.Length))
{
return null;
}
return DomainShaders[i];
}
public FxcShader GetGS(int id)
{
int i = id - 1;
if ((i < 0) || (GeometryShaders == null) || (i >= GeometryShaders.Length))
{
return null;
}
return GeometryShaders[i];
}
public FxcShader GetHS(int id)
{
int i = id - 1;
if ((i < 0) || (HullShaders == null) || (i >= HullShaders.Length))
{
return null;
}
return HullShaders[i];
}
public byte GetVSID(string name)
{
if (VertexShaders == null) return 0;
for (int i = 0; i < VertexShaders.Length; i++)
{
if (VertexShaders[i].Name == name)
{
return (byte)(i + 1);
}
}
return 0;
}
public byte GetPSID(string name)
{
if (PixelShaders == null) return 0;
for (int i = 0; i < PixelShaders.Length; i++)
{
if (PixelShaders[i].Name == name)
{
return (byte)(i + 1);
}
}
return 0;
}
public byte GetCSID(string name)
{
if (ComputeShaders == null) return 0;
for (int i = 0; i < ComputeShaders.Length; i++)
{
if (ComputeShaders[i].Name == name)
{
return (byte)(i + 1);
}
}
return 0;
}
public byte GetDSID(string name)
{
if (DomainShaders == null) return 0;
for (int i = 0; i < DomainShaders.Length; i++)
{
if (DomainShaders[i].Name == name)
{
return (byte)(i + 1);
}
}
return 0;
}
public byte GetGSID(string name)
{
if (GeometryShaders == null) return 0;
for (int i = 0; i < GeometryShaders.Length; i++)
{
if (GeometryShaders[i].Name == name)
{
return (byte)(i + 1);
}
}
return 0;
}
public byte GetHSID(string name)
{
if (HullShaders == null) return 0;
for (int i = 0; i < HullShaders.Length; i++)
{
if (HullShaders[i].Name == name)
{
return (byte)(i + 1);
}
}
return 0;
}
public static string ReadString(BinaryReader br)
{
byte sl = br.ReadByte();
if (sl == 0) return string.Empty;
byte[] ba = br.ReadBytes(sl);
return (sl > 1) ? Encoding.ASCII.GetString(ba, 0, sl - 1) : string.Empty;
}
public static string[] ReadStringArray(BinaryReader br)
{
string[] r = null;
byte sc = br.ReadByte();
if (sc > 0)
{
StringBuilder sb = new StringBuilder();
r = new string[sc];
for (int i = 0; i < sc; i++)
{
sb.Clear();
byte sl = br.ReadByte();
var ba = br.ReadBytes(sl);
r[i] = (sl > 1) ? Encoding.ASCII.GetString(ba, 0, sl - 1) : string.Empty;
}
}
return r;
}
public static void WriteString(BinaryWriter bw, string s)
{
if (string.IsNullOrEmpty(s))
{
bw.Write((byte)0);
}
else
{
if (s.Length > 255)
{ s = s.Substring(0, 255); }
var bytes = Encoding.ASCII.GetBytes(s);
bw.Write((byte)(bytes.Length + 1));
bw.Write(bytes);
bw.Write((byte)0);
}
}
public static void WriteStringArray(BinaryWriter bw, string[] a)
{
byte sc = (byte)(a?.Length ?? 0);
bw.Write(sc);
for (int i = 0; i < sc; i++)
{
var s = a[i];
if (s.Length > 255)
{ s = s.Substring(0, 255); }
var bytes = Encoding.ASCII.GetBytes(s);
bw.Write((byte)(bytes.Length + 1));
bw.Write(bytes);
bw.Write((byte)0);
}
}
}
[TC(typeof(EXP))] public class FxcPresetParam : IMetaXmlItem
{
public string Name { get; set; } //eg. __rage_drawbucket, ExposeAlphaMap
public byte Unused0 { get; set; } //always 0 - possibly type identifier?
public uint Value { get; set; }
public void Read(BinaryReader br)
{
Name = FxcFile.ReadString(br);
Unused0 = br.ReadByte(); //always 0
Value = br.ReadUInt32(); //eg 1, 2
}
public void Write(BinaryWriter bw)
{
FxcFile.WriteString(bw, Name);
bw.Write(Unused0);
bw.Write(Value);
}
public void WriteXml(StringBuilder sb, int indent)
{
FxcXml.StringTag(sb, indent, "Name", FxcXml.XmlEscape(Name));
FxcXml.ValueTag(sb, indent, "Value", Value.ToString());
}
public void ReadXml(XmlNode node)
{
Name = Xml.GetChildInnerText(node, "Name");
Value = Xml.GetChildUIntAttribute(node, "Value");
}
public override string ToString()
{
return Name + ": " + Value.ToString();
}
}
public enum FxcShaderType
{
VertexShader = 0,
PixelShader = 1,
ComputeShader = 2,
DomainShader = 3,
GeometryShader = 4,
HullShader = 5,
}
[TC(typeof(EXP))] public class FxcShaderGroup
{
public FxcShaderType Type { get; set; } //index in the fxc file
public byte ShaderCount { get; set; } //number of shaders in the section +1 (why +1 though? no idea)
public bool OffsetBy1 { get; set; }//don't know why, sometimes hull shaders get offset by 1 byte at the start
public string Name { get; set; } //"NULL"
public byte Unk1Byte { get; set; } //0
public byte Unk2Byte { get; set; } //0
public uint Unk3Uint { get; set; } //0
public FxcShader[] Shaders { get; set; }
public void Read(BinaryReader br, int gindex)
{
Type = (FxcShaderType)gindex;
ShaderCount = br.ReadByte();
if (ShaderCount == 0)
{
ShaderCount = br.ReadByte(); //sometimes a byte skip, but only happens for hull shaders (gindex=5)
OffsetBy1 = true;
}
Name = FxcFile.ReadString(br); //always "NULL"
Unk1Byte = br.ReadByte();
Unk2Byte = br.ReadByte();
Unk3Uint = br.ReadUInt32();
if (ShaderCount > 1)
{
Shaders = new FxcShader[ShaderCount-1];
for (int i = 1; i < ShaderCount; i++)
{
FxcShader shader = new FxcShader();
shader.Read(br, gindex);
Shaders[i-1] = shader;
}
}
}
public void Write(BinaryWriter bw, int gindex)
{
ShaderCount = (byte)((Shaders?.Length ?? 0) + 1);
if (OffsetBy1)
{
bw.Write((byte)0);
}
bw.Write(ShaderCount);
FxcFile.WriteString(bw, Name);
bw.Write(Unk1Byte);
bw.Write(Unk2Byte);
bw.Write(Unk3Uint);
for (int i = 1; i < ShaderCount; i++)
{
Shaders[i-1].Write(bw, gindex);
}
}
public void WriteXml(StringBuilder sb, int indent, string csofolder)
{
var sc = Shaders?.Length ?? 0;
var ci = indent + 1;
var si = ci + 1;
for (int i = 0; i < sc; i++)
{
var typen = "Item";// Index=\"" + i.ToString() + "\"";
FxcXml.OpenTag(sb, ci, typen);
Shaders[i].WriteXml(sb, si, csofolder);
FxcXml.CloseTag(sb, ci, "Item");
}
}
public void ReadXml(XmlNode node, string csofolder)
{
Name = "NULL";
var inodes = node.SelectNodes("Item");
if (inodes?.Count > 0)
{
var slist = new List<FxcShader>();
foreach (XmlNode inode in inodes)
{
var s = new FxcShader();
s.Type = Type;
s.ReadXml(inode, csofolder);
slist.Add(s);
}
Shaders = slist.ToArray();
}
}
public override string ToString()
{
return Name + ": " + Type.ToString() + ": " + ShaderCount.ToString() + ": " + Unk1Byte.ToString() + ": " + Unk2Byte.ToString() + ": " + Unk3Uint.ToString();
}
}
[TC(typeof(EXP))] public class FxcShader
{
public FxcShaderType Type { get; set; }
public long Offset { get; set; } //just for informational purposes
public bool OffsetBy1 { get; set; }//don't know why, sometimes geometry shaders get offset by 1 byte here
public string Name { get; set; }
public string[] Variables { get; set; }
public FxcShaderBufferRef[] Buffers { get; set; }//CBuffers
public byte VersionMajor { get; set; }
public byte VersionMinor { get; set; }
public string VersionString { get; set; }
public byte[] ByteCode { get; set; }
//public ShaderBytecode ByteCodeObj { get; set; }
//public ShaderProfile ShaderProfile { get; set; }
public string Disassembly { get; set; }//see FxcParser
public string LastError { get; set; } //see FxcParser
public void Read(BinaryReader br, int gindex)
{
Type = (FxcShaderType)gindex;
Offset = br.BaseStream.Position;
Name = FxcFile.ReadString(br);
if (Name.Length == 0)
{
Name = FxcFile.ReadString(br); //why (seems to be GS only)
OffsetBy1 = true;
}
Variables = FxcFile.ReadStringArray(br);
byte bufferCount = br.ReadByte();
if (bufferCount > 0)
{
var buffers = new List<FxcShaderBufferRef>();
for (int e = 0; e < bufferCount; e++)
{
FxcShaderBufferRef ext = new FxcShaderBufferRef();
ext.Read(br);
buffers.Add(ext);
}
Buffers = buffers.ToArray();
}
if (Type == FxcShaderType.GeometryShader) //GS seems to be slightly different format??
{
var exbyte = br.ReadByte(); //not sure what this is used for...
if (exbyte != 0)
{ }//no hit
}
uint datalength = br.ReadUInt32();
if (datalength > 0)
{
uint magic_dxbc = br.ReadUInt32();
if (magic_dxbc != 1128421444) //"DXBC" - directx bytecode header
{
//LastError += "Unexpected data found at DXBC header...\r\n";
return; //false; //didn't find the DXBC header... abort! (no hit here)
}
br.BaseStream.Position -= 4; //wind back because dx needs that header
ByteCode = br.ReadBytes((int)datalength);
switch (Type)
{
case FxcShaderType.VertexShader:
case FxcShaderType.PixelShader:
case FxcShaderType.GeometryShader: //only for VS,PS,GS
VersionMajor = br.ReadByte();//4,5 //appears to be shader model version
VersionMinor = br.ReadByte();
break;
}
#region disassembly not done here - see FxcParser.cs
//try
//{
// ByteCodeObj = new ShaderBytecode(ByteCode);
// ShaderProfile = ByteCodeObj.GetVersion();
// switch (ShaderProfile.Version)
// {
// case ShaderVersion.VertexShader:
// case ShaderVersion.PixelShader:
// case ShaderVersion.GeometryShader:
// VersionMajor = br.ReadByte();//4,5 //appears to be shader model version
// VersionMinor = br.ReadByte(); //perhaps shader minor version
// break;
// default:
// VersionMajor = (byte)ShaderProfile.Major;
// VersionMinor = (byte)ShaderProfile.Minor;
// break;
// }
// //do disassembly last, so any errors won't cause the file read to break
// Disassembly = ByteCodeObj.Disassemble();
//}
//catch (Exception ex)
//{
// LastError += ex.ToString() + "\r\n";
// return false;
//}
#endregion
}
}
public void Write(BinaryWriter bw, int gindex)
{
Type = (FxcShaderType)gindex; //not sure if this should be here, shouldn't be necessary
if (OffsetBy1)
{
bw.Write((byte)0);
}
FxcFile.WriteString(bw, Name);
FxcFile.WriteStringArray(bw, Variables);
var bufferCount = (byte)(Buffers?.Length ?? 0);
bw.Write(bufferCount);
for (int i = 0; i < bufferCount; i++)
{
Buffers[i].Write(bw);
}
if (Type == FxcShaderType.GeometryShader) //GS seems to be slightly different format??
{
bw.Write((byte)0); //why is this here..? crazy GS
}
var dataLength = (uint)(ByteCode?.Length ?? 0);
bw.Write(dataLength);
if (dataLength > 0)
{
bw.Write(ByteCode);
switch (Type)
{
case FxcShaderType.VertexShader:
case FxcShaderType.PixelShader:
case FxcShaderType.GeometryShader: //only for VS,PS,GS
bw.Write(VersionMajor);
bw.Write(VersionMinor);
break;
}
}
}
public void WriteXml(StringBuilder sb, int indent, string csofolder)
{
var fname = (Name?.Replace("/", "")?.Replace("\\", "") ?? "NameError") + ".cso";
FxcXml.StringTag(sb, indent, "Name", FxcXml.XmlEscape(Name));
FxcXml.StringTag(sb, indent, "File", FxcXml.XmlEscape(fname));
if (OffsetBy1)
{
FxcXml.ValueTag(sb, indent, "OffsetBy1", OffsetBy1.ToString());
}
switch (Type)
{
case FxcShaderType.VertexShader:
case FxcShaderType.PixelShader:
case FxcShaderType.GeometryShader: //only for VS,PS,GS
FxcXml.ValueTag(sb, indent, "VersionMajor", VersionMajor.ToString());
FxcXml.ValueTag(sb, indent, "VersionMinor", VersionMinor.ToString());
break;
}
if (Variables != null)
{
FxcXml.OpenTag(sb, indent, "Variables");
for (int i = 0; i < Variables.Length; i++)
{
FxcXml.StringTag(sb, indent + 1, "Item", FxcXml.XmlEscape(Variables[i]));
}
FxcXml.CloseTag(sb, indent, "Variables");
}
if (Buffers != null)
{
FxcXml.WriteItemArray(sb, Buffers, indent, "Buffers");
}
if (ByteCode != null)
{
var export = !string.IsNullOrEmpty(csofolder);
if (export)
{
try
{
if (!Directory.Exists(csofolder))
{
Directory.CreateDirectory(csofolder);
}
var filepath = Path.Combine(csofolder, fname);
File.WriteAllBytes(filepath, ByteCode);
}
catch
{ }
}
}
}
public void ReadXml(XmlNode node, string csofolder)
{
//Type should be set before calling this!
Name = Xml.GetChildInnerText(node, "Name");
OffsetBy1 = Xml.GetChildBoolAttribute(node, "OffsetBy1");
VersionMajor = (byte)Xml.GetChildUIntAttribute(node, "VersionMajor");
VersionMinor = (byte)Xml.GetChildUIntAttribute(node, "VersionMinor");
var vnode = node.SelectSingleNode("Variables");
if (vnode != null)
{
var inodes = vnode.SelectNodes("Item");
if (inodes?.Count > 0)
{
var slist = new List<string>();
foreach (XmlNode inode in inodes)
{
slist.Add(inode.InnerText);
}
Variables = slist.ToArray();
}
}
Buffers = XmlMeta.ReadItemArray<FxcShaderBufferRef>(node, "Buffers");
var filename = Xml.GetChildInnerText(node, "File")?.Replace("/", "")?.Replace("\\", "");
if (!string.IsNullOrEmpty(filename) && !string.IsNullOrEmpty(csofolder))
{
var filepath = Path.Combine(csofolder, filename);
if (File.Exists(filepath))
{
ByteCode = File.ReadAllBytes(filepath);
}
else
{
throw new Exception("Shader file not found:\n" + filepath);
}
}
}
public override string ToString()
{
return Name;
}
}
[TC(typeof(EXP))] public class FxcShaderBufferRef : IMetaXmlItem
{
public string Name { get; set; }
public ushort Slot { get; set; }
public void Read(BinaryReader br)
{
Name = FxcFile.ReadString(br);
Slot = br.ReadUInt16();
}
public void Write(BinaryWriter bw)
{
FxcFile.WriteString(bw, Name);
bw.Write(Slot);
}
public void WriteXml(StringBuilder sb, int indent)
{
FxcXml.StringTag(sb, indent, "Name", FxcXml.XmlEscape(Name));
FxcXml.ValueTag(sb, indent, "Slot", Slot.ToString());
}
public void ReadXml(XmlNode node)
{
Name = Xml.GetChildInnerText(node, "Name");
Slot = (ushort)Xml.GetChildUIntAttribute(node, "Slot");
}
public override string ToString()
{
return Name + ": " + Slot.ToString();
}
}
[TC(typeof(EXP))] public class FxcCBuffer : IMetaXmlItem
{
public uint Size { get; set; }
public ushort SlotVS { get; set; }
public ushort SlotPS { get; set; }
public ushort SlotCS { get; set; }
public ushort SlotDS { get; set; }
public ushort SlotGS { get; set; }
public ushort SlotHS { get; set; }
public string Name { get; set; }
public uint NameHash { get { return JenkHash.GenHash(Name?.ToLowerInvariant()); } }
public List<FxcVariable> VariablesList;
public FxcVariable[] Variables { get; set; }
public void Read(BinaryReader br)
{
Size = br.ReadUInt32(); //176, 16 //256
SlotVS = br.ReadUInt16(); //6, 5
SlotPS = br.ReadUInt16(); //6, 12
SlotCS = br.ReadUInt16(); //6, 5
SlotDS = br.ReadUInt16(); //6, 5
SlotGS = br.ReadUInt16(); //6, 5
SlotHS = br.ReadUInt16(); //6, 5
Name = FxcFile.ReadString(br); // <fxc name> _locals //"rage_matrices", "misc_globals", "lighting_globals", "more_stuff"
JenkIndex.Ensure(Name?.ToLowerInvariant()); //why not :P
}
public void Write(BinaryWriter bw)
{
bw.Write(Size);
bw.Write(SlotVS);
bw.Write(SlotPS);
bw.Write(SlotCS);
bw.Write(SlotDS);
bw.Write(SlotGS);
bw.Write(SlotHS);
FxcFile.WriteString(bw, Name);
}
public void WriteXml(StringBuilder sb, int indent)
{
FxcXml.StringTag(sb, indent, "Name", FxcXml.XmlEscape(Name));
FxcXml.ValueTag(sb, indent, "Size", Size.ToString());
FxcXml.ValueTag(sb, indent, "SlotVS", SlotVS.ToString());
FxcXml.ValueTag(sb, indent, "SlotPS", SlotPS.ToString());
FxcXml.ValueTag(sb, indent, "SlotCS", SlotCS.ToString());
FxcXml.ValueTag(sb, indent, "SlotDS", SlotDS.ToString());
FxcXml.ValueTag(sb, indent, "SlotGS", SlotGS.ToString());
FxcXml.ValueTag(sb, indent, "SlotHS", SlotHS.ToString());
}
public void ReadXml(XmlNode node)
{
Name = Xml.GetChildInnerText(node, "Name");
Size = Xml.GetChildUIntAttribute(node, "Size");
SlotVS = (ushort)Xml.GetChildUIntAttribute(node, "SlotVS");
SlotPS = (ushort)Xml.GetChildUIntAttribute(node, "SlotPS");
SlotCS = (ushort)Xml.GetChildUIntAttribute(node, "SlotCS");
SlotDS = (ushort)Xml.GetChildUIntAttribute(node, "SlotDS");
SlotGS = (ushort)Xml.GetChildUIntAttribute(node, "SlotGS");
SlotHS = (ushort)Xml.GetChildUIntAttribute(node, "SlotHS");
}
public override string ToString()
{
return Name + ": " + Size + ", " + SlotVS + ", " + SlotPS + ", " + SlotCS + ", " + SlotDS + ", " + SlotGS + ", " + SlotHS;
}
public void AddVariable(FxcVariable vari)
{
if (VariablesList == null) VariablesList = new List<FxcVariable>();
VariablesList.Add(vari);
}
public void ConsolidateVariables()
{
if (VariablesList != null)
{
//VariablesList.Sort((a, b) => a.Offset.CompareTo(b.Offset));
Variables = VariablesList.ToArray();
VariablesList = null;
}
}
}
public enum FxcVariableType : byte
{
Float = 2,
Float2 = 3,
Float3 = 4,
Float4 = 5,
Texture = 6, //also sampler
Boolean = 7,
Float3x4 = 8,
Float4x4 = 9,
Int = 11,
Int4 = 14,
Buffer = 15,
Unused1 = 17,
Unused2 = 18,
Unused3 = 19,
Unused4 = 20,
UAVBuffer = 21,
UAVTexture = 22,
}
[TC(typeof(EXP))] public class FxcVariable : IMetaXmlItem
{
public FxcVariableType Type { get; set; }
public byte Count { get; set; } //array size
public byte Slot { get; set; } //possibly GPU variable slot index for other platforms? or for CPU side
public byte Group { get; set; } //maybe - variables in same buffer usually have same value
public string Name1 { get; set; }
public string Name2 { get; set; }
public byte Offset { get; set; } //base offset (aligned to 16?)
public byte Variant { get; set; } //255,0,1,2,3,4,5,7,9 seems to be used when multiple variables at same offset in the buffer
public byte Unused0 { get; set; }//0
public byte Unused1 { get; set; }//0
public MetaHash CBufferName { get; set; }
public byte ParamCount { get; set; }
public FxcVariableParam[] Params { get; set; }
public byte ValueCount { get; set; }
public float[] ValuesF { get; set; }//optional default value for the variable, should match up with Type?
public uint[] ValuesU { get; set; }
private bool UseUIntValues
{
get
{
switch (Type)
{
case FxcVariableType.Int:
case FxcVariableType.Int4:
case FxcVariableType.Boolean:
case FxcVariableType.Texture:
case FxcVariableType.Buffer:
case FxcVariableType.UAVTexture:
case FxcVariableType.UAVBuffer: return true;
default: return false;
}
}
}
public void Read(BinaryReader br)
{
Type = (FxcVariableType)br.ReadByte();
Count = br.ReadByte();
Slot = br.ReadByte();
Group = br.ReadByte();
Name1 = FxcFile.ReadString(br);
Name2 = FxcFile.ReadString(br);
Offset = br.ReadByte();
Variant = br.ReadByte();
Unused0 = br.ReadByte(); //always 0
Unused1 = br.ReadByte(); //always 0
CBufferName = br.ReadUInt32();
ParamCount = br.ReadByte(); //1
if (ParamCount > 0)
{
List<FxcVariableParam> parms = new List<FxcVariableParam>();
for (int i = 0; i < ParamCount; i++)
{
FxcVariableParam parm = new FxcVariableParam();
parm.Read(br);
parms.Add(parm);
}
Params = parms.ToArray();
}
ValueCount = br.ReadByte();
if (ValueCount > 0)
{
if (UseUIntValues)
{
ValuesU = new uint[ValueCount];
for (int i = 0; i < ValueCount; i++)
{
ValuesU[i] = br.ReadUInt32();
}
}
else
{
ValuesF = new float[ValueCount];
for (int i = 0; i < ValueCount; i++)
{
ValuesF[i] = br.ReadSingle();
}
}
}
//switch (Group)
//{
// case 0:
// case 1:
// case 2:
// case 3:
// case 10:
// case 11:
// case 17:
// case 19:
// case 27:
// case 34:
// break;
// case 6:
// case 16:
// case 26:
// case 32:
// case 33:
// case 35:
// case 39:
// case 49:
// case 51:
// break;
// default:
// break;
//}
}
public void Write(BinaryWriter bw)
{
bw.Write((byte)Type);
bw.Write(Count);
bw.Write(Slot);
bw.Write(Group);
FxcFile.WriteString(bw, Name1);
FxcFile.WriteString(bw, Name2);
bw.Write(Offset);
bw.Write(Variant);
bw.Write(Unused0);
bw.Write(Unused1);
bw.Write(CBufferName);
ParamCount = (byte)(Params?.Length ?? 0);
bw.Write(ParamCount);
for (int i = 0; i < ParamCount; i++)
{
Params[i].Write(bw);
}
if (UseUIntValues)
{
ValueCount = (byte)(ValuesU?.Length ?? 0);
bw.Write(ValueCount);
for (int i = 0; i < ValueCount; i++)
{
bw.Write(ValuesU[i]);
}
}
else
{
ValueCount = (byte)(ValuesF?.Length ?? 0);
bw.Write(ValueCount);
for (int i = 0; i < ValueCount; i++)
{
bw.Write(ValuesF[i]);
}
}
}
public void WriteXml(StringBuilder sb, int indent)
{
FxcXml.StringTag(sb, indent, "Name1", FxcXml.XmlEscape(Name1));
FxcXml.StringTag(sb, indent, "Name2", FxcXml.XmlEscape(Name2));
FxcXml.StringTag(sb, indent, "Buffer", FxcXml.HashString(CBufferName));
FxcXml.StringTag(sb, indent, "Type", Type.ToString());
FxcXml.ValueTag(sb, indent, "Count", Count.ToString());
FxcXml.ValueTag(sb, indent, "Slot", Slot.ToString());
FxcXml.ValueTag(sb, indent, "Group", Group.ToString());
FxcXml.ValueTag(sb, indent, "Offset", Offset.ToString());
FxcXml.ValueTag(sb, indent, "Variant", Variant.ToString());
if (Params != null)
{
FxcXml.WriteItemArray(sb, Params, indent, "Params");
}
if (ValuesF != null)
{
FxcXml.WriteRawArray(sb, ValuesF, indent, "Values", "", FloatUtil.ToString);
}
if (ValuesU != null)
{
FxcXml.WriteRawArray(sb, ValuesU, indent, "Values", "");
}
}
public void ReadXml(XmlNode node)
{
Name1 = Xml.GetChildInnerText(node, "Name1");
Name2 = Xml.GetChildInnerText(node, "Name2");
CBufferName = XmlMeta.GetHash(Xml.GetChildInnerText(node, "Buffer"));
Type = Xml.GetChildEnumInnerText<FxcVariableType>(node, "Type");
Count = (byte)Xml.GetChildUIntAttribute(node, "Count");
Slot = (byte)Xml.GetChildUIntAttribute(node, "Slot");
Group = (byte)Xml.GetChildUIntAttribute(node, "Group");
Offset = (byte)Xml.GetChildUIntAttribute(node, "Offset");
Variant = (byte)Xml.GetChildUIntAttribute(node, "Variant");
Params = XmlMeta.ReadItemArray<FxcVariableParam>(node, "Params");
if (UseUIntValues)
{
ValuesU = Xml.GetChildRawUintArrayNullable(node, "Values");
}
else
{
ValuesF = Xml.GetChildRawFloatArrayNullable(node, "Values");
}
}
public override string ToString()
{
var pstr = (ParamCount > 0) ? (", " + ParamCount.ToString() + " params") : "";
var vstr = (ValueCount > 0) ? (", " + ValueCount.ToString() + " values") : "";
return Type.ToString() + ", " + Count.ToString() + ", " + Slot.ToString() + ", " + Group.ToString() + ", " + Offset.ToString() + ", " + Variant.ToString() + ", " + CBufferName.ToString() + ", " + Name1 + ", " + Name2 + pstr + vstr;
}
}
public enum FxcVariableParamType : byte
{
Int = 0,
Float = 1,
String = 2,
}
[TC(typeof(EXP))] public class FxcVariableParam : IMetaXmlItem
{
public string Name { get; set; }
public FxcVariableParamType Type { get; set; }
public object Value { get; set; }
public void Read(BinaryReader br)
{
Name = FxcFile.ReadString(br);
Type = (FxcVariableParamType)br.ReadByte();
switch (Type)
{
case FxcVariableParamType.Int:
Value = br.ReadInt32();
break;
case FxcVariableParamType.Float:
Value = br.ReadSingle();
break;
case FxcVariableParamType.String:
Value = FxcFile.ReadString(br);
break;
default:
break;
}
}
public void Write(BinaryWriter bw)
{
FxcFile.WriteString(bw, Name);
bw.Write((byte)Type);
switch (Type)
{
case FxcVariableParamType.Int:
bw.Write((int)Value);
break;
case FxcVariableParamType.Float:
bw.Write((float)Value);
break;
case FxcVariableParamType.String:
FxcFile.WriteString(bw, (string)Value);
break;
default:
break;
}
}
public void WriteXml(StringBuilder sb, int indent)
{
FxcXml.StringTag(sb, indent, "Name", FxcXml.XmlEscape(Name));
FxcXml.StringTag(sb, indent, "Type", Type.ToString());
switch (Type)
{
case FxcVariableParamType.Int:
FxcXml.ValueTag(sb, indent, "Value", ((int)Value).ToString());
break;
case FxcVariableParamType.Float:
FxcXml.ValueTag(sb, indent, "Value", FloatUtil.ToString((float)Value));
break;
case FxcVariableParamType.String:
FxcXml.StringTag(sb, indent, "Value", FxcXml.XmlEscape(Value as string));
break;
}
}
public void ReadXml(XmlNode node)
{
Name = Xml.GetChildInnerText(node, "Name");
Type = Xml.GetChildEnumInnerText<FxcVariableParamType>(node, "Type");
switch (Type)
{
case FxcVariableParamType.Int:
Value = Xml.GetChildIntAttribute(node, "Value");
break;
case FxcVariableParamType.Float:
Value = Xml.GetChildFloatAttribute(node, "Value");
break;
case FxcVariableParamType.String:
Value = Xml.GetChildInnerText(node, "Value");
break;
}
}
public override string ToString()
{
return Name + ": " + Value?.ToString();
}
}
[TC(typeof(EXP))] public class FxcTechnique : IMetaXmlItem
{
public string Name { get; set; }
public byte PassCount { get; set; }
public FxcPass[] Passes { get; set; }
public void Read(BinaryReader br)
{
Name = FxcFile.ReadString(br); //"draw", "deferred_draw", etc..
PassCount = br.ReadByte();//
if (PassCount > 0)
{
Passes = new FxcPass[PassCount];
for (int i = 0; i < PassCount; i++)
{
FxcPass p = new FxcPass();
p.Read(br);
Passes[i] = p;
}
}
}
public void Write(BinaryWriter bw)
{
FxcFile.WriteString(bw, Name);
PassCount = (byte)(Passes?.Length ?? 0);
bw.Write(PassCount);
for (int i = 0; i < PassCount; i++)
{
Passes[i].Write(bw);
}
}
public void WriteXml(StringBuilder sb, int indent)
{
FxcXml.StringTag(sb, indent, "Name", FxcXml.XmlEscape(Name));
FxcXml.WriteItemArray(sb, Passes, indent, "Passes");
}
public void ReadXml(XmlNode node)
{
Name = Xml.GetChildInnerText(node, "Name");
Passes = XmlMeta.ReadItemArray<FxcPass>(node, "Passes");
}
public void GetNamesFromIndices(FxcFile fxc)
{
if (Passes == null) return;
foreach (var pass in Passes)
{
pass.GetNamesFromIndices(fxc);
}
}
public void GetIndicesFromNames(FxcFile fxc)
{
if (Passes == null) return;
foreach (var pass in Passes)
{
pass.GetIndicesFromNames(fxc);
}
}
public override string ToString()
{
return Name + " (" + PassCount.ToString() + " pass" + (PassCount != 1 ? "es" : "") + ")";
}
}
[TC(typeof(EXP))] public class FxcPass : IMetaXmlItem
{
public byte VS { get; set; }
public byte PS { get; set; }
public byte CS { get; set; }
public byte DS { get; set; }
public byte GS { get; set; }
public byte HS { get; set; }
public byte ParamCount { get; set; }
public FxcPassParam[] Params { get; set; } //probably referring to eg SetBlendState, SetRasterizerState etc
public string VSName { get; set; }
public string PSName { get; set; }
public string CSName { get; set; }
public string DSName { get; set; }
public string GSName { get; set; }
public string HSName { get; set; }
public void Read(BinaryReader br)
{
VS = br.ReadByte();
PS = br.ReadByte();
CS = br.ReadByte();
DS = br.ReadByte();
GS = br.ReadByte();
HS = br.ReadByte();
ParamCount = br.ReadByte();
if (ParamCount > 0)
{
Params = new FxcPassParam[ParamCount];
for (int i = 0; i < ParamCount; i++)
{
FxcPassParam p = new FxcPassParam();
p.Read(br);
Params[i] = p;
}
}
}
public void Write(BinaryWriter bw)
{
bw.Write(VS);
bw.Write(PS);
bw.Write(CS);
bw.Write(DS);
bw.Write(GS);
bw.Write(HS);
ParamCount = (byte)(Params?.Length ?? 0);
bw.Write(ParamCount);
for (int i = 0; i < ParamCount; i++)
{
Params[i].Write(bw);
}
}
public void WriteXml(StringBuilder sb, int indent)
{
if (!string.IsNullOrEmpty(VSName)) FxcXml.StringTag(sb, indent, "VertexShader", FxcXml.XmlEscape(VSName));
if (!string.IsNullOrEmpty(PSName)) FxcXml.StringTag(sb, indent, "PixelShader", FxcXml.XmlEscape(PSName));
if (!string.IsNullOrEmpty(CSName)) FxcXml.StringTag(sb, indent, "ComputeShader", FxcXml.XmlEscape(CSName));
if (!string.IsNullOrEmpty(DSName)) FxcXml.StringTag(sb, indent, "DomainShader", FxcXml.XmlEscape(DSName));
if (!string.IsNullOrEmpty(GSName)) FxcXml.StringTag(sb, indent, "GeometryShader", FxcXml.XmlEscape(GSName));
if (!string.IsNullOrEmpty(HSName)) FxcXml.StringTag(sb, indent, "HullShader", FxcXml.XmlEscape(HSName));
if (Params != null)
{
FxcXml.WriteItemArray(sb, Params, indent, "Params");
}
}
public void ReadXml(XmlNode node)
{
VSName = Xml.GetChildInnerText(node, "VertexShader");
PSName = Xml.GetChildInnerText(node, "PixelShader");
CSName = Xml.GetChildInnerText(node, "ComputeShader");
DSName = Xml.GetChildInnerText(node, "DomainShader");
GSName = Xml.GetChildInnerText(node, "GeometryShader");
HSName = Xml.GetChildInnerText(node, "HullShader");
Params = XmlMeta.ReadItemArray<FxcPassParam>(node, "Params");
}
public void GetNamesFromIndices(FxcFile fxc)
{
VSName = fxc.GetVS(VS)?.Name;
PSName = fxc.GetPS(PS)?.Name;
CSName = fxc.GetCS(CS)?.Name;
DSName = fxc.GetDS(DS)?.Name;
GSName = fxc.GetGS(GS)?.Name;
HSName = fxc.GetHS(HS)?.Name;
}
public void GetIndicesFromNames(FxcFile fxc)
{
VS = fxc.GetVSID(VSName);
PS = fxc.GetPSID(PSName);
CS = fxc.GetCSID(CSName);
DS = fxc.GetDSID(DSName);
GS = fxc.GetGSID(GSName);
HS = fxc.GetHSID(HSName);
}
public override string ToString()
{
return VS.ToString() + ", " + PS.ToString() + ", " + CS.ToString() + ", " + DS.ToString() + ", " + GS.ToString() + ", " + HS.ToString();
}
}
[TC(typeof(EXP))] public class FxcPassParam : IMetaXmlItem
{
public uint Type { get; set; } //probably referring to eg SetBlendState, SetRasterizerState etc
public uint Value { get; set; }
public void Read(BinaryReader br)
{
Type = br.ReadUInt32();
Value = br.ReadUInt32();
//switch (Type)
//{
// case 10:
// case 3:
// case 6:
// case 7:
// case 19:
// case 20:
// case 21:
// case 22:
// case 2:
// case 11:
// case 25:
// case 23:
// case 4:
// case 5:
// case 24:
// case 26:
// case 27:
// case 14:
// case 12:
// case 13:
// case 15:
// case 16:
// case 17:
// case 18:
// case 0:
// case 9:
// case 8:
// case 29:
// break;
// default:
// break;
//}
//switch (Value)
//{
// case 0: //type 10, 3, 20, 21, 22, 2, 11, 18
// case 1: //type 6, 25, 23, 5, 24, 14, 12, 13, 0
// case 8: //type 7, 19
// case 5: //type 7, 9
// case 2: //type 4, 26
// case 6: //type 27
// case 7: //type 7, 16, 17
// case 3: //type 15
// case 4: //type 22
// case 15://type 20
// case 100://type 8
// case 9: //type 4
// case 12://type 16
// case 67://type 16
// case 64://type 17
// case 191://type 18
// case 0xBDCCCCCD://(-0.1f) type 29
// case 0x3E4CCCCD://(0.2f) type 29
// case 10://type 8
// break;
// default:
// break;
//}
}
public void Write(BinaryWriter bw)
{
bw.Write(Type);
bw.Write(Value);
}
public void WriteXml(StringBuilder sb, int indent)
{
FxcXml.ValueTag(sb, indent, "Type", Type.ToString());
FxcXml.ValueTag(sb, indent, "Value", Value.ToString());
}
public void ReadXml(XmlNode node)
{
Type = Xml.GetChildUIntAttribute(node, "Type");
Value = Xml.GetChildUIntAttribute(node, "Value");
}
public override string ToString()
{
return Type.ToString() + ", " + Value.ToString();
}
}
public class FxcXml : MetaXmlBase
{
public static string GetXml(FxcFile fxc, string outputFolder = "")
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(XmlHeader);
if ((fxc != null) && (fxc.Shaders != null))
{
var name = "Effects";
OpenTag(sb, 0, name);
fxc.WriteXml(sb, 1, outputFolder);
CloseTag(sb, 0, name);
}
return sb.ToString();
}
}
public class XmlFxc
{
public static FxcFile GetFxc(string xml, string inputFolder = "")
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
return GetFxc(doc, inputFolder);
}
public static FxcFile GetFxc(XmlDocument doc, string inputFolder = "")
{
FxcFile fxc = new FxcFile();
fxc.ReadXml(doc.DocumentElement, inputFolder);
return fxc;
}
}
}