diff --git a/.vs/Switch_Toolbox/v15/.suo b/.vs/Switch_Toolbox/v15/.suo index 938dd026..c450f294 100644 Binary files a/.vs/Switch_Toolbox/v15/.suo and b/.vs/Switch_Toolbox/v15/.suo differ diff --git a/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide b/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide index fe7ff0b3..db107b87 100644 Binary files a/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide and b/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide differ diff --git a/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-shm b/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-shm index cb9388e1..bebe0dd5 100644 Binary files a/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-shm and b/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-shm differ diff --git a/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-wal b/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-wal index cab22731..e577b46f 100644 Binary files a/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-wal and b/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-wal differ diff --git a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/SubFiles/FMDL.cs b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/SubFiles/FMDL.cs index 2271c3ab..9ec9c8f7 100644 --- a/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/SubFiles/FMDL.cs +++ b/Switch_FileFormatsMain/FileFormats/BFRES/Bfres Structs/SubFiles/FMDL.cs @@ -27,6 +27,9 @@ namespace Bfres.Structs public List shapes = new List(); public List depthSortedMeshes = new List(); + public override IEnumerable Objects => shapes; + public override IEnumerable Materials => materials.Values.ToList(); + public Dictionary materials = new Dictionary(); public Model Model; public ResU.Model ModelU; diff --git a/Switch_FileFormatsMain/FileFormats/MKAGPDX/Model/MKAGPDX_Model.cs b/Switch_FileFormatsMain/FileFormats/MKAGPDX/Model/MKAGPDX_Model.cs index ec93167f..ef4e4cfe 100644 --- a/Switch_FileFormatsMain/FileFormats/MKAGPDX/Model/MKAGPDX_Model.cs +++ b/Switch_FileFormatsMain/FileFormats/MKAGPDX/Model/MKAGPDX_Model.cs @@ -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 Materials = new List(); + 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(), ((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 CreateDisplayVertices() + { + display = lodMeshes[DisplayLODIndex].getDisplayFace().ToArray(); + + List displayVertList = new List(); + + 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 SelectedTypes = new List(); + + 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 Meshes = new List(); + + 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 Vs = new List(); + List Ds = new List(); + foreach (var m in Meshes) + { + m.Offset = poffset * 4; + List 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(BufferTarget.ArrayBuffer, (IntPtr)(Vertices.Length * DisplayVertex.Size), Vertices, BufferUsageHint.StaticDraw); + + GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements); + GL.BufferData(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 LinkNodes; //Links two nodes for some reason public List LowerNodes = new List(); - 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}"); - - if (UpperLevelNodeCount != 0) + reader.SeekBegin(pos); + for (int i = 0; i < MaterialCount; i++) { - for (int i = 0; i < UpperLevelNodeCount; i++) + Material mat = new Material(); + mat.Read(reader); + Materials.Add(mat); + + var genericMat = new STGenericMaterial(); + genericMat.Text = $"Material {i}"; + + for (int t = 0; t < mat.TextureIndices.Length; t++) { - reader.SeekBegin(UpperLevelNodeOffset + (i * 8)); + if(mat.TextureIndices[t] != -1) + { + 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 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); + } + } + + 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(); + 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(); + 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 NodeLookup, Node node) + { + for (int i = 0; i < NodeLookup.Count; i++) + { + if (NodeLookup[i].Position == node.Position) + return NodeLookup[i].Name; } - root.Nodes.Add(Node); + 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 Vertices = new List(); + public List Faces = new List(); + + 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 Children = new List(); + public List SubMeshes = new List(); + + 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(); - ChildNode.Read(reader); + //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 diff --git a/Switch_FileFormatsMain/obj/Release/DesignTimeResolveAssemblyReferences.cache b/Switch_FileFormatsMain/obj/Release/DesignTimeResolveAssemblyReferences.cache index b0e66d1f..b032478a 100644 Binary files a/Switch_FileFormatsMain/obj/Release/DesignTimeResolveAssemblyReferences.cache and b/Switch_FileFormatsMain/obj/Release/DesignTimeResolveAssemblyReferences.cache differ diff --git a/Switch_FileFormatsMain/obj/Release/Switch_FileFormatsMain.csprojAssemblyReference.cache b/Switch_FileFormatsMain/obj/Release/Switch_FileFormatsMain.csprojAssemblyReference.cache index 24c10549..1d01a3f6 100644 Binary files a/Switch_FileFormatsMain/obj/Release/Switch_FileFormatsMain.csprojAssemblyReference.cache and b/Switch_FileFormatsMain/obj/Release/Switch_FileFormatsMain.csprojAssemblyReference.cache differ diff --git a/Switch_Toolbox_Library/FileFormats/Assimp/AssimpSaver.cs b/Switch_Toolbox_Library/FileFormats/Assimp/AssimpSaver.cs index 518f96ed..d9117530 100644 --- a/Switch_Toolbox_Library/FileFormats/Assimp/AssimpSaver.cs +++ b/Switch_Toolbox_Library/FileFormats/Assimp/AssimpSaver.cs @@ -18,7 +18,11 @@ namespace Switch_Toolbox.Library STProgressBar progressBar; - public void SaveFromModel(STGenericModel model, string FileName, List Textures, STSkeleton skeleton = null, List NodeArray = null) + public void SaveFromModel(STGenericModel model, string FileName, List Textures, STSkeleton skeleton = null, List NodeArray = null) { + SaveFromModel(model.Objects.ToList(), model.Materials.ToList(), FileName, Textures, skeleton, NodeArray); + } + + public void SaveFromModel(List Meshes, List Materials, string FileName, List Textures, STSkeleton skeleton = null, List 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 NodeArray) + private void SaveMeshes(Scene scene, List Meshes, STSkeleton skeleton, string FileName, List 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); @@ -127,8 +131,14 @@ namespace Switch_Toolbox.Library { if (j < genericObj.VertexSkinCount) { - //Get the bone via the node array and bone index from the vertex - STBone STbone = skeleton.bones[NodeArray[v.boneIds[j]]]; + STBone STbone = null; + if (NodeArray != null) + { + //Get the bone via the node array and bone index from the vertex + 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 Textures) + private void SaveMaterials(Scene scene, List Materials, string FileName, List 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; diff --git a/Switch_Toolbox_Library/Generics/GenericModel.cs b/Switch_Toolbox_Library/Generics/GenericModel.cs index 5247766e..62835d49 100644 --- a/Switch_Toolbox_Library/Generics/GenericModel.cs +++ b/Switch_Toolbox_Library/Generics/GenericModel.cs @@ -20,23 +20,31 @@ namespace Switch_Toolbox.Library } - public List GetObjects() + private IEnumerable _materials; + private IEnumerable _objects; + + public virtual IEnumerable Materials { - List objects = new List(); - foreach (TreeNode node in Nodes) + get { - if (node is STGenericObject) - objects.Add(node as STGenericObject); - - if (node.Nodes.Count > 0) - { - foreach (TreeNode childNode in node.Nodes) - if (childNode is STGenericObject) - objects.Add(childNode as STGenericObject); - } + return _materials; } + set + { + _materials = value; + } + } - return objects; + public virtual IEnumerable Objects + { + get + { + return _objects; + } + set + { + _objects = value; + } } } } diff --git a/Toolbox/Shader/MKAGPDX/MKAGPDX_Model.frag b/Toolbox/Shader/MKAGPDX/MKAGPDX_Model.frag new file mode 100644 index 00000000..c4859bbd --- /dev/null +++ b/Toolbox/Shader/MKAGPDX/MKAGPDX_Model.frag @@ -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); +} diff --git a/Toolbox/Shader/MKAGPDX/MKAGPDX_Model.vert b/Toolbox/Shader/MKAGPDX/MKAGPDX_Model.vert new file mode 100644 index 00000000..1464e512 --- /dev/null +++ b/Toolbox/Shader/MKAGPDX/MKAGPDX_Model.vert @@ -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; + +} \ No newline at end of file diff --git a/Toolbox/Toolbox.csproj b/Toolbox/Toolbox.csproj index 6d8ffa9f..c0a5dc7a 100644 --- a/Toolbox/Toolbox.csproj +++ b/Toolbox/Toolbox.csproj @@ -237,6 +237,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest