/// <summary> /// Converts internal Mesh fields into Halo 2 compatible resource format /// </summary> /// <param name="resource_out">returns with array of Resource-meta structs represnting the blocks in the resource</param> /// <returns>array of bytes which holds the serialized Halo 2 resource</returns> public byte[] Serialize(out DResource[] resource_out, out DCompressionRanges compression_ranges, DCompressionRanges input_compression = null) { /* Intent: Write out the this Model instance data into a format that * the halo 2 version of blam! engine can use. * The resources that we will be focusing on are ShaderGroups, Indices, * Vertex position, texcoord, tangent space vectors, and a simple bonemap.*/ Log.Info(@"Entering Model.Serialize()"); if (input_compression == null) { input_compression = GenerateCompressionData(); } // Check that we have compression data available before continuing compression_ranges = input_compression; DResource[] resource = new DResource[7]; // Create resource defintion array MemoryStream buffer = new MemoryStream(); BinaryWriter bin = new BinaryWriter(buffer); // BinaryWriter Log.Info(string.Format(@"Writing header_tag @{0}", bin.BaseStream.Position)); bin.WriteFourCC("blkh"); // Write the header_tag value bin.Write(0); // [uint] resource_data_size (reserve) // * Begin resource_header // size: 112 Log.Info(string.Format(@"Writing shader_groups_count = {0} @{1}", Primitives.Length, bin.BaseStream.Position)); bin.Write(Primitives.Length); // * 0x00: shader_groups_count; bin.Write(new byte[28]); // * 0x08: some unused thing... count. Log.Info(string.Format(@"Writing indices_count = {0} @{1}", Indices.Length, bin.BaseStream.Position)); bin.Write(Indices.Length); // * 0x20: indices_count; bin.Write(new byte[20]); bin.Write(3); // * 0x38: vertex_resource_count; //special bin.Write(new byte[40]); bin.Write(1); // * 0x64: bone_map_count; bin.Write(new byte[8]); Log.Info(string.Format(@"Resource data_start_offset = {0}", bin.BaseStream.Position)); var resource_data_start_offset = bin.BaseStream.Position; // This is the offset to which all DResource block_offsets are written from bin.WriteFourCC("rsrc"); // shader_group resource begin resource[0] = new DResource(0, 72, Primitives.Length * 72, (int)(bin.BaseStream.Position - resource_data_start_offset)); foreach (var group in Primitives) bin.Write(group); // shader_group data bin.WriteFourCC("rsrc"); // indices resource begin resource[1] = new DResource(32, sizeof(ushort), sizeof(ushort) * this.Indices.Length, (int)(bin.BaseStream.Position - resource_data_start_offset)); foreach (ushort index in this.Indices) // write each index ushort bin.Write(index); // pad to word boundary bin.WritePadding(4); bin.WriteFourCC("rsrc"); // vertex_data_header? resource[2] = new DResource(56, 32, 32 * 3, (int)(bin.BaseStream.Position - resource_data_start_offset)); bin.Write(VERTEX_RESOURCE_HEADER_DATA); // laziness TODO: write out proper headers here to allow for other types bin.WriteFourCC("rsrc"); resource[3] = new DResource(56, 0, this.Coordinates.Length * sizeof(ushort) * 3, (int)(bin.BaseStream.Position - resource_data_start_offset), true); { foreach (var vertex in this.Coordinates) { bin.Write(Deflate(input_compression.X, vertex.X)); bin.Write(Deflate(input_compression.Y, vertex.Y)); bin.Write(Deflate(input_compression.Z, vertex.Z)); } bin.WritePadding(4); } bin.WriteFourCC("rsrc"); resource[4] = new DResource(56, 1, this.TextureCoordinates.Length * sizeof(ushort) * 2, (int)(bin.BaseStream.Position - resource_data_start_offset), true); { foreach (var vertex in this.TextureCoordinates) { bin.Write(Deflate(input_compression.U, vertex.X)); bin.Write(Deflate(input_compression.V, vertex.Y)); // flip this still? } } bin.WriteFourCC("rsrc"); resource[5] = new DResource(56, 2, this.Normals.Length * sizeof(uint) * 3, (int)(bin.BaseStream.Position - resource_data_start_offset), true); for(int i = 0; i < this.Normals.Length;++i) { bin.Write((uint)(Vector3t)Normals[i]); //cast to vector3t is destructive... bin.Write((uint)(Vector3t)Tangents[i]); bin.Write((uint)(Vector3t)Bitangents[i]); } bin.WriteFourCC("rsrc"); resource[6] = new DResource(100, 1, 1, (int)(bin.BaseStream.Position - resource_data_start_offset)); bin.Write(0); // default bone-map (no bones) bin.WriteFourCC("blkf"); int resource_size = (int)bin.BaseStream.Position; bin.Seek(4, SeekOrigin.Begin); bin.Write(resource_size - 124); // debug dump #if DEBUG try { using (var file = File.OpenWrite(@"D:\halo_2\model_raw.bin")) { file.Write(buffer.ToArray(), 0, (int)buffer.Length); } } catch { } #endif // end debug dump // 2. create a sections meta file for this, a bounding box, heck a whole mesh, why not. resource_out = resource; return buffer.ToArray(); }
public Resource(DResource dResource) : this() { this.SetDefinitionData(dResource); }