예제 #1
0
        /// <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();
        }
예제 #2
0
 public Resource(DResource dResource)
     : this()
 {
     this.SetDefinitionData(dResource);
 }