// 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 } }
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 } }