PKG : Include bsmat editing

This commit is contained in:
KillzXGaming 2021-11-19 18:03:41 -05:00
parent 84fdef5718
commit 8cc294e07f
5 changed files with 610 additions and 1 deletions

View file

@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Toolbox;
using System.Windows.Forms;
using Toolbox.Library;
using Toolbox.Library.IO;
using Toolbox.Library.Forms;
using Toolbox.Library.Security.Cryptography;
namespace MetroidDreadLibrary
{
public class BSMAT : IEditor<TextEditor>, IFileFormat, IConvertableTextFormat
{
public FileType FileType { get; set; } = FileType.Parameter;
public bool CanSave { get; set; } = true;
public string[] Description { get; set; } = new string[] { "BSMAT" };
public string[] Extension { get; set; } = new string[] { "*.bsmat" };
public string FileName { get; set; }
public string FilePath { get; set; }
public IFileInfo IFileInfo { get; set; }
public bool Identify(System.IO.Stream stream) {
return FileName.EndsWith(".bsmat");
}
public Type[] Types
{
get
{
List<Type> types = new List<Type>();
return types.ToArray();
}
}
private string JsonContents;
public TextEditor OpenForm()
{
var textEditor = new TextEditor();
return textEditor;
}
public void FillEditor(UserControl control)
{
((TextEditor)control).FileFormat = this;
((TextEditor)control).FillEditor(JsonContents);
((TextEditor)control).TextEditorChanged += delegate
{
JsonContents = ((TextEditor)control).GetText();
};
}
#region Text Converter Interface
public TextFileType TextFileType => TextFileType.Json;
public bool CanConvertBack => true;
public string ConvertToString() {
return JsonContents;
}
public void ConvertFromString(string text) {
JsonContents = text;
}
#endregion
public void Load(System.IO.Stream stream)
{
var bsmat = new BSMATMaterialFile(stream);
JsonContents = bsmat.ToJson();
}
public void Save(System.IO.Stream stream)
{
var bsmat = BSMATMaterialFile.Import(JsonContents);
bsmat.Save(stream);
}
public void Unload()
{
}
}
}

View file

