/// <summary> /// Read a single batch from BIN. /// </summary> /// <param name="br">The binaryreader to write with.</param> /// <param name="batchesOffset">Offset to batches.</param> public Batch(DhBinaryReader br, long batchesOffset) { // Read face count. FaceCount = br.ReadU16(); // Read primitive list size. ListSize = br.ReadS16(); // Read vertex attributes. VertexAttributes = (Attributes)br.ReadU32(); // Read UseNormals flag. UseNormals = br.ReadBool8(); // Read Position Winding. Positions = br.Read(); // Read UV Count. UvCount = br.Read(); // Read UseNBT flag. UseNBT = br.ReadBool8(); // Read Primitive offset. PrimitiveOffset = br.ReadU32(); // Read Unknown 1. (Padding?) Unknown1 = br.ReadS32s(2); // Save the current position. long currentPosition = br.Position(); // Go to the batch's primitive offset offset. br.Goto(batchesOffset + PrimitiveOffset); // Define list to hold batch's primitives. Primitives = new List <Primitive>(); // Define int to keep track of the amount of faces read. int readFaces = 0; // Read primitives until batch's face count has been reached. while ((readFaces < FaceCount) && (br.Position() < (batchesOffset + PrimitiveOffset + (ListSize << 5)))) { // Read primitive. Primitive binPrimitive = new Primitive(br, VertexAttributes, UseNBT); // Add the primitive to the batch's primitives. Primitives.Add(binPrimitive); // Add primitive's face count to the read faces counter. readFaces += binPrimitive.FaceCount; } // Go to the previously saved offset. br.Goto(currentPosition); }
/// <summary> /// Read a single texture from BIN. /// </summary> /// <param name="br">Binary Reader to use.</param> /// <param name="texturesOffset">Offset to textures.</param> public BinTexture(DhBinaryReader br, long texturesOffset) { // Read texture width. Width = br.ReadU16(); // Read texture height. Height = br.ReadU16(); // Read texture format. Format = br.ReadU8(); // Read texture unknown 1. (Flags?) Unknown1 = br.ReadU8(); // Read texture unknown 2. (Padding) Unknown2 = br.ReadU16(); // Read texture data offset. DataOffset = br.ReadU32(); // Save the current position. long currentPosition = br.Position(); // Go to the bin textures offset. br.Goto(texturesOffset); // Sail to the texture's data offset. br.Sail(DataOffset); // Read the texture's raw data. Data = br.Read((Width * Height) / 2); // Go to the previously saved offset. br.Goto(currentPosition); }
/// <summary> /// Read a single entry from JMP. /// </summary> /// <param name="br">Binary Reader to use.</param> /// <param name="fields">List of fields in JMP.</param> public JEntry(DhBinaryReader br, List <JField> fields) { long currentPosition = br.Position(); Values = new Dictionary <string, object>(); for (int i = 0; i < fields.Count; i++) { br.Sail(fields[i].Offset); object value; switch (fields[i].Type) { case JFieldType.INTEGER: value = ((br.ReadS32() & fields[i].Bitmask) >> fields[i].Shift); break; case JFieldType.STRING: value = br.ReadFixedStr(32); break; case JFieldType.FLOAT: value = br.ReadF32(); break; default: throw new InvalidDataException($"{fields[i].Type} is not a valid jmp entry type!"); } Values.Add(fields[i].Name, value); br.Goto(currentPosition); } }
/// <summary> /// Read a single entry from JMP. /// </summary> /// <param name="br">Binary Reader to use.</param> /// <param name="fields">List of fields in JMP.</param> public JEntry(DhBinaryReader br, List <JField> fields) { // Save the current position. long currentPosition = br.Position(); // Define a new object array to hold entry's values. Values = new object[fields.Count]; // Loop through each field in the JMP. for (int i = 0; i < fields.Count; i++) { // Seek from the current position to value's offset in the entry. br.Sail(fields[i].Offset); // Define a new object to hold our data. object value; // Check which type the current value is. switch (fields[i].Type) { case JFieldType.INTEGER: // Read the data as a integer. value = ((br.ReadS32() & fields[i].Bitmask) >> fields[i].Shift); break; case JFieldType.STRING: // Read the data as a 32-byte long string. value = br.ReadStr32(); break; case JFieldType.FLOAT: // Read the data as a float32. value = br.ReadF32(); break; default: // Something went horribly wrong. throw new InvalidDataException(); } // Set the value of this entry's value's data to the value we just read. Values[i] = value; // Seek back to the position we saved earlier. br.Goto(currentPosition); } }
public List <GraphObject> GetGraphObjects(DhBinaryReader br, int index) { // Save current offset. long currentPosition = br.Position(); // Goto a specific graph object offset based on it's index. br.Goto(Offsets[12] + (0x8C * index)); // Initialize the graph object at specific index. GraphObject graphObject = new GraphObject(br, Offsets[12]); // Goto previously saved offset. br.Goto(currentPosition); // Initialize a list to hold all graph objects. List <GraphObject> graphObjects = new List <GraphObject>(); // Add first graph object to list of graph objects. graphObjects.Add(graphObject); // Check if graph object specifies a child graph object. if (graphObject.ChildIndex >= 0) { // Add the child graph object (And it's child/next graph objects.) graphObjects.AddRange(GetGraphObjects(br, graphObject.ChildIndex)); } // Check if graph object specifies the next graph object. if (graphObject.NextIndex >= 0) { // Add the next graph object (And it's child/next graph objects.) graphObjects.AddRange(GetGraphObjects(br, graphObject.NextIndex)); } // Return the list of graph objects. return(graphObjects); }
/// <summary> /// Read a single graph object from BIN. /// </summary> /// <param name="br">Binary Reader to use.</param> /// <param name="graphObjectOffset">Offset to the graph objects.</param> public GraphObject(DhBinaryReader br, uint graphObjectOffset) // 112 bytes long { // Read Parent Index. ParentIndex = br.ReadS16(); // Read Child Index. ChildIndex = br.ReadS16(); // Read Next Index. NextIndex = br.ReadS16(); // Read Previous Index. PreviousIndex = br.ReadS16(); // Read Render Flags. RenderFlags = (GraphObjectRenderFlags)br.ReadU16(); // Unknown 1. (Padding?) Unknown1 = br.ReadU16(); // Read Scale. Scale = br.ReadVec3(); // Read Rotation. Rotation = br.ReadVec3(); // Read Position Position = br.ReadVec3(); // Read Bounding Box Minimum. BoundingBoxMinimum = br.ReadVec3(); // Read Bounding Box Maximum. BoundingBoxMaximum = br.ReadVec3(); // Read Bounding Sphere Radius. BoundingSphereRadius = br.ReadF32(); // Read Parent Index. PartCount = br.ReadS16(); // Unknown 3. (Padding?) Unknown3 = br.ReadU16(); // Read Parent Index. PartOffset = br.ReadS32(); // Unknown 4. (Padding?) Unknown4 = br.ReadU32s(7); // Initialize a new list to hold parts. Parts = new List <BinGraphObjectPart>(); // Offset to continue reading from. long currentPosition = br.Position(); // Goto graphobject's parts. br.Goto(graphObjectOffset + PartOffset); // Loop through parts. for (int i = 0; i < PartCount; i++) { // Read part and add it to the list of parts. Parts.Add(new BinGraphObjectPart(br)); } // Go back to return offset we saved earlier. br.Goto(currentPosition); }
/// <summary> /// Read a single batch from BIN. /// </summary> /// <param name="br">Binary Reader to use.</param> /// <param name="batchesOffset">Offset to batches.</param> public BinBatch(DhBinaryReader br, long batchesOffset) { // Read face count. FaceCount = br.ReadU16(); // Read primitive list size. ListSize = (ushort)(br.ReadS16() << 5); // Read vertex attributes. VertexAttributes = (BinBatchAttributes)br.ReadU32(); // Read UseNormals flag. UseNormals = br.Read(); // Read Position Winding. Positions = br.Read(); // Read UV Count. UvCount = br.Read(); // Read UseNBT flag. UseNBT = br.Read(); // Read Primitive offset. PrimitiveOffset = br.ReadU32(); // Define array to hold Unknown 1 values. Unknown1 = new int[2]; // Loop through Unknown 1 values. for (int i = 0; i < 2; i++) { // Read current Unknown 1 value. Unknown1[i] = br.ReadS32(); } // Save the current position. long currentPosition = br.Position(); // Go to the bin batches offset. br.Goto(batchesOffset); // Sail to the batches's primitive offset. br.Sail(PrimitiveOffset); // Define list to hold batch's primitives. Primitives = new List <BinPrimitive>(); // Define int to hold amount of faces read. int readFaces = 0; // Read primitives until batch's face count has been reached. while (readFaces < FaceCount && br.Position() < (batchesOffset + PrimitiveOffset + ListSize)) { // Read primitive. BinPrimitive binPrimitive = new BinPrimitive(br, UseNBT, UvCount, VertexAttributes); // Add the primitive to the batch's primitives. Primitives.Add(binPrimitive); // Add primitive's face count to the read faces counter. readFaces += binPrimitive.FaceCount; } // Go to the previously saved offset. br.Goto(currentPosition); }
public MDL(byte[] data) { // Define a binary reader to read with. DhBinaryReader br = new DhBinaryReader(data, DhEndian.Big); Header = new MDLHeader(br); br.Goto(Header.MatricesOffset); Matrices = new Mat4[Header.JointCount + Header.WeightCount]; for (int i = 0; i < Matrices.Length; i++) { Matrices[i] = Mat4.Identity; } for (int i = 0; i < Header.JointCount; i++) { float[] matrix = br.ReadF32s(12); Matrices[i] = new Mat4() { Row1 = new Vec4(matrix[0], matrix[1], matrix[2], matrix[3]), Row2 = new Vec4(matrix[4], matrix[5], matrix[6], matrix[7]), Row3 = new Vec4(matrix[8], matrix[9], matrix[10], matrix[11]), Row4 = new Vec4(0, 0, 0, 1), }; } br.Goto(Header.PositionOffset); Positions = br.ReadVec3s(Header.PositionCount).ToList(); br.Goto(Header.NormalOffset); Normals = br.ReadVec3s(Header.NormalCount).ToList(); br.Goto(Header.ColorOffset); Colors = br.ReadClr4s(Header.ColorCount).ToList(); br.Goto(Header.TextureCoordinateOffset); TextureCoordinates = br.ReadVec2s(Header.TextureCoordinateCount).ToList(); br.Goto(Header.PacketOffset); Packets = new List <MDLShapePacket>(); for (int i = 0; i < Header.PacketCount; i++) { Packets.Add(new MDLShapePacket(br)); } br.Goto(Header.ShapeOffset); Shapes = new List <MDLShape>(); for (int i = 0; i < Header.ShapeCount; i++) { Shapes.Add(new MDLShape(br, Packets)); } foreach (MDLShape shape in Shapes) { ushort[] matrixIndices = new ushort[10]; foreach (MDLShapePacket packet in shape.Packets) { for (int m = 0; m < packet.MatrixCount; m++) { if (packet.MatrixIndices[m] == ushort.MaxValue) { continue; } matrixIndices[m] = packet.MatrixIndices[m]; } DhBinaryReader reader = new DhBinaryReader(packet.Data, DhEndian.Big); while (reader.Position() < packet.DataSize) { ShapePacketData packetData = new ShapePacketData(); packetData.PrimitiveType = reader.ReadU8(); if (packetData.PrimitiveType == 0x00) { continue; } packetData.VertexCount = reader.ReadU16(); for (int i = 0; i < packetData.VertexCount; i++) { MDLVertex vertex = new MDLVertex(reader, Header, shape.UseNbt); if (vertex.MatrixIndex != -1) { vertex.MatrixDataIndex = matrixIndices[(vertex.MatrixIndex / 3)]; } packetData.Vertices.Add(vertex); } packet.PacketData.Add(packetData); } } } br.Goto(Header.TextureLocationOffset); Textures = new List <BTI>(); for (int i = 0; i < Header.TextureCount; i++) { uint offset = br.ReadU32(); long currentPosition = br.Position(); br.Goto(offset); BTI bti = new BTI(br, offset, Header.TextureLocationOffset); Textures.Add(bti); br.Goto(currentPosition); } br.Goto(Header.SamplerOffset); Samplers = new List <MDLSampler>(); for (int i = 0; i < Header.SamplerCount; i++) { Samplers.Add(new MDLSampler(br)); } br.Goto(Header.MaterialOffset); Materials = new List <MDLMaterial>(); for (int i = 0; i < Header.MaterialCount; i++) { Materials.Add(new MDLMaterial(br, Samplers)); } br.Goto(Header.DrawElementOffset); DrawElements = new List <MDLDrawElement>(); for (int i = 0; i < Header.DrawElementCount; i++) { DrawElements.Add(new MDLDrawElement(br, Materials, Shapes)); } br.Goto(Header.NodeOffset); Nodes = new List <MDLNode>(); for (int i = 0; i < Header.NodeCount; i++) { Nodes.Add(new MDLNode(br, DrawElements)); } }
/// <summary> /// Reads BIN from a stream. /// </summary> /// <param name="stream">The stream containing the BIN data.</param> public BIN(Stream stream) { // Define a binary reader to read with. DhBinaryReader br = new DhBinaryReader(stream, DhEndian.Big); // Read bin version. Version = br.Read(); // Make sure the bin version is either 0x01 or 0x02. if (Version == 0x00 || Version > 0x02) { throw new Exception(string.Format("{0} is not a valid bin version!", Version.ToString())); } // Read bin model name. ModelName = br.ReadStr(11).Trim('\0'); // Define a new list to hold the bin's offsets. Offsets = new List <uint>(); // Loop through the bin's offsets. for (int i = 0; i < 21; i++) { // Read offset and add it to the offsets list. Offsets.Add(br.ReadU32()); } // Go to the bin textures offset. br.Goto(Offsets[0]); // Define a new list to hold the bin's textures. Textures = new List <BinTexture>(); // Loop through bin's textures. TODO: This is static for now, add automatic texture count. for (int i = 0; i < 3; i++) { // Read texture and add it to the textures list. Textures.Add(new BinTexture(br, Offsets[0])); } // Go to the bin materials offset. br.Goto(Offsets[1]); // Define a new list to hold the bin's materials. Materials = new List <BinMaterial>(); // Loop through bin's materials. TODO: This is static for now, add automatic material count. for (int i = 0; i < 3; i++) { // Read texture and add it to the materials list. Materials.Add(new BinMaterial(br)); } // Go to the bin positions offset. br.Goto(Offsets[2]); // Define a new list to hold the bin's positions. Positions = new List <Vector3>(); // Loop through bin's positions. TODO: Fix this; This is a pretty shitty way to calculate amount of bin positions ... for (int i = 0; i < ((Math.Floor((decimal)(Offsets[3] - Offsets[2])) / 6) - 1); i++) { // Skip 6 bytes to "simulate" reading a bin position. br.Skip(6); // Make sure the currenet position has not passed the normals offset. if (!(br.Position() > Offsets[3])) { // Go back 6 bytes as we just "simulated" to read a bin position. br.Goto(br.Position() - 6); // Read a position and add it to the positions list. Positions.Add(new Vector3(br.ReadF16(), br.ReadF16(), br.ReadF16())); } } // Go to the bin normals offset. br.Goto(Offsets[3]); // Define a new list to hold the bin's normals. Normals = new List <Vector3>(); // Loop through bin's normals. TODO: This is static for now, add automatic normal count. for (int i = 0; i < 69; i++) { // Read a normal and add it to the normals list. Normals.Add(new Vector3(br.ReadF32(), br.ReadF32(), br.ReadF32())); } // Go to the bin texture coordinates offset. br.Goto(Offsets[6]); // Define a new list to hold the bin's texture coordinates. TextureCoordinates = new List <BinTextureCoordinate>(); // Loop through bin's texture coordinates. TODO: This is static for now, add automatic texture coordinates count. for (int i = 0; i < 72; i++) { // Read a bin texture coordinates and add it to the texture coordinates list. TextureCoordinates.Add(new BinTextureCoordinate(br)); } // Go to the bin shaders offset. br.Goto(Offsets[10]); // Define a new list to hold the bin's shaders. Shaders = new List <BinShader>(); // Loop through bin's shaders. TODO: This is static for now, add automatic shader count. for (int i = 0; i < 3; i++) { // Read a bin shader and add it to the shaders list. Shaders.Add(new BinShader(br)); } // Go to the bin batches offset. br.Goto(Offsets[11]); // Define a new list to hold the bin's batches. Batches = new List <BinBatch>(); // Loop through bin's batches. TODO: This is static for now, add automatic batch count. for (int i = 0; i < 2; i++) { // Read a bin batch and add it to the batches list. Batches.Add(new BinBatch(br, Offsets[11])); } }
/// <summary> /// Reads MP from a byte array. /// </summary> /// <param name="data">The byte array containing the MP data.</param> public MP(byte[] data) { // Define a binary reader to read with. DhBinaryReader br = new DhBinaryReader(data, DhEndian.Big); // Read Grid Scale. GridScale = br.ReadVec3(); // Read Minimum Bounds. MinimumBounds = br.ReadVec3(); // Read Axis Lengths. AxisLengths = br.ReadVec3(); // Define new array to hold offsets. Offsets = new int[7]; // Loop through our offsets. for (int i = 0; i < 7; i++) { // Read offset and store it to the offsets array. Offsets[i] = br.ReadS32(); } // Go to mp's vertex data offset. br.Goto(Offsets[0]); // Calculate amount of vertices. int verticeCount = (Offsets[1] - Offsets[0]) / 12; // Define new list to hold vertices. Vertices = new List <Vec3>(); // Loop through vertices. for (int i = 0; i < verticeCount; i++) { // Read vertex and add it to the list of vertices. Vertices.Add(br.ReadVec3()); } // Go to mp's normals offset. br.Goto(Offsets[1]); // Calculate amount of normals. int normalCount = (Offsets[2] - Offsets[1]) / 12; // Define new list to hold normals. Normals = new List <Vec3>(); // Loop through normals. for (int i = 0; i < normalCount; i++) { // Read normal and add it to the normal list. Normals.Add(br.ReadVec3()); } // Go to mp's triangle data offset. br.Goto(Offsets[2]); // Calculate amount of triangles. int triangleDataCount = (Offsets[3] - Offsets[2]) / 24; // Define new list to hold triangle data. TriangleData = new List <TriangleData>(); // Loop through triangles. for (int i = 0; i < triangleDataCount; i++) { // Read triangle and add it to the triangle data list. TriangleData.Add(new TriangleData(br)); } // Go to mp's triangle group offset. br.Goto(Offsets[3]); // Define new list to hold triangle groups. TriangleGroups = new List <TriangleGroup>(); // Make sure first ushort is 0xFFFF. if (br.ReadU16() != 0xFFFF) { throw new FormatException("Start of triangle groups section was not 0xFFFF!"); } // We'll read triangle groups as long as we're not entering the next section. while (br.Position() < Offsets[4] - 2) { // Read group and add it to the groups list. TriangleGroups.Add(new TriangleGroup(br)); } // Make sure last ushort is 0xFFFF. if (br.ReadU16() != 0xFFFF) { throw new FormatException("End of triangle groups section was not 0xFFFF!"); } // Go to mp's grid index offset. br.Goto(Offsets[4]); // Calculate amount of grid index entries. (Offset 5 is a duplicate of offset 4) int gridIndexCount = (Offsets[6] - Offsets[4]) / 8; // Define new list to hold grid indices. GridIndices = new List <GridIndex>(); // Loop through grid indices. for (int i = 0; i < gridIndexCount; i++) { GridIndices.Add(new GridIndex(br)); } // Go to mp's unknown offset. br.Goto(Offsets[6]); // Define new list to hold unknown data. Unknowns = new List <Unknown>(); // We'll read unknowns as long as we're not reading padding EOF. while (br.Position() < br.GetStream().Length) { // Check if next byte is 0xFF. (More data) if (br.Read() == 0xFF) { // Jump back a byte, since we checked for data. br.Sail(-1); // Read unknown and add it to the unknowns list. Unknowns.Add(new Unknown(br)); } else { // We've reached padding, stop reading. break; } } }