// Spriggan models, not sure which game.  SC, MWO uses 0800
        public override void Read(BinaryReader b)
        {
            base.Read(b);

            this.Flags2 = b.ReadUInt32(); // another filler
            uint tmpdataStreamType = b.ReadUInt32();

            this.DataStreamType = (DataStreamTypeEnum)Enum.ToObject(typeof(DataStreamTypeEnum), tmpdataStreamType);
            this.SkipBytes(b, 4);
            this.NumElements = b.ReadUInt32();     // number of elements in this chunk

            this.BytesPerElement = b.ReadUInt32(); // bytes per element
            //if (this.NumElements == 0) // For vertices, number of elements is frequently 0.
            //{

            //}
            this.SkipBytes(b, 8);

            // Now do loops to read for each of the different Data Stream Types.  If vertices, need to populate Vector3s for example.
            switch (this.DataStreamType)
            {
                #region case DataStreamTypeEnum.VERTICES:

            case DataStreamTypeEnum.VERTICES:      // Ref is 0x00000000
                this.Vertices = new Vector3[this.NumElements];
                for (Int32 i = 0; i < this.NumElements; i++)
                {
                    this.Vertices[i].x = b.ReadSingle();
                    this.Vertices[i].y = b.ReadSingle();
                    this.Vertices[i].z = b.ReadSingle();
                }
                break;

                #endregion
                #region case DataStreamTypeEnum.INDICES:

            case DataStreamTypeEnum.INDICES:      // Ref is
                this.Indices = new UInt32[NumElements];

                if (this.BytesPerElement == 2)
                {
                    for (Int32 i = 0; i < this.NumElements; i++)
                    {
                        this.Indices[i] = (UInt32)b.ReadUInt16();
                        //Console.WriteLine("Indices {0}: {1}", i, this.Indices[i]);
                    }
                }
                if (this.BytesPerElement == 4)
                {
                    for (Int32 i = 0; i < this.NumElements; i++)
                    {
                        this.Indices[i] = b.ReadUInt32();
                    }
                }
                //Utils.Log(LogLevelEnum.Debug, "Offset is {0:X}", b.BaseStream.Position);
                break;

                #endregion
                #region case DataStreamTypeEnum.NORMALS:

            case DataStreamTypeEnum.NORMALS:
                this.Normals = new Vector3[this.NumElements];
                for (Int32 i = 0; i < NumElements; i++)
                {
                    this.Normals[i].x = b.ReadSingle();
                    this.Normals[i].y = b.ReadSingle();
                    this.Normals[i].z = b.ReadSingle();
                }
                //Utils.Log(LogLevelEnum.Debug, "Offset is {0:X}", b.BaseStream.Position);
                break;

                #endregion
                #region case DataStreamTypeEnum.UVS:

            case DataStreamTypeEnum.UVS:
                this.UVs = new UV[this.NumElements];
                for (Int32 i = 0; i < this.NumElements; i++)
                {
                    this.UVs[i].U = b.ReadSingle();
                    this.UVs[i].V = b.ReadSingle();
                }
                //Utils.Log(LogLevelEnum.Debug, "Offset is {0:X}", b.BaseStream.Position);
                break;

                #endregion
                #region case DataStreamTypeEnum.TANGENTS:

            case DataStreamTypeEnum.TANGENTS:
                this.Tangents = new Tangent[this.NumElements, 2];
                this.Normals  = new Vector3[this.NumElements];
                for (Int32 i = 0; i < this.NumElements; i++)
                {
                    switch (this.BytesPerElement)
                    {
                    case 0x10:
                        // These have to be divided by 32767 to be used properly (value between 0 and 1)
                        this.Tangents[i, 0].x = b.ReadInt16();
                        this.Tangents[i, 0].y = b.ReadInt16();
                        this.Tangents[i, 0].z = b.ReadInt16();
                        this.Tangents[i, 0].w = b.ReadInt16();

                        this.Tangents[i, 1].x = b.ReadInt16();
                        this.Tangents[i, 1].y = b.ReadInt16();
                        this.Tangents[i, 1].z = b.ReadInt16();
                        this.Tangents[i, 1].w = b.ReadInt16();

                        break;

                    case 0x08:
                        // These have to be divided by 127 to be used properly (value between 0 and 1)
                        // Tangent
                        this.Tangents[i, 0].w = b.ReadSByte() / 127.0;
                        this.Tangents[i, 0].x = b.ReadSByte() / 127.0;
                        this.Tangents[i, 0].y = b.ReadSByte() / 127.0;
                        this.Tangents[i, 0].z = b.ReadSByte() / 127.0;

                        // Binormal
                        this.Tangents[i, 1].w = b.ReadSByte() / 127.0;
                        this.Tangents[i, 1].x = b.ReadSByte() / 127.0;
                        this.Tangents[i, 1].y = b.ReadSByte() / 127.0;
                        this.Tangents[i, 1].z = b.ReadSByte() / 127.0;

                        // Calculate the normal based on the cross product of the tangents.
                        //this.Normals[i].x = (Tangents[i,0].y * Tangents[i,1].z - Tangents[i,0].z * Tangents[i,1].y);
                        //this.Normals[i].y = 0 - (Tangents[i,0].x * Tangents[i,1].z - Tangents[i,0].z * Tangents[i,1].x);
                        //this.Normals[i].z = (Tangents[i,0].x * Tangents[i,1].y - Tangents[i,0].y * Tangents[i,1].x);
                        //Console.WriteLine("Tangent: {0:F6} {1:F6} {2:F6}", Tangents[i,0].x, Tangents[i, 0].y, Tangents[i, 0].z);
                        //Console.WriteLine("Binormal: {0:F6} {1:F6} {2:F6}", Tangents[i, 1].x, Tangents[i, 1].y, Tangents[i, 1].z);
                        //Console.WriteLine("Normal: {0:F6} {1:F6} {2:F6}", Normals[i].x, Normals[i].y, Normals[i].z);
                        break;

                    default:
                        throw new Exception("Need to add new Tangent Size");
                    }
                }
                // Utils.Log(LogLevelEnum.Debug, "Offset is {0:X}", b.BaseStream.Position);
                break;

                #endregion
                #region case DataStreamTypeEnum.COLORS:

            case DataStreamTypeEnum.COLORS:
                switch (this.BytesPerElement)
                {
                case 3:
                    this.RGBColors = new IRGB[this.NumElements];
                    for (Int32 i = 0; i < NumElements; i++)
                    {
                        this.RGBColors[i].r = b.ReadByte();
                        this.RGBColors[i].g = b.ReadByte();
                        this.RGBColors[i].b = b.ReadByte();
                    }
                    break;

                case 4:
                    this.RGBAColors = new IRGBA[this.NumElements];
                    for (Int32 i = 0; i < this.NumElements; i++)
                    {
                        this.RGBAColors[i].r = b.ReadByte();
                        this.RGBAColors[i].g = b.ReadByte();
                        this.RGBAColors[i].b = b.ReadByte();
                        this.RGBAColors[i].a = b.ReadByte();
                    }
                    break;

                default:
                    Utils.Log("Unknown Color Depth");
                    for (Int32 i = 0; i < this.NumElements; i++)
                    {
                        this.SkipBytes(b, this.BytesPerElement);
                    }
                    break;
                }
                break;

                #endregion
                #region case DataStreamTypeEnum.VERTSUVS:

            case DataStreamTypeEnum.VERTSUVS:      // 3 half floats for verts, 3 half floats for normals, 2 half floats for UVs
                // Utils.Log(LogLevelEnum.Debug, "In VertsUVs...");
                this.Vertices  = new Vector3[this.NumElements];
                this.Normals   = new Vector3[this.NumElements];
                this.RGBColors = new IRGB[this.NumElements];
                this.UVs       = new UV[this.NumElements];
                switch (this.BytesPerElement) // new Star Citizen files
                {
                case 20:                      // Dymek wrote this.  Used in 2.6 skin files.  3 floats for vertex position, 4 bytes for normals, 2 halfs for UVs.  Normals are calculated from Tangents
                    for (Int32 i = 0; i < this.NumElements; i++)
                    {
                        this.Vertices[i].x = b.ReadSingle();
                        this.Vertices[i].y = b.ReadSingle();
                        this.Vertices[i].z = b.ReadSingle();                          // For some reason, skins are an extra 1 meter in the z direction.

                        // Normals are stored in a signed byte, prob div by 127.
                        this.Normals[i].x = (float)b.ReadSByte() / 127;
                        this.Normals[i].y = (float)b.ReadSByte() / 127;
                        this.Normals[i].z = (float)b.ReadSByte() / 127;
                        b.ReadSByte();         // Should be FF.

                        Half uvu = new Half();
                        uvu.bits      = b.ReadUInt16();
                        this.UVs[i].U = uvu.ToSingle();

                        Half uvv = new Half();
                        uvv.bits      = b.ReadUInt16();
                        this.UVs[i].V = uvv.ToSingle();

                        //bver = b.ReadUInt16();
                        //ver = Byte4HexToFloat(bver.ToString("X8"));
                        //this.UVs[i].U = ver;

                        //bver = b.ReadUInt16();
                        //ver = Byte4HexToFloat(bver.ToString("X8"));
                        //this.UVs[i].V = ver;
                    }
                    break;

                case 16:           // Dymek updated this.
                    //Console.WriteLine("method: (5), 3 half floats for verts, 3 colors, 2 half floats for UVs");
                    for (Int32 i = 0; i < this.NumElements; i++)
                    {
                        ushort bver = 0;
                        float  ver  = 0;

                        bver = b.ReadUInt16();
                        ver  = Byte2HexIntFracToFloat2(bver.ToString("X4")) / 127;
                        this.Vertices[i].x = ver;

                        bver = b.ReadUInt16();
                        ver  = Byte2HexIntFracToFloat2(bver.ToString("X4")) / 127;
                        this.Vertices[i].y = ver;

                        bver = b.ReadUInt16();
                        ver  = Byte2HexIntFracToFloat2(bver.ToString("X4")) / 127;
                        this.Vertices[i].z = ver;

                        bver = b.ReadUInt16();
                        ver  = Byte2HexIntFracToFloat2(bver.ToString("X4")) / 127;
                        this.Vertices[i].w = ver;               // Almost always 1

                        // Next structure is Colors, not normals.  For 16 byte elements, normals are calculated from Tangent data.
                        //this.RGBColors[i].r = b.ReadByte();
                        //this.RGBColors[i].g = b.ReadByte();
                        //this.RGBColors[i].b = b.ReadByte();
                        //b.ReadByte();           // additional byte.

                        //this.Normals[i].x = (b.ReadByte() - 128.0f) / 127.5f;
                        //this.Normals[i].y = (b.ReadByte() - 128.0f) / 127.5f;
                        //this.Normals[i].z = (b.ReadByte() - 128.0f) / 127.5f;
                        //b.ReadByte();           // additional byte.

                        // Read a Quat, convert it to vector3
                        Vector4 quat = new Vector4();
                        quat.x            = (b.ReadByte() - 128.0f) / 127.5f;
                        quat.y            = (b.ReadByte() - 128.0f) / 127.5f;
                        quat.z            = (b.ReadByte() - 128.0f) / 127.5f;
                        quat.w            = (b.ReadByte() - 128.0f) / 127.5f;
                        this.Normals[i].x = (2 * (quat.x * quat.z + quat.y * quat.w));
                        this.Normals[i].y = (2 * (quat.y * quat.z - quat.x * quat.w));
                        this.Normals[i].z = (2 * (quat.z * quat.z + quat.w * quat.w)) - 1;


                        // UVs ABSOLUTELY should use the Half structures.
                        Half uvu = new Half();
                        uvu.bits      = b.ReadUInt16();
                        this.UVs[i].U = uvu.ToSingle();

                        Half uvv = new Half();
                        uvv.bits      = b.ReadUInt16();
                        this.UVs[i].V = uvv.ToSingle();

                        #region Legacy version using Halfs
                        //Half xshort = new Half();
                        //xshort.bits = b.ReadUInt16();
                        //this.Vertices[i].x = xshort.ToSingle();

                        //Half yshort = new Half();
                        //yshort.bits = b.ReadUInt16();
                        //this.Vertices[i].y = yshort.ToSingle();

                        //Half zshort = new Half();
                        //zshort.bits = b.ReadUInt16();
                        //this.Vertices[i].z = zshort.ToSingle();

                        //Half xnorm = new Half();
                        //xnorm.bits = b.ReadUInt16();
                        //this.Normals[i].x = xnorm.ToSingle();

                        //Half ynorm = new Half();
                        //ynorm.bits = b.ReadUInt16();
                        //this.Normals[i].y = ynorm.ToSingle();

                        //Half znorm = new Half();
                        //znorm.bits = b.ReadUInt16();
                        //this.Normals[i].z = znorm.ToSingle();

                        //Half uvu = new Half();
                        //uvu.bits = b.ReadUInt16();
                        //this.UVs[i].U = uvu.ToSingle();

                        //Half uvv = new Half();
                        //uvv.bits = b.ReadUInt16();
                        //this.UVs[i].V = uvv.ToSingle();
                        #endregion
                    }
                    break;

                default:
                    Utils.Log("Unknown VertUV structure");
                    for (Int32 i = 0; i < this.NumElements; i++)
                    {
                        this.SkipBytes(b, this.BytesPerElement);
                    }
                    break;
                }
                break;

                #endregion
                #region case DataStreamTypeEnum.BONEMAP:
            case DataStreamTypeEnum.BONEMAP:
                SkinningInfo skin = GetSkinningInfo();
                skin.HasBoneMapDatastream = true;

                skin.BoneMapping = new List <MeshBoneMapping>();

                // Bones should have 4 bone IDs (index) and 4 weights.
                for (int i = 0; i < NumElements; i++)
                {
                    MeshBoneMapping tmpMap = new MeshBoneMapping();
                    switch (this.BytesPerElement)
                    {
                    case 8:
                        tmpMap.BoneIndex = new int[4];
                        tmpMap.Weight    = new int[4];

                        for (int j = 0; j < 4; j++)                 // read the 4 bone indexes first
                        {
                            tmpMap.BoneIndex[j] = b.ReadByte();
                        }
                        for (int j = 0; j < 4; j++)                   // read the weights.
                        {
                            tmpMap.Weight[j] = b.ReadByte();
                        }
                        skin.BoneMapping.Add(tmpMap);
                        break;

                    case 12:
                        tmpMap.BoneIndex = new int[4];
                        tmpMap.Weight    = new int[4];

                        for (int j = 0; j < 4; j++)                 // read the 4 bone indexes first
                        {
                            tmpMap.BoneIndex[j] = b.ReadUInt16();
                        }
                        for (int j = 0; j < 4; j++)                   // read the weights.
                        {
                            tmpMap.Weight[j] = b.ReadByte();
                        }
                        skin.BoneMapping.Add(tmpMap);

                        break;

                    default:
                        Utils.Log("Unknown BoneMapping structure");
                        break;
                    }
                }

                break;


                #endregion
                #region DataStreamTypeEnum.Unknown1
            case DataStreamTypeEnum.UNKNOWN1:
                this.Tangents = new Tangent[this.NumElements, 2];
                this.Normals  = new Vector3[this.NumElements];
                for (Int32 i = 0; i < NumElements; i++)
                {
                    this.Tangents[i, 0].w = b.ReadSByte() / 127.0;
                    this.Tangents[i, 0].x = b.ReadSByte() / 127.0;
                    this.Tangents[i, 0].y = b.ReadSByte() / 127.0;
                    this.Tangents[i, 0].z = b.ReadSByte() / 127.0;

                    // Binormal
                    this.Tangents[i, 1].w = b.ReadSByte() / 127.0;
                    this.Tangents[i, 1].x = b.ReadSByte() / 127.0;
                    this.Tangents[i, 1].y = b.ReadSByte() / 127.0;
                    this.Tangents[i, 1].z = b.ReadSByte() / 127.0;

                    // Calculate the normal based on the cross product of the tangents.
                    this.Normals[i].x = (Tangents[i, 0].y * Tangents[i, 1].z - Tangents[i, 0].z * Tangents[i, 1].y);
                    this.Normals[i].y = 0 - (Tangents[i, 0].x * Tangents[i, 1].z - Tangents[i, 0].z * Tangents[i, 1].x);
                    this.Normals[i].z = (Tangents[i, 0].x * Tangents[i, 1].y - Tangents[i, 0].y * Tangents[i, 1].x);
                }
                break;
                #endregion // Prey normals?
                #region default:

            default:
                Utils.Log(LogLevelEnum.Debug, "***** Unknown DataStream Type *****");
                break;

                #endregion
            }
        }
