public void Load(Stream stream) { Header = new MDL_Parser(stream); foreach (var tex in Header.Textures) { Textures.Add(new Texture(tex) { Name = $"Texture{Textures.Count}" }); } ToGeneric().Skeleton.PreviewScale = 3; }
public void FromGeneric(STGenericScene scene) { var model = scene.Models[0]; bool useTriangeStrips = false; MDL_Parser mdl = new MDL_Parser(); mdl.FileHeader = new MDL_Parser.Header(); mdl.Meshes = new List <MDL_Parser.Mesh>(); List <Node> nodes = new List <Node>(); List <Matrix4> matrices = new List <Matrix4>(); List <Material> materials = new List <Material>(); List <TextureHeader> textures = new List <TextureHeader>(); List <Sampler> samplers = new List <Sampler>(); List <Vector3> positions = new List <Vector3>(); List <Vector3> normals = new List <Vector3>(); List <Vector2> texCoords = new List <Vector2>(); List <Vector4> colors = new List <Vector4>(); List <Shape> shapes = new List <Shape>(); List <ShapePacket> packets = new List <ShapePacket>(); List <DrawElement> elements = new List <DrawElement>(); List <MDL_Parser.Weight> weights = new List <MDL_Parser.Weight>(); model.Textures = model.Textures.OrderBy(x => GetTextureIndex(x.Name)).ToList(); model.OrderBones(model.Skeleton.Bones.OrderBy(x => GetBoneIndex(x.Name)).ToList()); foreach (var texture in model.Textures) { textures.Add(new TextureHeader() { Width = (ushort)texture.Width, Height = (ushort)texture.Height, Format = Decode_Gamecube.TextureFormats.CMPR, ImageData = Decode_Gamecube.EncodeFromBitmap(texture.GetBitmap(), Decode_Gamecube.TextureFormats.CMPR).Item1, }); } //If sampler list isn't replaced in json, force a new one if (Header.Samplers.Length == 0) { //Create samplers to map textures to materials foreach (var texture in model.Textures) { samplers.Add(new Sampler() { WrapModeU = 2, WrapModeV = 2, MagFilter = 0, MinFilter = 0, TextureIndex = (ushort)model.Textures.IndexOf(texture), }); } } else { samplers = Header.Samplers.ToList(); } //Create a root node if no bones are present if (model.Skeleton.Bones.Count == 0) { nodes.Add(new Node() { ChildIndex = 1, SiblingIndex = 0, ShapeCount = (ushort)model.Meshes.Count, ShapeIndex = 0, }); } //Create a node graph from a skeleton foreach (var bone in model.Skeleton.Bones.Where(x => x.ParentIndex == -1)) { CreateNodeGraph(nodes, bone); } //Set node transforms model.Skeleton.Reset(); foreach (var bone in model.Skeleton.Bones) { Matrix4 transform = bone.Transform; transform.Transpose(); transform.Invert(); matrices.Add(transform); } ushort shapeIndex = 0; //Adjust the node indices for (int i = 0; i < nodes.Count; i++) { nodes[i].NodeIndex = (ushort)i; if (i == 0) { //Store the total amount of drawn elements in nodes nodes[i].ShapeCount = (ushort)model.Meshes.Count; shapeIndex += (ushort)model.Meshes.Count; } foreach (var mesh in model.Meshes) { for (int v = 0; v < mesh.Vertices.Count; v++) { if (mesh.Vertices[v].BoneIndices.Contains(i)) { nodes[i].ShapeIndex = shapeIndex; } } } } List <STGenericMaterial> genericMats = model.GetMaterials(); genericMats = genericMats.OrderBy(x => GetMaterialIndex(x.Name)).ToList(); //Create a new material and assign the first tev stage mapped textures foreach (var material in genericMats) { var mat = new Material(); if (material.TextureMaps.Count > 0) { string name = material.TextureMaps[0].Name; int index = model.Textures.FindIndex(x => x.Name == name); int samplerIndex = samplers.FindIndex(x => x.TextureIndex == index); if (samplerIndex != -1) { mat.TevStages[0].Unknown = (ushort)0; mat.TevStages[0].SamplerIndex = (ushort)samplerIndex; } } materials.Add(mat); } if (genericMats.Count == 0) { var mat = new Material(); materials.Add(mat); } //Create shapes and draw elements int packetIndex = 0; mdl.FileHeader.FaceCount = 0; foreach (var mesh in model.Meshes) { int materialIndex = 0; if (mesh.PolygonGroups[0].Material != null) { materialIndex = genericMats.IndexOf(mesh.PolygonGroups[0].Material); } List <ushort> boneIndices = new List <ushort>(); //Create packets to store our vertex data //Packets will split based on joint indices //A single packet can hold up to 10 indices //There will be either rigid indices (directly rigs to joints) //Or smooth indices (rigs to weight table. Indexes higher than joint count) List <ShapePacket> shapePackets = new List <ShapePacket>(); ShapePacket packet = new ShapePacket(); shapePackets.Add(packet); int vindex = 0; mdl.FileHeader.FaceCount += (ushort)(mesh.PolygonGroups.Sum(x => x.Faces.Count) / 3); var group = mesh.PolygonGroups[0]; for (int v = 0; v < group.Faces.Count; v += 3) { //Check the current triangle and find the max amount of indices currently in use. int maxBoneIndices = boneIndices.Count; for (int i = 0; i < 3; i++) { var vertex = mesh.Vertices[(int)group.Faces[v + (2 - i)]]; for (int j = 0; j < vertex.BoneIndices.Count; j++) { int index = vertex.BoneIndices[j]; if (!boneIndices.Contains((ushort)index) || vertex.BoneIndices.Count > 1) { maxBoneIndices++; } } } //Reset the bone indices depending on how many are used currently if (maxBoneIndices > 9) { //Create a new packet to store additional indices boneIndices = new List <ushort>(); packet = new ShapePacket(); shapePackets.Add(packet); } ShapePacket.DrawList drawList = new ShapePacket.DrawList(); drawList.OpCode = (byte)GXOpCodes.DRAW_TRIANGLES; packet.DrawLists.Add(drawList); for (int i = 0; i < 3; i++) { ShapePacket.VertexGroup vertexGroup = new ShapePacket.VertexGroup(); drawList.Vertices.Add(vertexGroup); var vertex = mesh.Vertices[(int)group.Faces[v + (2 - i)]]; //Round the values Vector3 pos = vertex.Position; Vector3 nrm = vertex.Normal; if (vertex.TexCoords.Length > 0) { if (!texCoords.Contains(vertex.TexCoords[0])) { texCoords.Add(vertex.TexCoords[0]); } vertexGroup.TexCoordIndex = (short)texCoords.IndexOf(vertex.TexCoords[0]); } //Note the bone indices list will store the real index //The vertex data will just index the bone indices list instead if (vertex.BoneIndices.Count == 1) { ushort index = (ushort)vertex.BoneIndices[0]; if (!boneIndices.Contains(index)) { boneIndices.Add(index); } //Index our rigid skinning index from the index list of the current packet vertexGroup.MatrixIndex = (sbyte)(boneIndices.IndexOf(index) * 3); vertexGroup.Tex0MatrixIndex = (sbyte)(boneIndices.IndexOf(index) * 3); vertexGroup.Tex1MatrixIndex = (sbyte)(boneIndices.IndexOf(index) * 3); //Rigid indices require vertices to be inversed by the matrix var matrix = matrices[index]; matrix.Transpose(); pos = Vector3.TransformPosition(pos, matrix); nrm = Vector3.TransformNormal(nrm, matrix); } else if (vertex.BoneIndices.Count > 1) { vertex.SortBoneIndices(); //Create a weight entry used to index our weight table var weightEntry = new MDL_Parser.Weight(); for (int j = 0; j < vertex.BoneWeights.Count; j++) { weightEntry.Weights.Add(vertex.BoneWeights[j]); } for (int j = 0; j < vertex.BoneIndices.Count; j++) { weightEntry.JointIndices.Add(vertex.BoneIndices[j]); } MDL_Parser.Weight existingWeight = null; for (int w = 0; w < weights.Count; w++) { int matchedWeights = 0; for (int j = 0; j < vertex.BoneIndices.Count; j++) { int jointIndex = weights[w].JointIndices.IndexOf(vertex.BoneIndices[j]); if (jointIndex == -1) { continue; } if (weights[w].Weights[jointIndex] == vertex.BoneWeights[j]) { matchedWeights++; } } if (matchedWeights == vertex.BoneIndices.Count) { existingWeight = weights[w]; } } //Find an existing weight table entry that matches if (existingWeight == null) { existingWeight = weightEntry; weights.Add(existingWeight); } //Index our weight table entry //These indices shift by rigid index ushort rigidIndex = (ushort)nodes.Count; ushort index = (ushort)(weights.IndexOf(existingWeight) + rigidIndex); if (!boneIndices.Contains(index)) { boneIndices.Add(index); } //Index our smooth skinning index from the index list of the current packet vertexGroup.MatrixIndex = (sbyte)(boneIndices.IndexOf(index) * 3); vertexGroup.Tex0MatrixIndex = (sbyte)(boneIndices.IndexOf(index) * 3); vertexGroup.Tex1MatrixIndex = (sbyte)(boneIndices.IndexOf(index) * 3); } else if (vertex.BoneIndices.Count == 0) { if (!boneIndices.Contains(0)) { boneIndices.Add(0); } vertexGroup.MatrixIndex = 0; vertexGroup.Tex0MatrixIndex = 0; vertexGroup.Tex1MatrixIndex = 0; } if (!positions.Contains(pos)) { positions.Add(pos); } if (!normals.Contains(nrm)) { normals.Add(nrm); } vertexGroup.PositionIndex = (short)positions.IndexOf(pos); vertexGroup.NormalIndex = (short)normals.IndexOf(nrm); //Update the matrix indices for (int j = 0; j < boneIndices.Count; j++) { packet.MatrixIndices[j] = boneIndices[j]; } packet.MatrixIndicesCount = (ushort)boneIndices.Count; vindex++; } } elements.Add(new DrawElement() { ShapeIndex = (ushort)shapes.Count, MaterialIndex = (ushort)materialIndex, }); shapes.Add(new Shape() { PacketBeginIndex = (ushort)packetIndex, PacketCount = (ushort)shapePackets.Count, }); packetIndex += shapePackets.Count; packets.AddRange(shapePackets); } foreach (var packet in packets) { packet.Data = packet.CreateDrawList(packet.DrawLists, false, normals.Count > 0, texCoords.Count > 0, colors.Count > 0); packet.DataSize = (uint)packet.Data.Length; } var lodPackets = new List <ShapePacket>(); foreach (var packet in packets) { var lodPacket = new ShapePacket(); lodPacket.MatrixIndices = packet.MatrixIndices; lodPacket.MatrixIndicesCount = packet.MatrixIndicesCount; lodPacket.Data = packet.CreateDrawList(packet.DrawLists, true, normals.Count > 0, texCoords.Count > 0, colors.Count > 0); lodPacket.DataSize = (uint)lodPacket.Data.Length; lodPackets.Add(lodPacket); } packets.AddRange(lodPackets); mdl.Matrix4Table = new Matrix4[matrices.Count]; for (int i = 0; i < matrices.Count; i++) { mdl.Matrix4Table[i] = matrices[i]; } mdl.Materials = materials.ToArray(); mdl.Nodes = nodes.ToArray(); mdl.Samplers = samplers.ToArray(); mdl.Colors = colors.ToArray(); mdl.Positions = positions.ToArray(); mdl.TexCoords = texCoords.ToArray(); mdl.Normals = normals.ToArray(); mdl.DrawElements = elements.ToArray(); mdl.Shapes = shapes.ToArray(); mdl.ShapePackets = packets.ToArray(); mdl.Weights = weights.ToArray(); mdl.Textures = textures.ToArray(); mdl.LODPositions = new Vector3[0]; mdl.LODNormals = new Vector3[0]; Header = mdl; }