Example #1
0
        public float SumOfDistances(IRGBA second)
        {
            float dist = Math.Abs(R - second.R) +
                         Math.Abs(G - second.G) + Math.Abs(B - second.B);

            return(dist);
        }
Example #2
0
 public bool RGBAEqual(IRGBA other)
 {
     if (other.A == 0 && A == 0)
     {
         return(true);
     }
     return(R == other.R && G == other.G && B == other.B && A == other.A);
 }
Example #3
0
        public RGBA Mix(IRGBA c2, byte?alpha)
        {
            RGBA color2 = c2.Value;

            color2.Change(alpha);
            var color = Blend(this, color2);

            color.Change((byte)(color2.A + ((color2.A * (255 - color2.A)) >> 8)));
            return(color);
        }
Example #4
0
        public RGBA GetGradient(IRGBA second, float k)
        {
            float r, g, b, a;

            r = (float)(R + (second.R - R) * k);
            g = (float)(G + (second.G - G) * k);
            b = (float)(B + (second.B - B) * k);
            a = (float)(A + (second.A - A) * k);
            return(new RGBA(r, g, b, a));
        }
Example #5
0
        public RGBA Lerp(IRGBA to, float amount)
        {
            // start colours as lerp-able floats
            float sr = R, sg = G, sb = B;

            // end colours as lerp-able floats
            float er = to.R, eg = to.G, eb = to.B;

            // lerp the colours to get the difference
            byte r = (byte)Lerp(sr, er, amount),
                 g = (byte)Lerp(sg, eg, amount),
                 b = (byte)Lerp(sb, eb, amount);

            // return the new colour
            return(new RGBA(r, g, b, (byte)255));
        }
Example #6
0
        public RGBA GetTweenColor(IRGBA second, float RatioOf2)
        {
            if (RatioOf2 <= 0)
            {
                return(this);
            }

            if (RatioOf2 >= 1f)
            {
                return(new RGBA(second.R, second.G, second.B, second.A));
            }

            // figure out how much of each color we should be.
            float RatioOf1 = 1f - RatioOf2;

            return(new RGBA(
                       R * RatioOf1 + second.R * RatioOf2,
                       G * RatioOf1 + second.G * RatioOf2,
                       B * RatioOf1 + second.B * RatioOf2));
        }
Example #7
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;
            }
        }
Example #8
0
 public RGBA(IRGBA c, float newAlpha) :
     this(c.R, c.G, c.B, (byte)(newAlpha * 255))
 {
 }
Example #9
0
 bool IEquatable <IRGBA> .Equals(IRGBA c) =>
 c.R == R && c.G == G && c.B == B && c.A == A;
Example #10
0
 public RGBA(IRGBA c, byte newAlpha) :
     this(c.R, c.G, c.B, newAlpha)
 {
 }
Example #11
0
 public RGBA Blend(IRGBA c2, float e0 = 0)
 {
     return(Colours.Blend(this, c2.Value, e0));
 }
