Example #1
0
        public static void WriteMeshData(Stream stream, Pmo pmo)
        {
            bool hasSwappedToSecondModel = false;

            // Write Mesh Data.
            for (int j = 0; j < pmo.Meshes.Count; j++)
            {
                if (!hasSwappedToSecondModel && pmo.Meshes[j].MeshNumber == 1 && pmo.header.MeshOffset0 != 0)
                {
                    hasSwappedToSecondModel = true;

                    for (uint b = 0; b < 0xC; b++)
                    {
                        stream.Write((byte)0x00);
                    }

                    for (uint b = 0; stream.Position % 0x10 != 0; b++)
                    {
                        stream.Write((byte)0x00);
                    }
                }

                MeshChunks chunk = pmo.Meshes[j];

                Mapping.WriteObject <Pmo.MeshSection>(stream, chunk.SectionInfo);
                if (chunk.SectionInfo_opt1 != null)
                {
                    Mapping.WriteObject <Pmo.MeshSectionOptional1>(stream, chunk.SectionInfo_opt1);
                }
                if (chunk.SectionInfo_opt2 != null)
                {
                    Mapping.WriteObject <Pmo.MeshSectionOptional2>(stream, chunk.SectionInfo_opt2);
                }

                if (chunk.TriangleStripValues.Length > 0)
                {
                    for (int z = 0; z < chunk.TriangleStripValues.Length; z++)
                    {
                        stream.Write((ushort)chunk.TriangleStripValues[z]);
                    }
                }

                for (int k = 0; k < pmo.Meshes[j].SectionInfo.VertexCount; k++)
                {
                    long vertexStartPos       = stream.Position;
                    int  vertexIncreaseAmount = 0;

                    VertexFlags flags = Pmo.GetFlags(chunk.SectionInfo);

                    // Write Joints.
                    if (flags.WeightFormat != CoordinateFormat.NO_VERTEX)
                    {
                        for (int w = 0; w < flags.SkinningWeightsCount + 1; w++)
                        {
                            int currentIndex = w + (k * (flags.SkinningWeightsCount + 1));

                            switch (flags.WeightFormat)
                            {
                            case CoordinateFormat.NORMALIZED_8_BITS:
                                stream.Write((byte)(chunk.jointWeights[k].weights[currentIndex] * 127.0f));
                                break;

                            case CoordinateFormat.NORMALIZED_16_BITS:
                                stream.Write((byte)(chunk.jointWeights[k].weights[currentIndex] * 32767.0f));
                                break;

                            case CoordinateFormat.FLOAT_32_BITS:
                                StreamExtensions.Write(stream, chunk.jointWeights[k].weights[currentIndex]);
                                break;
                            }
                        }
                    }

                    // Write Texture Coords.
                    switch (flags.TextureCoordinateFormat)
                    {
                    case CoordinateFormat.NORMALIZED_8_BITS:
                        stream.Write((byte)(chunk.textureCoordinates[k].X * 128.0f));
                        stream.Write((byte)(chunk.textureCoordinates[k].Y * 128.0f));
                        break;

                    case CoordinateFormat.NORMALIZED_16_BITS:
                        vertexIncreaseAmount = ((0x2 - (Convert.ToInt32(stream.Position - vertexStartPos) & 0x1)) & 0x1);
                        for (int a = 0; a < vertexIncreaseAmount; a++)
                        {
                            stream.Write((byte)0xAB);
                        }

                        stream.Write((ushort)(chunk.textureCoordinates[k].X * 32768.0f));
                        stream.Write((ushort)(chunk.textureCoordinates[k].Y * 32768.0f));
                        break;

                    case CoordinateFormat.FLOAT_32_BITS:
                        vertexIncreaseAmount = ((0x4 - (Convert.ToInt32(stream.Position - vertexStartPos) & 0x3)) & 0x3);
                        for (int a = 0; a < vertexIncreaseAmount; a++)
                        {
                            stream.Write((byte)0xAB);
                        }

                        StreamExtensions.Write(stream, chunk.textureCoordinates[k].X);
                        StreamExtensions.Write(stream, chunk.textureCoordinates[k].Y);
                        break;
                    }

                    // Write colors.
                    switch (flags.ColorFormat)
                    {
                    case Pmo.ColorFormat.NO_COLOR:
                        break;

                    case Pmo.ColorFormat.BGR_5650_16BITS:
                        break;

                    case Pmo.ColorFormat.ABGR_5551_16BITS:
                        break;

                    case Pmo.ColorFormat.ABGR_4444_16BITS:
                        break;

                    case Pmo.ColorFormat.ABGR_8888_32BITS:
                        vertexIncreaseAmount = ((0x4 - (Convert.ToInt32(stream.Position - vertexStartPos) & 0x3)) & 0x3);
                        for (int a = 0; a < vertexIncreaseAmount; a++)
                        {
                            stream.Write((byte)0xAB);
                        }

                        stream.Write((byte)(chunk.colors[k].X));
                        stream.Write((byte)(chunk.colors[k].Y));
                        stream.Write((byte)(chunk.colors[k].Z));
                        stream.Write((byte)(chunk.colors[k].W));
                        break;
                    }

                    // Write vertices.
                    switch (flags.PositionFormat)
                    {
                    case CoordinateFormat.NORMALIZED_8_BITS:
                        StreamExtensions.Write(stream, (sbyte)(chunk.vertices[k].X * 128.0f));
                        StreamExtensions.Write(stream, (sbyte)(chunk.vertices[k].Y * 128.0f));
                        StreamExtensions.Write(stream, (sbyte)(chunk.vertices[k].Z * 128.0f));
                        break;

                    case CoordinateFormat.NORMALIZED_16_BITS:
                        vertexIncreaseAmount = ((0x2 - (Convert.ToInt32(stream.Position - vertexStartPos) & 0x1)) & 0x1);
                        for (int a = 0; a < vertexIncreaseAmount; a++)
                        {
                            stream.Write((byte)0xAB);
                        }

                        StreamExtensions.Write(stream, (short)(chunk.vertices[k].X * 32768.0f));
                        StreamExtensions.Write(stream, (short)(chunk.vertices[k].Y * 32768.0f));
                        StreamExtensions.Write(stream, (short)(chunk.vertices[k].Z * 32768.0f));
                        break;

                    case CoordinateFormat.FLOAT_32_BITS:
                        vertexIncreaseAmount = ((0x4 - (Convert.ToInt32(stream.Position - vertexStartPos) & 0x3)) & 0x3);
                        for (int a = 0; a < vertexIncreaseAmount; a++)
                        {
                            stream.Write((byte)0xAB);
                        }

                        StreamExtensions.Write(stream, chunk.vertices[k].X);
                        StreamExtensions.Write(stream, chunk.vertices[k].Y);
                        StreamExtensions.Write(stream, chunk.vertices[k].Z);
                        break;
                    }

                    int padding = ((int)vertexStartPos + chunk.SectionInfo.VertexSize) - (int)stream.Position;
                    for (int p = 0; p < padding; p++)
                    {
                        stream.Write((byte)0xAB);
                    }
                }

                // Remainder.
                uint remainder = (uint)stream.Position % 4;
                for (int p = 0; p < remainder; p++)
                {
                    stream.Write((byte)0x00);
                }

                if (j == (pmo.Meshes.Count - 1))
                {
                    for (uint b = 0; b < 0xC; b++)
                    {
                        try
                        {
                            stream.Write((byte)0x00);
                        }
                        catch (Exception ex)
                        {
                            ex.ToString();
                        }
                    }


                    int pd = (int)stream.Position % 0x10;

                    for (int n = 0; pd != 0; n++)
                    {
                        try
                        {
                            stream.Write((byte)0x00);
                        }
                        catch (Exception ex)
                        {
                            ex.ToString();
                        }

                        pd = (int)stream.Position % 0x10;
                    }
                }
            }
        }
