A serialization context for serializing and deserializing resource definition structures.
Inheritance: ISerializationContext
        public override bool Execute(List<string> args)
        {
            if (args.Count != 0)
                return false;

            // Load resource caches
            Console.WriteLine("Loading resource caches...");
            var resourceManager = new ResourceDataManager();
            try
            {
                resourceManager.LoadCachesFromDirectory(Info.CacheFile.DirectoryName);
            }
            catch
            {
                Console.WriteLine("Unable to load the resource .dat files.");
                Console.WriteLine("Make sure that they all exist and are valid.");
                return true;
            }

            if (BSP.CollisionBSPResource == null)
            {
                Console.WriteLine("Collision BSP does not have a resource associated with it.");
                return true;
            }

            // Deserialize the collision resource definition
            var resourceContext = new ResourceSerializationContext(BSP.CollisionBSPResource);
            var definition = Info.Deserializer.Deserialize<CollisionBSPResourceDefinition>(resourceContext);

            // Reserialize the collision resource definition
            Info.Serializer.Serialize(resourceContext, definition);

            // Reserialize the tag definition
            using (var cacheStream = Info.OpenCacheReadWrite())
            {
                var tagContext = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, Tag);
                Info.Serializer.Serialize(tagContext, BSP);
            }

            return true;
        }
Esempio n. 2
0
        public void ExtractDds(TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream outStream)
        {
            // TODO: Make sure 3D textures and cube maps work

            // Deserialize the resource definition and verify it
            var resource = bitmap.Resources[imageIndex];
            var resourceContext = new ResourceSerializationContext(resource.Resource);
            var definition = deserializer.Deserialize<BitmapTextureResourceDefinition>(resourceContext);
            if (definition.Texture == null || definition.Texture.Definition == null)
                throw new ArgumentException("Invalid bitmap definition");
            var dataReference = definition.Texture.Definition.Data;
            if (dataReference.Address.Type != ResourceAddressType.Resource)
                throw new InvalidOperationException("Invalid resource data address");

            var header = CreateDdsHeader(definition);
            var resourceDataStream = new MemoryStream();
            _resourceManager.Extract(resource.Resource, resourceDataStream);
            header.WriteTo(outStream);
            resourceDataStream.Position = dataReference.Address.Offset;
            StreamUtil.Copy(resourceDataStream, outStream, dataReference.Size);
        }
Esempio n. 3
0
        public void InjectDds(TagSerializer serializer, TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream ddsStream)
        {
            var resource = bitmap.Resources[imageIndex].Resource;
            var newResource = (resource == null);
            ResourceSerializationContext resourceContext;
            BitmapTextureResourceDefinition definition;
            if (newResource)
            {
                // Create a new resource reference
                resource = new ResourceReference
                {
                    DefinitionFixups = new List<ResourceDefinitionFixup>(),
                    D3DObjectFixups = new List<D3DObjectFixup>(),
                    Type = 1, // TODO: Map out this type enum instead of using numbers
                    Unknown68 = 1
                };
                bitmap.Resources[imageIndex].Resource = resource;
                resourceContext = new ResourceSerializationContext(resource);
                definition = new BitmapTextureResourceDefinition
                {
                    Texture = new D3DPointer<BitmapTextureResourceDefinition.BitmapDefinition>
                    {
                        Definition = new BitmapTextureResourceDefinition.BitmapDefinition()
                    }
                };
            }
            else
            {
                // Deserialize the old definition
                resourceContext = new ResourceSerializationContext(resource);
                definition = deserializer.Deserialize<BitmapTextureResourceDefinition>(resourceContext);
            }
            if (definition.Texture == null || definition.Texture.Definition == null)
                throw new ArgumentException("Invalid bitmap definition");
            var texture = definition.Texture.Definition;
            var imageData = bitmap.Images[imageIndex];

            // Read the DDS header and modify the definition to match
            var dds = DdsHeader.Read(ddsStream);
            var dataSize = (int)(ddsStream.Length - ddsStream.Position);
            texture.Data = new ResourceDataReference(dataSize, new ResourceAddress(ResourceAddressType.Resource, 0));
            texture.Width = (short)dds.Width;
            texture.Height = (short)dds.Height;
            texture.Depth = (sbyte)Math.Max(1, dds.Depth);
            texture.Levels = (sbyte)Math.Max(1, dds.MipMapCount);
            texture.Type = BitmapDdsFormatDetection.DetectType(dds);
            texture.D3DFormatUnused = (int)((dds.D3D10Format != DxgiFormat.Bc5UNorm) ? dds.FourCc : DdsFourCc.FromString("ATI2"));
            texture.Format = BitmapDdsFormatDetection.DetectFormat(dds);

            // Set flags based on the format
            switch (texture.Format)
            {
                case BitmapFormat.Dxt1:
                case BitmapFormat.Dxt3:
                case BitmapFormat.Dxt5:
                case BitmapFormat.Dxn:
                    texture.Flags = BitmapFlags.Compressed;
                    break;
                default:
                    texture.Flags = BitmapFlags.None;
                    break;
            }
            if ((texture.Width & (texture.Width - 1)) == 0 && (texture.Height & (texture.Height - 1)) == 0)
                texture.Flags |= BitmapFlags.PowerOfTwoDimensions;

            // If creating a new image, then add a new resource, otherwise replace the existing one
            if (newResource)
                _resourceManager.Add(resource, ResourceLocation.Textures, ddsStream);
            else
                _resourceManager.Replace(resource, ddsStream);

            // Serialize the new resource definition
            serializer.Serialize(resourceContext, definition);

            // Modify the image data in the bitmap tag to match the definition
            imageData.Width = texture.Width;
            imageData.Height = texture.Height;
            imageData.Depth = texture.Depth;
            imageData.Type = texture.Type;
            imageData.Format = texture.Format;
            imageData.Flags = texture.Flags;
            imageData.MipmapCount = (sbyte)(texture.Levels - 1);
            imageData.DataOffset = texture.Data.Address.Offset;
            imageData.DataSize = texture.Data.Size;
            imageData.Unknown15 = texture.Unknown35;
        }
