1
0
mirror of synced 2024-12-02 11:07:26 +01:00
Switch-Toolbox/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/FMAT.cs
KillzXGaming f51dd17f94 Many improvements and new formats.
Add in nutexb file format. While not finished, it can preview and export them.
Batch exporting for nuteb (tools menu).
Rework GTX code. This is WIP and not finished.
Add XTX code. Unifnished atm.
Add saving for wii u and include fmat exporting.
Proper error handling for assimp and texture swizzling.
2018-11-27 21:21:31 -05:00

444 lines
16 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Syroot.NintenTools.NSW.Bfres;
using System.Windows.Forms;
using Switch_Toolbox.Library;
using Switch_Toolbox.Library.IO;
using Switch_Toolbox.Library.Rendering;
using Switch_Toolbox.Library.Forms;
using ResU = Syroot.NintenTools.Bfres;
using FirstPlugin;
using OpenTK;
namespace Bfres.Structs
{
public class FMATFolder : TreeNodeCustom
{
public FMATFolder()
{
Text = "Materials";
Name = "FmatFolder";
ContextMenu = new ContextMenu();
MenuItem import = new MenuItem("Add Material");
ContextMenu.MenuItems.Add(import);
import.Click += Import;
}
public void Import(object sender, EventArgs args)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Bfres Material |*.bfmat;";
ofd.Multiselect = true;
if (ofd.ShowDialog() == DialogResult.OK)
{
foreach (string file in ofd.FileNames)
((FMDL)Parent).AddMaterials(file, false);
}
}
public override void OnClick(TreeView treeView)
{
}
}
public class FMAT : STGenericMaterial
{
public FMAT()
{
Checked = true;
ImageKey = "material";
SelectedImageKey = "material";
ContextMenu = new ContextMenu();
MenuItem export = new MenuItem("Export");
ContextMenu.MenuItems.Add(export);
export.Click += Export;
MenuItem replace = new MenuItem("Replace");
ContextMenu.MenuItems.Add(replace);
replace.Click += Replace;
MenuItem copy = new MenuItem("Copy");
ContextMenu.MenuItems.Add(copy);
copy.Click += Copy;
MenuItem rename = new MenuItem("Rename");
ContextMenu.MenuItems.Add(rename);
rename.Click += Rename;
}
public bool Enabled = true;
public override void OnClick(TreeView treeView)
{
UpdateFMATEditor();
}
public void UpdateFMATEditor()
{
FMATEditor docked = (FMATEditor)LibraryGUI.Instance.GetContentDocked(new FMATEditor());
if (docked == null)
{
docked = new FMATEditor();
LibraryGUI.Instance.LoadDockContent(docked, PluginRuntime.FSHPDockState);
}
docked.Text = Text;
docked.Dock = DockStyle.Fill;
docked.LoadMaterial(this);
}
public ResFile GetResFile()
{
//ResourceFile -> FMDL -> Material Folder -> this
return ((FMDL)Parent.Parent).GetResFile();
}
public ResU.ResFile GetResFileU()
{
return ((FMDL)Parent.Parent).GetResFileU();
}
public void UpdateTextureMaps()
{
((ResourceFile)Parent.Parent.Parent.Parent).BFRESRender.UpdateSingleMaterialTextureMaps(this);
}
public void SetActiveGame()
{
Runtime.activeGame = Runtime.ActiveGame.SMO;
return;
string ShaderName = shaderassign.ShaderArchive;
string ShaderModel = shaderassign.ShaderModel;
if (ShaderName == "alRenderMaterial" || ShaderName == "alRenderCloudLayer" || ShaderName == "alRenderSky")
Runtime.activeGame = Runtime.ActiveGame.SMO;
else if (ShaderName == "Turbo_UBER")
Runtime.activeGame = Runtime.ActiveGame.MK8D;
else if (ShaderName.Contains("uking_mat"))
Runtime.activeGame = Runtime.ActiveGame.BOTW;
else if (ShaderName.Contains("Blitz_UBER"))
Runtime.activeGame = Runtime.ActiveGame.Splatoon2;
else
Runtime.activeGame = Runtime.ActiveGame.KSA;
}
private void Rename(object sender, EventArgs args)
{
RenameDialog dialog = new RenameDialog();
dialog.SetString(Text);
if (dialog.ShowDialog() == DialogResult.OK)
{
((FMDL)Parent.Parent).materials.Remove(Text);
Text = dialog.textBox1.Text;
((FMDL)Parent.Parent).materials.Add(Text, this);
}
}
private void Copy(object sender, EventArgs args)
{
((FMDL)Parent.Parent).CopyMaterial(this);
}
private void Export(object sender, EventArgs args)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Supported Formats|*.bfmat;";
sfd.DefaultExt = ".bfmat";
sfd.FileName = Text;
if (sfd.ShowDialog() == DialogResult.OK)
{
if (BFRES.IsWiiU)
MaterialU.Export(sfd.FileName, GetResFileU());
else
Material.Export(sfd.FileName, GetResFile());
}
}
private void Replace(object sender, EventArgs args)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Supported Formats|*.bfmat;";
if (ofd.ShowDialog() == DialogResult.OK)
{
if (BFRES.IsWiiU)
{
MaterialU.Import(ofd.FileName, GetResFileU());
MaterialU.Name = Text;
BfresWiiU.ReadMaterial(this, MaterialU);
}
else
{
Material.Import(ofd.FileName);
Material.Name = Text;
BfresSwitch.ReadMaterial(this, Material);
}
}
}
public Dictionary<string, float[]> anims = new Dictionary<string, float[]>();
public Dictionary<string, int> Samplers = new Dictionary<string, int>();
public List<MatTexture> textures = new List<MatTexture>();
public List<BfresRenderInfo> renderinfo = new List<BfresRenderInfo>();
public List<SamplerInfo> samplerinfo = new List<SamplerInfo>();
public Dictionary<string, BfresShaderParam> matparam = new Dictionary<string, BfresShaderParam>();
public Material Material;
public ResU.Material MaterialU;
public ShaderAssign shaderassign = new ShaderAssign();
public class ShaderAssign
{
public string ShaderModel = "";
public string ShaderArchive = "";
public Dictionary<string, string> options = new Dictionary<string, string>();
public Dictionary<string, string> samplers = new Dictionary<string, string>();
public Dictionary<string, string> attributes = new Dictionary<string, string>();
}
public class SamplerInfo
{
public int WrapModeU;
public int WrapModeV;
public int WrapModeW;
}
public bool HasDiffuseMap = false;
public bool HasNormalMap = false;
public bool HasSpecularMap = false;
public bool HasEmissionMap = false;
public bool HasDiffuseLayer = false;
public bool HasTeamColorMap = false; //Splatoon uses this (TLC)
public bool HasTransparencyMap = false;
public bool HasShadowMap = false;
public bool HasAmbientOcclusionMap = false;
public bool HasLightMap = false;
public bool HasSphereMap = false;
public bool HasSubSurfaceScatteringMap = false;
//PBR (Switch) data
public bool HasMetalnessMap = false;
public bool HasRoughnessMap = false;
public bool HasMRA = false;
}
public class BfresShaderParam
{
public ShaderParamType Type;
public string Name;
public float[] ValueFloat;
public bool[] ValueBool;
public uint[] ValueUint;
public int[] ValueInt;
public byte[] ValueReserved;
public Srt2D ValueSrt2D;
public Srt3D ValueSrt3D;
public TexSrt ValueTexSrt;
public TexSrtEx ValueTexSrtEx;
//If a data set is not defined then defaults in this to save back properly
//Note this may be rarely needed or not at all
public byte[] Value_Unk;
private void ReadSRT2D(FileReader reader)
{
ValueSrt2D = new Srt2D();
ValueSrt2D.Scaling = reader.ReadVec2SY();
ValueSrt2D.Rotation = reader.ReadSingle();
ValueSrt2D.Translation = reader.ReadVec2SY();
}
private void ReadSRT3D(FileReader reader)
{
ValueSrt3D = new Srt3D();
ValueSrt3D.Scaling = reader.ReadVec3SY();
ValueSrt3D.Rotation = reader.ReadVec3SY();
ValueSrt3D.Translation = reader.ReadVec3SY();
}
private void ReadTexSrt(FileReader reader)
{
ValueTexSrt = new TexSrt();
ValueTexSrt.Mode = reader.ReadEnum<TexSrtMode>(false);
ValueTexSrt.Scaling = reader.ReadVec2SY();
ValueTexSrt.Rotation = reader.ReadSingle();
ValueTexSrt.Translation = reader.ReadVec2SY();
}
private void ReadTexSrtEx(FileReader reader)
{
ValueTexSrtEx = new TexSrtEx();
ValueTexSrtEx.Mode = reader.ReadEnum<TexSrtMode>(true);
ValueTexSrtEx.Scaling = reader.ReadVec2SY();
ValueTexSrtEx.Rotation = reader.ReadSingle();
ValueTexSrtEx.Translation = reader.ReadVec2SY();
ValueTexSrtEx.MatrixPointer = reader.ReadUInt32();
}
public ShaderParamType GetTypeWiiU(ResU.ShaderParamType type)
{
return (ShaderParamType)System.Enum.Parse(typeof(ShaderParamType), type.ToString());
}
public ResU.ShaderParamType SetTypeWiiU(ShaderParamType type)
{
return (ResU.ShaderParamType)System.Enum.Parse(typeof(ResU.ShaderParamType), type.ToString());
}
public void ReadValue(FileReader reader, int Size)
{
switch (Type)
{
case ShaderParamType.Bool:
case ShaderParamType.Bool2:
case ShaderParamType.Bool3:
case ShaderParamType.Bool4:
ValueBool = reader.ReadBooleans(Size / sizeof(bool)); break;
case ShaderParamType.Float:
case ShaderParamType.Float2:
case ShaderParamType.Float3:
case ShaderParamType.Float4:
case ShaderParamType.Float2x2:
case ShaderParamType.Float2x3:
case ShaderParamType.Float2x4:
case ShaderParamType.Float4x2:
case ShaderParamType.Float4x3:
case ShaderParamType.Float4x4:
ValueFloat = reader.ReadSingles(Size / sizeof(float)); break;
case ShaderParamType.Int:
case ShaderParamType.Int2:
case ShaderParamType.Int3:
case ShaderParamType.Int4:
ValueInt = reader.ReadInt32s(Size / sizeof(int)); break;
case ShaderParamType.Reserved2:
case ShaderParamType.Reserved3:
case ShaderParamType.Reserved4:
ValueReserved = reader.ReadBytes(Size / sizeof(byte)); break;
case ShaderParamType.Srt2D:
ReadSRT2D(reader); break;
case ShaderParamType.Srt3D:
ReadSRT3D(reader); break;
case ShaderParamType.TexSrt:
ReadTexSrt(reader); break;
case ShaderParamType.TexSrtEx:
ReadTexSrtEx(reader); break;
case ShaderParamType.UInt:
case ShaderParamType.UInt2:
case ShaderParamType.UInt3:
case ShaderParamType.UInt4:
ValueUint = reader.ReadUInt32s(Size / sizeof(uint)); break;
// Invalid
default:
throw new ArgumentException($"Invalid {nameof(ShaderParamType)} {Type}.",
nameof(Type));
}
}
public void WriteValue(FileWriter writer)
{
switch (Type)
{
case ShaderParamType.Bool:
case ShaderParamType.Bool2:
case ShaderParamType.Bool3:
case ShaderParamType.Bool4:
writer.Write(ValueBool); break;
case ShaderParamType.Float:
case ShaderParamType.Float2:
case ShaderParamType.Float3:
case ShaderParamType.Float4:
case ShaderParamType.Float2x2:
case ShaderParamType.Float2x3:
case ShaderParamType.Float2x4:
case ShaderParamType.Float4x2:
case ShaderParamType.Float4x3:
case ShaderParamType.Float4x4:
writer.Write(ValueFloat); break;
case ShaderParamType.Int:
case ShaderParamType.Int2:
case ShaderParamType.Int3:
case ShaderParamType.Int4:
writer.Write(ValueInt); break;
case ShaderParamType.Reserved2:
case ShaderParamType.Reserved3:
case ShaderParamType.Reserved4:
writer.Write(ValueInt); break;
case ShaderParamType.Srt2D:
WriteSRT2D(writer); break;
case ShaderParamType.Srt3D:
WriteSRT3D(writer); break;
case ShaderParamType.TexSrt:
WriteTexSrt(writer); break;
case ShaderParamType.TexSrtEx:
WriteTexSrtEx(writer); break;
case ShaderParamType.UInt:
case ShaderParamType.UInt2:
case ShaderParamType.UInt3:
case ShaderParamType.UInt4:
writer.Write(ValueUint); break;
// Invalid
default:
throw new ArgumentException($"Invalid {nameof(ShaderParamType)} {Type}.",
nameof(Type));
}
}
private void WriteSRT2D(FileWriter writer)
{
writer.Write(ValueSrt2D.Scaling);
writer.Write(ValueSrt2D.Rotation);
writer.Write(ValueSrt2D.Translation);
}
private void WriteSRT3D(FileWriter writer)
{
writer.Write(ValueSrt3D.Scaling);
writer.Write(ValueSrt3D.Rotation);
writer.Write(ValueSrt3D.Translation);
}
private void WriteTexSrt(FileWriter writer)
{
writer.Write((uint)ValueTexSrt.Mode);
writer.Write(ValueTexSrt.Scaling);
writer.Write(ValueTexSrt.Rotation);
writer.Write(ValueTexSrt.Translation);
}
private void WriteTexSrtEx(FileWriter writer)
{
writer.Write((uint)ValueTexSrtEx.Mode);
writer.Write(ValueTexSrtEx.Scaling);
writer.Write(ValueTexSrtEx.Rotation);
writer.Write(ValueTexSrtEx.Translation);
writer.Write(ValueTexSrtEx.MatrixPointer);
}
}
public class BfresRenderInfo
{
public string Name;
public long DataOffset;
public RenderInfoType Type;
public int ArrayLength;
//Data Section by "Type"
public int[] ValueInt;
public string[] ValueString;
public float[] ValueFloat;
public RenderInfoType GetTypeWiiU(ResU.RenderInfoType type)
{
return (RenderInfoType)System.Enum.Parse(typeof(RenderInfoType), type.ToString());
}
public ResU.RenderInfoType SetTypeWiiU(RenderInfoType type)
{
return (ResU.RenderInfoType)System.Enum.Parse(typeof(ResU.RenderInfoType), type.ToString());
}
}
public class MatTexture : STGenericMatTexture
{
public int hash;
public string SamplerName;
//Note samplers will get converted to another sampler type sometimes in the shader assign section
//Use this string if not empty for our bfres fragment shader to produce the accurate affects
//An example of a conversion maybe be like a1 - t0 so texture gets used as a transparent map/alpha texture
public string FragShaderSampler = "";
public MatTexture()
{
}
}
}