public DdsHeader( uint size, DdsFlags flags, uint height, uint width, uint pitchOrLinearSize, uint depth, uint mipMapCount, uint[] reserved1, DdsPixelFormat pixelFormat, DdsCaps1 caps1, DdsCaps2 caps2, uint caps3, uint caps4, uint reserved2) { this.Size = size; this.Flags = flags; this.Height = height; this.Width = width; this.PitchOrLinearSize = pitchOrLinearSize; this.Depth = depth; this.MipMapCount = mipMapCount; this.Reserved1 = reserved1; this.PixelFormat = pixelFormat; this.Caps1 = caps1; this.Caps2 = caps2; this.Caps3 = caps3; this.Caps4 = caps4; this.Reserved2 = reserved2; }
public DdsHeader(Stream s) { BinaryReader r = new BinaryReader(s); // -- DWORD dwMagic -- magic = (DdsMagic)r.ReadUInt32(); if (!Enum.IsDefined(typeof(DdsMagic), magic)) throw new InvalidDataException(String.Format( "DDS Magic Number invalid. Got 0x{0:X8}, expected 0x{1:X8} ('DDS '). At 0x{2:X8}." , (uint)magic , (uint)DdsMagic.dds_ , s.Position ) ); // -- DDS_HEADER header -- size = r.ReadUInt32(); if (size == 0) { Console.WriteLine(String.Format( "DDS Header Size is zero, expected 124. At 0x{0:X8}. Correcting..." , s.Position )); size = 124; } else if (size != 124) throw new InvalidDataException(String.Format( "DDS Header Size invalid. Got {0}, expected 124. At 0x{1:X8}." , size , s.Position )); flags = (DdsFlags)r.ReadUInt32(); if (((uint)(flags & (writeFlags | DdsFlags.pitch | DdsFlags.linearSize))).Bits() != ((uint)writeFlags).Bits() + 1) { Console.WriteLine(String.Format( "DDS Header Flags invalid. Got {0}, expected {1} and either _pitch or _linearSize. At 0x{2:X8}. Correcting..." , flags , writeFlags , s.Position )); flags |= writeFlags; // We can't know yet which is best to pick of _pitch and _linearSize } height = r.ReadUInt32(); if (height == 0) throw new InvalidDataException(String.Format( "DDS Height invalid. Got 0, expected non-zero value. At 0x{1:X8}" , s.Position ) ); width = r.ReadUInt32(); if (width == 0) throw new InvalidDataException(String.Format( "DDS Width invalid. Got 0, expected non-zero value. At 0x{1:X8}" , s.Position ) ); pitchOrLinearSize = r.ReadUInt32(); depth = r.ReadUInt32(); if ((flags & DdsFlags.depth) != 0 && depth != 0) { Console.WriteLine(String.Format( "Only simple DDS Textures are supported. This DDS has depth {0}. At 0x{1:X8}. Clearing flag and _depth to zero..." , depth , s.Position )); flags &= ~DdsFlags.depth; depth = 0; } if ((flags & DdsFlags.depth) != 0 || depth != 0) { Console.WriteLine(String.Format( "DDS Header invalid. Inconsistent depth flag ({0}) and _depth ({1}). At 0x{2:X8}. Clearing flag and _depth to zero..." , flags & DdsFlags.depth , depth , s.Position )); flags &= ~DdsFlags.depth; depth = 0; } numMipMaps = r.ReadUInt32(); if ((flags & DdsFlags.mipMapCount) != 0 && numMipMaps != 1) { Console.WriteLine(String.Format( "Only simple DDS Textures are supported. This DDS has {0} mip maps. At 0x{1:X8}. Clearing flag and setting count to one..." , numMipMaps , s.Position )); flags &= ~DdsFlags.mipMapCount; numMipMaps = 1; } if ((flags & DdsFlags.mipMapCount) != 0 || numMipMaps == 0) { Console.WriteLine(String.Format( "DDS Header invalid. Inconsistent mipMapCount flag ({0}) and _numMipMaps ({1}). At 0x{2:X8}. Clearing flag and setting count to one..." , flags & DdsFlags.mipMapCount , numMipMaps , s.Position )); flags &= ~DdsFlags.mipMapCount; numMipMaps = 1; } for (int i = 0; i < reserved1.Length; i++) reserved1[i] = r.ReadUInt32(); for (int i = 0; i < reserved1.Length; i++) reserved1[i] = 0; pixelFormat = new DdsPixelFormat(s); var mask = (pixelFormat.FourCC == 0) ? DdsFlags.pitch : DdsFlags.linearSize; var notMask = (pixelFormat.FourCC != 0) ? DdsFlags.pitch : DdsFlags.linearSize; if ((flags & mask) == 0) { Console.WriteLine(String.Format( "DDS Header Flags invalid. {0} not set. At 0x{1:X8}. Correcting..." , mask , s.Position )); flags &= ~notMask; flags |= mask; } surfaceCaps = (DdsSurfaceCaps)r.ReadUInt32(); if ((surfaceCaps & ~DdsSurfaceCaps.texture) != 0) { Console.WriteLine(String.Format( "Only simple DDS Textures are supported. This DDS has other surface capabilities: {0}. At 0x{1:X8}. Clearing unsupported capabilities..." , surfaceCaps , s.Position )); surfaceCaps &= DdsSurfaceCaps.texture; } if (surfaceCaps == 0) { Console.WriteLine(String.Format( "DDS Header Surface Caps invalid. Got zero, expected texture. At 0x{0:X8}. Correcting..." , s.Position )); surfaceCaps |= DdsSurfaceCaps.texture; } cubeMapCaps = (DdsCubeMapCaps)r.ReadUInt32(); if (cubeMapCaps != 0) { Console.WriteLine(String.Format( "Only simple DDS Textures are supported. This DDS has cube map capabilities: {0}. At 0x{1:X8}. Clearing unsupported capabilities..." , cubeMapCaps , s.Position )); cubeMapCaps = 0; } unusedCaps3 = r.ReadUInt32(); unusedCaps4 = r.ReadUInt32(); reserved2 = r.ReadUInt32(); unusedCaps3 = unusedCaps4 = reserved2 = 0; // -- DDS_HEADER_DX10 header10 -- Not Supported }
uint reserved2;//124 #endregion public DdsHeader(DdsFormat ddsFormat, int width, int height) { this.magic = DdsMagic.dds_; this.size = 124; //flags this.height = (uint)height; this.width = (uint)width; //pitchOrLinearSize this.depth = 0; this.numMipMaps = 0; for (int i = 0; i < reserved1.Length; i++) this.reserved1[i] = 0; this.pixelFormat = new DdsPixelFormat(ddsFormat); this.surfaceCaps = DdsSurfaceCaps.texture; this.cubeMapCaps = 0; this.unusedCaps3 = 0; this.unusedCaps4 = 0; this.reserved2 = 0; this.flags = writeFlags | (IsBlockCompressed ? DdsFlags.linearSize : DdsFlags.pitch); this.pitchOrLinearSize = IsBlockCompressed ? LinearSize : Pitch; }
private static void EncodeDDSHeader(BinaryWriter writer, TextureDescription description, DdsFlags flags) { if (!TextureHelper.IsValidDds(description.Format)) throw new ArgumentException("Invalid texture format.", "description"); if (TextureHelper.IsPalettized(description.Format)) throw new NotSupportedException("Palettized texture formats are not supported."); if (description.ArraySize > 1) { if (description.ArraySize != 6 || description.Dimension != TextureDimension.Texture2D || description.Dimension != TextureDimension.TextureCube) { // Texture1D arrays, Texture2D arrays, and TextureCube arrays must be stored using 'DX10' extended header flags |= DdsFlags.ForceDX10Ext; } } if ((flags & DdsFlags.ForceDX10ExtMisc2) != 0) flags |= DdsFlags.ForceDX10Ext; PixelFormat ddpf = default(PixelFormat); if ((flags & DdsFlags.ForceDX10Ext) == 0) { switch (description.Format) { case DataFormat.R8G8B8A8_UNORM: ddpf = PixelFormat.A8B8G8R8; break; case DataFormat.R16G16_UNORM: ddpf = PixelFormat.G16R16; break; case DataFormat.R8G8_UNORM: ddpf = PixelFormat.A8L8; break; case DataFormat.R16_UNORM: ddpf = PixelFormat.L16; break; case DataFormat.R8_UNORM: ddpf = PixelFormat.L8; break; case DataFormat.A8_UNORM: ddpf = PixelFormat.A8; break; case DataFormat.R8G8_B8G8_UNORM: ddpf = PixelFormat.R8G8_B8G8; break; case DataFormat.G8R8_G8B8_UNORM: ddpf = PixelFormat.G8R8_G8B8; break; case DataFormat.BC1_UNORM: ddpf = PixelFormat.DXT1; break; case DataFormat.BC2_UNORM: ddpf = /* (description.AlphaMode == AlphaMode.Premultiplied) ? PixelFormat.DXT2 : */ PixelFormat.DXT3; break; case DataFormat.BC3_UNORM: ddpf = /* (description.AlphaMode == AlphaMode.Premultiplied) ? PixelFormat.DXT2 : */ PixelFormat.DXT5; break; case DataFormat.BC4_UNORM: ddpf = PixelFormat.BC4_UNorm; break; case DataFormat.BC4_SNORM: ddpf = PixelFormat.BC4_SNorm; break; case DataFormat.BC5_UNORM: ddpf = PixelFormat.BC5_UNorm; break; case DataFormat.BC5_SNORM: ddpf = PixelFormat.BC5_SNorm; break; case DataFormat.B5G6R5_UNORM: ddpf = PixelFormat.R5G6B5; break; case DataFormat.B5G5R5A1_UNORM: ddpf = PixelFormat.A1R5G5B5; break; case DataFormat.R8G8_SNORM: ddpf = PixelFormat.V8U8; break; case DataFormat.R8G8B8A8_SNORM: ddpf = PixelFormat.Q8W8V8U8; break; case DataFormat.R16G16_SNORM: ddpf = PixelFormat.V16U16; break; case DataFormat.B8G8R8A8_UNORM: ddpf = PixelFormat.A8R8G8B8; break; // DXGI 1.1 case DataFormat.B8G8R8X8_UNORM: ddpf = PixelFormat.X8R8G8B8; break; // DXGI 1.1 //#if DIRECTX11_1 case DataFormat.B4G4R4A4_UNORM: ddpf = PixelFormat.A4R4G4B4; break; case DataFormat.YUY2: ddpf = PixelFormat.YUY2; break; //#endif // Legacy D3DX formats using D3DFMT enum value as FourCC case DataFormat.R32G32B32A32_FLOAT: ddpf.Size = Marshal.SizeOf(typeof(PixelFormat)); ddpf.Flags = PixelFormatFlags.FourCC; ddpf.FourCC = 116; // D3DFMT_A32B32G32R32F break; case DataFormat.R16G16B16A16_FLOAT: ddpf.Size = Marshal.SizeOf(typeof(PixelFormat)); ddpf.Flags = PixelFormatFlags.FourCC; ddpf.FourCC = 113; // D3DFMT_A16B16G16R16F break; case DataFormat.R16G16B16A16_UNORM: ddpf.Size = Marshal.SizeOf(typeof(PixelFormat)); ddpf.Flags = PixelFormatFlags.FourCC; ddpf.FourCC = 36; // D3DFMT_A16B16G16R16 break; case DataFormat.R16G16B16A16_SNORM: ddpf.Size = Marshal.SizeOf(typeof(PixelFormat)); ddpf.Flags = PixelFormatFlags.FourCC; ddpf.FourCC = 110; // D3DFMT_Q16W16V16U16 break; case DataFormat.R32G32_FLOAT: ddpf.Size = Marshal.SizeOf(typeof(PixelFormat)); ddpf.Flags = PixelFormatFlags.FourCC; ddpf.FourCC = 115; // D3DFMT_G32R32F break; case DataFormat.R16G16_FLOAT: ddpf.Size = Marshal.SizeOf(typeof(PixelFormat)); ddpf.Flags = PixelFormatFlags.FourCC; ddpf.FourCC = 112; // D3DFMT_G16R16F break; case DataFormat.R32_FLOAT: ddpf.Size = Marshal.SizeOf(typeof(PixelFormat)); ddpf.Flags = PixelFormatFlags.FourCC; ddpf.FourCC = 114; // D3DFMT_R32F break; case DataFormat.R16_FLOAT: ddpf.Size = Marshal.SizeOf(typeof(PixelFormat)); ddpf.Flags = PixelFormatFlags.FourCC; ddpf.FourCC = 111; // D3DFMT_R16F break; } } writer.Write(MagicHeader); var header = new Header(); header.Size = Marshal.SizeOf(typeof(Header)); header.Flags = HeaderFlags.Texture; header.SurfaceFlags = SurfaceFlags.Texture; if (description.MipLevels > 0) { header.Flags |= HeaderFlags.Mipmap; header.MipMapCount = description.MipLevels; if (header.MipMapCount > 1) header.SurfaceFlags |= SurfaceFlags.Mipmap; } switch (description.Dimension) { case TextureDimension.Texture1D: header.Height = description.Height; header.Width = header.Depth = 1; break; case TextureDimension.Texture2D: case TextureDimension.TextureCube: header.Height = description.Height; header.Width = description.Width; header.Depth = 1; if (description.Dimension == TextureDimension.TextureCube) { header.SurfaceFlags |= SurfaceFlags.Cubemap; header.CubemapFlags |= CubemapFlags.AllFaces; } break; case TextureDimension.Texture3D: header.Flags |= HeaderFlags.Volume; header.CubemapFlags |= CubemapFlags.Volume; header.Height = description.Height; header.Width = description.Width; header.Depth = description.Depth; break; default: throw new NotSupportedException("The specified texture dimension is not supported."); } int rowPitch, slicePitch; TextureHelper.ComputePitch(description.Format, description.Width, description.Height, out rowPitch, out slicePitch); if (TextureHelper.IsBCn(description.Format)) { header.Flags |= HeaderFlags.LinearSize; header.PitchOrLinearSize = slicePitch; } else { header.Flags |= HeaderFlags.Pitch; header.PitchOrLinearSize = rowPitch; } if (ddpf.Size != 0) { header.PixelFormat = ddpf; writer.BaseStream.WriteStruct(header); } else { header.PixelFormat = PixelFormat.DX10; var ext = new HeaderDXT10(); ext.DXGIFormat = description.Format; switch (description.Dimension) { case TextureDimension.Texture1D: ext.ResourceDimension = ResourceDimension.Texture1D; break; case TextureDimension.Texture2D: case TextureDimension.TextureCube: ext.ResourceDimension = ResourceDimension.Texture2D; break; case TextureDimension.Texture3D: ext.ResourceDimension = ResourceDimension.Texture3D; break; } if (description.Dimension == TextureDimension.TextureCube) { ext.MiscFlags |= ResourceOptionFlags.TextureCube; ext.ArraySize = description.ArraySize / 6; } else { ext.ArraySize = description.ArraySize; } if ((flags & DdsFlags.ForceDX10ExtMisc2) != 0) { // This was formerly 'reserved'. D3DX10 and D3DX11 will fail if this value is anything other than 0. //ext.MiscFlags2 = description.MiscFlags2; throw new NotImplementedException("DdsFlags.ForceDX10ExtMisc2 is not implemented."); } writer.BaseStream.WriteStruct(header); writer.BaseStream.WriteStruct(ext); } }
private static TextureDescription DecodeDDSHeader(BinaryReader reader, DdsFlags flags, out ConversionFlags convFlags) { Debug.Assert(Marshal.SizeOf(typeof(Header)) == 124, "DDS Header size mismatch"); Debug.Assert(Marshal.SizeOf(typeof(HeaderDXT10)) == 20, "DDS DX10 Extended Header size mismatch"); var description = new TextureDescription(); convFlags = ConversionFlags.None; long size = reader.BaseStream.Length - reader.BaseStream.Position; int sizeOfTGAHeader = Marshal.SizeOf(typeof(Header)); if (size < sizeOfTGAHeader) throw new InvalidDataException("The DDS file is corrupt."); // DDS files always start with the same magic number ("DDS "). if (reader.ReadUInt32() != MagicHeader) throw new InvalidDataException("The file does not appear to be a DDS file."); var header = reader.BaseStream.ReadStruct<Header>(); // Verify header to validate DDS file if (header.Size != Marshal.SizeOf(typeof(Header)) || header.PixelFormat.Size != Marshal.SizeOf(typeof(PixelFormat))) throw new InvalidDataException("Incorrect sizes in DDS file."); description.MipLevels = header.MipMapCount; if (description.MipLevels == 0) description.MipLevels = 1; // Check for DX10 extension if ((header.PixelFormat.Flags & PixelFormatFlags.FourCC) != 0 && (new FourCC('D', 'X', '1', '0') == header.PixelFormat.FourCC)) { // Buffer must be big enough for both headers and magic value if (reader.BaseStream.Length < (Marshal.SizeOf(typeof(Header)) + Marshal.SizeOf(typeof(HeaderDXT10)) + sizeof(uint))) throw new InvalidDataException("The DDS files is truncated."); var headerDX10 = reader.BaseStream.ReadStruct<HeaderDXT10>(); convFlags |= ConversionFlags.DX10; description.ArraySize = headerDX10.ArraySize; if (description.ArraySize == 0) throw new InvalidDataException("Invalid array size specified in DDS file."); description.Format = headerDX10.DXGIFormat; if (!TextureHelper.IsValidDds(description.Format) || TextureHelper.IsPalettized(description.Format)) throw new InvalidDataException("Invalid format specified in DDS file."); switch (headerDX10.ResourceDimension) { case ResourceDimension.Texture1D: // D3DX writes 1D textures with a fixed Height of 1 if ((header.Flags & HeaderFlags.Height) != 0 && header.Height != 1) throw new InvalidDataException("Invalid height for 1D texture specified in DDS file."); description.Dimension = TextureDimension.Texture1D; description.Width = header.Width; description.Height = 1; description.Depth = 1; break; case ResourceDimension.Texture2D: if ((headerDX10.MiscFlags & ResourceOptionFlags.TextureCube) != 0) { description.Dimension = TextureDimension.TextureCube; description.ArraySize *= 6; } else { description.Dimension = TextureDimension.Texture2D; } description.Width = header.Width; description.Height = header.Height; description.Depth = 1; break; case ResourceDimension.Texture3D: if ((header.Flags & HeaderFlags.Volume) == 0) throw new InvalidDataException("Volume flag for 3D texture is missing in DDS file."); if (description.ArraySize > 1) throw new InvalidDataException("Invalid array size for 3D texture specified in DDS file."); description.Dimension = TextureDimension.Texture3D; description.Width = header.Width; description.Height = header.Height; description.Depth = header.Depth; break; default: throw new InvalidDataException(string.Format(CultureInfo.InvariantCulture, "Invalid texture dimension specified in DDS file.")); } } else { description.ArraySize = 1; if ((header.Flags & HeaderFlags.Volume) != 0) { description.Dimension = TextureDimension.Texture3D; description.Width = header.Width; description.Height = header.Height; description.Depth = header.Depth; } else { if ((header.CubemapFlags & CubemapFlags.CubeMap) != 0) { // We require all six faces to be defined if ((header.CubemapFlags & CubemapFlags.AllFaces) != CubemapFlags.AllFaces) throw new InvalidDataException("Cube map faces missing in DDS file. All six faces required."); description.Dimension = TextureDimension.TextureCube; description.ArraySize = 6; } else { description.Dimension = TextureDimension.Texture2D; } description.Width = header.Width; description.Height = header.Height; description.Depth = 1; // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture } description.Format = GetDXGIFormat(ref header.PixelFormat, flags, out convFlags); if (description.Format == DataFormat.Unknown) throw new NotSupportedException("The texture format used in the DDS file is not supported."); // Premultiplied formats are considered deprecated. //if ((convFlags & ConversionFlags.PremultipliedAlpha) != 0) // Description.AlphaMode = AlphaMode.Premultiplied; // Special flag for handling LUMINANCE legacy formats if ((flags & DdsFlags.ExpandLuminance) != 0) { switch (description.Format) { case DataFormat.R8_UNORM: description.Format = DataFormat.R8G8B8A8_UNORM; convFlags |= ConversionFlags.FormatL8 | ConversionFlags.Expand; break; case DataFormat.R8G8_UNORM: description.Format = DataFormat.R8G8B8A8_UNORM; convFlags |= ConversionFlags.FormatA8L8 | ConversionFlags.Expand; break; case DataFormat.R16_UNORM: description.Format = DataFormat.R16G16B16A16_UNORM; convFlags |= ConversionFlags.FormatL16 | ConversionFlags.Expand; break; } } } // Special flag for handling BGR DXGI 1.1 formats if ((flags & DdsFlags.ForceRgb) != 0) { switch (description.Format) { case DataFormat.B8G8R8A8_UNORM: description.Format = DataFormat.R8G8B8A8_UNORM; convFlags |= ConversionFlags.Swizzle; break; case DataFormat.B8G8R8X8_UNORM: description.Format = DataFormat.R8G8B8A8_UNORM; convFlags |= ConversionFlags.Swizzle | ConversionFlags.NoAlpha; break; case DataFormat.B8G8R8A8_TYPELESS: description.Format = DataFormat.R8G8B8A8_TYPELESS; convFlags |= ConversionFlags.Swizzle; break; case DataFormat.B8G8R8A8_UNORM_SRGB: description.Format = DataFormat.R8G8B8A8_UNORM_SRGB; convFlags |= ConversionFlags.Swizzle; break; case DataFormat.B8G8R8X8_TYPELESS: description.Format = DataFormat.R8G8B8A8_TYPELESS; convFlags |= ConversionFlags.Swizzle | ConversionFlags.NoAlpha; break; case DataFormat.B8G8R8X8_UNORM_SRGB: description.Format = DataFormat.R8G8B8A8_UNORM_SRGB; convFlags |= ConversionFlags.Swizzle | ConversionFlags.NoAlpha; break; } } // Special flag for handling 16bpp formats if ((flags & DdsFlags.No16Bpp) != 0) { switch (description.Format) { case DataFormat.B5G6R5_UNORM: case DataFormat.B5G5R5A1_UNORM: case DataFormat.B4G4R4A4_UNORM: description.Format = DataFormat.R8G8B8A8_UNORM; convFlags |= ConversionFlags.Expand; if (description.Format == DataFormat.B5G6R5_UNORM) convFlags |= ConversionFlags.NoAlpha; break; } } return description; }
/// <summary> /// Saves the specified texture in DDS format. /// </summary> /// <param name="texture">The texture.</param> /// <param name="stream">The stream to write to.</param> /// <param name="flags">Additional options.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="texture"/> or <paramref name="stream"/> is <see langword="null"/>. /// </exception> public static void Save(Texture texture, Stream stream, DdsFlags flags) { if (texture == null) throw new ArgumentNullException("texture"); if (stream == null) throw new ArgumentNullException("stream"); #if NET45 using (var writer = new BinaryWriter(stream, Encoding.Default, true)) #else using (var writer = new BinaryWriter(stream, Encoding.Default)) // Warning: Closes the stream! #endif { var description = texture.Description; EncodeDDSHeader(writer, description, flags); switch (description.Dimension) { case TextureDimension.Texture1D: case TextureDimension.Texture2D: case TextureDimension.TextureCube: { int index = 0; for (int item = 0; item < description.ArraySize; ++item) { for (int level = 0; level < description.MipLevels; ++level) { var image = texture.Images[index]; stream.Write(image.Data, 0, image.Data.Length); ++index; } } } break; case TextureDimension.Texture3D: { if (description.ArraySize != 1) throw new NotSupportedException("Arrays of volume textures are not supported."); int d = description.Depth; int index = 0; for (int level = 0; level < description.MipLevels; ++level) { for (int slice = 0; slice < d; ++slice) { var image = texture.Images[index]; stream.Write(image.Data, 0, image.Data.Length); ++index; } if (d > 1) d >>= 1; } } break; default: throw new NotSupportedException("The specified texture dimension is not supported."); } } }
/// <summary> /// Loads the specified DDS texture. /// </summary> /// <param name="stream">The stream to read from.</param> /// <param name="flags">Additional options.</param> /// <returns>The <see cref="Texture"/>.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="stream"/> is <see langword="null"/>. /// </exception> public static Texture Load(Stream stream, DdsFlags flags) { if (stream == null) throw new ArgumentNullException("stream"); using (var reader = new BinaryReader(stream)) { ConversionFlags conversionFlags; var description = DecodeDDSHeader(reader, flags, out conversionFlags); uint[] pal8 = null; if ((conversionFlags & ConversionFlags.Pal8) != 0) { pal8 = new uint[256]; for (int i = 0; i < pal8.Length; i++) pal8[i] = reader.ReadUInt32(); } var computePitchFlags = (flags & DdsFlags.LegacyDword) != 0 ? ComputePitchFlags.LegacyDword : ComputePitchFlags.None; return CopyImage(reader, description, computePitchFlags, conversionFlags, pal8); } }
// Note that many common DDS reader/writers (including D3DX) swap the // the RED/BLUE masks for 10:10:10:2 formats. We assume // below that the 'backwards' header mask is being used since it is most // likely written by D3DX. The more robust solution is to use the 'DX10' // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly // We do not support the following legacy Direct3D 9 formats: // D3DFMT_A2W10V10U10 // BumpLuminance D3DFMT_L6V5U5, D3DFMT_X8L8V8U8 // FourCC 117 D3DFMT_CxV8U8 // ZBuffer D3DFMT_D16_LOCKABLE // FourCC 82 D3DFMT_D32F_LOCKABLE private static DataFormat GetDXGIFormat(ref PixelFormat pixelFormat, DdsFlags flags, out ConversionFlags conversionFlags) { conversionFlags = ConversionFlags.None; int index; for (index = 0; index < LegacyMaps.Length; ++index) { var entry = LegacyMaps[index]; if ((pixelFormat.Flags & entry.PixelFormat.Flags) != 0) { if ((entry.PixelFormat.Flags & PixelFormatFlags.FourCC) != 0) { if (pixelFormat.FourCC == entry.PixelFormat.FourCC) break; } else if ((entry.PixelFormat.Flags & PixelFormatFlags.Pal8) != 0) { if (pixelFormat.RGBBitCount == entry.PixelFormat.RGBBitCount) break; } else if (pixelFormat.RGBBitCount == entry.PixelFormat.RGBBitCount) { // RGB, RGBA, ALPHA, LUMINANCE if (pixelFormat.RBitMask == entry.PixelFormat.RBitMask && pixelFormat.GBitMask == entry.PixelFormat.GBitMask && pixelFormat.BBitMask == entry.PixelFormat.BBitMask && pixelFormat.ABitMask == entry.PixelFormat.ABitMask) break; } } } if (index >= LegacyMaps.Length) return DataFormat.Unknown; conversionFlags = LegacyMaps[index].ConversionFlags; var format = LegacyMaps[index].Format; if ((conversionFlags & ConversionFlags.Expand) != 0 && (flags & DdsFlags.NoLegacyExpansion) != 0) return DataFormat.Unknown; if (format == DataFormat.R10G10B10A2_UNORM && (flags & DdsFlags.NoR10B10G10A2Fixup) != 0) { conversionFlags ^= ConversionFlags.Swizzle; } return format; }