1
0
mirror of synced 2024-11-30 18:24:39 +01:00

Add MKAGPDX model viewing and exporting

This commit is contained in:
KillzXGaming 2019-06-19 14:57:59 -04:00
parent a076fc6f92
commit 54c4bac8bc
13 changed files with 934 additions and 63 deletions

Binary file not shown.

View File

@ -27,6 +27,9 @@ namespace Bfres.Structs
public List<FSHP> shapes = new List<FSHP>();
public List<FSHP> depthSortedMeshes = new List<FSHP>();
public override IEnumerable<STGenericObject> Objects => shapes;
public override IEnumerable<STGenericMaterial> Materials => materials.Values.ToList();
public Dictionary<string, FMAT> materials = new Dictionary<string, FMAT>();
public Model Model;
public ResU.Model ModelU;

View File

@ -1,13 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using Switch_Toolbox;
using System.Windows.Forms;
using Switch_Toolbox.Library;
using Switch_Toolbox.Library.IO;
using Switch_Toolbox.Library.Forms;
using Switch_Toolbox.Library.Rendering;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using GL_EditorFramework.Interfaces;
using GL_EditorFramework.GL_Core;
namespace FirstPlugin
{
@ -17,7 +22,7 @@ namespace FirstPlugin
public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "Mario Kart Arcade GP DX" };
public string[] Extension { get; set; } = new string[] { "*.bin" };
public string[] Extension { get; set; } = new string[] { "*.bin", "*.mot" };
public string FileName { get; set; }
public string FilePath { get; set; }
public IFileInfo IFileInfo { get; set; }
@ -41,11 +46,41 @@ namespace FirstPlugin
Header header;
public DrawableContainer DrawableContainer = new DrawableContainer();
public void Load(System.IO.Stream stream)
{
DrawableContainer.Name = FileName;
Text = FileName;
header = new Header();
header.Read(new FileReader(stream), this);
ContextMenuStrip = new STContextMenuStrip();
ContextMenuStrip.Items.Add(new ToolStripMenuItem("Export Model", null, ExportModel, Keys.Control | Keys.E));
}
private void ExportModel(object sender, EventArgs args)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Supported Formats|*.dae;";
if (sfd.ShowDialog() == DialogResult.OK)
{
AssimpSaver assimp = new AssimpSaver();
ExportModelSettings settings = new ExportModelSettings();
List<STGenericMaterial> Materials = new List<STGenericMaterial>();
foreach (STGenericMaterial mat in Nodes[0].Nodes)
Materials.Add(mat);
var model = new STGenericModel();
model.Materials = Materials;
model.Objects = ((Renderer)DrawableContainer.Drawables[1]).Meshes;
assimp.SaveFromModel(model, sfd.FileName, new List<STGenericTexture>(), ((STSkeleton)DrawableContainer.Drawables[0]));
}
}
public void Unload()
{
@ -55,6 +90,340 @@ namespace FirstPlugin
return null;
}
public struct DisplayVertex
{
// Used for rendering.
public Vector3 pos;
public Vector3 nrm;
public Vector3 tan;
public Vector2 uv;
public Vector4 col;
public Vector4 node;
public Vector4 weight;
public Vector2 uv2;
public Vector2 uv3;
public static int Size = 4 * (3 + 3 + 3 + 2 + 4 + 4 + 4 + 2 + 2);
}
public class MeshWrapper : STGenericObject
{
public int[] display;
public int DisplayId;
public List<DisplayVertex> CreateDisplayVertices()
{
display = lodMeshes[DisplayLODIndex].getDisplayFace().ToArray();
List<DisplayVertex> displayVertList = new List<DisplayVertex>();
if (lodMeshes[DisplayLODIndex].faces.Count <= 3)
return displayVertList;
foreach (Vertex v in vertices)
{
DisplayVertex displayVert = new DisplayVertex()
{
pos = v.pos,
nrm = v.nrm,
tan = v.tan.Xyz,
col = v.col,
uv = v.uv0,
uv2 = v.uv1,
uv3 = v.uv2,
node = new Vector4(
v.boneIds.Count > 0 ? v.boneIds[0] : -1,
v.boneIds.Count > 1 ? v.boneIds[1] : -1,
v.boneIds.Count > 2 ? v.boneIds[2] : -1,
v.boneIds.Count > 3 ? v.boneIds[3] : -1),
weight = new Vector4(
v.boneWeights.Count > 0 ? v.boneWeights[0] : 0,
v.boneWeights.Count > 1 ? v.boneWeights[1] : 0,
v.boneWeights.Count > 2 ? v.boneWeights[2] : 0,
v.boneWeights.Count > 3 ? v.boneWeights[3] : 0),
};
displayVertList.Add(displayVert);
/* Console.WriteLine($"---------------------------------------------------------------------------------------");
Console.WriteLine($"Position {displayVert.pos.X} {displayVert.pos.Y} {displayVert.pos.Z}");
Console.WriteLine($"Normal {displayVert.nrm.X} {displayVert.nrm.Y} {displayVert.nrm.Z}");
Console.WriteLine($"Tanget {displayVert.tan.X} {displayVert.tan.Y} {displayVert.tan.Z}");
Console.WriteLine($"Color {displayVert.col.X} {displayVert.col.Y} {displayVert.col.Z} {displayVert.col.W}");
Console.WriteLine($"UV Layer 1 {displayVert.uv.X} {displayVert.uv.Y}");
Console.WriteLine($"UV Layer 2 {displayVert.uv2.X} {displayVert.uv2.Y}");
Console.WriteLine($"UV Layer 3 {displayVert.uv3.X} {displayVert.uv3.Y}");
Console.WriteLine($"Bone Index {displayVert.node.X} {displayVert.node.Y} {displayVert.node.Z} {displayVert.node.W}");
Console.WriteLine($"Weights {displayVert.weight.X} {displayVert.weight.Y} {displayVert.weight.Z} {displayVert.weight.W}");
Console.WriteLine($"---------------------------------------------------------------------------------------");*/
}
return displayVertList;
}
}
public class Renderer : AbstractGlDrawable
{
public Vector3 Max = new Vector3(0);
public Vector3 Min = new Vector3(0);
public List<ushort> SelectedTypes = new List<ushort>();
public Vector3 position = new Vector3(0, 0, 0);
protected bool Selected = false;
protected bool Hovered = false;
// public override bool IsSelected() => Selected;
// public override bool IsSelected(int partIndex) => Selected;
public bool IsHovered() => Selected;
// gl buffer objects
int vbo_position;
int ibo_elements;
public List<MeshWrapper> Meshes = new List<MeshWrapper>();
private void GenerateBuffers()
{
GL.GenBuffers(1, out vbo_position);
GL.GenBuffers(1, out ibo_elements);
}
public void Destroy()
{
GL.DeleteBuffer(vbo_position);
GL.DeleteBuffer(ibo_elements);
}
public void UpdateVertexData()
{
if (!Runtime.OpenTKInitialized)
return;
DisplayVertex[] Vertices;
int[] Faces;
int poffset = 0;
int voffset = 0;
List<DisplayVertex> Vs = new List<DisplayVertex>();
List<int> Ds = new List<int>();
foreach (var m in Meshes)
{
m.Offset = poffset * 4;
List<DisplayVertex> pv = m.CreateDisplayVertices();
Vs.AddRange(pv);
for (int i = 0; i < m.lodMeshes[m.DisplayLODIndex].displayFaceSize; i++)
{
Ds.Add(m.display[i] + voffset);
}
poffset += m.lodMeshes[m.DisplayLODIndex].displayFaceSize;
voffset += pv.Count;
}
// Binds
Vertices = Vs.ToArray();
Faces = Ds.ToArray();
// Bind only once!
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
GL.BufferData<DisplayVertex>(BufferTarget.ArrayBuffer, (IntPtr)(Vertices.Length * DisplayVertex.Size), Vertices, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements);
GL.BufferData<int>(BufferTarget.ElementArrayBuffer, (IntPtr)(Faces.Length * sizeof(int)), Faces, BufferUsageHint.StaticDraw);
LibraryGUI.Instance.UpdateViewport();
}
public ShaderProgram defaultShaderProgram;
public override void Prepare(GL_ControlModern control)
{
string pathFrag = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "MKAGPDX") + "\\MKAGPDX_Model.frag";
string pathVert = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "MKAGPDX") + "\\MKAGPDX_Model.vert";
var defaultFrag = new FragmentShader(File.ReadAllText(pathFrag));
var defaultVert = new VertexShader(File.ReadAllText(pathVert));
defaultShaderProgram = new ShaderProgram(defaultFrag, defaultVert);
}
public override void Prepare(GL_ControlLegacy control)
{
}
private void CheckBuffers()
{
if (!Runtime.OpenTKInitialized)
return;
bool buffersWereInitialized = ibo_elements != 0 && vbo_position != 0;
if (!buffersWereInitialized)
{
GenerateBuffers();
UpdateVertexData();
}
}
public override void Draw(GL_ControlLegacy control, Pass pass)
{
CheckBuffers();
if (!Runtime.OpenTKInitialized)
return;
}
public override void Draw(GL_ControlModern control, Pass pass)
{
CheckBuffers();
if (!Runtime.OpenTKInitialized)
return;
control.CurrentShader = defaultShaderProgram;
SetRenderSettings(defaultShaderProgram);
Matrix4 camMat = control.ModelMatrix * control.CameraMatrix * control.ProjectionMatrix;
GL.Disable(EnableCap.CullFace);
GL.Uniform3(defaultShaderProgram["difLightDirection"], Vector3.TransformNormal(new Vector3(0f, 0f, -1f), camMat.Inverted()).Normalized());
GL.Uniform3(defaultShaderProgram["difLightColor"], new Vector3(1));
GL.Uniform3(defaultShaderProgram["ambLightColor"], new Vector3(1));
defaultShaderProgram.EnableVertexAttributes();
foreach (var mdl in Meshes)
{
DrawModel(mdl, defaultShaderProgram);
}
defaultShaderProgram.DisableVertexAttributes();
GL.UseProgram(0);
GL.Disable(EnableCap.DepthTest);
GL.Enable(EnableCap.DepthTest);
GL.Enable(EnableCap.CullFace);
}
private void SetRenderSettings(ShaderProgram shader)
{
shader.SetBoolToInt("renderVertColor", Runtime.renderVertColor);
GL.Uniform1(defaultShaderProgram["renderType"], (int)Runtime.viewportShading);
}
private void DrawModel(MeshWrapper m, ShaderProgram shader, bool drawSelection = false)
{
if (m.lodMeshes[m.DisplayLODIndex].faces.Count <= 3)
return;
SetVertexAttributes(m, shader);
if (m.Checked)
{
if ((m.IsSelected))
{
DrawModelSelection(m, shader);
}
else
{
if (Runtime.RenderModelWireframe)
{
DrawModelWireframe(m, shader);
}
if (Runtime.RenderModels)
{
GL.DrawElements(PrimitiveType.Triangles, m.lodMeshes[m.DisplayLODIndex].displayFaceSize, DrawElementsType.UnsignedInt, m.Offset);
}
}
}
}
private static void DrawModelSelection(MeshWrapper p, ShaderProgram shader)
{
//This part needs to be reworked for proper outline. Currently would make model disappear
GL.DrawElements(PrimitiveType.Triangles, p.lodMeshes[p.DisplayLODIndex].displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
GL.Enable(EnableCap.StencilTest);
// use vertex color for wireframe color
GL.Uniform1(shader["colorOverride"], 1);
GL.PolygonMode(MaterialFace.Front, PolygonMode.Line);
GL.Enable(EnableCap.LineSmooth);
GL.LineWidth(1.5f);
GL.DrawElements(PrimitiveType.Triangles, p.lodMeshes[p.DisplayLODIndex].displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
GL.Uniform1(shader["colorOverride"], 0);
GL.Enable(EnableCap.DepthTest);
}
private void SetVertexAttributes(MeshWrapper m, ShaderProgram shader)
{
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
GL.VertexAttribPointer(shader.GetAttribute("vPosition"), 3, VertexAttribPointerType.Float, false, DisplayVertex.Size, 0); //+12
GL.VertexAttribPointer(shader.GetAttribute("vNormal"), 3, VertexAttribPointerType.Float, false, DisplayVertex.Size, 12); //+12
GL.VertexAttribPointer(shader.GetAttribute("vTangent"), 3, VertexAttribPointerType.Float, false, DisplayVertex.Size, 24); //+12
GL.VertexAttribPointer(shader.GetAttribute("vUV0"), 2, VertexAttribPointerType.Float, false, DisplayVertex.Size, 36); //+8
GL.VertexAttribPointer(shader.GetAttribute("vColor"), 4, VertexAttribPointerType.Float, false, DisplayVertex.Size, 44); //+16
GL.VertexAttribIPointer(shader.GetAttribute("vBone"), 4, VertexAttribIntegerType.Int, DisplayVertex.Size, new IntPtr(60)); //+16
GL.VertexAttribPointer(shader.GetAttribute("vWeight"), 4, VertexAttribPointerType.Float, false, DisplayVertex.Size, 76);//+16
GL.VertexAttribPointer(shader.GetAttribute("vUV1"), 2, VertexAttribPointerType.Float, false, DisplayVertex.Size, 92);//+8
GL.VertexAttribPointer(shader.GetAttribute("vUV2"), 2, VertexAttribPointerType.Float, false, DisplayVertex.Size, 100);//+8
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements);
}
private static void DrawModelWireframe(MeshWrapper p, ShaderProgram shader)
{
// use vertex color for wireframe color
GL.Uniform1(shader["colorOverride"], 1);
GL.PolygonMode(MaterialFace.Front, PolygonMode.Line);
GL.Enable(EnableCap.LineSmooth);
GL.LineWidth(1.5f);
GL.DrawElements(PrimitiveType.Triangles, p.lodMeshes[p.DisplayLODIndex].displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
GL.Uniform1(shader["colorOverride"], 0);
}
}
Viewport viewport
{
get
{
var editor = LibraryGUI.Instance.GetObjectEditor();
return editor.GetViewport();
}
set
{
var editor = LibraryGUI.Instance.GetObjectEditor();
editor.LoadViewport(value);
}
}
bool DrawablesLoaded = false;
public override void OnClick(TreeView treeView)
{
if (Runtime.UseOpenGL)
{
if (viewport == null)
{
viewport = new Viewport(ObjectEditor.GetDrawableContainers());
viewport.Dock = DockStyle.Fill;
}
if (!DrawablesLoaded)
{
ObjectEditor.AddContainer(DrawableContainer);
DrawablesLoaded = true;
}
viewport.ReloadDrawables(DrawableContainer);
LibraryGUI.Instance.LoadEditor(viewport);
viewport.Text = Text;
}
}
public class Header
{
public uint Version { get; set; }
@ -68,10 +437,33 @@ namespace FirstPlugin
public Tuple<Node, Node> LinkNodes; //Links two nodes for some reason
public List<Node> LowerNodes = new List<Node>();
public void Read(FileReader reader, TreeNode root)
public STSkeleton Skeleton { get; set; }
Renderer DrawableRenderer { get; set; }
public void Read(FileReader reader, MKAGPDX_Model root)
{
Skeleton = new STSkeleton();
DrawableRenderer = new Renderer();
root.DrawableContainer.Drawables.Add(Skeleton);
root.DrawableContainer.Drawables.Add(DrawableRenderer);
reader.ReadSignature(4, "BIKE");
Version = reader.ReadUInt32();
ushort Type = reader.ReadUInt16();
ushort Unknown = reader.ReadUInt16();
if (Type == 0)
{
}
else if ((Type == 1))
{
throw new Exception("Animation files not supported yet!");
}
else
{
throw new Exception("Unknown type found! " + Type);
}
Alignment = reader.ReadUInt32();
uint Padding = reader.ReadUInt32();
uint MaterialCount = reader.ReadUInt32();
@ -90,12 +482,9 @@ namespace FirstPlugin
uint Padding2 = reader.ReadUInt32();
uint[] Unknowns = reader.ReadUInt32s(10);
for (int i = 0; i < MaterialCount; i++)
{
Material mat = new Material();
mat.Read(reader);
Materials.Add(mat);
}
root.Nodes.Add("Materials");
long pos = reader.Position;
if (TextureMapsOffset != 0)
{
@ -104,52 +493,176 @@ namespace FirstPlugin
{
TextureMaps.Add(reader.ReadNameOffset(false, typeof(uint)));
}
}
Console.WriteLine($"MiddleLevelNodeCount {UpperLevelNodeCount}");
Console.WriteLine($"MiddleLevelNodeOffset {UpperLevelNodeOffset}");
reader.SeekBegin(pos);
for (int i = 0; i < MaterialCount; i++)
{
Material mat = new Material();
mat.Read(reader);
Materials.Add(mat);
if (UpperLevelNodeCount != 0)
var genericMat = new STGenericMaterial();
genericMat.Text = $"Material {i}";
for (int t = 0; t < mat.TextureIndices.Length; t++)
{
for (int i = 0; i < UpperLevelNodeCount; i++)
if(mat.TextureIndices[t] != -1)
{
reader.SeekBegin(UpperLevelNodeOffset + (i * 8));
Console.WriteLine("TextureIndices " + mat.TextureIndices[t]);
string Texture = TextureMaps[mat.TextureIndices[t]];
var textureMap = new STGenericMatTexture();
textureMap.Name = Texture;
genericMat.TextureMaps.Add(textureMap);
if (Texture.EndsWith("col.dds"))
textureMap.Type = STGenericMatTexture.TextureType.Diffuse;
if (Texture.EndsWith("col.mot"))
textureMap.Type = STGenericMatTexture.TextureType.Diffuse;
}
}
root.Nodes[0].Nodes.Add(genericMat);
}
if (LowerLevelNodeCount != 0)
{
for (int i = 0; i < LowerLevelNodeCount; i++)
{
reader.SeekBegin(LowerLevelNodeOffset + (i * 8));
string NodeName = reader.ReadNameOffset(false, typeof(uint));
uint Offset = reader.ReadUInt32();
Console.WriteLine($"NodeName {NodeName} Offset {Offset}");
if (Offset != 0)
{
reader.SeekBegin(Offset);
Node node = new Node();
node.Text = NodeName;
node.Name = NodeName;
node.Read(reader);
UpperNodes.Add(node);
LowerNodes.Add(node);
}
}
}
foreach (var node in UpperNodes)
LoadChildern(UpperNodes, node, root);
if (FirstNodeOffset != 0)
{
reader.SeekBegin(FirstNodeOffset);
uint NodeOffset = reader.ReadUInt32();
reader.SeekBegin(NodeOffset);
Node node = new Node();
node.Name = GetNodeName(LowerNodes, node);
node.Read(reader);
LoadChildern(LowerNodes, node, root);
}
Skeleton.update();
Skeleton.reset();
}
private void LoadChildern(List<Node> NodeLookup, Node Node, TreeNode root)
{
if (Node.ChildNode != null)
{
if (NodeLookup.Contains(Node.ChildNode))
{
int index = NodeLookup.IndexOf(Node.ChildNode);
Node.ChildNode.Text = NodeLookup[index].Text;
var NewNode = SetWrapperNode(Node);
root.Nodes.Add(NewNode);
Node.Nodes.Add(Node.ChildNode);
LoadChildern(NodeLookup, Node.ChildNode, Node.ChildNode);
for (int i = 0; i < Node.Children.Count; i++)
{
Node.Children[i].Name = GetNodeName(NodeLookup, Node.Children[i]);
var newChild = SetWrapperNode(Node.Children[i]);
NewNode.Nodes.Add(newChild);
LoadChildern(NodeLookup, Node.Children[i], newChild);
}
}
root.Nodes.Add(Node);
private TreeNode SetWrapperNode(Node Node)
{
if (Node.IsBone)
{
STBone boneNode = new STBone(Skeleton);
boneNode.RotationType = STBone.BoneRotationType.Euler;
boneNode.Checked = true;
boneNode.Text = Node.Name;
boneNode.position = new float[3];
boneNode.scale = new float[3];
boneNode.rotation = new float[4];
boneNode.position[0] = Node.Translation.X;
boneNode.position[1] = Node.Translation.Y;
boneNode.position[2] = Node.Translation.Z;
boneNode.rotation[0] = Node.Rotation.X;
boneNode.rotation[1] = Node.Rotation.Y;
boneNode.rotation[2] = Node.Rotation.Z;
boneNode.scale[0] = Node.Scale.X;
boneNode.scale[1] = Node.Scale.Y;
boneNode.scale[2] = Node.Scale.Z;
if (Node.IsBone)
Skeleton.bones.Add(boneNode);
return boneNode;
}
else if (Node.IsMesh)
{
MeshWrapper meshNode = new MeshWrapper();
meshNode.ImageKey = "mesh";
meshNode.SelectedImageKey = "mesh";
int i = 0;
meshNode.lodMeshes = new List<MeshWrapper.LOD_Mesh>();
var msh = new MeshWrapper.LOD_Mesh();
msh.PrimitiveType = STPolygonType.Triangle;
msh.FirstVertex = 0;
msh.faces = Node.SubMeshes[0].Faces;
meshNode.vertices = Node.SubMeshes[0].Vertices;
meshNode.lodMeshes.Add(msh);
foreach (SubMesh subMesh in Node.SubMeshes)
{
if (i > 0)
{
MeshWrapper subMeshNode = new MeshWrapper();
subMeshNode.ImageKey = "mesh";
subMeshNode.SelectedImageKey = "mesh";
subMeshNode.lodMeshes = new List<MeshWrapper.LOD_Mesh>();
var submsh = new MeshWrapper.LOD_Mesh();
submsh.PrimitiveType = STPolygonType.Triangle;
submsh.FirstVertex = 0;
submsh.faces = subMesh.Faces;
subMeshNode.lodMeshes.Add(submsh);
subMeshNode.vertices = subMesh.Vertices;
DrawableRenderer.Meshes.Add(subMeshNode);
}
i++;
}
meshNode.Checked = true;
meshNode.Text = Node.Name;
DrawableRenderer.Meshes.Add(meshNode);
return meshNode;
}
else
return new TreeNode(Node.Name);
}
private static string GetNodeName(List<Node> NodeLookup, Node node)
{
for (int i = 0; i < NodeLookup.Count; i++)
{
if (NodeLookup[i].Position == node.Position)
return NodeLookup[i].Name;
}
return "";
}
}
@ -158,6 +671,7 @@ namespace FirstPlugin
public Vector4 Ambient;
public Vector4 Diffuse;
public Vector4 Specular;
public Vector4 Ambience;
public float Shiny;
public Vector4 Transparency;
public float TransGlossy;
@ -176,6 +690,7 @@ namespace FirstPlugin
Ambient = new Vector4(0.3f, 0.3f, 0.3f,1.0f);
Diffuse = new Vector4(0.7f, 0.7f, 0.7f, 1.0f);
Specular = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);
Ambience = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);
Shiny = 50;
Transparency = new Vector4(0.0f, 0.0f, 0.0f, 1.0f);
TextureIndices = new short[10];
@ -186,6 +701,8 @@ namespace FirstPlugin
Ambient = reader.ReadVec4();
Diffuse = reader.ReadVec4();
Specular = reader.ReadVec4();
Ambience = reader.ReadVec4();
Shiny = reader.ReadSingle();
Transparency = reader.ReadVec4();
TransGlossy = reader.ReadSingle();
@ -196,36 +713,195 @@ namespace FirstPlugin
IndexRefreaction = reader.ReadSingle();
Translucency = reader.ReadSingle();
Unknown = reader.ReadSingle();
TextureIndices = reader.ReadInt16s(10);
TextureIndices = reader.ReadInt16s(6);
Unknowns = reader.ReadUInt32s(10);
}
}
public class Node : TreeNode
public class SubMesh
{
public Node ParentNode { get; set; }
public Material Material { get; set; }
public List<Vertex> Vertices = new List<Vertex>();
public List<int> Faces = new List<int>();
public SubMesh(Node parentNode)
{
ParentNode = parentNode;
}
public void Read(FileReader reader)
{
uint Padding = reader.ReadUInt32();
uint FaceCount = reader.ReadUInt32();
uint[] Unknowns = reader.ReadUInt32s(5);
uint VertexCount = reader.ReadUInt32();
uint VertexPositionOffset = reader.ReadUInt32();
uint VertexNormalOffset = reader.ReadUInt32();
uint UnknownOffset = reader.ReadUInt32();
uint TexCoord0Offset = reader.ReadUInt32();
uint TexCoord1Offset = reader.ReadUInt32();
uint Unknown1Offset = reader.ReadUInt32();
uint Unknown2Offset = reader.ReadUInt32();
uint FaceOffset = reader.ReadUInt32();
uint SkinCount = reader.ReadUInt32(); //Unsure
uint Unknown = reader.ReadUInt32(); //Something related to count
uint WeightOffset = reader.ReadUInt32();
uint Unknown2 = reader.ReadUInt32();
for (int i = 0; i < VertexCount; i++)
{
Vertex vertex = new Vertex();
Vertices.Add(vertex);
if (VertexPositionOffset != 0)
{
reader.SeekBegin(VertexPositionOffset + (i * 12));
vertex.pos = reader.ReadVec3();
vertex.pos = Vector3.TransformPosition(vertex.pos, ParentNode.Transform);
}
if (VertexNormalOffset != 0)
{
reader.SeekBegin(VertexNormalOffset + (i * 12));
vertex.nrm = reader.ReadVec3();
vertex.nrm = Vector3.TransformNormal(vertex.nrm, ParentNode.Transform);
}
if (TexCoord0Offset != 0)
{
reader.SeekBegin(TexCoord0Offset + (i * 8));
vertex.uv0 = reader.ReadVec2();
}
}
reader.SeekBegin(FaceOffset);
for (int i = 0; i < FaceCount * 3; i++)
{
Faces.Add(reader.ReadUInt16());
}
}
}
public class Node
{
public string Name { get; set; }
public bool Visible { get; set; }
public Vector3 Scale { get; set; }
public Vector3 Rotation { get; set; }
public Vector3 Translation { get; set; }
public byte[] Unknowns;
public Node ChildNode { get; set; }
public List<Node> Children = new List<Node>();
public List<SubMesh> SubMeshes = new List<SubMesh>();
internal long Position;
public bool IsBone
{
get { return Name.Contains("jnt") || Name.Contains("center"); }
}
public bool IsMesh
{
get { return SubMeshes.Count > 0; }
}
public Matrix4 Transform { get; set; }
public void Read(FileReader reader)
{
Position = reader.Position;
Visible = reader.ReadUInt32() == 1;
Scale = reader.ReadVec3();
Rotation = reader.ReadVec3();
Translation = reader.ReadVec3();
Unknowns = reader.ReadBytes(16);
uint BufferArrayOffset = reader.ReadUInt32();
uint ChildNodeOffset = reader.ReadUInt32();
uint SubMeshArrayOffsetPtr = reader.ReadUInt32();
uint ChildNodeOffsetPtr = reader.ReadUInt32();
if (ChildNodeOffset != 0)
Matrix4 TranslateMat = Matrix4.CreateTranslation(Translation);
Matrix4 RotXMat = Matrix4.CreateRotationX(Rotation.X);
Matrix4 RotYMat = Matrix4.CreateRotationY(Rotation.Y);
Matrix4 RotZMat = Matrix4.CreateRotationZ(Rotation.Z);
Matrix4 ScaleMat = Matrix4.CreateTranslation(Scale);
Transform = ScaleMat * (RotXMat * RotYMat * RotZMat) * TranslateMat;
if (SubMeshArrayOffsetPtr != 0)
{
reader.SeekBegin(ChildNodeOffset);
ChildNode = new Node();
//4 possible sub meshes
reader.SeekBegin(SubMeshArrayOffsetPtr);
uint SubMeshArrayOffset1 = reader.ReadUInt32();
uint SubMeshArrayOffset2 = reader.ReadUInt32();
uint SubMeshArrayOffset3 = reader.ReadUInt32();
uint SubMeshArrayOffset4 = reader.ReadUInt32();
if (SubMeshArrayOffset1 != 0)
{
reader.SeekBegin(SubMeshArrayOffset1);
SubMesh subMesh = new SubMesh(this);
subMesh.Read(reader);
SubMeshes.Add(subMesh);
}
if (SubMeshArrayOffset2 != 0)
{
reader.SeekBegin(SubMeshArrayOffset2);
SubMesh subMesh = new SubMesh(this);
subMesh.Read(reader);
SubMeshes.Add(subMesh);
}
if (SubMeshArrayOffset3 != 0)
{
reader.SeekBegin(SubMeshArrayOffset3);
SubMesh subMesh = new SubMesh(this);
subMesh.Read(reader);
SubMeshes.Add(subMesh);
}
if (SubMeshArrayOffset4 != 0)
{
reader.SeekBegin(SubMeshArrayOffset4);
SubMesh subMesh = new SubMesh(this);
subMesh.Read(reader);
SubMeshes.Add(subMesh);
}
}
if (ChildNodeOffsetPtr != 0)
{
//4 possible children
reader.SeekBegin(ChildNodeOffsetPtr);
uint ChildNodeOffset1 = reader.ReadUInt32();
uint ChildNodeOffset2 = reader.ReadUInt32();
uint ChildNodeOffset3 = reader.ReadUInt32();
uint ChildNodeOffset4 = reader.ReadUInt32();
if (ChildNodeOffset1 != 0)
{
reader.SeekBegin(ChildNodeOffset1);
Node ChildNode = new Node();
ChildNode.Read(reader);
Children.Add(ChildNode);
}
if (ChildNodeOffset2 != 0)
{
reader.SeekBegin(ChildNodeOffset2);
Node ChildNode = new Node();
ChildNode.Read(reader);
Children.Add(ChildNode);
}
if (ChildNodeOffset3 != 0)
{
reader.SeekBegin(ChildNodeOffset3);
Node ChildNode = new Node();
ChildNode.Read(reader);
Children.Add(ChildNode);
}
if (ChildNodeOffset4 != 0)
{
reader.SeekBegin(ChildNodeOffset4);
Node ChildNode = new Node();
ChildNode.Read(reader);
Children.Add(ChildNode);
}
}
//After repeats a fairly similar structure, with SRT values

View File

@ -18,7 +18,11 @@ namespace Switch_Toolbox.Library
STProgressBar progressBar;
public void SaveFromModel(STGenericModel model, string FileName, List<STGenericTexture> Textures, STSkeleton skeleton = null, List<int> NodeArray = null)
public void SaveFromModel(STGenericModel model, string FileName, List<STGenericTexture> Textures, STSkeleton skeleton = null, List<int> NodeArray = null) {
SaveFromModel(model.Objects.ToList(), model.Materials.ToList(), FileName, Textures, skeleton, NodeArray);
}
public void SaveFromModel(List<STGenericObject> Meshes, List<STGenericMaterial> Materials, string FileName, List<STGenericTexture> Textures, STSkeleton skeleton = null, List<int> NodeArray = null)
{
ExtractedTextures.Clear();
@ -33,17 +37,17 @@ namespace Switch_Toolbox.Library
progressBar.Refresh();
SaveSkeleton(skeleton, scene.RootNode);
SaveMaterials(scene, model, FileName, Textures);
SaveMaterials(scene, Materials, FileName, Textures);
progressBar.Task = "Exorting Meshes...";
progressBar.Value = 50;
SaveMeshes(scene, model, skeleton, FileName, NodeArray);
SaveMeshes(scene, Meshes, skeleton, FileName, NodeArray);
progressBar.Task = "Saving File...";
progressBar.Value = 80;
SaveScene(FileName, scene, model.GetObjects());
SaveScene(FileName, scene, Meshes);
progressBar.Value = 100;
progressBar.Close();
@ -78,10 +82,10 @@ namespace Switch_Toolbox.Library
}
private void SaveMeshes(Scene scene, STGenericModel model, STSkeleton skeleton, string FileName, List<int> NodeArray)
private void SaveMeshes(Scene scene, List<STGenericObject> Meshes, STSkeleton skeleton, string FileName, List<int> NodeArray)
{
int MeshIndex = 0;
foreach (var obj in model.Nodes[0].Nodes)
foreach (var obj in Meshes)
{
var mesh = SaveMesh((STGenericObject)obj, MeshIndex, skeleton, NodeArray);
scene.Meshes.Add(mesh);
@ -126,9 +130,15 @@ namespace Switch_Toolbox.Library
for (int j = 0; j < v.boneIds.Count; j++)
{
if (j < genericObj.VertexSkinCount)
{
STBone STbone = null;
if (NodeArray != null)
{
//Get the bone via the node array and bone index from the vertex
STBone STbone = skeleton.bones[NodeArray[v.boneIds[j]]];
STbone = skeleton.bones[NodeArray[v.boneIds[j]]];
}
else
STbone = skeleton.bones[v.boneIds[j]];
//Find the index of a bone. If it doesn't exist then we add it
int boneInd = mesh.Bones.FindIndex(x => x.Name == STbone.Text);
@ -478,7 +488,7 @@ namespace Switch_Toolbox.Library
writer.Flush();
}
private void SaveMaterials(Scene scene, STGenericModel model, string FileName, List<STGenericTexture> Textures)
private void SaveMaterials(Scene scene, List<STGenericMaterial> Materials, string FileName, List<STGenericTexture> Textures)
{
string TextureExtension = ".png";
string TexturePath = System.IO.Path.GetDirectoryName(FileName);
@ -503,7 +513,7 @@ namespace Switch_Toolbox.Library
}
}
foreach (var mat in model.Nodes[1].Nodes)
foreach (var mat in Materials)
{
var genericMat = (STGenericMaterial)mat;

View File

@ -20,23 +20,31 @@ namespace Switch_Toolbox.Library
}
public List<STGenericObject> GetObjects()
{
List<STGenericObject> objects = new List<STGenericObject>();
foreach (TreeNode node in Nodes)
{
if (node is STGenericObject)
objects.Add(node as STGenericObject);
private IEnumerable<STGenericMaterial> _materials;
private IEnumerable<STGenericObject> _objects;
if (node.Nodes.Count > 0)
public virtual IEnumerable<STGenericMaterial> Materials
{
foreach (TreeNode childNode in node.Nodes)
if (childNode is STGenericObject)
objects.Add(childNode as STGenericObject);
get
{
return _materials;
}
set
{
_materials = value;
}
}
return objects;
public virtual IEnumerable<STGenericObject> Objects
{
get
{
return _objects;
}
set
{
_objects = value;
}
}
}
}

View File

@ -0,0 +1,36 @@
#version 330
in vec3 normal;
in vec3 position;
in vec2 f_texcoord0;
in vec2 f_texcoord1;
in vec2 f_texcoord2;
in vec2 f_texcoord3;
in vec4 vertexColor;
in vec3 tangent;
in vec3 boneWeightsColored;
uniform vec3 difLightDirection;
uniform vec3 difLightColor;
uniform vec3 ambLightColor;
uniform int colorOverride;
uniform int renderType;
uniform int renderVertColor;
uniform mat4 modelview;
uniform int HasDiffuse;
uniform sampler2D DiffuseMap;
uniform sampler2D UVTestPattern;
out vec4 FragColor;
void main()
{
vec3 displayNormal = (normal.xyz * 0.5) + 0.5;
FragColor = vec4(displayNormal.rgb,1);
}

View File

@ -0,0 +1,132 @@
#version 330
const int MY_ARRAY_SIZE = 200;
in vec3 vPosition;
in vec3 vNormal;
in vec3 vTangent;
in vec2 vUV0;
in vec4 vColor;
in vec4 vBone;
in vec4 vWeight;
in vec2 vUV1;
in vec2 vUV2;
out vec2 f_texcoord0;
out vec2 f_texcoord1;
out vec2 f_texcoord2;
out vec2 f_texcoord3;
out vec3 normal;
out vec4 vertexColor;
out vec3 position;
out vec3 tangent;
out vec3 boneWeightsColored;
uniform int boneIds[190];
// Skinning uniforms
uniform mat4 bones[190];
uniform mat4 mtxCam;
uniform mat4 mtxMdl;
uniform mat4 previewScale;
// Bone Weight Display
uniform sampler2D weightRamp1;
uniform sampler2D weightRamp2;
uniform int selectedBoneIndex;
uniform int debugOption;
uniform int NoSkinning;
uniform int RigidSkinning;
uniform int SingleBoneIndex;
vec2 ST0_Translate;
float ST0_Rotate;
vec2 ST0_Scale;
vec4 skin(vec3 pos, ivec4 index)
{
vec4 newPosition = vec4(pos.xyz, 1.0);
newPosition = bones[index.x] * vec4(pos, 1.0) * vWeight.x;
newPosition += bones[index.y] * vec4(pos, 1.0) * vWeight.y;
newPosition += bones[index.z] * vec4(pos, 1.0) * vWeight.z;
if (vWeight.w < 1) //Necessary. Bones may scale weirdly without
newPosition += bones[index.w] * vec4(pos, 1.0) * vWeight.w;
return newPosition;
}
vec3 skinNRM(vec3 nr, ivec4 index)
{
vec3 newNormal = vec3(0);
newNormal = mat3(bones[index.x]) * nr * vWeight.x;
newNormal += mat3(bones[index.y]) * nr * vWeight.y;
newNormal += mat3(bones[index.z]) * nr * vWeight.z;
newNormal += mat3(bones[index.w]) * nr * vWeight.w;
return newNormal;
}
vec3 BoneWeightColor(float weights)
{
float rampInputLuminance = weights;
rampInputLuminance = clamp((rampInputLuminance), 0.001, 0.999);
if (debugOption == 1) // Greyscale
return vec3(weights);
else if (debugOption == 2) // Color 1
return texture(weightRamp1, vec2(1 - rampInputLuminance, 0.50)).rgb;
else // Color 2
return texture(weightRamp2, vec2(1 - rampInputLuminance, 0.50)).rgb;
}
float BoneWeightDisplay(ivec4 index)
{
float weight = 0;
if (selectedBoneIndex == boneIds[index.x])
weight += vWeight.x;
if (selectedBoneIndex == boneIds[index.y])
weight += vWeight.y;
if (selectedBoneIndex == boneIds[index.z])
weight += vWeight.z;
if (selectedBoneIndex == boneIds[index.w])
weight += vWeight.w;
if (selectedBoneIndex == boneIds[index.x] && RigidSkinning == 1)
weight = 1;
if (selectedBoneIndex == SingleBoneIndex && NoSkinning == 1)
weight = 1;
return weight;
}
void main()
{
ivec4 index = ivec4(vBone);
vec4 objPos = vec4(vPosition.xyz, 1.0);
if (vBone.x != -1.0)
objPos = skin(vPosition, index);
if(vBone.x != -1.0)
normal = normalize((skinNRM(vNormal.xyz, index)).xyz);
vec4 position = mtxCam * mtxMdl * vec4(objPos.xyz, 1.0);
normal = vNormal;
vertexColor = vColor;
position = objPos;
f_texcoord0 = vUV0;
f_texcoord1 = vUV1;
f_texcoord2 = vUV2;
tangent = vTangent;
gl_Position = mtxCam * mtxMdl * vec4(vPosition.xyz, 1.0);
float totalWeight = BoneWeightDisplay(index);
boneWeightsColored = BoneWeightColor(totalWeight).rgb;
}

View File

@ -237,6 +237,12 @@
<None Include="Shader\Legacy\KCL.vert">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Shader\MKAGPDX\MKAGPDX_Model.frag">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Shader\MKAGPDX\MKAGPDX_Model.vert">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Shader\PBR\brdf.frag">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>