mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-08-21 01:19:21 +08:00
1080 lines
34 KiB
C#
1080 lines
34 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
//GTAV FXC file reader by dexyfex.
|
|
// use this however you want. some credit would be nice.
|
|
|
|
namespace CodeWalker.GameFiles
|
|
{
|
|
[TypeConverter(typeof(ExpandableObjectConverter))]
|
|
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 FxcHeaderExt[] Exts { get; set; }
|
|
public FxcHeaderChunk[] Chunks { get; set; }
|
|
public FxcShader[] Shaders { 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[] 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 string LastError { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void Load(byte[] data, RpfFileEntry entry)
|
|
{
|
|
FileEntry = entry;
|
|
Name = entry.Name;
|
|
Hash = entry.ShortNameHash;
|
|
|
|
LastError = string.Empty;
|
|
|
|
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 ec0 = br.ReadByte();
|
|
var exts1 = new List<FxcHeaderExt>();
|
|
for (int e = 0; e < ec0; e++)
|
|
{
|
|
FxcHeaderExt ext = new FxcHeaderExt();
|
|
ext.Name = ReadString(br);
|
|
ext.Unk0Byte = br.ReadByte(); //0
|
|
ext.Unk1Uint = br.ReadUInt32(); //2
|
|
exts1.Add(ext);
|
|
}
|
|
Exts = exts1.ToArray();
|
|
|
|
|
|
List<FxcShader>[] shadergrps = new List<FxcShader>[6];
|
|
|
|
var chunks = new List<FxcHeaderChunk>();
|
|
var shaders = new List<FxcShader>();
|
|
int gindex = 0;
|
|
while (gindex<6)// (sc0 > 0)
|
|
{
|
|
var shadergrp = new List<FxcShader>();
|
|
shadergrps[gindex] = shadergrp;
|
|
|
|
gindex++;
|
|
byte sc0 = br.ReadByte();
|
|
if (sc0 == 0)
|
|
{
|
|
sc0 = br.ReadByte(); //this is a little odd, sometimes a byte skip
|
|
}
|
|
FxcHeaderChunk chunk = new FxcHeaderChunk();
|
|
chunk.Read(br);
|
|
chunk.Gindex = gindex;
|
|
chunk.ShaderCount = sc0;
|
|
chunks.Add(chunk);
|
|
for (int s = 1; s < sc0; s++)
|
|
{
|
|
bool exbyteflag1 = (gindex==5); //GS seems to be in diff format??
|
|
bool vsgsps = (gindex == 1) || (gindex == 2) || (gindex == 5);
|
|
FxcShader shader = new FxcShader();
|
|
if (!shader.Read(br, exbyteflag1, vsgsps))
|
|
{
|
|
LastError += shader.LastError;
|
|
//gindex = 6; //get outta the loop?
|
|
//break;
|
|
}
|
|
shaders.Add(shader);
|
|
shadergrp.Add(shader);
|
|
}
|
|
}
|
|
|
|
Shaders = shaders.ToArray();
|
|
VertexShaders = shadergrps[0]?.ToArray();
|
|
PixelShaders = shadergrps[1]?.ToArray();
|
|
ComputeShaders = shadergrps[2]?.ToArray();
|
|
DomainShaders = shadergrps[3]?.ToArray();
|
|
GeometryShaders = shadergrps[4]?.ToArray();
|
|
HullShaders = shadergrps[5]?.ToArray();
|
|
|
|
|
|
Chunks = chunks.ToArray();
|
|
|
|
//ms.Dispose();
|
|
//return;
|
|
|
|
List<FxcVariable> globalVars = new List<FxcVariable>();
|
|
CBufferDict = new Dictionary<uint, FxcCBuffer>();
|
|
FxcCBuffer cbtmp = null;
|
|
|
|
try //things can be uncertain after this...
|
|
{
|
|
|
|
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 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 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);
|
|
techniques.Add(tech);
|
|
}
|
|
Techniques = techniques.ToArray();
|
|
}
|
|
|
|
|
|
foreach (var cbuf in CBufferDict.Values)
|
|
{
|
|
cbuf.ConsolidateVariables();
|
|
}
|
|
GlobalVariables = globalVars.ToArray();
|
|
|
|
|
|
if (ms.Position != ms.Length)
|
|
{ }
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LastError = ex.ToString();
|
|
}
|
|
|
|
ms.Dispose();
|
|
}
|
|
|
|
|
|
|
|
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 (Exts != null)
|
|
{
|
|
sb.AppendLine("Header");
|
|
foreach (var ext in Exts)
|
|
{
|
|
sb.AppendLine(" " + ext.ToString());
|
|
}
|
|
sb.AppendLine();
|
|
}
|
|
|
|
if (Chunks != null)
|
|
{
|
|
sb.AppendLine("Sections");
|
|
foreach (var chunk in Chunks)
|
|
{
|
|
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.Params != null) && (shader.Params.Length > 0))
|
|
{
|
|
sb.AppendLine(" (Params)");
|
|
foreach (var parm in shader.Params)
|
|
{
|
|
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.Values != null) && (p.Values.Length > 0))
|
|
{
|
|
sb.AppendLine(" (Values)");
|
|
foreach (var d in p.Values)
|
|
{
|
|
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.Values != null) && (p.Values.Length > 0))
|
|
{
|
|
sb.AppendLine(" (Values)");
|
|
foreach (var d in p.Values)
|
|
{
|
|
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 static string ReadString(BinaryReader br)
|
|
{
|
|
byte sl = br.ReadByte();
|
|
if (sl == 0) return string.Empty;
|
|
byte[] ba = new byte[sl];
|
|
br.Read(ba, 0, sl);
|
|
return (sl > 1) ? ASCIIEncoding.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();
|
|
for (int n = 0; n < sl; n++)
|
|
{
|
|
sb.Append((char)br.ReadByte());
|
|
}
|
|
r[i] = sb.ToString().Replace("\0", "");
|
|
}
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class FxcHeaderExt
|
|
{
|
|
public string Name { get; set; }
|
|
public byte Unk0Byte { get; set; }
|
|
public uint Unk1Uint { get; set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return Name + ": " + Unk0Byte.ToString() + ": " + Unk1Uint.ToString();
|
|
}
|
|
}
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class FxcHeaderChunk
|
|
{
|
|
public string Name { get; set; }
|
|
public byte Unk1Byte { get; set; }
|
|
public byte Unk2Byte { get; set; }
|
|
public uint Unk3Uint { get; set; }
|
|
public int Gindex { get; set; } //index in the fxc file
|
|
public byte ShaderCount { get; set; } //number of shaders in the section
|
|
|
|
public void Read(BinaryReader br)
|
|
{
|
|
Name = FxcFile.ReadString(br); //usually "NULL"
|
|
Unk1Byte = br.ReadByte();
|
|
Unk2Byte = br.ReadByte();
|
|
Unk3Uint = br.ReadUInt32();
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return Name + ": " + Gindex.ToString() + ": " + ShaderCount.ToString() + ": " + Unk1Byte.ToString() + ": " + Unk2Byte.ToString() + ": " + Unk3Uint.ToString();
|
|
}
|
|
}
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class FxcShader
|
|
{
|
|
public long Offset { get; set; }
|
|
public string Name { get; set; }
|
|
public string[] Params { 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; }
|
|
public string LastError { get; set; }
|
|
|
|
public bool Read(BinaryReader br, bool exbyteflag, bool vsgsps)
|
|
{
|
|
Offset = br.BaseStream.Position;
|
|
|
|
Name = FxcFile.ReadString(br);
|
|
|
|
if (Name.Length == 0)
|
|
{
|
|
Name = FxcFile.ReadString(br); //why (seems to be GS only)
|
|
exbyteflag = true;
|
|
}
|
|
|
|
|
|
Params = FxcFile.ReadStringArray(br);
|
|
|
|
byte bufferCount = br.ReadByte();
|
|
var buffers = new List<FxcShaderBufferRef>();
|
|
for (int e = 0; e < bufferCount; e++)
|
|
{
|
|
FxcShaderBufferRef ext = new FxcShaderBufferRef();
|
|
ext.Name = FxcFile.ReadString(br);
|
|
ext.Unk0Ushort = br.ReadUInt16();
|
|
buffers.Add(ext);
|
|
}
|
|
Buffers = buffers.ToArray();
|
|
|
|
byte exbyte = 0;
|
|
if (exbyteflag)
|
|
{
|
|
exbyte = br.ReadByte(); //not sure what this is used for...
|
|
if ((exbyte != 0))
|
|
{ }
|
|
}
|
|
|
|
|
|
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!
|
|
}
|
|
br.BaseStream.Position -= 4; //wind back because dx needs that header
|
|
|
|
ByteCode = br.ReadBytes((int)datalength);
|
|
|
|
if (vsgsps)
|
|
{
|
|
VersionMajor = br.ReadByte();//4,5 //appears to be shader model version
|
|
VersionMinor = br.ReadByte(); //perhaps shader minor version
|
|
}
|
|
|
|
//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;
|
|
//}
|
|
}
|
|
else
|
|
{
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
public override string ToString()
|
|
{
|
|
return Name;
|
|
}
|
|
}
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class FxcShaderBufferRef
|
|
{
|
|
public string Name { get; set; } //Buffer name
|
|
public ushort Unk0Ushort { get; set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return Name + ": " + Unk0Ushort.ToString();
|
|
}
|
|
}
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class FxcCBuffer
|
|
{
|
|
public uint u003 { get; set; }
|
|
public ushort us001 { get; set; }
|
|
public ushort us002 { get; set; }
|
|
public ushort us003 { get; set; }
|
|
public ushort us004 { get; set; }
|
|
public ushort us005 { get; set; }
|
|
public ushort us006 { get; set; }
|
|
public string Name { get; set; }
|
|
|
|
public uint NameHash { get { return JenkHash.GenHash(Name); } }
|
|
public List<FxcVariable> VariablesList;
|
|
public FxcVariable[] Variables { get; set; }
|
|
|
|
public void Read(BinaryReader br)
|
|
{
|
|
u003 = br.ReadUInt32(); //176, 16 //256
|
|
us001 = br.ReadUInt16(); //6, 5
|
|
us002 = br.ReadUInt16(); //6, 12
|
|
us003 = br.ReadUInt16(); //6, 5
|
|
us004 = br.ReadUInt16(); //6, 5
|
|
us005 = br.ReadUInt16(); //6, 5
|
|
us006 = br.ReadUInt16(); //6, 5
|
|
Name = FxcFile.ReadString(br); // <fxc name> _locals //"rage_matrices", "misc_globals", "lighting_globals", "more_stuff"
|
|
JenkIndex.Ensure(Name); //why not :P
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return Name + ": " + u003 + ", " + us001 + ", " + us002 + ", " + us003 + ", " + us004 + ", " + us005 + ", " + us006;
|
|
}
|
|
|
|
public void AddVariable(FxcVariable vari)
|
|
{
|
|
if (VariablesList == null) VariablesList = new List<FxcVariable>();
|
|
VariablesList.Add(vari);
|
|
}
|
|
public void ConsolidateVariables()
|
|
{
|
|
if (VariablesList != null)
|
|
{
|
|
Variables = VariablesList.ToArray();
|
|
VariablesList = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class FxcVariable
|
|
{
|
|
public byte b0 { get; set; }
|
|
public byte b1 { get; set; }
|
|
public byte b2 { get; set; }
|
|
public byte b3 { get; set; }
|
|
public string Name1 { get; set; }
|
|
public string Name2 { get; set; }
|
|
public byte b4 { get; set; }
|
|
public byte b5 { get; set; }
|
|
public byte b6 { get; set; }
|
|
public byte b7 { get; set; }
|
|
public MetaHash CBufferName { get; set; }
|
|
public byte ParamCount { get; set; }
|
|
public FxcVariableParam[] Params { get; set; }
|
|
public byte ValueCount { get; set; }
|
|
public float[] Values { get; set; }
|
|
|
|
|
|
public void Read(BinaryReader br)
|
|
{
|
|
b0 = br.ReadByte(); //5
|
|
b1 = br.ReadByte(); //0,1
|
|
b2 = br.ReadByte(); //19 //17
|
|
b3 = br.ReadByte(); //2 //27
|
|
Name1 = FxcFile.ReadString(br);
|
|
Name2 = FxcFile.ReadString(br);
|
|
b4 = br.ReadByte(); //32
|
|
b5 = br.ReadByte(); //
|
|
b6 = br.ReadByte(); //
|
|
b7 = br.ReadByte(); //
|
|
CBufferName = br.ReadUInt32(); //hash
|
|
|
|
|
|
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)
|
|
{
|
|
Values = new float[ValueCount];
|
|
for (int i = 0; i < ValueCount; i++)
|
|
{
|
|
Values[i] = br.ReadSingle(); //TODO: how to know what types to use?
|
|
}
|
|
}
|
|
|
|
|
|
#region debug validation
|
|
|
|
switch (b0)
|
|
{
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
case 11:
|
|
case 14:
|
|
case 17:
|
|
case 20:
|
|
break;
|
|
case 15:
|
|
case 18:
|
|
case 19:
|
|
case 21:
|
|
case 22:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (b1)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 8:
|
|
case 12:
|
|
case 254:
|
|
case 255:
|
|
break;
|
|
case 14:
|
|
case 16:
|
|
case 24:
|
|
case 40:
|
|
case 117:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (CBufferName)
|
|
{
|
|
case 2165770756:
|
|
case 3458315595:
|
|
case 1059338858:
|
|
case 3779850771:
|
|
case 2988188919:
|
|
case 713939274:
|
|
case 3369176576:
|
|
case 1927486087:
|
|
case 4135739982:
|
|
case 1032736383:
|
|
case 3084860475:
|
|
case 3844532749:
|
|
case 3635751376:
|
|
case 2172777116:
|
|
case 4255900365:
|
|
case 2725372071:
|
|
case 3661207622:
|
|
case 4213364555:
|
|
case 1519748817:
|
|
case 118958736:
|
|
case 2397841684:
|
|
case 1340365912:
|
|
case 2531859994:
|
|
case 0:
|
|
break;
|
|
case 482774302:
|
|
case 2300268537:
|
|
case 2714887816:
|
|
case 2049538169:
|
|
case 1316881611:
|
|
case 3367312321:
|
|
case 4017086211:
|
|
case 3743503190:
|
|
case 938670440:
|
|
case 2782027784:
|
|
case 2865440919:
|
|
case 2384984532:
|
|
case 486482914:
|
|
case 3162602184:
|
|
case 1834530379:
|
|
case 1554708878:
|
|
case 1142002603:
|
|
case 3049310097:
|
|
case 764124013:
|
|
case 2526104914:
|
|
case 1561144077:
|
|
case 970248680:
|
|
case 3899781660:
|
|
case 1853474951:
|
|
case 2224880237:
|
|
case 3766848419:
|
|
case 2718810031:
|
|
case 115655537:
|
|
case 4224116138:
|
|
case 3572088685:
|
|
case 1438660507:
|
|
case 4092686193:
|
|
case 871214106:
|
|
case 2121263542:
|
|
case 3502503908:
|
|
case 586499600:
|
|
case 4046148196:
|
|
case 2999112456:
|
|
case 2355014976:
|
|
case 579364910:
|
|
case 2193272593:
|
|
case 1641847936:
|
|
case 1286180849:
|
|
case 3291504934:
|
|
case 278397346:
|
|
case 3346871633:
|
|
case 4091106477:
|
|
case 832855465:
|
|
case 3616072140:
|
|
case 3977262900:
|
|
case 2062541604:
|
|
case 950211059:
|
|
case 2380663322:
|
|
case 2783177544:
|
|
case 1100625170:
|
|
case 1279142172:
|
|
case 1004646027:
|
|
case 2092585241:
|
|
case 4165560568:
|
|
case 2651790209:
|
|
case 3453406875:
|
|
case 488789527:
|
|
case 3375019131:
|
|
case 519785780:
|
|
case 729415208:
|
|
case 556501613:
|
|
case 2829744882:
|
|
case 1778702372:
|
|
case 2564407213:
|
|
case 3291498326:
|
|
case 1275817784:
|
|
case 962813362:
|
|
case 2020034807:
|
|
case 2017746823:
|
|
case 1237102223:
|
|
case 4029270406:
|
|
case 673228990:
|
|
case 201854132:
|
|
case 1866965008:
|
|
case 957783816:
|
|
case 2522030664:
|
|
case 1910375705:
|
|
case 2656344872:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (b3)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return b0.ToString() + ", " + b1.ToString() + ", " + b2.ToString() + ", " + b3.ToString() + ", " + b4.ToString() + ", " + b5.ToString() + ", " + b6.ToString() + ", " + b7.ToString() + ", " + CBufferName.ToString() + ", " + Name1 + ", " + Name2;
|
|
}
|
|
}
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class FxcVariableParam
|
|
{
|
|
public string Name { get; set; }
|
|
public byte Type { get; set; }
|
|
public object Value { get; set; }
|
|
|
|
public void Read(BinaryReader br)
|
|
{
|
|
Name = FxcFile.ReadString(br);
|
|
Type = br.ReadByte();
|
|
switch (Type)
|
|
{
|
|
case 0:
|
|
Value = br.ReadUInt32();
|
|
break;
|
|
case 1:
|
|
Value = br.ReadSingle();
|
|
break;
|
|
case 2:
|
|
Value = FxcFile.ReadString(br);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return Name + ": " + Value?.ToString();
|
|
}
|
|
}
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class FxcTechnique
|
|
{
|
|
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 override string ToString()
|
|
{
|
|
return Name + " (" + PassCount.ToString() + " pass" + (PassCount != 1 ? "es" : "") + ")";
|
|
}
|
|
}
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class FxcPass
|
|
{
|
|
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; }
|
|
|
|
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.u0 = br.ReadUInt32();
|
|
p.u1 = br.ReadUInt32();
|
|
Params[i] = p;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return VS.ToString() + ", " + PS.ToString() + ", " + CS.ToString() + ", " + DS.ToString() + ", " + GS.ToString() + ", " + HS.ToString();
|
|
}
|
|
|
|
}
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class FxcPassParam
|
|
{
|
|
public uint u0 { get; set; }
|
|
public uint u1 { get; set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return u0.ToString() + ", " + u1.ToString();
|
|
}
|
|
}
|
|
|
|
|
|
}
|