/// <summary> /// Reads a DDS header from a stream. On return, the stream will be positioned at the beginning of the texture data. /// </summary> /// <param name="stream">The stream to read from.</param> /// <returns>The header that was read.</returns> /// <exception cref="System.InvalidOperationException">Thrown if the DDS header is invalid.</exception> public static DdsHeader Read(Stream stream) { var reader = new BinaryReader(stream); if (stream.Length - stream.Position < 128) { throw new InvalidOperationException("Invalid DDS file: header is too small"); } var result = new DdsHeader(); // Read and verify magic if (reader.ReadUInt32() != DdsFourCc.FromString("DDS ")) { throw new InvalidOperationException("Invalid DDS file: invalid header magic"); } // Read the DDS header result.ReadDdsHeader(reader); // If the format FourCC is 'DX10', read the extended header if (result.FourCc == DdsFourCc.FromString("DX10")) { result.ReadDdsD3D10Header(reader); } return(result); }
private void WriteDdsPixelFormat(BinaryWriter writer) { writer.Write(32); writer.Write((uint)CalculateFormatFlags()); writer.Write((D3D10Format == DxgiFormat.Unknown) ? FourCc : DdsFourCc.FromString("DX10")); writer.Write(BitsPerPixel); writer.Write(RBitMask); writer.Write(GBitMask); writer.Write(BBitMask); writer.Write(ABitMask); }
/// <summary> /// Writes the DDS header to a stream. On return, the stream will be positioned where the texture data should go. /// </summary> /// <param name="stream">The stream to write to.</param> /// <exception cref="System.InvalidOperationException">Thrown if an error occurs while saving.</exception> public void WriteTo(Stream stream) { var writer = new BinaryWriter(stream); writer.Write(DdsFourCc.FromString("DDS ")); WriteDdsHeader(writer); if (D3D10Format != DxgiFormat.Unknown) { WriteDdsD3D10Header(writer); } }
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; }
public void InjectDds(TagSerializer serializer, TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream ddsStream, ResourceLocation location = ResourceLocation.Textures) { var resource = bitmap.Resources[imageIndex].Resource; var newResource = (resource == null); ResourceSerializationContext resourceContext; BitmapTextureInteropResource definition; if (newResource) { // Create a new resource reference resource = new PageableResource { Page = new RawPage(), Resource = new TagResourceGen3 { ResourceFixups = new List <TagResourceGen3.ResourceFixup>(), ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(), ResourceType = TagResourceTypeGen3.Bitmap, Unknown2 = 1 } }; bitmap.Resources[imageIndex].Resource = resource; resourceContext = new ResourceSerializationContext(CacheContext, resource); definition = new BitmapTextureInteropResource { Texture = new TagStructureReference <BitmapTextureInteropResource.BitmapDefinition> { Definition = new BitmapTextureInteropResource.BitmapDefinition { Data = new TagData(), UnknownData = new TagData(), } } }; } else { // Deserialize the old definition resourceContext = new ResourceSerializationContext(CacheContext, resource); definition = deserializer.Deserialize <BitmapTextureInteropResource>(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 TagData(dataSize, new CacheResourceAddress(CacheResourceAddressType.Resource, 0)); texture.Width = (short)dds.Width; texture.Height = (short)dds.Height; texture.Depth = (sbyte)Math.Max(1, dds.Depth); texture.MipmapCount = (sbyte)Math.Max(1, dds.MipMapCount); texture.Type = BitmapDdsFormatDetection.DetectType(dds); texture.D3DFormat = (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) { resource.ChangeLocation(location); CacheContext.AddResource(resource, ddsStream); } else { CacheContext.ReplaceResource(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.MipmapCount - 1); imageData.DataOffset = texture.Data.Address.Offset; imageData.DataSize = texture.Data.Size; imageData.Curve = (BitmapImageCurve)texture.Curve; }