Esempio n. 4
0
 public ResourceDataBlock(ResourceSerializationContext context)
 {
     _context = context;
     Stream   = new MemoryStream();
     Writer   = new BinaryWriter(Stream);
 }
 public ResourceDataBlock(ResourceSerializationContext context)
 {
     _context = context;
     Stream = new MemoryStream();
     Writer = new BinaryWriter(Stream);
 }
        public override bool Execute(List<string> args)
        {
            if (args.Count != 3)
                return false;

            var variantName = args[0];
            var fileType = args[1];
            var fileName = args[2];

            if (fileType != "obj" && fileType != "amf")
                return false;

            // Find the variant to extract
            if (Definition.RenderModel == null)
            {
                Console.WriteLine("The model does not have a render model associated with it.");
                return true;
            }

            var variant = Definition.Variants.FirstOrDefault(v => (Info.StringIDs.GetString(v.Name) ?? v.Name.ToString()) == variantName);
            if (variant == null && Definition.Variants.Count > 0)
            {
                Console.WriteLine("Unable to find variant \"{0}\"", variantName);
                Console.WriteLine("Use \"listvariants\" to list available variants.");
                return true;
            }

            if (fileType == "amf")
                return ExtractAMF(variant, fileName);

            // Load resource caches
            Console.WriteLine("Loading resource caches...");
            var resourceManager = new ResourceDataManager();
            try
            {
                resourceManager.LoadCachesFromDirectory(Info.CacheFile.DirectoryName);
            }
            catch
            {
                Console.WriteLine("Unable to load the resource .dat files.");
                Console.WriteLine("Make sure that they all exist and are valid.");
                return true;
            }

            // Deserialize the render model tag
            Console.WriteLine("Reading model data...");
            RenderModel renderModel;
            using (var cacheStream = Info.CacheFile.OpenRead())
            {
                var renderModelContext = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, Definition.RenderModel);
                renderModel = Info.Deserializer.Deserialize<RenderModel>(renderModelContext);
            }

            if (renderModel.Geometry.Resource == null)
            {
                Console.WriteLine("Render model does not have a resource associated with it");
                return true;
            }

            // Deserialize the resource definition
            var resourceContext = new ResourceSerializationContext(renderModel.Geometry.Resource);
            var definition = Info.Deserializer.Deserialize<RenderGeometryResourceDefinition>(resourceContext);

            using (var resourceStream = new MemoryStream())
            {
                // Extract the resource data
                resourceManager.Extract(renderModel.Geometry.Resource, resourceStream);

                Directory.CreateDirectory(Path.GetDirectoryName(fileName));

                using (var objFile = new StreamWriter(File.Open(fileName, FileMode.Create, FileAccess.Write)))
                {
                    var objExtractor = new ObjExtractor(objFile);
                    var vertexCompressor = new VertexCompressor(renderModel.Geometry.Compression[0]); // Create a (de)compressor from the first compression block

                    if (variant != null)
                    {
                        // Extract each region in the variant
                        foreach (var region in variant.Regions)
                        {
                            // Get the corresonding region in the render model tag
                            if (region.RenderModelRegionIndex >= renderModel.Regions.Count)
                                continue;

                            var renderModelRegion = renderModel.Regions[region.RenderModelRegionIndex];

                            // Get the corresponding permutation in the render model tag
                            // (Just extract the first permutation for now)
                            if (region.Permutations.Count == 0)
                                continue;

                            var permutation = region.Permutations[0];

                            if (permutation.RenderModelPermutationIndex < 0 ||
                                permutation.RenderModelPermutationIndex >= renderModelRegion.Permutations.Count)
                                continue;

                            var renderModelPermutation = renderModelRegion.Permutations[permutation.RenderModelPermutationIndex];

                            // Extract each mesh in the permutation
                            var meshIndex = renderModelPermutation.MeshIndex;
                            var meshCount = renderModelPermutation.MeshCount;
                            var regionName = Info.StringIDs.GetString(region.Name) ?? region.Name.ToString();
                            var permutationName = Info.StringIDs.GetString(permutation.Name) ?? permutation.Name.ToString();

                            Console.WriteLine("Extracting {0} mesh(es) for {1}:{2}...", meshCount, regionName, permutationName);

                            for (var i = 0; i < meshCount; i++)
                            {
                                // Create a MeshReader for the mesh and pass it to the obj extractor
                                var meshReader = new MeshReader(Info.Version, renderModel.Geometry.Meshes[meshIndex + i], definition);
                                objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream);
                            }
                        }
                    }
                    else
                    {
                        // No variant - just extract every mesh
                        Console.WriteLine("Extracting {0} mesh(es)...", renderModel.Geometry.Meshes.Count);

                        foreach (var mesh in renderModel.Geometry.Meshes)
                        {
                            // Create a MeshReader for the mesh and pass it to the obj extractor
                            var meshReader = new MeshReader(Info.Version, mesh, definition);
                            objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream);
                        }
                    }

                    objExtractor.Finish();
                }
            }
            Console.WriteLine("Done!");
            return true;
        }
        private bool ExtractAMF(Model.Variant variant, string fileName)
        {
            // Load resource caches
            Console.WriteLine("Loading resource caches...");
            var resourceManager = new ResourceDataManager();
            try
            {
                resourceManager.LoadCachesFromDirectory(Info.CacheFile.DirectoryName);
            }
            catch
            {
                Console.WriteLine("Unable to load the resource .dat files.");
                Console.WriteLine("Make sure that they all exist and are valid.");
                return true;
            }

            // Deserialize the render model tag
            Console.WriteLine("Reading model data...");
            RenderModel renderModel;
            using (var cacheStream = Info.CacheFile.OpenRead())
            {
                var renderModelContext = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, Definition.RenderModel);
                renderModel = Info.Deserializer.Deserialize<RenderModel>(renderModelContext);
            }

            if (renderModel.Geometry.Resource == null)
            {
                Console.WriteLine("Render model does not have a resource associated with it");
                return true;
            }

            // Deserialize the resource definition
            var resourceContext = new ResourceSerializationContext(renderModel.Geometry.Resource);
            var definition = Info.Deserializer.Deserialize<RenderGeometryResourceDefinition>(resourceContext);

            using (var resourceStream = new MemoryStream())
            {
                // Extract the resource data
                resourceManager.Extract(renderModel.Geometry.Resource, resourceStream);

                var regionMeshes = new Dictionary<string, Mesh>();

                foreach (var region in variant.Regions)
                {
                    regionMeshes[Info.StringIDs.GetString(region.Name)] = renderModel.Geometry.Meshes[region.RenderModelRegionIndex];
                }

                var headerAddressList = new List<int>();
                var headerValueList = new List<int>();
                var markerAddressList = new List<int>();
                var markerValueList = new List<int>();
                var permAddressList = new List<int>();
                var permValueList = new List<int>();
                var vertAddressList = new List<int>();
                var indxAddressList = new List<int>();
                var meshAddressList = new List<int>();

                using (var bw = new BinaryWriter(File.Create(fileName)))
                {
                    #region Header
                    bw.Write("AMF!".ToCharArray());
                    bw.Write(2.0f); //format version
                    bw.Write((Info.StringIDs.GetString(renderModel.Name) + "\0").ToCharArray());

                    bw.Write(renderModel.Nodes.Count);
                    headerAddressList.Add((int)bw.BaseStream.Position);
                    bw.Write(0);

                    bw.Write(renderModel.MarkerGroups.Count);
                    headerAddressList.Add((int)bw.BaseStream.Position);
                    bw.Write(0);

                    bw.Write(regionMeshes.Count);
                    headerAddressList.Add((int)bw.BaseStream.Position);
                    bw.Write(0);

                    bw.Write(renderModel.Materials.Count);
                    headerAddressList.Add((int)bw.BaseStream.Position);
                    bw.Write(0);
                    #endregion
                    #region Nodes
                    headerValueList.Add((int)bw.BaseStream.Position);
                    foreach (var node in renderModel.Nodes)
                    {
                        bw.Write((Info.StringIDs.GetString(node.Name) + "\0").ToCharArray());
                        bw.Write((short)node.ParentNode);
                        bw.Write((short)node.FirstChildNode);
                        bw.Write((short)node.NextSiblingNode);
                        bw.Write(node.DefaultTranslation.X * 100);
                        bw.Write(node.DefaultTranslation.Y * 100);
                        bw.Write(node.DefaultTranslation.Z * 100);
                        bw.Write(node.DefaultRotation.X);
                        bw.Write(node.DefaultRotation.Y);
                        bw.Write(node.DefaultRotation.Z);
                        bw.Write(node.DefaultRotation.W);
                    }
                    #endregion
                    #region Marker Groups
                    headerValueList.Add((int)bw.BaseStream.Position);
                    foreach (var group in renderModel.MarkerGroups)
                    {
                        bw.Write((Info.StringIDs.GetString(group.Name) + "\0").ToCharArray());
                        bw.Write(group.Markers.Count);
                        markerAddressList.Add((int)bw.BaseStream.Position);
                        bw.Write(0);
                    }
                    #endregion
                    #region Markers
                    foreach (var group in renderModel.MarkerGroups)
                    {
                        markerValueList.Add((int)bw.BaseStream.Position);
                        foreach (var marker in group.Markers)
                        {
                            bw.Write((byte)marker.RegionIndex);
                            bw.Write((byte)marker.PermutationIndex);
                            bw.Write((short)marker.NodeIndex);
                            bw.Write(marker.Translation.X * 100);
                            bw.Write(marker.Translation.Y * 100);
                            bw.Write(marker.Translation.Z * 100);
                            bw.Write(marker.Rotation.X);
                            bw.Write(marker.Rotation.Y);
                            bw.Write(marker.Rotation.Z);
                            bw.Write(marker.Rotation.W);
                        }
                    }
                    #endregion
                    #region Regions
                    headerValueList.Add((int)bw.BaseStream.Position);
                    foreach (var region in renderModel.Regions)
                    {
                        bw.Write((Info.StringIDs.GetString(region.Name) + "\0").ToCharArray());
                        bw.Write(regionMeshes.Count);
                        permAddressList.Add((int)bw.BaseStream.Position);
                        bw.Write(0);
                    }
                    #endregion
                    #region Permutations
                    foreach (var part in regionMeshes)
                    {
                        permValueList.Add((int)bw.BaseStream.Position);
                        bw.Write((Info.StringIDs.GetString(variant.Name) + "\0").ToCharArray());

                        if (part.Value.Type == VertexType.Rigid)
                            bw.Write((byte)1);
                        else if (part.Value.Type == VertexType.Skinned)
                            bw.Write((byte)2);
                        else
                            throw new NotImplementedException();

                        bw.Write((byte)part.Value.RigidNodeIndex);

                        bw.Write(definition.VertexBuffers[part.Value.VertexBuffers[0]].Definition.Count);
                        vertAddressList.Add((int)bw.BaseStream.Position);
                        bw.Write(0);

                        int count = 0;
                        foreach (var submesh in part.Value.SubParts)
                            count += submesh.IndexCount;

                        bw.Write(count);
                        indxAddressList.Add((int)bw.BaseStream.Position);
                        bw.Write(0);

                        bw.Write(part.Value.SubParts.Count);
                        meshAddressList.Add((int)bw.BaseStream.Position);
                        bw.Write(0);

                        bw.Write(float.NaN); //no transforms (render_models are pre-transformed)
                    }
                    #endregion
                }
            }

            return true;
        }