internal static XSkinWeights Read(XFileTokenReader tokenReader)
        {
            var skin = new XSkinWeights();

            if (tokenReader.FileReader.GetNextToken() == XToken.Name)
            {
                skin.Name = tokenReader.ReadName();
            }

            tokenReader.ReadAssert(XToken.OpenedBrace);

            skin.TransformNodeName = tokenReader.ReadString();

            int nWeights = tokenReader.ReadIntegerFromList();

            skin.VertexIndices.Capacity = nWeights;
            skin.Weights.Capacity       = nWeights;

            for (int i = 0; i < nWeights; i++)
            {
                skin.VertexIndices.Add(tokenReader.ReadIntegerFromList());
            }

            tokenReader.ReadSeparator();

            for (int i = 0; i < nWeights; i++)
            {
                skin.Weights.Add(tokenReader.ReadFloatFromList());
            }

            tokenReader.ReadSeparator();

            skin.MatrixOffset = new XMatrix4x4
            {
                Matrix = tokenReader.ReadFloatArrayFromList(16)
            };

            tokenReader.ReadAssert(XToken.ClosedBrace);

            return(skin);
        }
        internal static XMesh Read(XFileTokenReader tokenReader)
        {
            var mesh = new XMesh();

            if (tokenReader.FileReader.GetNextToken() == XToken.Name)
            {
                mesh.Name = tokenReader.ReadName();
            }

            tokenReader.ReadAssert(XToken.OpenedBrace);

            int nVertices = tokenReader.ReadIntegerFromList();

            mesh.Vertices.Capacity = nVertices;

            for (int i = 0; i < nVertices; i++)
            {
                var vector = new XVector
                {
                    X = tokenReader.ReadFloatFromList(),
                    Y = tokenReader.ReadFloatFromList(),
                    Z = tokenReader.ReadFloatFromList()
                };

                mesh.Vertices.Add(vector);
            }

            int nFaces = tokenReader.ReadIntegerFromList();

            mesh.FacesIndices.Capacity = nFaces;

            for (int faceIndex = 0; faceIndex < nFaces; faceIndex++)
            {
                int indicesCount = tokenReader.ReadIntegerFromList();
                var vertices     = new List <int>(indicesCount);

                for (int i = 0; i < indicesCount; i++)
                {
                    vertices.Add(tokenReader.ReadIntegerFromList());
                }

                mesh.FacesIndices.Add(vertices);
            }

            bool meshMaterialListRead         = false;
            bool meshNormalsRead              = false;
            bool meshTextureCoordsRead        = false;
            bool vertexDuplicationIndicesRead = false;
            bool meshVertexColorsRead         = false;
            bool xSkinMeshHeaderRead          = false;
            bool fvfDataRead        = false;
            bool vertexElementsRead = false;

            while (tokenReader.FileReader.GetNextToken() != XToken.ClosedBrace)
            {
                string identifier = tokenReader.ReadName();

                if (string.IsNullOrEmpty(identifier))
                {
                    if (tokenReader.FileReader is XFileBinaryReader binaryReader)
                    {
                        identifier = binaryReader.ReadNullTerminatedString();
                    }
                }

                switch (identifier)
                {
                case "MeshMaterialList":
                    if (meshMaterialListRead)
                    {
                        throw new InvalidDataException();
                    }

                    mesh.ReadMeshMaterialList(tokenReader);
                    meshMaterialListRead = true;
                    break;

                case "MeshNormals":
                    if (meshNormalsRead)
                    {
                        //throw new InvalidDataException();
                        mesh.Normals.Clear();
                        mesh.FacesNormalsIndices.Clear();
                    }

                    mesh.ReadMeshNormals(tokenReader);
                    meshNormalsRead = true;
                    break;

                case "MeshTextureCoords":
                    if (meshTextureCoordsRead)
                    {
                        //throw new InvalidDataException();
                        mesh.TextureCoords.Clear();
                    }

                    mesh.ReadMeshTextureCoords(tokenReader);
                    meshTextureCoordsRead = true;
                    break;

                case "VertexDuplicationIndices":
                    if (vertexDuplicationIndicesRead)
                    {
                        throw new InvalidDataException();
                    }

                    mesh.ReadVertexDuplicationIndices(tokenReader);
                    vertexDuplicationIndicesRead = true;
                    break;

                case "MeshVertexColors":
                    if (meshVertexColorsRead)
                    {
                        throw new InvalidDataException();
                    }

                    mesh.ReadMeshVertexColors(tokenReader);
                    meshVertexColorsRead = true;
                    break;

                case "XSkinMeshHeader":
                    if (xSkinMeshHeaderRead)
                    {
                        throw new InvalidDataException();
                    }

                    mesh.ReadXSkinMeshHeader(tokenReader);
                    xSkinMeshHeaderRead = true;
                    break;

                case "SkinWeights":
                {
                    XSkinWeights skin = XSkinWeights.Read(tokenReader);
                    mesh.SkinWeights.Add(skin);
                    break;
                }

                case "FVFData":
                {
                    if (fvfDataRead)
                    {
                        throw new InvalidDataException();
                    }

                    mesh.ReadFVFData(tokenReader);
                    fvfDataRead = true;
                    break;
                }

                case "DeclData":
                {
                    if (vertexElementsRead)
                    {
                        throw new InvalidDataException();
                    }

                    mesh.ReadVertexElements(tokenReader);
                    vertexElementsRead = true;
                    break;
                }

                case "":
                    throw new InvalidDataException();

                default:
                    throw new NotImplementedException();
                }
            }

            tokenReader.ReadAssert(XToken.ClosedBrace);

            return(mesh);
        }