Example #12
0
        public override void Read(BinaryReader b)
        {
            base.Read(b);

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

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

            if (_model.FileVersion == FileVersionEnum.CryTek_3_5 || _model.FileVersion == FileVersionEnum.CryTek_3_4)
            {
                BytesPerElement = b.ReadUInt32();
            }
            if (_model.FileVersion == FileVersionEnum.CryTek_3_6)
            {
                BytesPerElement = (uint)b.ReadInt16();        // Star Citizen 2.0 is using an int16 here now.
                b.ReadInt16();                                // unknown value.   Doesn't look like padding though.
            }

            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 (DataStreamType)
            {
                #region case DataStreamTypeEnum.VERTICES:

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

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

                case 8:          // Prey files, and old Star Citizen files
                    for (int i = 0; i < NumElements; i++)
                    {
                        //uint bver = 0;
                        //float ver = 0;

                        // 2 byte floats.  Use the Half structure from TK.Math
                        //bver = b.ReadUInt16();
                        //ver = Byte4HexToFloat(bver.ToString("X8"));
                        //Vertices[i].x = ver;

                        //bver = b.ReadUInt16();
                        //ver = Byte4HexToFloat(bver.ToString("X8"));
                        //Vertices[i].y = ver; bver = b.ReadUInt16();

                        //bver = b.ReadUInt16();
                        //ver = Byte4HexToFloat(bver.ToString("X8"));
                        //Vertices[i].z = ver;

                        //bver = b.ReadUInt16();
                        //ver = Byte4HexToFloat(bver.ToString("X8"));
                        //Vertices[i].w = ver;
                        Half xshort = new Half();
                        xshort.bits   = b.ReadUInt16();
                        Vertices[i].x = xshort.ToSingle();

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

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

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

                #endregion
                #region case DataStreamTypeEnum.INDICES:

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

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

                #endregion
                #region case DataStreamTypeEnum.NORMALS:

            case DataStreamTypeEnum.NORMALS:
                Normals = new Vector3[NumElements];
                for (int i = 0; i < NumElements; i++)
                {
                    Normals[i].x = b.ReadSingle();
                    Normals[i].y = b.ReadSingle();
                    Normals[i].z = b.ReadSingle();
                }
                break;

                #endregion
                #region case DataStreamTypeEnum.UVS:

            case DataStreamTypeEnum.UVS:
                UVs = new UV[NumElements];
                for (Int32 i = 0; i < NumElements; i++)
                {
                    UVs[i].U = b.ReadSingle();
                    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:
                Tangents = new Tangent[NumElements, 2];
                Normals  = new Vector3[NumElements];
                for (int 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 = b.ReadInt16();
                        Tangents[i, 0].y = b.ReadInt16();
                        Tangents[i, 0].z = b.ReadInt16();
                        Tangents[i, 0].w = b.ReadInt16();

                        Tangents[i, 1].x = b.ReadInt16();
                        Tangents[i, 1].y = b.ReadInt16();
                        Tangents[i, 1].z = b.ReadInt16();
                        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
                        Tangents[i, 0].w = b.ReadSByte() / 127.0;
                        Tangents[i, 0].x = b.ReadSByte() / 127.0;
                        Tangents[i, 0].y = b.ReadSByte() / 127.0;
                        Tangents[i, 0].z = b.ReadSByte() / 127.0;

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

                        // 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");
                    }
                }
                // Utils.Log(LogLevelEnum.Debug, "Offset is {0:X}", b.BaseStream.Position);
                break;

                #endregion
                #region case DataStreamTypeEnum.COLORS:

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

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

                default:
                    Utils.Log("Unknown Color Depth");
                    for (int i = 0; i < NumElements; i++)
                    {
                        SkipBytes(b, 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...");
                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   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 (int i = 0; i < NumElements; i++)
                    {
                        Vertices[i].x = b.ReadSingle();
                        Vertices[i].y = b.ReadSingle();
                        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.
                        Normals[i].x = (float)b.ReadSByte() / 127;
                        Normals[i].y = (float)b.ReadSByte() / 127;
                        Normals[i].z = (float)b.ReadSByte() / 127;
                        b.ReadSByte();         // Should be FF.

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

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

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

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

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

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

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

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

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

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

                        //Normals[i].x = (b.ReadByte() - 128.0f) / 127.5f;
                        //Normals[i].y = (b.ReadByte() - 128.0f) / 127.5f;
                        //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;
                        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.
                        Half uvu = new Half();
                        uvu.bits = b.ReadUInt16();
                        UVs[i].U = uvu.ToSingle();

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

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

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

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

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

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

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

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

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

                default:
                    Utils.Log("Unknown VertUV structure");
                    for (Int32 i = 0; i < NumElements; i++)
                    {
                        SkipBytes(b, 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 (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:
                Tangents = new Tangent[NumElements, 2];
                Normals  = new Vector3[NumElements];
                for (int i = 0; i < NumElements; i++)
                {
                    Tangents[i, 0].w = b.ReadSByte() / 127.0;
                    Tangents[i, 0].x = b.ReadSByte() / 127.0;
                    Tangents[i, 0].y = b.ReadSByte() / 127.0;
                    Tangents[i, 0].z = b.ReadSByte() / 127.0;

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

                    // 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;
                #endregion // Prey normals?
                #region default:

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

                #endregion
            }
        }