示例#1
0
        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;
        }
示例#2
0
        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;
        }