Example #2
0
        public static void ReadMeshData(Stream stream, Pmo pmo, int MeshNumber = 0)
        {
            // Go to mesh position.
            if (MeshNumber == 0)
            {
                stream.Seek(pmo.PMO_StartPosition + pmo.header.MeshOffset0, SeekOrigin.Begin);
            }
            else
            {
                stream.Seek(pmo.PMO_StartPosition + pmo.header.MeshOffset1, SeekOrigin.Begin);
            }

            UInt16 VertCnt = 0xFFFF;

            while (VertCnt > 0)
            {
                MeshChunks meshChunk = new MeshChunks();
                meshChunk.MeshNumber = MeshNumber;

                meshChunk.SectionInfo = Mapping.ReadObject <MeshSection>(stream);

                // Exit if Vertex Count is zero.
                if (meshChunk.SectionInfo.VertexCount <= 0)
                {
                    break;
                }

                meshChunk.TextureID = meshChunk.SectionInfo.TextureID;
                VertexFlags flags = GetFlags(meshChunk.SectionInfo);

                bool isColorFlagRisen = flags.UniformDiffuseFlag;

                if (pmo.header.SkeletonOffset != 0)
                {
                    meshChunk.SectionInfo_opt1 = Mapping.ReadObject <MeshSectionOptional1>(stream);
                }
                if (isColorFlagRisen)
                {
                    meshChunk.SectionInfo_opt2 = Mapping.ReadObject <MeshSectionOptional2>(stream);
                }
                if (meshChunk.SectionInfo.TriangleStripCount > 0)
                {
                    meshChunk.TriangleStripValues = new UInt16[meshChunk.SectionInfo.TriangleStripCount];
                    for (int i = 0; i < meshChunk.SectionInfo.TriangleStripCount; i++)
                    {
                        meshChunk.TriangleStripValues[i] = stream.ReadUInt16();
                    }
                }

                // Get Formats.
                CoordinateFormat TexCoordFormat       = flags.TextureCoordinateFormat;
                CoordinateFormat VertexPositionFormat = flags.PositionFormat;
                CoordinateFormat WeightFormat         = flags.WeightFormat;
                ColorFormat      ColorFormat          = flags.ColorFormat;
                UInt32           SkinningWeightsCount = flags.SkinningWeightsCount;
                BinaryReader     r = new BinaryReader(stream);
                long             positionAfterHeader = stream.Position;

                if (meshChunk.SectionInfo.TriangleStripCount > 0)
                {
                    int vertInd = 0;
                    for (int p = 0; p < meshChunk.SectionInfo.TriangleStripCount; p++)
                    {
                        for (int s = 0; s < (meshChunk.TriangleStripValues[p] - 2); s++)
                        {
                            if (s % 2 == 0)
                            {
                                meshChunk.Indices.Add(vertInd + s + 0);
                                meshChunk.Indices.Add(vertInd + s + 1);
                                meshChunk.Indices.Add(vertInd + s + 2);
                            }
                            else
                            {
                                meshChunk.Indices.Add(vertInd + s + 0);
                                meshChunk.Indices.Add(vertInd + s + 2);
                                meshChunk.Indices.Add(vertInd + s + 1);
                            }
                        }

                        vertInd += meshChunk.TriangleStripValues[p];
                    }
                }
                else
                {
                    if (flags.Primitive == PrimitiveType.PRIMITIVE_TRIANGLE_STRIP)
                    {
                        for (int s = 0; s < (meshChunk.SectionInfo.VertexCount - 2); s++)
                        {
                            if (s % 2 == 0)
                            {
                                meshChunk.Indices.Add(s + 0);
                                meshChunk.Indices.Add(s + 1);
                                meshChunk.Indices.Add(s + 2);
                            }
                            else
                            {
                                meshChunk.Indices.Add(s + 1);
                                meshChunk.Indices.Add(s + 0);
                                meshChunk.Indices.Add(s + 2);
                            }
                        }
                    }
                }

                for (int v = 0; v < meshChunk.SectionInfo.VertexCount; v++)
                {
                    long vertexStartPos       = stream.Position;
                    int  vertexIncreaseAmount = 0;

                    // Vertex Weights.
                    if (pmo.header.SkeletonOffset != 0 && WeightFormat != CoordinateFormat.NO_VERTEX)
                    {
                        WeightData WeightList = new WeightData();
                        WeightList.weights      = new List <float>();
                        WeightList.coordFormart = WeightFormat;

                        for (int i = 0; i < (SkinningWeightsCount + 1); i++)
                        {
                            switch (WeightFormat)
                            {
                            case CoordinateFormat.NORMALIZED_8_BITS:
                                WeightList.weights.Add(stream.ReadByte() / 128.0f);
                                break;

                            case CoordinateFormat.NORMALIZED_16_BITS:
                                WeightList.weights.Add(stream.ReadUInt16() / 32768.0f);
                                break;

                            case CoordinateFormat.FLOAT_32_BITS:
                                WeightList.weights.Add(stream.ReadFloat());
                                break;

                            case CoordinateFormat.NO_VERTEX:
                                break;
                            }
                        }

                        meshChunk.jointWeights.Add(WeightList);
                    }

                    Vector2 currentTexCoord = new Vector2(0, 0);

                    switch (TexCoordFormat)
                    {
                    case CoordinateFormat.NORMALIZED_8_BITS:
                        currentTexCoord.X = stream.ReadByte() / 128.0f;
                        currentTexCoord.Y = stream.ReadByte() / 128.0f;
                        meshChunk.textureCoordinates.Add(currentTexCoord);
                        break;

                    case CoordinateFormat.NORMALIZED_16_BITS:
                        vertexIncreaseAmount = ((0x2 - (Convert.ToInt32(stream.Position - vertexStartPos) & 0x1)) & 0x1);
                        stream.Seek(vertexIncreaseAmount, SeekOrigin.Current);

                        currentTexCoord.X = stream.ReadUInt16() / 32768.0f;
                        currentTexCoord.Y = stream.ReadUInt16() / 32768.0f;
                        meshChunk.textureCoordinates.Add(currentTexCoord);
                        break;

                    case CoordinateFormat.FLOAT_32_BITS:
                        vertexIncreaseAmount = ((0x4 - (Convert.ToInt32(stream.Position - vertexStartPos) & 0x3)) & 0x3);
                        stream.Seek(vertexIncreaseAmount, SeekOrigin.Current);

                        currentTexCoord.X = stream.ReadFloat();
                        currentTexCoord.Y = stream.ReadFloat();
                        meshChunk.textureCoordinates.Add(currentTexCoord);
                        break;

                    case CoordinateFormat.NO_VERTEX:
                        meshChunk.textureCoordinates.Add(currentTexCoord);
                        break;
                    }

                    Vector4 col;

                    if (isColorFlagRisen)
                    {
                        uint c = meshChunk.SectionInfo_opt2.DiffuseColor;
                        col.X = c % 0x100;
                        col.Y = (c >> 8) % 0x100;
                        col.Z = (c >> 16) % 0x100;
                        col.W = (c >> 24) % 0x100;

                        meshChunk.colors.Add(col);
                    }
                    else
                    {
                        switch (ColorFormat)
                        {
                        case Pmo.ColorFormat.NO_COLOR:
                            meshChunk.colors.Add(new Vector4(0xFF, 0xFF, 0xFF, 0xFF));
                            break;

                        case Pmo.ColorFormat.BGR_5650_16BITS:
                            stream.ReadUInt16();
                            break;

                        case Pmo.ColorFormat.ABGR_5551_16BITS:
                            stream.ReadUInt16();
                            break;

                        case Pmo.ColorFormat.ABGR_4444_16BITS:
                            stream.ReadUInt16();
                            break;

                        case Pmo.ColorFormat.ABGR_8888_32BITS:
                            vertexIncreaseAmount = ((0x4 - (Convert.ToInt32(stream.Position - vertexStartPos) & 0x3)) & 0x3);
                            stream.Seek(vertexIncreaseAmount, SeekOrigin.Current);

                            col.X = stream.ReadByte();
                            col.Y = stream.ReadByte();
                            col.Z = stream.ReadByte();
                            col.W = stream.ReadByte();
                            meshChunk.colors.Add(col);
                            break;
                        }
                    }

                    Vector3 currentVertex;

                    // Handle triangles and triangle strips.
                    switch (VertexPositionFormat)
                    {
                    case CoordinateFormat.NORMALIZED_8_BITS:
                        currentVertex.X = r.ReadSByte() / 128.0f;
                        currentVertex.Y = r.ReadSByte() / 128.0f;
                        currentVertex.Z = r.ReadSByte() / 128.0f;
                        meshChunk.vertices.Add(currentVertex);
                        break;

                    case CoordinateFormat.NORMALIZED_16_BITS:
                        vertexIncreaseAmount = ((0x2 - (Convert.ToInt32(stream.Position - vertexStartPos) & 0x1)) & 0x1);
                        stream.Seek(vertexIncreaseAmount, SeekOrigin.Current);

                        currentVertex.X = (float)stream.ReadInt16() / 32768.0f;
                        currentVertex.Y = (float)stream.ReadInt16() / 32768.0f;
                        currentVertex.Z = (float)stream.ReadInt16() / 32768.0f;
                        meshChunk.vertices.Add(currentVertex);
                        break;

                    case CoordinateFormat.FLOAT_32_BITS:
                        vertexIncreaseAmount = ((0x4 - (Convert.ToInt32(stream.Position - vertexStartPos) & 0x3)) & 0x3);
                        stream.Seek(vertexIncreaseAmount, SeekOrigin.Current);

                        currentVertex.X = stream.ReadFloat();
                        currentVertex.Y = stream.ReadFloat();
                        currentVertex.Z = stream.ReadFloat();
                        meshChunk.vertices.Add(currentVertex);
                        break;
                    }

                    stream.Seek(vertexStartPos + meshChunk.SectionInfo.VertexSize, SeekOrigin.Begin);

                    if (flags.Primitive == PrimitiveType.PRIMITIVE_TRIANGLE)
                    {
                        meshChunk.Indices.Add(v);
                    }
                }

                VertCnt = meshChunk.SectionInfo.VertexCount;
                pmo.Meshes.Add(meshChunk);

                // Find position of next data chunk.
                stream.Seek(positionAfterHeader + (meshChunk.SectionInfo.VertexCount * meshChunk.SectionInfo.VertexSize), SeekOrigin.Begin);
                stream.Seek(stream.Position % 4, SeekOrigin.Current);
            }
        }