Exemplo n.º 2
0
        public override void Read(BinaryReader r)
        {
            base.Read(r);
            Flags2 = r.ReadUInt32(); // another filler
            var tmpdataStreamType = r.ReadUInt32();

            DataStreamType = (DataStreamTypeEnum)Enum.ToObject(typeof(DataStreamTypeEnum), tmpdataStreamType);
            NumElements    = r.ReadUInt32(); // number of elements in this chunk
            if (_model.FileVersion == FileVersionEnum.CryTek_3_5 || _model.FileVersion == FileVersionEnum.CryTek_3_4)
            {
                BytesPerElement = r.ReadUInt32(); // bytes per element
            }
            if (_model.FileVersion == FileVersionEnum.CryTek_3_6)
            {
                BytesPerElement = (uint)r.ReadInt16();        // Star Citizen 2.0 is using an int16 here now.
                r.ReadInt16();                                // unknown value.   Doesn't look like padding though.
            }
            SkipBytes(r, 8);

            // Now do loops to read for each of the different Data Stream Types.  If vertices, need to populate Vector3s for example.
            switch (DataStreamType)
            {
            case DataStreamTypeEnum.VERTICES:      // Ref is 0x00000000
                Vertices = new Vector3[NumElements];
                switch (BytesPerElement)
                {
                case 12:
                    for (var i = 0; i < NumElements; i++)
                    {
                        Vertices[i].x = r.ReadSingle();
                        Vertices[i].y = r.ReadSingle();
                        Vertices[i].z = r.ReadSingle();
                    }
                    break;

                case 8:          // Prey files, and old Star Citizen files
                    for (var i = 0; i < NumElements; i++)
                    {
                        // 2 byte floats.  Use the Half structure from TK.Math
                        //Vertices[i].x = Byte4HexToFloat(r.ReadUInt16().ToString("X8"));
                        //Vertices[i].y = Byte4HexToFloat(r.ReadUInt16().ToString("X8")); r.ReadUInt16();
                        //Vertices[i].z = Byte4HexToFloat(r.ReadUInt16().ToString("X8"));
                        //Vertices[i].w = Byte4HexToFloat(r.ReadUInt16().ToString("X8"));
                        Vertices[i].x = new Half {
                            bits = r.ReadUInt16()
                        }.ToSingle();
                        Vertices[i].y = new Half {
                            bits = r.ReadUInt16()
                        }.ToSingle();
                        Vertices[i].z = new Half {
                            bits = r.ReadUInt16()
                        }.ToSingle();
                        r.ReadUInt16();
                    }
                    break;

                case 16:
                    //Console.WriteLine("method: (3)");
                    for (var i = 0; i < NumElements; i++)
                    {
                        Vertices[i].x = r.ReadSingle();
                        Vertices[i].y = r.ReadSingle();
                        Vertices[i].z = r.ReadSingle();
                        Vertices[i].w = r.ReadSingle();         // TODO:  Sometimes there's a W to these structures.  Will investigate.
                    }
                    break;
                }
                break;

            case DataStreamTypeEnum.INDICES:      // Ref is
                Indices = new uint[NumElements];
                if (BytesPerElement == 2)
                {
                    for (var i = 0; i < NumElements; i++)
                    {
                        Indices[i] = (uint)r.ReadUInt16();     //Console.WriteLine(R"Indices {i}: {Indices[i]}");
                    }
                }
                if (BytesPerElement == 4)
                {
                    for (var i = 0; i < NumElements; i++)
                    {
                        Indices[i] = r.ReadUInt32();
                    }
                }
                //Log($"Offset is {r.BaseStream.Position:X}");
                break;

            case DataStreamTypeEnum.NORMALS:
                Normals = new Vector3[NumElements];
                for (var i = 0; i < NumElements; i++)
                {
                    Normals[i].x = r.ReadSingle();
                    Normals[i].y = r.ReadSingle();
                    Normals[i].z = r.ReadSingle();
                }
                //Log($"Offset is {r.BaseStream.Position:X}");
                break;

            case DataStreamTypeEnum.UVS:
                UVs = new UV[NumElements];
                for (var i = 0; i < NumElements; i++)
                {
                    UVs[i].U = r.ReadSingle();
                    UVs[i].V = r.ReadSingle();
                }
                //Log($"Offset is {r..BaseStream.Position:X}");
                break;

            case DataStreamTypeEnum.TANGENTS:
                Tangents = new Tangent[NumElements, 2];
                Normals  = new Vector3[NumElements];
                for (var i = 0; i < NumElements; i++)
                {
                    switch (BytesPerElement)
                    {
                    case 0x10:
                        // These have to be divided by 32767 to be used properly (value between 0 and 1)
                        Tangents[i, 0].x = r.ReadInt16();
                        Tangents[i, 0].y = r.ReadInt16();
                        Tangents[i, 0].z = r.ReadInt16();
                        Tangents[i, 0].w = r.ReadInt16();
                        //
                        Tangents[i, 1].x = r.ReadInt16();
                        Tangents[i, 1].y = r.ReadInt16();
                        Tangents[i, 1].z = r.ReadInt16();
                        Tangents[i, 1].w = r.ReadInt16();
                        break;

                    case 0x08:
                        // These have to be divided by 127 to be used properly (value between 0 and 1)
                        // Tangent
                        Tangents[i, 0].w = r.ReadSByte() / 127.0f;
                        Tangents[i, 0].x = r.ReadSByte() / 127.0f;
                        Tangents[i, 0].y = r.ReadSByte() / 127.0f;
                        Tangents[i, 0].z = r.ReadSByte() / 127.0f;
                        // Binormal
                        Tangents[i, 1].w = r.ReadSByte() / 127.0f;
                        Tangents[i, 1].x = r.ReadSByte() / 127.0f;
                        Tangents[i, 1].y = r.ReadSByte() / 127.0f;
                        Tangents[i, 1].z = r.ReadSByte() / 127.0f;
                        // Calculate the normal based on the cross product of the tangents.
                        //Normals[i].x = (Tangents[i,0].y * Tangents[i,1].z - Tangents[i,0].z * Tangents[i,1].y);
                        //Normals[i].y = 0 - (Tangents[i,0].x * Tangents[i,1].z - Tangents[i,0].z * Tangents[i,1].x);
                        //Normals[i].z = (Tangents[i,0].x * Tangents[i,1].y - Tangents[i,0].y * Tangents[i,1].x);
                        //Console.WriteLine("Tangent: {0:F6} {1:F6} {2:F6}", Tangents[i,0].x, Tangents[i, 0].y, Tangents[i, 0].z);
                        //Console.WriteLine("Binormal: {0:F6} {1:F6} {2:F6}", Tangents[i, 1].x, Tangents[i, 1].y, Tangents[i, 1].z);
                        //Console.WriteLine("Normal: {0:F6} {1:F6} {2:F6}", Normals[i].x, Normals[i].y, Normals[i].z);
                        break;

                    default: throw new Exception("Need to add new Tangent Size");
                    }
                }
                //Log($"Offset is {r.BaseStream.Position:X}");
                break;

            case DataStreamTypeEnum.COLORS:
                switch (BytesPerElement)
                {
                case 3:
                    RGBColors = new IRGB[NumElements];
                    for (var i = 0; i < NumElements; i++)
                    {
                        RGBColors[i].r = r.ReadByte();
                        RGBColors[i].g = r.ReadByte();
                        RGBColors[i].b = r.ReadByte();
                    }
                    break;

                case 4:
                    RGBAColors = new IRGBA[NumElements];
                    for (var i = 0; i < NumElements; i++)
                    {
                        RGBAColors[i].r = r.ReadByte();
                        RGBAColors[i].g = r.ReadByte();
                        RGBAColors[i].b = r.ReadByte();
                        RGBAColors[i].a = r.ReadByte();
                    }
                    break;

                default:
                    Log("Unknown Color Depth");
                    for (var i = 0; i < NumElements; i++)
                    {
                        SkipBytes(r, BytesPerElement);
                    }
                    break;
                }
                break;

            case DataStreamTypeEnum.VERTSUVS:      // 3 half floats for verts, 3 half floats for normals, 2 half floats for UVs
                Vertices  = new Vector3[NumElements];
                Normals   = new Vector3[NumElements];
                RGBColors = new IRGB[NumElements];
                UVs       = new UV[NumElements];
                switch (BytesPerElement) // new Star Citizen files
                {
                case 20:                 // Dymek wrote this.  Used in 2.6 skin files.  3 floats for vertex position, 4 bytes for normals, 2 halfs for UVs.  Normals are calculated from Tangents
                    for (var i = 0; i < NumElements; i++)
                    {
                        Vertices[i].x = r.ReadSingle();
                        Vertices[i].y = r.ReadSingle();
                        Vertices[i].z = r.ReadSingle();         // For some reason, skins are an extra 1 meter in the z direction.
                        // Normals are stored in a signed byte, prob div by 127.
                        Normals[i].x = (float)r.ReadSByte() / 127;
                        Normals[i].y = (float)r.ReadSByte() / 127;
                        Normals[i].z = (float)r.ReadSByte() / 127;
                        r.ReadSByte();         // Should be FF.
                        UVs[i].U = new Half {
                            bits = r.ReadUInt16()
                        }.ToSingle();
                        UVs[i].V = new Half {
                            bits = r.ReadUInt16()
                        }.ToSingle();
                        //UVs[i].U = Byte4HexToFloat(r.ReadUInt16().ToString("X8"));
                        //UVs[i].V = Byte4HexToFloat(r.ReadUInt16().ToString("X8"));
                    }
                    break;

                case 16:           // Dymek updated this.
                                   //Console.WriteLine("method: (5), 3 half floats for verts, 3 colors, 2 half floats for UVs");
                    for (var i = 0; i < NumElements; i++)
                    {
                        ushort bver = 0;
                        var    ver  = 0F;
                        Vertices[i].x = Byte2HexIntFracToFloat2(r.ReadUInt16().ToString("X4")) / 127f;
                        Vertices[i].y = Byte2HexIntFracToFloat2(r.ReadUInt16().ToString("X4")) / 127f;
                        Vertices[i].z = Byte2HexIntFracToFloat2(r.ReadUInt16().ToString("X4")) / 127f;
                        Vertices[i].w = Byte2HexIntFracToFloat2(r.ReadUInt16().ToString("X4")) / 127f;         // Almost always 1
                        // Next structure is Colors, not normals.  For 16 byte elements, normals are calculated from Tangent data.
                        //RGBColors[i].r = r.ReadByte();
                        //RGBColors[i].g = r.ReadByte();
                        //RGBColors[i].b = r.ReadByte();
                        //r.ReadByte();           // additional byte.
                        //
                        //Normals[i].x = (r.ReadByte() - 128.0f) / 127.5f;
                        //Normals[i].y = (r.ReadByte() - 128.0f) / 127.5f;
                        //Normals[i].z = (r.ReadByte() - 128.0f) / 127.5f;
                        //r.ReadByte();           // additional byte.
                        // Read a Quat, convert it to vector3
                        var quat = new Vector4
                        {
                            x = (r.ReadByte() - 128.0f) / 127.5f,
                            y = (r.ReadByte() - 128.0f) / 127.5f,
                            z = (r.ReadByte() - 128.0f) / 127.5f,
                            w = (r.ReadByte() - 128.0f) / 127.5f
                        };
                        Normals[i].x = (2 * (quat.x * quat.z + quat.y * quat.w));
                        Normals[i].y = (2 * (quat.y * quat.z - quat.x * quat.w));
                        Normals[i].z = (2 * (quat.z * quat.z + quat.w * quat.w)) - 1;

                        // UVs ABSOLUTELY should use the Half structures.
                        UVs[i].U = new Half {
                            bits = r.ReadUInt16()
                        }.ToSingle();
                        UVs[i].V = new Half {
                            bits = r.ReadUInt16()
                        }.ToSingle();

                        //Vertices[i].x = new Half { bits = r.ReadUInt16() }.ToSingle();
                        //Vertices[i].y = new Half { bits = r.ReadUInt16() }.ToSingle();
                        //Vertices[i].z = new Half { bits = r.ReadUInt16() }.ToSingle();
                        //Normals[i].x = new Half { bits = r.ReadUInt16() }.ToSingle();
                        //Normals[i].y = new Half { bits = r.ReadUInt16() }.ToSingle();
                        //Normals[i].z = new Half { bits = r.ReadUInt16() }.ToSingle();
                        //UVs[i].U = new Half { bits = r.ReadUInt16() }.ToSingle();
                        //UVs[i].V = new Half { bits = r.ReadUInt16() }.ToSingle();
                    }
                    break;

                default:
                    Log("Unknown VertUV structure");
                    SkipBytes(r, NumElements * BytesPerElement);
                    break;
                }
                break;

            case DataStreamTypeEnum.BONEMAP:
                var skin = GetSkinningInfo();
                skin.HasBoneMapDatastream = true;
                skin.BoneMapping          = new List <MeshBoneMapping>();
                // Bones should have 4 bone IDs (index) and 4 weights.
                for (var i = 0; i < NumElements; i++)
                {
                    var tmpMap = new MeshBoneMapping();
                    switch (BytesPerElement)
                    {
                    case 8:
                        tmpMap.BoneIndex = new int[4];
                        tmpMap.Weight    = new int[4];
                        for (var j = 0; j < 4; j++)                 // read the 4 bone indexes first
                        {
                            tmpMap.BoneIndex[j] = r.ReadByte();
                        }
                        for (var j = 0; j < 4; j++)                   // read the weights.
                        {
                            tmpMap.Weight[j] = r.ReadByte();
                        }
                        skin.BoneMapping.Add(tmpMap);
                        break;

                    case 12:
                        tmpMap.BoneIndex = new int[4];
                        tmpMap.Weight    = new int[4];
                        for (var j = 0; j < 4; j++)                 // read the 4 bone indexes first
                        {
                            tmpMap.BoneIndex[j] = r.ReadUInt16();
                        }
                        for (var j = 0; j < 4; j++)                   // read the weights.
                        {
                            tmpMap.Weight[j] = r.ReadByte();
                        }
                        skin.BoneMapping.Add(tmpMap);
                        break;

                    default: Log("Unknown BoneMapping structure"); break;
                    }
                }
                break;

            case DataStreamTypeEnum.UNKNOWN1:
                Tangents = new Tangent[NumElements, 2];
                Normals  = new Vector3[NumElements];
                for (var i = 0; i < NumElements; i++)
                {
                    Tangents[i, 0].w = r.ReadSByte() / 127.0f;
                    Tangents[i, 0].x = r.ReadSByte() / 127.0f;
                    Tangents[i, 0].y = r.ReadSByte() / 127.0f;
                    Tangents[i, 0].z = r.ReadSByte() / 127.0f;
                    // Binormal
                    Tangents[i, 1].w = r.ReadSByte() / 127.0f;
                    Tangents[i, 1].x = r.ReadSByte() / 127.0f;
                    Tangents[i, 1].y = r.ReadSByte() / 127.0f;
                    Tangents[i, 1].z = r.ReadSByte() / 127.0f;
                    // Calculate the normal based on the cross product of the tangents.
                    Normals[i].x = (Tangents[i, 0].y * Tangents[i, 1].z - Tangents[i, 0].z * Tangents[i, 1].y);
                    Normals[i].y = 0 - (Tangents[i, 0].x * Tangents[i, 1].z - Tangents[i, 0].z * Tangents[i, 1].x);
                    Normals[i].z = (Tangents[i, 0].x * Tangents[i, 1].y - Tangents[i, 0].y * Tangents[i, 1].x);
                }
                break;

            default: Log("***** Unknown DataStream Type *****"); break;
            }
        }
        public override void Read(BinaryReader b)
        {
            base.Read(b);

            this.Flags2 = Utils.SwapUIntEndian(b.ReadUInt32()); // another filler
            uint tmpdataStreamType = Utils.SwapUIntEndian(b.ReadUInt32());

            this.DataStreamType  = (DataStreamTypeEnum)Enum.ToObject(typeof(DataStreamTypeEnum), tmpdataStreamType);
            this.NumElements     = Utils.SwapUIntEndian(b.ReadUInt32()); // number of elements in this chunk
            this.BytesPerElement = Utils.SwapUIntEndian(b.ReadUInt32());

            this.SkipBytes(b, 8);

            // Now do loops to read for each of the different Data Stream Types.  If vertices, need to populate Vector3s for example.
            switch (this.DataStreamType)
            {
                #region case DataStreamTypeEnum.VERTICES:

            case DataStreamTypeEnum.VERTICES:      // Ref is 0x00000000
                this.Vertices = new Vector3[this.NumElements];

                switch (BytesPerElement)
                {
                case 12:
                    for (Int32 i = 0; i < this.NumElements; i++)
                    {
                        this.Vertices[i].x = Utils.SwapSingleEndian(b.ReadSingle());
                        this.Vertices[i].y = Utils.SwapSingleEndian(b.ReadSingle());
                        this.Vertices[i].z = Utils.SwapSingleEndian(b.ReadSingle());
                    }
                    break;
                }
                break;

                #endregion
                #region case DataStreamTypeEnum.INDICES:

            case DataStreamTypeEnum.INDICES:      // Ref is
                this.Indices = new UInt32[NumElements];

                if (this.BytesPerElement == 2)
                {
                    for (Int32 i = 0; i < this.NumElements; i++)
                    {
                        this.Indices[i] = (UInt32)Utils.SwapUInt16Endian(b.ReadUInt16());
                    }
                }
                if (this.BytesPerElement == 4)
                {
                    for (Int32 i = 0; i < this.NumElements; i++)
                    {
                        this.Indices[i] = Utils.SwapUIntEndian(b.ReadUInt32());
                    }
                }
                break;

                #endregion
                #region case DataStreamTypeEnum.NORMALS:

            case DataStreamTypeEnum.NORMALS:
                this.Normals = new Vector3[this.NumElements];
                for (Int32 i = 0; i < NumElements; i++)
                {
                    this.Normals[i].x = Utils.SwapSingleEndian(b.ReadSingle());
                    this.Normals[i].y = Utils.SwapSingleEndian(b.ReadSingle());
                    this.Normals[i].z = Utils.SwapSingleEndian(b.ReadSingle());
                }
                //Utils.Log(LogLevelEnum.Debug, "Offset is {0:X}", b.BaseStream.Position);
                break;

                #endregion
                #region case DataStreamTypeEnum.UVS:

            case DataStreamTypeEnum.UVS:
                this.UVs = new UV[this.NumElements];
                for (Int32 i = 0; i < this.NumElements; i++)
                {
                    this.UVs[i].U = Utils.SwapSingleEndian(b.ReadSingle());
                    this.UVs[i].V = Utils.SwapSingleEndian(b.ReadSingle());
                }
                break;

                #endregion
                #region case DataStreamTypeEnum.TANGENTS:

            case DataStreamTypeEnum.TANGENTS:
                this.Tangents = new Tangent[this.NumElements, 2];
                this.Normals  = new Vector3[this.NumElements];
                for (Int32 i = 0; i < this.NumElements; i++)
                {
                    switch (this.BytesPerElement)
                    {
                    case 0x10:
                        // These have to be divided by 32767 to be used properly (value between 0 and 1)
                        this.Tangents[i, 0].x = Utils.SwapIntEndian(b.ReadInt16());
                        this.Tangents[i, 0].y = Utils.SwapIntEndian(b.ReadInt16());
                        this.Tangents[i, 0].z = Utils.SwapIntEndian(b.ReadInt16());
                        this.Tangents[i, 0].w = Utils.SwapIntEndian(b.ReadInt16());

                        this.Tangents[i, 1].x = Utils.SwapIntEndian(b.ReadInt16());
                        this.Tangents[i, 1].y = Utils.SwapIntEndian(b.ReadInt16());
                        this.Tangents[i, 1].z = Utils.SwapIntEndian(b.ReadInt16());
                        this.Tangents[i, 1].w = Utils.SwapIntEndian(b.ReadInt16());

                        break;

                    case 0x08:
                        // These have to be divided by 127 to be used properly (value between 0 and 1)
                        // Tangent
                        this.Tangents[i, 0].w = b.ReadSByte() / 127.0;
                        this.Tangents[i, 0].x = b.ReadSByte() / 127.0;
                        this.Tangents[i, 0].y = b.ReadSByte() / 127.0;
                        this.Tangents[i, 0].z = b.ReadSByte() / 127.0;

                        // Binormal
                        this.Tangents[i, 1].w = b.ReadSByte() / 127.0;
                        this.Tangents[i, 1].x = b.ReadSByte() / 127.0;
                        this.Tangents[i, 1].y = b.ReadSByte() / 127.0;
                        this.Tangents[i, 1].z = b.ReadSByte() / 127.0;

                        break;

                    default:
                        throw new Exception("Need to add new Tangent Size");
                    }
                }
                break;

                #endregion
                #region case DataStreamTypeEnum.COLORS:
            case DataStreamTypeEnum.COLORS:
                switch (this.BytesPerElement)
                {
                case 3:
                    this.RGBColors = new IRGB[this.NumElements];
                    for (Int32 i = 0; i < NumElements; i++)
                    {
                        this.RGBColors[i].r = b.ReadByte();
                        this.RGBColors[i].g = b.ReadByte();
                        this.RGBColors[i].b = b.ReadByte();
                    }
                    break;

                case 4:
                    this.RGBAColors = new IRGBA[this.NumElements];
                    for (Int32 i = 0; i < this.NumElements; i++)
                    {
                        this.RGBAColors[i].r = b.ReadByte();
                        this.RGBAColors[i].g = b.ReadByte();
                        this.RGBAColors[i].b = b.ReadByte();
                        this.RGBAColors[i].a = b.ReadByte();
                    }
                    break;

                default:
                    Utils.Log("Unknown Color Depth");
                    for (Int32 i = 0; i < this.NumElements; i++)
                    {
                        this.SkipBytes(b, this.BytesPerElement);
                    }
                    break;
                }
                break;

                #endregion
                #region case DataStreamTypeEnum.BONEMAP:
            case DataStreamTypeEnum.BONEMAP:
                SkinningInfo skin = GetSkinningInfo();
                skin.HasBoneMapDatastream = true;

                skin.BoneMapping = new List <MeshBoneMapping>();

                // Bones should have 4 bone IDs (index) and 4 weights.
                for (int i = 0; i < NumElements; i++)
                {
                    MeshBoneMapping tmpMap = new MeshBoneMapping();
                    switch (this.BytesPerElement)
                    {
                    case 8:
                        tmpMap.BoneIndex = new int[4];
                        tmpMap.Weight    = new int[4];

                        for (int j = 0; j < 4; j++)                 // read the 4 bone indexes first
                        {
                            tmpMap.BoneIndex[j] = b.ReadByte();
                        }
                        for (int j = 0; j < 4; j++)                   // read the weights.
                        {
                            tmpMap.Weight[j] = b.ReadByte();
                        }
                        skin.BoneMapping.Add(tmpMap);
                        break;

                    case 12:
                        tmpMap.BoneIndex = new int[4];
                        tmpMap.Weight    = new int[4];

                        for (int j = 0; j < 4; j++)                 // read the 4 bone indexes first
                        {
                            tmpMap.BoneIndex[j] = Utils.SwapUInt16Endian(b.ReadUInt16());
                        }
                        for (int j = 0; j < 4; j++)                   // read the weights.
                        {
                            tmpMap.Weight[j] = b.ReadByte();
                        }
                        skin.BoneMapping.Add(tmpMap);

                        break;

                    default:
                        Utils.Log("Unknown BoneMapping structure");
                        break;
                    }
                }

                break;

                #endregion
                #region DataStreamTypeEnum.Unknown1
            case DataStreamTypeEnum.UNKNOWN1:
                this.Tangents = new Tangent[this.NumElements, 2];
                this.Normals  = new Vector3[this.NumElements];
                for (Int32 i = 0; i < NumElements; i++)
                {
                    this.Tangents[i, 0].w = b.ReadSByte() / 127.0;
                    this.Tangents[i, 0].x = b.ReadSByte() / 127.0;
                    this.Tangents[i, 0].y = b.ReadSByte() / 127.0;
                    this.Tangents[i, 0].z = b.ReadSByte() / 127.0;

                    // Binormal
                    this.Tangents[i, 1].w = b.ReadSByte() / 127.0;
                    this.Tangents[i, 1].x = b.ReadSByte() / 127.0;
                    this.Tangents[i, 1].y = b.ReadSByte() / 127.0;
                    this.Tangents[i, 1].z = b.ReadSByte() / 127.0;

                    // Calculate the normal based on the cross product of the tangents.
                    this.Normals[i].x = (Tangents[i, 0].y * Tangents[i, 1].z - Tangents[i, 0].z * Tangents[i, 1].y);
                    this.Normals[i].y = 0 - (Tangents[i, 0].x * Tangents[i, 1].z - Tangents[i, 0].z * Tangents[i, 1].x);
                    this.Normals[i].z = (Tangents[i, 0].x * Tangents[i, 1].y - Tangents[i, 0].y * Tangents[i, 1].x);
                }
                break;
                #endregion // Prey normals?
                #region default:

            default:
                Utils.Log(LogLevelEnum.Debug, "***** Unknown DataStream Type *****");
                break;

                #endregion
            }
        }