Example #1
0
        private STVertex ToVertex(ShapePacket.VertexGroup drawList, ref Matrix4 transform)
        {
            Vector3 position = Header.Positions[drawList.PositionIndex];
            Vector3 normal   = new Vector3();
            Vector2 texCoord = new Vector2();
            Vector4 color    = Vector4.One;

            List <int>   boneIndices = new List <int>();
            List <float> boneWeights = new List <float>();

            if (drawList.NormalIndex != -1)
            {
                normal = Header.Normals[drawList.NormalIndex];
            }
            if (drawList.TexCoordIndex != -1)
            {
                texCoord = Header.TexCoords[drawList.TexCoordIndex];
            }
            if (drawList.ColorIndex != -1)
            {
                color = Header.Colors[drawList.ColorIndex];
            }

            //Rigid matrices start first, 0 - joint count
            //Skinned ones are after and will index the weight table instead of directly rigging to a matrix
            if (drawList.MatrixDataIndex >= Header.FileHeader.JointCount)
            {
                var weightIndex = drawList.MatrixDataIndex - Header.FileHeader.JointCount;

                var weights = Header.Weights[weightIndex];
                for (int i = 0; i < weights.JointIndices.Count; i++)
                {
                    boneIndices.Add(weights.JointIndices[i]);
                    boneWeights.Add(weights.Weights[i]);
                }
            }  //If the matrix is rigid and used then bind it directly to the joint with a weight of 1
            else if (drawList.MatrixIndex != -1)
            {
                boneIndices.Add(drawList.MatrixDataIndex);
                boneWeights.Add(1);
            }

            position = Vector3.TransformPosition(position, transform);
            normal   = Vector3.TransformNormal(normal, transform);

            return(new STVertex()
            {
                Position = position,
                Normal = normal,
                BoneIndices = boneIndices,
                BoneWeights = boneWeights,
                TexCoords = new Vector2[1] {
                    texCoord
                },
                Colors = new Vector4[1] {
                    color
                },
            });
        }
Example #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;
        }
        private List <ShapePacket> ParsePackets(Mesh mesh, int startLODIndex, FileReader reader, DrawElement element)
        {
            List <ShapePacket> drawpackets = new List <ShapePacket>();

            ushort[] matrixIndices = new ushort[10];
            int      startIndex    = startLODIndex + mesh.Shape.PacketBeginIndex;

            for (int i = startIndex; i < startIndex + mesh.Shape.PacketCount; i++)
            {
                var packet = ShapePackets[i];
                drawpackets.Add(packet);

                bool isLOD = startLODIndex > 0;

                for (int m = 0; m < packet.MatrixIndicesCount; m++)
                {
                    if (packet.MatrixIndices[m] == ushort.MaxValue)
                    {
                        continue;
                    }
                    matrixIndices[m] = packet.MatrixIndices[m];
                }

                reader.SeekBegin(packet.DataOffset);
                while (reader.BaseStream.Position < packet.DataOffset + packet.DataSize)
                {
                    byte opcode = reader.ReadByte();
                    if (opcode == 0)
                    {
                        continue;
                    }

                    ShapePacket.DrawList drawPacket = new ShapePacket.DrawList();
                    drawPacket.OpCode = opcode;
                    packet.DrawLists.Add(drawPacket);

                    ushort numVertices = reader.ReadUInt16();
                    drawPacket.Vertices = new List <ShapePacket.VertexGroup>();

                    for (int v = 0; v < numVertices; v++)
                    {
                        var drawList = new ShapePacket.VertexGroup();
                        if (!isLOD)
                        {
                            drawList.MatrixIndex = reader.ReadSByte();
                            if (drawList.MatrixIndex != -1)
                            {
                                drawList.MatrixDataIndex = matrixIndices[(drawList.MatrixIndex / 3)];
                            }

                            drawList.Tex0MatrixIndex = reader.ReadSByte();
                            drawList.Tex1MatrixIndex = reader.ReadSByte();
                            drawList.PositionIndex   = reader.ReadInt16();

                            if (FileHeader.NormalCount > 0)
                            {
                                drawList.NormalIndex = reader.ReadInt16();
                            }
                            if (mesh.Shape.NormalFlags > 1) //NBT
                            {
                                drawList.TangentIndex  = reader.ReadInt16();
                                drawList.BinormalIndex = reader.ReadInt16();
                            }

                            if (FileHeader.ColorCount > 0)
                            {
                                drawList.ColorIndex = reader.ReadInt16();
                            }
                            if (FileHeader.TexcoordCount > 0)
                            {
                                drawList.TexCoordIndex = reader.ReadInt16();
                            }
                        }
                        else
                        {
                            drawList.MatrixIndex = reader.ReadSByte();
                            if (drawList.MatrixIndex != -1)
                            {
                                drawList.MatrixDataIndex = matrixIndices[(drawList.MatrixIndex / 3)];
                            }

                            drawList.PositionIndex = reader.ReadInt16();
                            if (FileHeader.NormalCount > 0)
                            {
                                drawList.NormalIndex = reader.ReadByte();
                            }
                        }

                        drawPacket.Vertices.Add(drawList);
                    }
                }
            }
            return(drawpackets);
        }