using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using SELib; using Switch_Toolbox.Library.Rendering; using OpenTK; namespace Switch_Toolbox.Library { public class SEModel { public List objects = new List(); public List materials = new List(); public STSkeleton skeleton; public static void Save(string FileName, List Meshes, List Materials, List bones) { SELib.SEModel seModel = new SELib.SEModel(); for (int i = 0; i < Meshes.Count; i++) seModel.AddMesh(SaveMesh(Meshes[i])); for (int i = 0; i < Materials.Count; i++) seModel.AddMaterial(SaveMaterial(Materials[i])); // for (int i = 0; i < bones.Count; i++) // seModel.AddBone(SaveBone(bones[i])); } private static SELib.SEModelMesh SaveMesh(STGenericObject mesh) { var seMesh = new SELib.SEModelMesh(); var MeshLevel = mesh.lodMeshes[mesh.DisplayLODIndex]; for (int i = 0; i < MeshLevel.faces.Count; i++) { seMesh.AddFace((uint)MeshLevel.faces[i], (uint)MeshLevel.faces[i++], (uint)MeshLevel.faces[i++]); } return seMesh; } private static SELib.SEModelMaterial SaveMaterial(STGenericMaterial material) { var seMaterial = new SELib.SEModelMaterial(); return seMaterial; } private static SELib.SEModelBone SaveBone(STBone bone) { var seBone = new SELib.SEModelBone(); return seBone; } public void CreateGenericModel(string FileName) { skeleton = new STSkeleton(); var seModel = SELib.SEModel.Read(FileName); for (int i = 0; i < seModel.MeshCount; i++) objects.Add(CreateGenericObject(seModel, seModel.Meshes[i])); for (int i = 0; i < seModel.MaterialCount; i++) materials.Add(CreateGenericMaterial(seModel, seModel.Materials[i])); for (int i = 0; i < seModel.BoneCount; i++) skeleton.bones.Add(CreateGenericBone(seModel, seModel.Bones[i])); } public STBone CreateGenericBone(SELib.SEModel seModel, SELib.SEModelBone seBone) { STBone bone = new STBone(skeleton); bone.Text = seBone.BoneName; bone.parentIndex = seBone.BoneParent; bone.RotationType = STBone.BoneRotationType.Euler; Vector3 rotEular = ToEular(seBone.LocalRotation); bone.position = new float[] { (float)seBone.LocalPosition.X, (float)seBone.LocalPosition.Y, (float)seBone.LocalPosition.Z }; bone.scale = new float[] { (float)seBone.Scale.X, (float)seBone.Scale.Y, (float)seBone.Scale.Z }; bone.rotation = new float[] { rotEular.X, rotEular.Y, rotEular.Z, 0 }; return bone; } public STGenericMaterial CreateGenericMaterial(SELib.SEModel seModel, SELib.SEModelMaterial seMaterial) { STGenericMaterial material = new STGenericMaterial(); material.Text = seMaterial.Name; if (seMaterial.MaterialData is SEModelSimpleMaterial) { if (((SEModelSimpleMaterial)seMaterial.MaterialData).DiffuseMap != string.Empty) { string TextureName = ((SEModelSimpleMaterial)seMaterial.MaterialData).DiffuseMap; material.TextureMaps.Add(new STGenericMatTexture() { Name = TextureName, Type = STGenericMatTexture.TextureType.Diffuse }); } if (((SEModelSimpleMaterial)seMaterial.MaterialData).NormalMap != string.Empty) { string TextureName = ((SEModelSimpleMaterial)seMaterial.MaterialData).NormalMap; material.TextureMaps.Add(new STGenericMatTexture() { Name = TextureName, Type = STGenericMatTexture.TextureType.Normal }); } if (((SEModelSimpleMaterial)seMaterial.MaterialData).SpecularMap != string.Empty) { string TextureName = ((SEModelSimpleMaterial)seMaterial.MaterialData).SpecularMap; material.TextureMaps.Add(new STGenericMatTexture() { Name = TextureName, Type = STGenericMatTexture.TextureType.Specular }); } } return material; } public STGenericObject CreateGenericObject(SELib.SEModel seModel, SELib.SEModelMesh seMesh) { int Index = seModel.Meshes.IndexOf(seMesh); STGenericObject mesh = new STGenericObject(); mesh.ObjectName = $"Mesh_{Index}"; if (seMesh.MaterialReferenceIndicies.Count > 0) mesh.MaterialIndex = seMesh.MaterialReferenceIndicies[0]; mesh.HasPos = true; for (int v = 0; v < seMesh.VertexCount; v++) { if (seMesh.Verticies[v].UVSets.Count > 0) mesh.HasUv0 = true; if (seMesh.Verticies[v].Weights.Count > 0) { mesh.HasIndices = true; for (int w = 0; w < seMesh.Verticies[v].WeightCount; w++) { if (seMesh.Verticies[v].Weights[w].BoneWeight != 0) mesh.HasWeights = true; } } if (seMesh.Verticies[v].VertexColor != SELib.Utilities.Color.White) mesh.HasVertColors = true; if (seMesh.Verticies[v].VertexNormal != SELib.Utilities.Vector3.Zero) mesh.HasNrm = true; Vertex vertex = new Vertex(); mesh.vertices.Add(vertex); vertex.pos = ToTKVector3(seMesh.Verticies[v].Position); vertex.nrm = ToTKVector3(seMesh.Verticies[v].VertexNormal); vertex.col = ToTKVector4(seMesh.Verticies[v].VertexColor); for (int u = 0; u < seMesh.Verticies[v].UVSetCount; u++) { if (u == 0) vertex.uv0 = ToTKVector2(seMesh.Verticies[v].UVSets[u]); if (u == 1) vertex.uv1 = ToTKVector2(seMesh.Verticies[v].UVSets[u]); if (u == 2) vertex.uv2 = ToTKVector2(seMesh.Verticies[v].UVSets[u]); } for (int w = 0; w < seMesh.Verticies[v].WeightCount; w++) { //Get the bone name from the index. Indices for formats get set after the importer string BoneName = seModel.Bones[(int)seMesh.Verticies[v].Weights[w].BoneIndex].BoneName; float BoneWeight = seMesh.Verticies[v].Weights[w].BoneWeight; vertex.boneNames.Add(BoneName); vertex.boneWeights.Add(BoneWeight); } } mesh.lodMeshes = new List(); var lodMesh = new STGenericObject.LOD_Mesh(); lodMesh.PrimitiveType = STPolygonType.Triangle; mesh.lodMeshes.Add(lodMesh); for (int f = 0; f < seMesh.FaceCount; f++) { lodMesh.faces.Add((int)seMesh.Faces[f].FaceIndex1); lodMesh.faces.Add((int)seMesh.Faces[f].FaceIndex2); lodMesh.faces.Add((int)seMesh.Faces[f].FaceIndex3); } return mesh; } private Vector2 ToTKVector2(SELib.Utilities.Vector2 value) { return new Vector2((float)value.X, (float)value.Y); } private Vector3 ToTKVector3(SELib.Utilities.Vector3 value) { return new Vector3((float)value.X, (float)value.Y, (float)value.Z); } private Vector4 ToTKVector4(SELib.Utilities.Color value) { return new Vector4((float)(value.R / 255), (float)(value.G / 255), (float)(value.B / 255), (float)(value.A / 255)); } private static Vector3 ToEular(SELib.Utilities.Quaternion selibQuat) { OpenTK.Quaternion q = new Quaternion((float)selibQuat.X, (float)selibQuat.Y, (float)selibQuat.Z, (float)selibQuat.W); Matrix4 mat = Matrix4.CreateFromQuaternion(q); float x, y, z; y = (float)Math.Asin(Clamp(mat.M13, -1, 1)); if (Math.Abs(mat.M13) < 0.99999) { x = (float)Math.Atan2(-mat.M23, mat.M33); z = (float)Math.Atan2(-mat.M12, mat.M11); } else { x = (float)Math.Atan2(mat.M32, mat.M22); z = 0; } return new Vector3(x, y, z) * -1; } private static float Clamp(float v, float min, float max) { if (v < min) return min; if (v > max) return max; return v; } } }