@ -0,0 +1,456 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Toolbox.Library.IO;
using Toolbox.Library;
namespace MetroidDreadLibrary
{
public class BSMATMaterialFile
{
const int TYPE_ID = 1114114;
public string Name { get; set; }
public string ShaderPath { get; set; }
public TranslucencyType TranslucencyState { get; set; }
public uint RenderLayer { get; set; }
public BlendState Blending { get; set; }
public PolygonState PolygonInfo { get; set; }
public StencilState Stencil { get; set; }
public AlphaState AlphaTest { get; set; }
public DepthState DepthTest { get; set; }
public FillMode PolyFillMode { get; set; }
public ShaderStage[] ShaderStages { get; set; }
public BSMATMaterialFile() { }
public BSMATMaterialFile(Stream stream)
{
using (var reader = new FileReader(stream)) {
Read(reader);
}
}
public void Save(Stream stream)
{
using (var writer = new FileWriter(stream)) {
Write(writer);
}
}
public void Read(FileReader reader)
{
reader.ReadSignature(4, "MSUR");
reader.ReadInt32(); //type
Name = reader.ReadZeroTerminatedString();
TranslucencyState = (TranslucencyType)reader.ReadUInt32();
RenderLayer = reader.ReadUInt32();
ShaderPath = reader.ReadZeroTerminatedString();
Blending = reader.ReadStruct<BlendState>();
PolygonInfo = reader.ReadStruct<PolygonState>();
Stencil = reader.ReadStruct<StencilState>();
AlphaTest = reader.ReadStruct<AlphaState>();
PolyFillMode = reader.ReadEnum<FillMode>(false);
DepthTest = reader.ReadStruct<DepthState>();
reader.ReadBytes(4);
uint numStages = reader.ReadUInt32();
ShaderStages = new ShaderStage[numStages];
for (int i = 0; i < numStages; i++)
ShaderStages[i] = new ShaderStage(reader);
}
public void Export(string filePath) {
File.WriteAllText(filePath, ToJson());
}
public string ToJson() {
var conv = new Newtonsoft.Json.Converters.StringEnumConverter();
return JsonConvert.SerializeObject(this, Formatting.Indented, conv);
}
public static BSMATMaterialFile ImportFromFile(string filePath) {
return Import(File.ReadAllText(filePath));
}
public static BSMATMaterialFile Import(string text)
{
var conv = new Newtonsoft.Json.Converters.StringEnumConverter();
var bsmat = JsonConvert.DeserializeObject<BSMATMaterialFile>(text, conv);
foreach (var stage in bsmat.ShaderStages)
{
List< UniformParam > uniformList = new List<UniformParam>();
foreach (var uniform in stage.UniformData)
{
var uniformParam = new UniformParam();
uniformList.Add(uniformParam);
uniformParam.Name = uniform.Key;
//Basic type define via the start of uniform name.
//All params have starting characters (f float, i int, v vec, etc)
uniformParam.DataType = ParamType.Float;
if (uniform.Key.StartsWith("i"))
uniformParam.DataType = ParamType.Int;
//Turn the data into normal array objects
if (uniformParam.DataType == ParamType.Float)
uniformParam.Data = ((Newtonsoft.Json.Linq.JArray)uniform.Value).ToObject<float[]>();
if (uniformParam.DataType == ParamType.Int)
uniformParam.Data = ((Newtonsoft.Json.Linq.JArray)uniform.Value).ToObject<int[]>();
}
stage.Uniforms = uniformList.ToArray();
}
return bsmat;
}
public void Write(FileWriter writer)
{
writer.WriteSignature("MSUR");
writer.Write(TYPE_ID);
writer.WriteString(Name);
writer.Write((uint)TranslucencyState);
writer.Write(RenderLayer);
writer.WriteString(ShaderPath);
writer.WriteStruct(Blending);
writer.WriteStruct(PolygonInfo);
writer.WriteStruct(Stencil);
writer.WriteStruct(AlphaTest);
writer.Write((uint)PolyFillMode);
writer.WriteStruct(DepthTest);
writer.Write((uint)0);
writer.Write(ShaderStages.Length);
foreach (var stage in ShaderStages)
stage.Write(writer);
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class BlendState
{
public byte Enabled;
public BlendOp BlendOperation;
public BlendMode SrcBlend;
public BlendMode DstBlend;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class PolygonState
{
public CullMode CullMode;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class StencilState
{
public byte Enabled;
public uint Mask;
public uint Ref;
public StencilOp StencilFail;
public StencilOp StencilPass;
public StencilOp DepthFail;
public StencilOp DepthPass;
public CompareMode CompareMode;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class AlphaState
{
public byte EnableAlphaTest;
public CompareMode CompareMode;
public float Ref;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class DepthState
{
public byte EnableDepthTest;
public byte EnableDepthWrite;
public CompareMode CompareMode;
public byte zPrePass;
}
public class ShaderStage
{
//Better json display for params
[JsonProperty(ItemConverterType = typeof(NoFormattingConverter))]
public Dictionary<string, object> UniformData = new Dictionary<string, object>();
[JsonIgnore]
public UniformParam[] Uniforms;
public SamplerParam[] Samplers;
public ShaderType Type;
public ShaderStage() { }
public ShaderStage(FileReader reader)
{
Type = (ShaderType)reader.ReadUInt32();
uint numParams = reader.ReadUInt32();
Uniforms = new UniformParam[numParams];
for (int i = 0; i < numParams; i++)
Uniforms[i] = new UniformParam(reader);
uint numSamplers = reader.ReadUInt32();
Samplers = new SamplerParam[numSamplers];
for (int i = 0; i < numSamplers; i++)
Samplers[i] = new SamplerParam(reader);
foreach (var uniform in Uniforms)
UniformData.Add(uniform.Name, uniform.Data);
}
public void Write(FileWriter writer)
{
writer.Write((uint)Type);
writer.Write(Uniforms.Length);
foreach (var uniform in Uniforms)
uniform.Write(writer);
writer.Write(Samplers.Length);
foreach (var sampler in Samplers)
sampler.Write(writer);
}
public enum ShaderType
{
Vertex,
Fragment,
}
}
public class UniformParam
{
public object Data { get; set; }
[JsonIgnore]
public string Name { get; set; }
[JsonIgnore]
public ParamType DataType { get; set; }
Dictionary<char, ParamType> FormatList = new Dictionary<char, ParamType>()
{
{ 'f', ParamType.Float },
{ 'i', ParamType.Int },
{ 'u', ParamType.Uint },
};
public UniformParam() { }
public UniformParam(FileReader reader)
{
Name = reader.ReadZeroTerminatedString();
byte format = reader.ReadByte();
DataType = FormatList[(char)format];
int count = reader.ReadInt32();
switch (DataType)
{
case ParamType.Float: Data = reader.ReadSingles(count); break;
case ParamType.Uint: Data = reader.ReadUInt32s(count); break;
case ParamType.Int: Data = reader.ReadInt32s(count); break;
}
}
public void Write(FileWriter writer)
{
var format = FormatList.FirstOrDefault(x => x.Value == this.DataType).Key;
writer.WriteString(Name);
writer.Write((byte)format);
writer.Write(((Array)Data).Length);
switch (DataType)
{
case ParamType.Float: writer.Write((float[])Data); break;
case ParamType.Uint: writer.Write((uint[])Data); break;
case ParamType.Int: writer.Write((int[])Data); break;
}
}
}
public class SamplerParam
{
public string Name { get; set; }
public string Sampler { get; set; }
public string Type { get; set; }
public uint SlotID { get; set; }
public string FilePath { get; set; }
public uint[] Parameters { get; set; }
public FilterMode MinFilter;
public FilterMode MagFilter;
public FilterMode MipFilter;
public CompareMode CompMode;
public TileWrapMode WrapModeU;
public TileWrapMode WrapModeV;
public uint uBorderColor = 0xFFFFFF0F;
public float fMinLod;
public float fLodBias;
public float fAnisotropic;
public float fMaxMipLevel;
public float fMaxAnisotropy;
public SamplerParam() { }
public SamplerParam(FileReader reader)
{
Name = reader.ReadZeroTerminatedString();
Sampler = reader.ReadZeroTerminatedString();
Type = reader.ReadZeroTerminatedString();
SlotID = reader.ReadUInt32();
FilePath = reader.ReadZeroTerminatedString();
MinFilter = (FilterMode)reader.ReadUInt32();
MagFilter = (FilterMode)reader.ReadUInt32();
MipFilter = (FilterMode)reader.ReadUInt32();
CompMode = (CompareMode)reader.ReadUInt32();
WrapModeU = (TileWrapMode)reader.ReadUInt32();
WrapModeV = (TileWrapMode)reader.ReadUInt32();
uBorderColor = reader.ReadUInt32();
fMinLod = reader.ReadSingle();
fLodBias = reader.ReadSingle();
fAnisotropic = reader.ReadSingle();
fMaxMipLevel = reader.ReadSingle();
fMaxAnisotropy = reader.ReadSingle();
}
public void Write(FileWriter writer)
{
writer.WriteString(Name);
writer.WriteString(Sampler);
writer.WriteString(Type);
writer.Write(SlotID);
writer.WriteString(FilePath);
writer.Write((uint)MinFilter);
writer.Write((uint)MagFilter);
writer.Write((uint)MipFilter);
writer.Write((uint)CompMode);
writer.Write((uint)WrapModeU);
writer.Write((uint)WrapModeV);
writer.Write(uBorderColor);
writer.Write(fMinLod);
writer.Write(fLodBias);
writer.Write(fAnisotropic);
writer.Write(fMaxMipLevel);
writer.Write(fMaxAnisotropy);
}
}
public enum ParamType
{
Float,
Uint,
Int,
}
public enum FillMode
{
SOLID = 0x0,
WIRE = 0x1,
}
public enum ShaderType
{
VERTEX = 0x0,
PIXEL = 0x1,
GEOMETRY = 0x2,
}
public enum TileWrapMode
{
CLAMP = 0x0,
CLAMPCOLOR = 0x1,
REPEAT = 0x2,
MIRROR = 0x3,
}
public enum FilterMode
{
NEAREST = 0x0,
LINEAR = 0x1,
NEARESTMIPNEAREST = 0x2,
NEARESTMIPLINEAR = 0x3,
LINEARMIPNEAREST = 0x4,
LINEARMIPLINEAR = 0x5,
}
public enum CompareMode
{
ALWAYS = 0x0,
NEVER = 0x1,
EQUAL = 0x2,
NOTEQUAL = 0x3,
LESS = 0x4,
LESSEQUAL = 0x5,
GREATER = 0x6,
GREATEREQUAL = 0x7,
}
public enum StencilOp
{
KEEP = 0x0,
ZERO = 0x1,
REPLACE = 0x2,
INCRSAT = 0x3,
DECRSAT = 0x4,
INVERT = 0x5,
INCR = 0x6,
DECR = 0x7,
}
public enum BlendMode
{
ZERO = 0x0,
ONE = 0x1,
SRC_COLOR = 0x2,
INV_SRC_COLOR = 0x3,
DST_COLOR = 0x4,
INV_DST_COLOR = 0x5,
SRC_ALPHA = 0x6,
INV_SRC_ALPHA = 0x7,
DST_ALPHA = 0x8,
INV_DST_ALPHA = 0x9,
}
public enum BlendOp
{
ADD = 0x0,
SUBDST = 0x1,
SUBSRC = 0x2,
MIN = 0x3,
MAX = 0x4,
}
public enum CullMode
{
FRONT = 0x2,
BACK = 0x3,
NONE = 0x4,
}
public enum TranslucencyType
{
NONE = 0x0,
OPAQUE = 0x1,
TRANSLUCENT = 0x2,
SUBSTRACTIVE = 0x4,
ADDITIVE = 0x8,
OPAQUE_FWD = 0x10,
ALL = 0x1f,
NOT_OPAQUE = 0xe,
}
}
}

View file

@ -0,0 +1,63 @@
using System;
using Newtonsoft.Json;
namespace MetroidDreadLibrary
{
public class NoFormattingConverter : JsonConverter
{
[ThreadStatic]
static bool cannotWrite;
// Disables the converter in a thread-safe manner.
bool CannotWrite { get { return cannotWrite; } set { cannotWrite = value; } }
public override bool CanWrite { get { return !CannotWrite; } }
public override bool CanRead { get { return false; } }
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException(); // Should be applied as a property rather than included in the JsonSerializerSettings.Converters list.
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
using (new PushValue<bool>(true, () => CannotWrite, val => CannotWrite = val))
using (new PushValue<Formatting>(Formatting.None, () => writer.Formatting, val => writer.Formatting = val))
{
serializer.Serialize(writer, value);
}
}
}
public struct PushValue<T> : IDisposable
{
Action<T> setValue;
T oldValue;
public PushValue(T value, Func<T> getValue, Action<T> setValue)
{
if (getValue == null || setValue == null)
throw new ArgumentNullException();
this.setValue = setValue;
this.oldValue = getValue();
setValue(value);
}
#region IDisposable Members
// By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
public void Dispose()
{
if (setValue != null)
setValue(oldValue);
}
#endregion
}
}

View file

@ -239,6 +239,9 @@
<Compile Include="FileFormats\BCH\Wrappers\SkeletalAnimation\H3DSkeletalAnimWrapper.cs" />
<Compile Include="FileFormats\BCSV\BCSV.cs" />
<Compile Include="FileFormats\BCSV\BCSVParse.cs" />
<Compile Include="FileFormats\BSMAT\BSMATMaterialFile.cs" />
<Compile Include="FileFormats\BSMAT\BSMAT.cs" />
<Compile Include="FileFormats\BSMAT\NoFormattingConverter.cs" />
<Compile Include="FileFormats\Byaml\XmlByamlConverter.cs" />
<Compile Include="FileFormats\Byaml\YamlByamlConverter.cs" />
<Compile Include="FileFormats\Font\BXFNT\CMAP.cs" />

View file

@ -455,7 +455,7 @@ namespace FirstPlugin
Formats.Add(typeof(PKG));
Formats.Add(typeof(MTXT));
Formats.Add(typeof(NKN));
Formats.Add(typeof(MetroidDreadLibrary.BSMAT));
//Formats.Add(typeof(XLINK_FILE));