mirror of
https://github.com/AssetRipper/ShaderRecoveryPlugin.git
synced 2026-11-13 18:07:38 -10:00
580 lines
16 KiB
C#
580 lines
16 KiB
C#
using AssetRipper.Core.Classes.Shader;
|
|
using AssetRipper.Core.Classes.Shader.Blob;
|
|
using AssetRipper.Core.Classes.Shader.Enums;
|
|
using AssetRipper.Core.Classes.Shader.Enums.GpuProgramType;
|
|
using AssetRipper.Core.Classes.Shader.SerializedShader;
|
|
using AssetRipper.Core.Classes.Shader.SerializedShader.Enum;
|
|
using AssetRipper.Core.Extensions;
|
|
using System;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
|
|
namespace ShaderTextRestorer.IO
|
|
{
|
|
public static class SerializedExtensions
|
|
{
|
|
public static void Export(this SerializedPass _this, ShaderWriter writer)
|
|
{
|
|
writer.WriteIndent(2);
|
|
writer.Write("{0} ", _this.Type.ToString());
|
|
|
|
if (_this.Type == SerializedPassType.UsePass)
|
|
{
|
|
writer.Write("\"{0}\"\n", _this.UseName);
|
|
}
|
|
else
|
|
{
|
|
writer.Write("{\n");
|
|
|
|
if (_this.Type == SerializedPassType.GrabPass)
|
|
{
|
|
if (_this.TextureName.Length > 0)
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("\"{0}\"\n", _this.TextureName);
|
|
}
|
|
}
|
|
else if (_this.Type == SerializedPassType.Pass)
|
|
{
|
|
_this.State.Export(writer);
|
|
|
|
if ((_this.ProgramMask & ShaderType.Vertex.ToProgramMask()) != 0)
|
|
{
|
|
_this.ProgVertex.Export(writer, ShaderType.Vertex);
|
|
}
|
|
if ((_this.ProgramMask & ShaderType.Fragment.ToProgramMask()) != 0)
|
|
{
|
|
_this.ProgFragment.Export(writer, ShaderType.Fragment);
|
|
}
|
|
if ((_this.ProgramMask & ShaderType.Geometry.ToProgramMask()) != 0)
|
|
{
|
|
_this.ProgGeometry.Export(writer, ShaderType.Geometry);
|
|
}
|
|
if ((_this.ProgramMask & ShaderType.Hull.ToProgramMask()) != 0)
|
|
{
|
|
_this.ProgHull.Export(writer, ShaderType.Hull);
|
|
}
|
|
if ((_this.ProgramMask & ShaderType.Domain.ToProgramMask()) != 0)
|
|
{
|
|
_this.ProgDomain.Export(writer, ShaderType.Domain);
|
|
}
|
|
if ((_this.ProgramMask & ShaderType.RayTracing.ToProgramMask()) != 0)
|
|
{
|
|
_this.ProgDomain.Export(writer, ShaderType.RayTracing);
|
|
}
|
|
|
|
#warning HasInstancingVariant?
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException($"Unsupported pass type {_this.Type}");
|
|
}
|
|
|
|
writer.WriteIndent(2);
|
|
writer.Write("}\n");
|
|
}
|
|
}
|
|
|
|
public static void Export(this SerializedProgram _this, ShaderWriter writer, ShaderType type)
|
|
{
|
|
if (_this.SubPrograms.Length == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
writer.WriteIndent(3);
|
|
writer.Write("Program \"{0}\" {{\n", type.ToProgramTypeString());
|
|
int tierCount = _this.GetTierCount();
|
|
for (int i = 0; i < _this.SubPrograms.Length; i++)
|
|
{
|
|
_this.SubPrograms[i].Export(writer, type, tierCount > 1);
|
|
}
|
|
writer.WriteIndent(3);
|
|
writer.Write("}\n");
|
|
}
|
|
|
|
public static void Export(this SerializedProperties _this, TextWriter writer)
|
|
{
|
|
writer.WriteIndent(1);
|
|
writer.Write("Properties {\n");
|
|
foreach (SerializedProperty prop in _this.Props)
|
|
{
|
|
prop.Export(writer);
|
|
}
|
|
writer.WriteIndent(1);
|
|
writer.Write("}\n");
|
|
}
|
|
|
|
public static void Export(this SerializedProperty _this, TextWriter writer)
|
|
{
|
|
writer.WriteIndent(2);
|
|
foreach (string attribute in _this.Attributes)
|
|
{
|
|
writer.Write("[{0}] ", attribute);
|
|
}
|
|
if (_this.Flags.IsHideInInspector())
|
|
{
|
|
writer.Write("[HideInInspector] ");
|
|
}
|
|
if (_this.Flags.IsPerRendererData())
|
|
{
|
|
writer.Write("[PerRendererData] ");
|
|
}
|
|
if (_this.Flags.IsNoScaleOffset())
|
|
{
|
|
writer.Write("[NoScaleOffset] ");
|
|
}
|
|
if (_this.Flags.IsNormal())
|
|
{
|
|
writer.Write("[Normal] ");
|
|
}
|
|
if (_this.Flags.IsHDR())
|
|
{
|
|
writer.Write("[HDR] ");
|
|
}
|
|
if (_this.Flags.IsGamma())
|
|
{
|
|
writer.Write("[Gamma] ");
|
|
}
|
|
|
|
writer.Write("{0} (\"{1}\", ", _this.Name, _this.Description);
|
|
|
|
switch (_this.Type)
|
|
{
|
|
case SerializedPropertyType.Color:
|
|
case SerializedPropertyType.Vector:
|
|
writer.Write(nameof(SerializedPropertyType.Vector));
|
|
break;
|
|
|
|
case SerializedPropertyType.Int:
|
|
//case SerializedPropertyType.Float:
|
|
writer.Write(nameof(SerializedPropertyType.Float));
|
|
break;
|
|
|
|
case SerializedPropertyType.Range:
|
|
writer.Write("{0}({1}, {2})",
|
|
nameof(SerializedPropertyType.Range),
|
|
_this.DefValue1.ToString(CultureInfo.InvariantCulture),
|
|
_this.DefValue2.ToString(CultureInfo.InvariantCulture));
|
|
break;
|
|
|
|
case SerializedPropertyType._2D:
|
|
//case SerializedPropertyType._3D:
|
|
//case SerializedPropertyType.Cube:
|
|
switch (_this.DefTexture.TexDim)
|
|
{
|
|
case 1:
|
|
writer.Write("any");
|
|
break;
|
|
case 2:
|
|
writer.Write("2D");
|
|
break;
|
|
case 3:
|
|
writer.Write("3D");
|
|
break;
|
|
case 4:
|
|
writer.Write(nameof(SerializedPropertyType.Cube));
|
|
break;
|
|
case 5:
|
|
writer.Write("2DArray");
|
|
break;
|
|
case 6:
|
|
writer.Write(nameof(SerializedPropertyType.CubeArray));
|
|
break;
|
|
default:
|
|
throw new NotSupportedException("Texture dimension isn't supported");
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
throw new NotSupportedException($"Serialized property type {_this.Type} isn't supported");
|
|
}
|
|
writer.Write(") = ");
|
|
|
|
switch (_this.Type)
|
|
{
|
|
case SerializedPropertyType.Color:
|
|
case SerializedPropertyType.Vector:
|
|
writer.Write("({0},{1},{2},{3})",
|
|
_this.DefValue0.ToString(CultureInfo.InvariantCulture),
|
|
_this.DefValue1.ToString(CultureInfo.InvariantCulture),
|
|
_this.DefValue2.ToString(CultureInfo.InvariantCulture),
|
|
_this.DefValue3.ToString(CultureInfo.InvariantCulture));
|
|
break;
|
|
|
|
case SerializedPropertyType.Int:
|
|
//case SerializedPropertyType.Float:
|
|
case SerializedPropertyType.Range:
|
|
writer.Write(_this.DefValue0.ToString(CultureInfo.InvariantCulture));
|
|
break;
|
|
|
|
case SerializedPropertyType._2D:
|
|
//case SerializedPropertyType._3D:
|
|
//case SerializedPropertyType.Cube:
|
|
writer.Write("\"{0}\" {{}}", _this.DefTexture.DefaultName);
|
|
break;
|
|
|
|
default:
|
|
throw new NotSupportedException($"Serialized property type {_this.Type} isn't supported");
|
|
}
|
|
writer.Write('\n');
|
|
}
|
|
|
|
public static void Export(this SerializedShader _this, ShaderWriter writer)
|
|
{
|
|
writer.Write("Shader \"{0}\" {{\n", _this.Name);
|
|
|
|
_this.PropInfo.Export(writer);
|
|
|
|
for (int i = 0; i < _this.SubShaders.Length; i++)
|
|
{
|
|
_this.SubShaders[i].Export(writer);
|
|
}
|
|
|
|
if (_this.FallbackName.Length != 0)
|
|
{
|
|
writer.WriteIndent(1);
|
|
writer.Write("Fallback \"{0}\"\n", _this.FallbackName);
|
|
}
|
|
|
|
if (_this.CustomEditorName.Length != 0)
|
|
{
|
|
writer.WriteIndent(1);
|
|
writer.Write("CustomEditor \"{0}\"\n", _this.CustomEditorName);
|
|
}
|
|
|
|
writer.Write('}');
|
|
}
|
|
|
|
public static void Export(this SerializedShaderRTBlendState _this, TextWriter writer, int index)
|
|
{
|
|
if (!_this.SrcBlendValue.IsOne() || !_this.DestBlendValue.IsZero() || !_this.SrcBlendAlphaValue.IsOne() || !_this.DestBlendAlphaValue.IsZero())
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("Blend ");
|
|
if (index != -1)
|
|
{
|
|
writer.Write("{0} ", index);
|
|
}
|
|
writer.Write("{0} {1}", _this.SrcBlendValue, _this.DestBlendValue);
|
|
if (!_this.SrcBlendAlphaValue.IsOne() || !_this.DestBlendAlphaValue.IsZero())
|
|
{
|
|
writer.Write(", {0} {1}", _this.SrcBlendAlphaValue, _this.DestBlendAlphaValue);
|
|
}
|
|
writer.Write('\n');
|
|
}
|
|
|
|
if (!_this.BlendOpValue.IsAdd() || !_this.BlendOpAlphaValue.IsAdd())
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("BlendOp ");
|
|
if (index != -1)
|
|
{
|
|
writer.Write("{0} ", index);
|
|
}
|
|
writer.Write(_this.BlendOpValue.ToString());
|
|
if (!_this.BlendOpAlphaValue.IsAdd())
|
|
{
|
|
writer.Write(", {0}", _this.BlendOpAlphaValue);
|
|
}
|
|
writer.Write('\n');
|
|
}
|
|
|
|
if (!_this.ColMaskValue.IsRBGA())
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("ColorMask ");
|
|
if (_this.ColMaskValue.IsNone())
|
|
{
|
|
writer.Write(0);
|
|
}
|
|
else
|
|
{
|
|
if (_this.ColMaskValue.IsRed())
|
|
{
|
|
writer.Write(nameof(ColorMask.R));
|
|
}
|
|
if (_this.ColMaskValue.IsGreen())
|
|
{
|
|
writer.Write(nameof(ColorMask.G));
|
|
}
|
|
if (_this.ColMaskValue.IsBlue())
|
|
{
|
|
writer.Write(nameof(ColorMask.B));
|
|
}
|
|
if (_this.ColMaskValue.IsAlpha())
|
|
{
|
|
writer.Write(nameof(ColorMask.A));
|
|
}
|
|
}
|
|
writer.Write(" {0}\n", index);
|
|
}
|
|
}
|
|
|
|
public static void Export(this SerializedShaderState _this, TextWriter writer)
|
|
{
|
|
if (_this.Name != string.Empty)
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("Name \"{0}\"\n", _this.Name);
|
|
}
|
|
if (_this.LOD != 0)
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("LOD {0}\n", _this.LOD);
|
|
}
|
|
_this.Tags.Export(writer, 3);
|
|
|
|
_this.RtBlend0.Export(writer, _this.RtSeparateBlend ? 0 : -1);
|
|
_this.RtBlend1.Export(writer, 1);
|
|
_this.RtBlend2.Export(writer, 2);
|
|
_this.RtBlend3.Export(writer, 3);
|
|
_this.RtBlend4.Export(writer, 4);
|
|
_this.RtBlend5.Export(writer, 5);
|
|
_this.RtBlend6.Export(writer, 6);
|
|
_this.RtBlend7.Export(writer, 7);
|
|
|
|
if (_this.AlphaToMaskValue)
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("AlphaToMask On\n");
|
|
}
|
|
|
|
if (!_this.ZClipValue.IsOn())
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("ZClip {0}\n", _this.ZClipValue);
|
|
}
|
|
if (!_this.ZTestValue.IsLEqual() && !_this.ZTestValue.IsNone())
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("ZTest {0}\n", _this.ZTestValue);
|
|
}
|
|
if (!_this.ZWriteValue.IsOn())
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("ZWrite {0}\n", _this.ZWriteValue);
|
|
}
|
|
if (!_this.CullingValue.IsBack())
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("Cull {0}\n", _this.CullingValue);
|
|
}
|
|
if (!_this.OffsetFactor.IsZero || !_this.OffsetUnits.IsZero)
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("Offset {0}, {1}\n", _this.OffsetFactor.Val, _this.OffsetUnits.Val);
|
|
}
|
|
|
|
if (!_this.StencilRef.IsZero || !_this.StencilReadMask.IsMax || !_this.StencilWriteMask.IsMax || !_this.StencilOp.IsDefault || !_this.StencilOpFront.IsDefault || !_this.StencilOpBack.IsDefault)
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("Stencil {\n");
|
|
if (!_this.StencilRef.IsZero)
|
|
{
|
|
writer.WriteIndent(4);
|
|
writer.Write("Ref {0}\n", _this.StencilRef.Val);
|
|
}
|
|
if (!_this.StencilReadMask.IsMax)
|
|
{
|
|
writer.WriteIndent(4);
|
|
writer.Write("ReadMask {0}\n", _this.StencilReadMask.Val);
|
|
}
|
|
if (!_this.StencilWriteMask.IsMax)
|
|
{
|
|
writer.WriteIndent(4);
|
|
writer.Write("WriteMask {0}\n", _this.StencilWriteMask.Val);
|
|
}
|
|
if (!_this.StencilOp.IsDefault)
|
|
{
|
|
_this.StencilOp.Export(writer, StencilType.Base);
|
|
}
|
|
if (!_this.StencilOpFront.IsDefault)
|
|
{
|
|
_this.StencilOpFront.Export(writer, StencilType.Front);
|
|
}
|
|
if (!_this.StencilOpBack.IsDefault)
|
|
{
|
|
_this.StencilOpBack.Export(writer, StencilType.Back);
|
|
}
|
|
writer.WriteIndent(3);
|
|
writer.Write("}\n");
|
|
}
|
|
|
|
if (!_this.FogMode.IsUnknown() || !_this.FogColor.IsZero || !_this.FogDensity.IsZero || !_this.FogStart.IsZero || !_this.FogEnd.IsZero)
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("Fog {\n");
|
|
if (!_this.FogMode.IsUnknown())
|
|
{
|
|
writer.WriteIndent(4);
|
|
writer.Write("Mode {0}\n", _this.FogMode);
|
|
}
|
|
if (!_this.FogColor.IsZero)
|
|
{
|
|
writer.WriteIndent(4);
|
|
writer.Write("Color ({0},{1},{2},{3})\n",
|
|
_this.FogColor.X.Val.ToString(CultureInfo.InvariantCulture),
|
|
_this.FogColor.Y.Val.ToString(CultureInfo.InvariantCulture),
|
|
_this.FogColor.Z.Val.ToString(CultureInfo.InvariantCulture),
|
|
_this.FogColor.W.Val.ToString(CultureInfo.InvariantCulture));
|
|
}
|
|
if (!_this.FogDensity.IsZero)
|
|
{
|
|
writer.WriteIndent(4);
|
|
writer.Write("Density {0}\n", _this.FogDensity.Val.ToString(CultureInfo.InvariantCulture));
|
|
}
|
|
if (!_this.FogStart.IsZero || !_this.FogEnd.IsZero)
|
|
{
|
|
writer.WriteIndent(4);
|
|
writer.Write("Range {0}, {1}\n",
|
|
_this.FogStart.Val.ToString(CultureInfo.InvariantCulture),
|
|
_this.FogEnd.Val.ToString(CultureInfo.InvariantCulture));
|
|
}
|
|
writer.WriteIndent(3);
|
|
writer.Write("}\n");
|
|
}
|
|
|
|
if (_this.Lighting)
|
|
{
|
|
writer.WriteIndent(3);
|
|
writer.Write("Lighting {0}\n", _this.LightingValue);
|
|
}
|
|
writer.WriteIndent(3);
|
|
writer.Write("GpuProgramID {0}\n", _this.GpuProgramID);
|
|
}
|
|
|
|
public static void Export(this SerializedStencilOp _this, TextWriter writer, StencilType type)
|
|
{
|
|
writer.WriteIndent(4);
|
|
writer.Write("Comp{0} {1}\n", type.ToSuffixString(), _this.CompValue);
|
|
writer.WriteIndent(4);
|
|
writer.Write("Pass{0} {1}\n", type.ToSuffixString(), _this.PassValue);
|
|
writer.WriteIndent(4);
|
|
writer.Write("Fail{0} {1}\n", type.ToSuffixString(), _this.FailValue);
|
|
writer.WriteIndent(4);
|
|
writer.Write("ZFail{0} {1}\n", type.ToSuffixString(), _this.ZFailValue);
|
|
}
|
|
|
|
public static void Export(this SerializedSubProgram _this, ShaderWriter writer, ShaderType type, bool isTier)
|
|
{
|
|
writer.WriteIndent(4);
|
|
#warning TODO: convertion (DX to HLSL)
|
|
ShaderGpuProgramType programType = _this.GetProgramType(writer.Version);
|
|
GPUPlatform graphicApi = programType.ToGPUPlatform(writer.Platform);
|
|
writer.Write("SubProgram \"{0} ", graphicApi);
|
|
if (isTier)
|
|
{
|
|
writer.Write("hw_tier{0} ", _this.ShaderHardwareTier.ToString("00"));
|
|
}
|
|
writer.Write("\" {\n");
|
|
writer.WriteIndent(5);
|
|
|
|
int platformIndex = writer.Shader.Platforms.IndexOf(graphicApi);
|
|
writer.Shader.Blobs[platformIndex].SubPrograms[_this.BlobIndex].Export(writer, type);
|
|
|
|
writer.Write('\n');
|
|
writer.WriteIndent(4);
|
|
writer.Write("}\n");
|
|
}
|
|
|
|
public static void Export(this SerializedSubShader _this, ShaderWriter writer)
|
|
{
|
|
writer.WriteIndent(1);
|
|
writer.Write("SubShader {\n");
|
|
if (_this.LOD != 0)
|
|
{
|
|
writer.WriteIndent(2);
|
|
writer.Write("LOD {0}\n", _this.LOD);
|
|
}
|
|
_this.Tags.Export(writer, 2);
|
|
for (int i = 0; i < _this.Passes.Length; i++)
|
|
{
|
|
_this.Passes[i].Export(writer);
|
|
}
|
|
writer.WriteIndent(1);
|
|
writer.Write("}\n");
|
|
}
|
|
|
|
public static void Export(this SerializedTagMap _this, TextWriter writer, int indent)
|
|
{
|
|
if (_this.Tags.Count != 0)
|
|
{
|
|
writer.WriteIndent(indent);
|
|
writer.Write("Tags { ");
|
|
foreach (var kvp in _this.Tags)
|
|
{
|
|
writer.Write("\"{0}\" = \"{1}\" ", kvp.Key, kvp.Value);
|
|
}
|
|
writer.Write("}\n");
|
|
}
|
|
}
|
|
|
|
public static void Export(this ShaderSubProgram _this, ShaderWriter writer, ShaderType type)
|
|
{
|
|
if (_this.GlobalKeywords.Length > 0)
|
|
{
|
|
writer.Write("Keywords { ");
|
|
foreach (string keyword in _this.GlobalKeywords)
|
|
{
|
|
writer.Write("\"{0}\" ", keyword);
|
|
}
|
|
if (ShaderSubProgram.HasLocalKeywords(writer.Version))
|
|
{
|
|
foreach (string keyword in _this.LocalKeywords)
|
|
{
|
|
writer.Write("\"{0}\" ", keyword);
|
|
}
|
|
}
|
|
writer.Write("}\n");
|
|
writer.WriteIndent(5);
|
|
}
|
|
|
|
#warning TODO: convertion (DX to HLSL)
|
|
ShaderGpuProgramType programType = _this.GetProgramType(writer.Version);
|
|
writer.Write("\"{0}", programType.ToProgramDataKeyword(writer.Platform, type));
|
|
if (_this.ProgramData.Length > 0)
|
|
{
|
|
writer.Write("\n");
|
|
writer.WriteIndent(5);
|
|
|
|
writer.WriteShaderData(ref _this);
|
|
}
|
|
writer.Write('"');
|
|
}
|
|
|
|
public static void Export(this ShaderSubProgramBlob _this, ShaderWriter writer, string header)
|
|
{
|
|
int j = 0;
|
|
while (true)
|
|
{
|
|
int index = header.IndexOf(ShaderSubProgramBlob.GpuProgramIndexName, j);
|
|
if (index == -1)
|
|
{
|
|
break;
|
|
}
|
|
|
|
int length = index - j;
|
|
writer.WriteString(header, j, length);
|
|
j += length + ShaderSubProgramBlob.GpuProgramIndexName.Length + 1;
|
|
|
|
int subIndex = -1;
|
|
for (int startIndex = j; j < header.Length; j++)
|
|
{
|
|
if (!char.IsDigit(header[j]))
|
|
{
|
|
string numberStr = header.Substring(startIndex, j - startIndex);
|
|
subIndex = int.Parse(numberStr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// we don't know shader type so pass vertex
|
|
_this.SubPrograms[subIndex].Export(writer, ShaderType.Vertex);
|
|
}
|
|
writer.WriteString(header, j, header.Length - j);
|
|
}
|
|
}
|
|
}
|