public Vector3 TransformLocal(Vector3 position, int BoneIndex, bool IsSingleBind, bool IsPos = true) { try { var skel = GetParentModel().Skeleton; Matrix4 trans = Matrix4.Identity; if (IsSingleBind) { if (BoneIndex >= skel.Node_Array.Length || BoneIndex == -1) { return(position); } var bone = skel.bones[skel.Node_Array[BoneIndex]]; trans = bone.invert; } else { var bone = skel.bones[BoneIndex]; trans = bone.invert; } if (IsPos) { return(Vector3.TransformPosition(position, trans)); } else { return(Vector3.TransformNormal(position, trans)); } } catch { STConsole.WriteLine("Failed to bind bone to mesh " + Text, System.Drawing.Color.Red); return(position); } }
public List <ushort> GetIndices(FSKL fskl) { List <ushort> indices = new List <ushort>(); List <string> BoneNodes = new List <string>(); foreach (Vertex vtx in vertices) { foreach (int index in vtx.boneIds) { var bone = fskl.bones[fskl.Node_Array[index]]; ushort ind = (ushort)fskl.bones.IndexOf(bone); if (!indices.Contains(ind)) { STConsole.WriteLine($"Saving bone index {bone.Name} {index}"); indices.Add(ind); } } } STConsole.WriteLine($"Total Indices for {Text} {indices.Count}"); return(indices); }
private static string SatisfyFileTables(IFileFormat FileFormat, string FilePath, Stream Data, uint DecompressedSize, uint CompressedSize, bool IsYaz0Compressed) { string FileLog = ""; bool IsBotwFile = FilePath.IsSubPathOf(Runtime.BotwGamePath); bool IsTPHDFile = FilePath.IsSubPathOf(Runtime.TpGamePath); STConsole.WriteLine($"IsTPHDFile {IsTPHDFile}"); if (Runtime.ResourceTables.BotwTable && IsBotwFile) { string newFilePath = FilePath.Replace(Runtime.BotwGamePath, string.Empty).Remove(0, 1); newFilePath = newFilePath.Replace(".s", "."); newFilePath = newFilePath.Replace( @"\", "/"); string RealExtension = Path.GetExtension(newFilePath).Replace(".s", "."); string RstbPath = Path.Combine($"{Runtime.BotwGamePath}", "System", "Resource", "ResourceSizeTable.product.srsizetable"); RSTB BotwResourceTable = new RSTB(); BotwResourceTable.LoadFile(RstbPath); //Create a backup first if one doesn't exist if (!File.Exists($"{RstbPath}.backup")) { STConsole.WriteLine($"RSTB File found. Creating backup..."); BotwResourceTable.Write(new FileWriter($"{RstbPath}.backup")); File.WriteAllBytes($"{RstbPath}.backup", EveryFileExplorer.YAZ0.Compress($"{RstbPath}.backup")); } //Now apply the file table then save the table if (BotwResourceTable.IsInTable(newFilePath)) { FileLog += $"File found in resource table! {newFilePath}"; STConsole.WriteLine(FileLog, 1); } else { FileLog += $"File NOT found in resource table! {newFilePath}"; STConsole.WriteLine(FileLog, 0); } BotwResourceTable.SetEntry(newFilePath, Data, IsYaz0Compressed); BotwResourceTable.Write(new FileWriter(RstbPath)); File.WriteAllBytes(RstbPath, EveryFileExplorer.YAZ0.Compress(RstbPath)); } if (Runtime.ResourceTables.TpTable && IsTPHDFile) { string newFilePath = FilePath.Replace(Runtime.TpGamePath, string.Empty).Remove(0, 1); newFilePath = newFilePath.Replace(@"\", "/"); //Read the compressed tables and set the new sizes if paths match TPFileSizeTable CompressedFileTbl = new TPFileSizeTable(); CompressedFileTbl.ReadCompressedTable(new FileReader($"{Runtime.TpGamePath}/FileSizeList.txt")); if (CompressedFileTbl.IsInFileSizeList(newFilePath)) { STConsole.WriteLine("Found matching path in File Size List table! " + newFilePath, 1); CompressedFileTbl.SetFileSizeEntry(newFilePath, CompressedSize); } else STConsole.WriteLine("Failed to find path in File Size List table! " + newFilePath, 0); //Read decompressed file sizes TPFileSizeTable DecompressedFileTbl = new TPFileSizeTable(); DecompressedFileTbl.ReadDecompressedTable(new FileReader($"{Runtime.TpGamePath}/DecompressedSizeList.txt")); newFilePath = $"./DVDRoot/{newFilePath}"; newFilePath = newFilePath.Replace(".gz", string.Empty); //Write the decompressed file size if (DecompressedFileTbl.IsInDecompressedFileSizeList(newFilePath)) { STConsole.WriteLine("Found matching path in File Size List table! " + newFilePath, 1); DecompressedFileTbl.SetDecompressedFileSizeEntry(newFilePath, CompressedSize, DecompressedSize); } else STConsole.WriteLine("Failed to find path in File Size List table! " + newFilePath, 0); if (FileFormat == null) return FileLog; //Check if archive type bool IsArchive = false; foreach (var inter in FileFormat.GetType().GetInterfaces()) { if (inter == typeof(IArchiveFile)) IsArchive = true; } //Write all the file sizes in the archive if it's an archive type //Note this seems uneeded atm //Todo store both compressed and decompressed sizes in archive info /* if (IsArchive) { IArchiveFile Archive = (IArchiveFile)FileFormat; foreach (var file in Archive.Files) { uint DecompressedArchiveFileSize = (uint)file.FileData.Length; string ArchiveFilePath = $"/DVDRoot/{file.FileName}"; if (DecompressedFileTbl.IsInDecompressedFileSizeList(ArchiveFilePath)) { STConsole.WriteLine("Found matching path in File Size List table! " + ArchiveFilePath, 1); DecompressedFileTbl.SetDecompressedFileSizeEntry(ArchiveFilePath, DecompressedArchiveFileSize, DecompressedArchiveFileSize); } else STConsole.WriteLine("Failed to find path in File Size List table! " + ArchiveFilePath, 0); } }*/ CompressedFileTbl.WriteCompressedTable(new FileWriter($"{Runtime.TpGamePath}/FileSizeList.txt")); DecompressedFileTbl.WriteDecompressedTable(new FileWriter($"{Runtime.TpGamePath}/DecompressedSizeList.txt")); } return FileLog; }
public static void SaveSkeleton(FSKL fskl, List <STBone> Bones) { fskl.node.Skeleton.Bones.Clear(); fskl.node.Skeleton.MatrixToBoneList = new List <ushort>(); fskl.node.Skeleton.InverseModelMatrices = new List <Syroot.Maths.Matrix3x4>(); ushort SmoothIndex = 0; foreach (STBone genericBone in Bones) { genericBone.BillboardIndex = ushort.MaxValue; STConsole.WriteLine($"Applying bone " + genericBone.Text); //Clone a generic bone with the generic data BfresBone bn = new BfresBone(fskl); bn.CloneBaseInstance(genericBone); //Set the bfres bone data if (bn.Bone == null) { bn.Bone = new Bone(); } bn.GenericToBfresBone(); if (bn.SmoothMatrixIndex != short.MaxValue) { fskl.node.Skeleton.MatrixToBoneList.Add(SmoothIndex++); } fskl.node.Skeleton.InverseModelMatrices.Add(Syroot.Maths.Matrix3x4.Zero); fskl.bones.Add(bn); } foreach (BfresBone wrapper in fskl.bones) { //Check duplicated names // List<string> names = fskl.bones.Select(o => o.Text).ToList(); // wrapper.Text = Utils.RenameDuplicateString(names, wrapper.Text); wrapper.Bone.Name = wrapper.Text; fskl.node.Skeleton.Bones.Add(wrapper.Bone); //Add bones to tree if (wrapper.Parent == null) { fskl.node.Nodes.Add(wrapper); } } fskl.update(); fskl.reset(); fskl.Node_Array = new int[fskl.node.Skeleton.MatrixToBoneList.Count]; int nodes = 0; foreach (ushort node in fskl.node.Skeleton.MatrixToBoneList) { fskl.Node_Array[nodes] = node; nodes++; } }
//Function addes shapes, vertices and meshes public void AddOjects(string FileName, ResFile resFileNX, ResU.ResFile resFileU, bool Replace = true) { int totalSkinCountLimiter = 0; bool IsWiiU = (resFileU != null); if (shapes.Count > 0) { totalSkinCountLimiter = shapes[0].VertexSkinCount; } int MatStartIndex = materials.Count; string ext = System.IO.Path.GetExtension(FileName); ext = ext.ToLower(); switch (ext) { case ".bfobj": Cursor.Current = Cursors.WaitCursor; if (Replace) { shapes.Clear(); Nodes["FshpFolder"].Nodes.Clear(); } if (IsWiiU) { var shpS = new ResU.Shape(); var vertexBufferU = new ResU.VertexBuffer(); shpS.Import(FileName, vertexBufferU, resFileU); FSHP shapeS = new FSHP(); shapeS.ShapeU = shpS; BfresWiiU.ReadShapesVertices(shapeS, shpS, vertexBufferU, this); shapes.Add(shapeS); Nodes["FshpFolder"].Nodes.Add(shapeS); } else { Shape shpS = new Shape(); VertexBuffer vertexBuffer = new VertexBuffer(); shpS.Import(FileName, vertexBuffer); FSHP shapeS = new FSHP(); shapeS.Shape = shpS; BfresSwitch.ReadShapesVertices(shapeS, shpS, vertexBuffer, this); shapes.Add(shapeS); Nodes["FshpFolder"].Nodes.Add(shapeS); } IsEdited = true; Cursor.Current = Cursors.Default; break; case ".bfmdl": Cursor.Current = Cursors.WaitCursor; if (Replace) { shapes.Clear(); Nodes["FshpFolder"].Nodes.Clear(); materials.Clear(); Nodes["FmatFolder"].Nodes.Clear(); } if (IsWiiU) { var mdlU = new ResU.Model(); mdlU.Import(FileName, resFileU); mdlU.Name = Text; BfresWiiU.ReadModel(this, mdlU); } else { Model mdl = new Model(); mdl.Import(FileName, resFileNX); mdl.Name = Text; Console.WriteLine(mdl.ShapeCount); Console.WriteLine(mdl.MaterialCount); Console.WriteLine(mdl.VertexBufferCount); Console.WriteLine(mdl.Skeleton.Bones.Count); BfresSwitch.ReadModel(this, mdl); } IsEdited = true; Cursor.Current = Cursors.Default; break; case ".csv": CsvModel csvModel = new CsvModel(); csvModel.LoadFile(new System.IO.FileStream(FileName, System.IO.FileMode.Open), true); if (csvModel.objects.Count == 0) { MessageBox.Show("No models found!"); return; } BfresModelImportSettings csvsettings = new BfresModelImportSettings(); csvsettings.DisableMaterialEdits(); csvsettings.SkinCountLimit = totalSkinCountLimiter; csvsettings.SetModelAttributes(csvModel.objects[0]); if (csvsettings.ShowDialog() == DialogResult.OK) { if (Replace) { shapes.Clear(); Nodes["FshpFolder"].Nodes.Clear(); } Cursor.Current = Cursors.WaitCursor; foreach (STGenericObject obj in csvModel.objects) { FSHP shape = new FSHP(); Nodes["FshpFolder"].Nodes.Add(shape); shapes.Add(shape); shape.VertexBufferIndex = shapes.Count; shape.vertices = obj.vertices; shape.MaterialIndex = 0; shape.vertexAttributes = csvsettings.CreateNewAttributes(); shape.BoneIndex = 0; shape.Text = obj.ObjectName; shape.lodMeshes = obj.lodMeshes; shape.CreateNewBoundingBoxes(); shape.CreateBoneList(obj, this); shape.CreateIndexList(obj, this); //Todo find better way. Currently uses import settings now shape.ApplyImportSettings(csvsettings, GetMaterial(shape.MaterialIndex)); shape.VertexSkinCount = obj.GetMaxSkinInfluenceCount(); shape.BoneIndices = shape.GetIndices(Skeleton); shape.SaveShape(IsWiiU); shape.SaveVertexBuffer(); if (IsWiiU) { shape.ShapeU.SubMeshBoundingIndices = new List <ushort>(); shape.ShapeU.SubMeshBoundingIndices.Add(0); shape.ShapeU.SubMeshBoundingNodes = new List <ResU.BoundingNode>(); shape.ShapeU.SubMeshBoundingNodes.Add(new ResU.BoundingNode() { LeftChildIndex = 0, NextSibling = 0, SubMeshIndex = 0, RightChildIndex = 0, Unknown = 0, SubMeshCount = 1, }); } if (IsWiiU) { BfresWiiU.ReadShapesVertices(shape, shape.ShapeU, shape.VertexBufferU, this); } else { BfresSwitch.ReadShapesVertices(shape, shape.Shape, shape.VertexBuffer, this); } } Cursor.Current = Cursors.Default; } IsEdited = true; break; default: AssimpData assimp = new AssimpData(); assimp.LoadFile(FileName); if (assimp.objects.Count == 0) { MessageBox.Show("No models found!"); return; } BfresModelImportSettings settings = new BfresModelImportSettings(); settings.SetModelAttributes(assimp.objects[0]); if (settings.ShowDialog() == DialogResult.OK) { bool UseMats = settings.ExternalMaterialPath != string.Empty; if (Replace) { shapes.Clear(); Nodes["FshpFolder"].Nodes.Clear(); } Cursor.Current = Cursors.WaitCursor; if (Replace && UseMats) { materials.Clear(); Nodes["FmatFolder"].Nodes.Clear(); MatStartIndex = 0; } if (UseMats) { foreach (STGenericMaterial mat in assimp.materials) { FMAT fmat = new FMAT(); if (IsWiiU) { fmat.MaterialU = new ResU.Material(); fmat.MaterialU.Import(settings.ExternalMaterialPath, resFileU); BfresWiiU.ReadMaterial(fmat, fmat.MaterialU); } else { fmat.Material = new Material(); fmat.Material.Import(settings.ExternalMaterialPath); fmat.ReadMaterial(fmat.Material); } fmat.Text = mat.Text; //Setup placeholder textures //Note we can't add/remove samplers so we must fill these slots foreach (var t in fmat.TextureMaps) { t.wrapModeS = 0; t.wrapModeT = 0; switch (t.Type) { case STGenericMatTexture.TextureType.Diffuse: t.Name = "Basic_Alb"; break; case STGenericMatTexture.TextureType.Emission: t.Name = "Basic_Emm"; break; case STGenericMatTexture.TextureType.Normal: t.Name = "Basic_Nrm"; break; case STGenericMatTexture.TextureType.Specular: t.Name = "Basic_Spm"; break; case STGenericMatTexture.TextureType.SphereMap: t.Name = "Basic_Sphere"; break; case STGenericMatTexture.TextureType.Metalness: t.Name = "Basic_Mtl"; break; case STGenericMatTexture.TextureType.Roughness: t.Name = "Basic_Rgh"; break; case STGenericMatTexture.TextureType.MRA: t.Name = "Basic_MRA"; break; case STGenericMatTexture.TextureType.Shadow: t.Name = "Basic_Bake_st0"; break; case STGenericMatTexture.TextureType.Light: t.Name = "Basic_Bake_st1"; break; } } if (PluginRuntime.bntxContainers.Count > 0 && Parent != null) { foreach (var node in Parent.Parent.Nodes) { if (node is BNTX) { var bntx = (BNTX)node; bntx.ImportBasicTextures("Basic_Alb"); bntx.ImportBasicTextures("Basic_Nrm"); bntx.ImportBasicTextures("Basic_Spm"); bntx.ImportBasicTextures("Basic_Sphere"); bntx.ImportBasicTextures("Basic_Mtl"); bntx.ImportBasicTextures("Basic_Rgh"); bntx.ImportBasicTextures("Basic_MRA"); bntx.ImportBasicTextures("Basic_Bake_st0"); bntx.ImportBasicTextures("Basic_Bake_st1"); bntx.ImportBasicTextures("Basic_Emm"); } } } if (PluginRuntime.ftexContainers.Count > 0 && Parent != null) { foreach (var node in Parent.Parent.Nodes) { if (node is BFRESGroupNode) { if (((BFRESGroupNode)node).Type == BRESGroupType.Textures) { var ftexCont = (BFRESGroupNode)node; ftexCont.ImportBasicTextures("Basic_Alb"); ftexCont.ImportBasicTextures("Basic_Nrm"); ftexCont.ImportBasicTextures("Basic_Spm"); ftexCont.ImportBasicTextures("Basic_Sphere"); ftexCont.ImportBasicTextures("Basic_Mtl"); ftexCont.ImportBasicTextures("Basic_Rgh"); ftexCont.ImportBasicTextures("Basic_MRA"); ftexCont.ImportBasicTextures("Basic_Bake_st0"); ftexCont.ImportBasicTextures("Basic_Bake_st1"); ftexCont.ImportBasicTextures("Basic_Emm"); } } } } foreach (var tex in mat.TextureMaps) { foreach (var t in fmat.TextureMaps) { if (t.Type == tex.Type) { t.Name = tex.Name; t.wrapModeS = tex.wrapModeS; t.wrapModeT = tex.wrapModeT; t.wrapModeW = tex.wrapModeW; t.Type = tex.Type; } } } List <string> keyList = new List <string>(materials.Keys); fmat.Text = Utils.RenameDuplicateString(keyList, fmat.Text); if (IsWiiU) { fmat.MaterialU.Name = Text; fmat.SetMaterial(fmat.MaterialU, resFileU); } else { fmat.Material.Name = Text; fmat.SetMaterial(fmat.Material); } materials.Add(fmat.Text, fmat); Nodes["FmatFolder"].Nodes.Add(fmat); } } if (settings.ImportBones) { if (assimp.skeleton.bones.Count > 0) { Skeleton.bones.Clear(); Skeleton.node.Nodes.Clear(); if (IsWiiU) { BfresWiiU.SaveSkeleton(Skeleton, assimp.skeleton.bones); } else { BfresSwitch.SaveSkeleton(Skeleton, assimp.skeleton.bones); } } } if (materials.Count <= 0) { //Force material creation if there is none present FMAT fmat = new FMAT(); fmat.Text = "NewMaterial"; materials.Add(fmat.Text, fmat); Nodes["FmatFolder"].Nodes.Add(fmat); if (IsWiiU) { fmat.MaterialU = new ResU.Material(); fmat.MaterialU.Name = "NewMaterial"; BfresWiiU.ReadMaterial(fmat, fmat.MaterialU); } else { fmat.Material = new Material(); fmat.Material.Name = "NewMaterial"; fmat.ReadMaterial(fmat.Material); } } foreach (STGenericObject obj in assimp.objects) { FSHP shape = new FSHP(); Nodes["FshpFolder"].Nodes.Add(shape); shapes.Add(shape); shape.VertexBufferIndex = shapes.Count; shape.vertices = obj.vertices; shape.vertexAttributes = settings.CreateNewAttributes(); shape.BoneIndex = obj.BoneIndex; STConsole.WriteLine(Text + " " + obj.MaterialIndex); if (UseMats) { shape.MaterialIndex = obj.MaterialIndex + MatStartIndex; } else { shape.MaterialIndex = 0; } if (shape.MaterialIndex >= materials.Count) { shape.MaterialIndex = 0; } shape.Text = obj.ObjectName; shape.lodMeshes = obj.lodMeshes; shape.CreateNewBoundingBoxes(); shape.CreateBoneList(obj, this); shape.CreateIndexList(obj, this); shape.ApplyImportSettings(settings, GetMaterial(shape.MaterialIndex)); shape.VertexSkinCount = obj.GetMaxSkinInfluenceCount(); shape.BoneIndices = shape.GetIndices(Skeleton); shape.SaveShape(IsWiiU); shape.SaveVertexBuffer(); if (IsWiiU) { shape.ShapeU.SubMeshBoundingIndices = new List <ushort>(); shape.ShapeU.SubMeshBoundingIndices.Add(0); shape.ShapeU.SubMeshBoundingNodes = new List <ResU.BoundingNode>(); shape.ShapeU.SubMeshBoundingNodes.Add(new ResU.BoundingNode() { LeftChildIndex = 0, NextSibling = 0, SubMeshIndex = 0, RightChildIndex = 0, Unknown = 0, SubMeshCount = 1, }); } List <string> keyList = shapes.Select(o => o.Text).ToList(); shape.Text = Utils.RenameDuplicateString(keyList, shape.Text); if (IsWiiU) { BfresWiiU.ReadShapesVertices(shape, shape.ShapeU, shape.VertexBufferU, this); } else { BfresSwitch.ReadShapesVertices(shape, shape.Shape, shape.VertexBuffer, this); } } IsEdited = true; Cursor.Current = Cursors.Default; } break; } if (IsEdited) { UpdateVertexData(); } }