private static float ReadDataLayout(FileReader reader, GXVertexLayout layout)
        {
            if (layout.Divisor != 0)
            {
                switch (layout.CompType)
                {
                case GXComponentType.S8: return(reader.ReadSByte() / layout.Divisor);

                case GXComponentType.U8: return(reader.ReadByte() / layout.Divisor);

                case GXComponentType.U16: return(reader.ReadUInt16() / layout.Divisor);

                case GXComponentType.S16: return(reader.ReadInt16() / layout.Divisor);
                }
            }

            switch (layout.CompType)
            {
            case GXComponentType.S8: return(reader.ReadSByte());

            case GXComponentType.U8: return(reader.ReadByte());

            case GXComponentType.U16: return(reader.ReadUInt16());

            case GXComponentType.S16: return(reader.ReadInt16());

            case GXComponentType.F32: return(reader.ReadSingle());
            }
            return(0);
        }
        private static Vector4 ReadDataColorLayout(FileReader reader, GXVertexLayout layout)
        {
            switch (layout.CompType)
            {
            case GXComponentType.RGBA8:
                return(new Vector4(
                           reader.ReadByte() / 255.0f, reader.ReadByte() / 255.0f,
                           reader.ReadByte() / 255.0f, reader.ReadByte() / 255.0f));

            case GXComponentType.RGB8:
                return(new Vector4(
                           reader.ReadByte() / 255.0f, reader.ReadByte() / 255.0f,
                           reader.ReadByte() / 255.0f, 1.0f));

            case GXComponentType.RGBX8:
                return(new Vector4(
                           reader.ReadByte() / 255.0f, reader.ReadByte() / 255.0f,
                           reader.ReadByte() / 255.0f, 1.0f));

            case GXComponentType.RGB565:
            {
                short value = reader.ReadInt16();
                int   R     = (value & 0xF800) >> 11;
                int   G     = (value & 0x07E0) >> 5;
                int   B     = (value & 0x001F);
                return(new Vector4(R / 255f, G / 255f, B / 255f, 1.0f));
            }

            case GXComponentType.RGBA4:
            {
                ushort value = reader.ReadUInt16();
                float  R     = (float)((value >> 12) & 0x0F) / 0x0F;
                float  G     = (float)((value >> 8) & 0x0F) / 0x0F;
                float  B     = (float)((value >> 4) & 0x0F) / 0x0F;
                float  A     = (float)((value >> 0) & 0x0F) / 0x0F;

                return(new Vector4(R, G, B, A));
            }

            case GXComponentType.RGBA6:
            {
                int value = reader.ReadInt32();
                int R     = (value & 0xFC0000) >> 18;
                int G     = (value & 0x03F000) >> 12;
                int B     = (value & 0x000FC0) >> 6;
                int A     = (value & 0x00003F);
                return(new Vector4(R / 255f, G / 255f, B / 255f, A / 255f));
            }

            default:
                return(new Vector4(
                           reader.ReadByte() / 255f, reader.ReadByte() / 255f,
                           reader.ReadByte() / 255f, reader.ReadByte() / 255f));
            }
            return(new Vector4(255, 255, 255, 255));
        }
        private static ushort ReadLayout(FileReader reader, GXVertexLayout layout)
        {
            switch (layout.AttType)
            {
            case GXAttributeType.INDEX16: return(reader.ReadUInt16());

            case GXAttributeType.INDEX8: return(reader.ReadByte());
            }
            return(0);
        }
        static bool IsColor(GXVertexLayout layout)
        {
            switch (layout.CompType)
            {
            case GXComponentType.RGBA4:
            case GXComponentType.RGBA8:
            case GXComponentType.RGBX8:
            case GXComponentType.RGB565:
            case GXComponentType.RGB8:
                return(layout.Attribute == GXAttributes.Color0 ||
                       layout.Attribute == GXAttributes.Color1);

            default:
                return(false);
            }
        }
        private static void ParseData(STVertex vertex, FileReader dataReader, GXVertexLayout layout, int index, ushort[] matrixIndices)
        {
            int numElements = GetElementCount(layout.Attribute);
            int stride      = GetDataStride(layout.CompType) * numElements;

            if (IsColor(layout))
            {
                stride = GetColorDataStride(layout.CompType);
            }

            using (dataReader.TemporarySeek(layout.DataOffset + (index * stride), SeekOrigin.Begin))
            {
                // Console.WriteLine($"attribute {layout.Attribute} stride {stride} index {index}");
                switch (layout.Attribute)
                {
                case GXAttributes.Position:
                {
                    float X = ReadDataLayout(dataReader, layout);
                    float Y = ReadDataLayout(dataReader, layout);
                    float Z = ReadDataLayout(dataReader, layout);
                    vertex.Position = new OpenTK.Vector3(X, Y, Z);
                }
                break;

                case GXAttributes.Normal:
                {
                    float X = ReadDataLayout(dataReader, layout);
                    float Y = ReadDataLayout(dataReader, layout);
                    float Z = ReadDataLayout(dataReader, layout);
                    vertex.Normal = new OpenTK.Vector3(X, Y, Z).Normalized();
                }
                break;

                case GXAttributes.NormalBinormalTangent:
                {
                    float NormalX   = ReadDataLayout(dataReader, layout);
                    float NormalY   = ReadDataLayout(dataReader, layout);
                    float NormalZ   = ReadDataLayout(dataReader, layout);
                    float BinormalX = ReadDataLayout(dataReader, layout);
                    float BinormalY = ReadDataLayout(dataReader, layout);
                    float BinormalZ = ReadDataLayout(dataReader, layout);
                    float TangentX  = ReadDataLayout(dataReader, layout);
                    float TangentY  = ReadDataLayout(dataReader, layout);
                    float TangentZ  = ReadDataLayout(dataReader, layout);
                    vertex.Normal    = new OpenTK.Vector3(NormalX, NormalY, NormalZ).Normalized();
                    vertex.Bitangent = new OpenTK.Vector4(BinormalX, BinormalY, BinormalZ, 1);
                    vertex.Tangent   = new OpenTK.Vector4(TangentX, TangentY, TangentZ, 1);
                }
                break;

                case GXAttributes.TexCoord0:
                case GXAttributes.TexCoord1:
                case GXAttributes.TexCoord2:
                case GXAttributes.TexCoord3:
                case GXAttributes.TexCoord4:
                case GXAttributes.TexCoord5:
                case GXAttributes.TexCoord6:
                case GXAttributes.TexCoord7:
                {
                    int   channel = GetChannel(layout.Attribute);
                    float X       = ReadDataLayout(dataReader, layout);
                    float Y       = ReadDataLayout(dataReader, layout);
                    vertex.TexCoords[channel] = new OpenTK.Vector2(X, Y);
                }
                break;

                case GXAttributes.Color0:
                case GXAttributes.Color1:
                {
                    int channel = GetChannel(layout.Attribute);
                    var color   = ReadDataColorLayout(dataReader, layout);
                    vertex.Colors[0] = new OpenTK.Vector4(color.X, color.Y, color.Z, color.W);
                }
                break;

                case GXAttributes.PosNormMatrix:
                {
                    if (index != -1)
                    {
                        int boneID = index / 3;
                        if (matrixIndices != null)
                        {
                            boneID = matrixIndices[index / 3];
                        }
                        Console.WriteLine($"BONEID {index} real {boneID}");

                        vertex.BoneIndices.Add(boneID);
                        vertex.BoneWeights.Add(1.0f);
                    }
                }
                break;
                }
            }
        }
        private static void ParseData(STVertex vertex, FileReader dataReader, GXVertexLayout layout, int index)
        {
            int numElements = GetElementCount(layout.Attribute);
            int stride      = GetDataStride(layout.CompType) * numElements;

            if (IsColor(layout))
            {
                stride = GetColorDataStride(layout.CompType);
            }

            using (dataReader.TemporarySeek(layout.DataOffset + (index * stride), SeekOrigin.Begin))
            {
                // Console.WriteLine($"attribute {layout.Attribute} stride {stride} index {index}");
                switch (layout.Attribute)
                {
                case GXAttributes.Position:
                {
                    float X = ReadDataLayout(dataReader, layout);
                    float Y = ReadDataLayout(dataReader, layout);
                    float Z = ReadDataLayout(dataReader, layout);
                    vertex.Position = new OpenTK.Vector3(X, Y, Z);
                }
                break;

                case GXAttributes.Normal:
                {
                    float X = ReadDataLayout(dataReader, layout);
                    float Y = ReadDataLayout(dataReader, layout);
                    float Z = ReadDataLayout(dataReader, layout);
                    vertex.Normal = new OpenTK.Vector3(X, Y, Z).Normalized();
                }
                break;

                case GXAttributes.TexCoord0:
                case GXAttributes.TexCoord1:
                case GXAttributes.TexCoord2:
                case GXAttributes.TexCoord3:
                case GXAttributes.TexCoord4:
                case GXAttributes.TexCoord5:
                case GXAttributes.TexCoord6:
                case GXAttributes.TexCoord7:
                {
                    int   channel = (int)(layout.Attribute - GXAttributes.TexCoord0);
                    float X       = ReadDataLayout(dataReader, layout);
                    float Y       = ReadDataLayout(dataReader, layout);
                    vertex.TexCoords[0] = new OpenTK.Vector2(X, Y);
                }
                break;

                case GXAttributes.Color0:
                case GXAttributes.Color1:
                {
                    int channel = (int)(layout.Attribute - GXAttributes.Color0);
                    var color   = ReadDataColorLayout(dataReader, layout);
                    vertex.Colors[0] = new OpenTK.Vector4(color.X, color.Y, color.Z, color.W);
                }
                break;

                case GXAttributes.PosNormMatrix:
                {
                    if (index != -1)
                    {
                        int boneID = index / 3;
                        vertex.BoneIndices.Add(boneID);
                        vertex.BoneWeights.Add(1.0f);
                    }
                }
                break;
                }
            }
        }