public void SetFlags(DXGI_FORMAT Format) { header.flags = (uint)(DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PIXELFORMAT | DDSD.MIPMAPCOUNT | DDSD.LINEARSIZE); header.caps = (uint)DDSCAPS.TEXTURE; if (header.mipmapCount > 1) { header.caps |= (uint)(DDSCAPS.COMPLEX | DDSCAPS.MIPMAP); } switch (Format) { case DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM: case DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: header.ddspf.flags = (uint)(DDPF.RGB | DDPF.ALPHAPIXELS); header.ddspf.RGBBitCount = 0x8 * 4; header.ddspf.RBitMask = 0x000000FF; header.ddspf.GBitMask = 0x0000FF00; header.ddspf.BBitMask = 0x00FF0000; header.ddspf.ABitMask = 0xFF000000; break; case DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM_SRGB: case DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM: header.ddspf.flags = (uint)DDPF.FOURCC; header.ddspf.fourCC = FOURCC_DXT1; break; case DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM_SRGB: case DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM: header.ddspf.flags = (uint)DDPF.FOURCC; header.ddspf.fourCC = FOURCC_DXT3; break; case DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM_SRGB: case DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM: header.ddspf.flags = (uint)DDPF.FOURCC; header.ddspf.fourCC = FOURCC_DXT5; break; case DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM: case DXGI_FORMAT.DXGI_FORMAT_BC4_SNORM: case DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM: case DXGI_FORMAT.DXGI_FORMAT_BC5_SNORM: case DXGI_FORMAT.DXGI_FORMAT_BC6H_UF16: case DXGI_FORMAT.DXGI_FORMAT_BC6H_SF16: case DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM: case DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM_SRGB: header.ddspf.flags = (uint)DDPF.FOURCC; header.ddspf.fourCC = FOURCC_DX10; if (DX10header == null) { DX10header = new DX10Header(); } IsDX10 = true; DX10header.DXGI_Format = Format; break; } }
private void ReadDX10Header(BinaryDataReader reader) { DX10header = new DX10Header(); DX10header.DXGI_Format = reader.ReadEnum <DXGI_FORMAT>(true); DX10header.ResourceDim = reader.ReadUInt32(); DX10header.miscFlag = reader.ReadUInt32(); DX10header.arrayFlag = reader.ReadUInt32(); DX10header.miscFlags2 = reader.ReadUInt32(); }
public void Load(Stream stream) { Name = FileInfo.FileName; using (var reader = new FileReader(stream)) { MainHeader = reader.ReadStruct <Header>(); PfHeader = reader.ReadStruct <DDSPFHeader>(); if (IsDX10) { Dx10Header = reader.ReadStruct <DX10Header>(); } byte[] Components = new byte[4] { 0, 1, 2, 3 }; bool Compressed = false; bool HasLuminance = false; bool HasAlpha = false; bool IsRGB = false; switch (PfHeader.Flags) { case 4: Compressed = true; break; case 2: case (uint)DDPF.LUMINANCE: HasLuminance = true; break; case (uint)DDPF.RGB: IsRGB = true; break; case 0x41: IsRGB = true; HasAlpha = true; break; } ToGenericFormat(); if (!IsDX10 && !this.IsBCNCompressed()) { Platform.OutputFormat = DDS_RGBA.GetUncompressedType(this, Components, IsRGB, HasAlpha, HasLuminance, PfHeader); } Depth = 1; Width = MainHeader.Width; Height = MainHeader.Height; MipCount = MainHeader.MipCount == 0 ? 1 : MainHeader.MipCount; ArrayCount = IsCubeMap ? (uint)6 : 1; } }
private void WriteDX10Header(BinaryDataWriter writer) { if (DX10header == null) { DX10header = new DX10Header(); } writer.Write((uint)DX10header.DXGI_Format); writer.Write(DX10header.ResourceDim); writer.Write(DX10header.miscFlag); writer.Write(DX10header.arrayFlag); writer.Write(DX10header.miscFlags2); }
public void Load(Stream stream) { using (var reader = new FileReader(stream)) { MainHeader = reader.ReadStruct <Header>(); PfHeader = reader.ReadStruct <DDSPFHeader>(); if (IsDX10) { Dx10Header = reader.ReadStruct <DX10Header>(); } int Dx10Size = Dx10Header != null ? 20 : 0; reader.TemporarySeek((int)(4 + MainHeader.Size + Dx10Size), SeekOrigin.Begin); ImageData = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position)); } }
/// <summary> /// Encodes the DDS Header and if DX10, the DX10 Header /// </summary> /// <param name="header">DDS Header</param> /// <param name="dx10Header">DX10 Header</param> /// <returns>Resulting DDS File Header in bytes</returns> public static byte[] EncodeDDSHeader(DDSHeader header, DX10Header dx10Header) { // Create stream using (var output = new BinaryWriter(new MemoryStream())) { // Write DDS Magic output.Write(DDSHeader.DDSMagic); // Write Header output.Write(StructToBytes(header)); // Check for DX10 Header if (header.PixelFormat.FourCC == PixelFormats.DX10.FourCC) { // Write Header output.Write(StructToBytes(dx10Header)); } // Done return(((MemoryStream)(output.BaseStream)).ToArray()); } }
public void SetFlags(DXGI_FORMAT Format) { header.flags = (uint)(DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PIXELFORMAT | DDSD.MIPMAPCOUNT | DDSD.LINEARSIZE); header.caps = (uint)DDSCAPS.TEXTURE; if (header.mipmapCount > 1) { header.caps |= (uint)(DDSCAPS.COMPLEX | DDSCAPS.MIPMAP); } switch (Format) { case DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM: case DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: header.ddspf.flags = (uint)(DDPF.RGB | DDPF.ALPHAPIXELS); header.ddspf.RGBBitCount = 0x8 * 4; header.ddspf.RBitMask = 0x000000FF; header.ddspf.GBitMask = 0x0000FF00; header.ddspf.BBitMask = 0x00FF0000; header.ddspf.ABitMask = 0xFF000000; pixelInternalFormat = PixelInternalFormat.SrgbAlpha; pixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Rgba; break; case DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM_SRGB: case DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM: header.ddspf.flags = (uint)DDPF.FOURCC; header.ddspf.fourCC = FOURCC_DXT1; pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext; break; case DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM_SRGB: case DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM: header.ddspf.flags = (uint)DDPF.FOURCC; header.ddspf.fourCC = FOURCC_DXT3; pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt3Ext; break; case DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM_SRGB: case DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM: header.ddspf.flags = (uint)DDPF.FOURCC; header.ddspf.fourCC = FOURCC_DXT5; pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt5Ext; break; case DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM: case DXGI_FORMAT.DXGI_FORMAT_BC4_SNORM: pixelInternalFormat = PixelInternalFormat.CompressedRedRgtc1; break; case DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM: case DXGI_FORMAT.DXGI_FORMAT_BC5_SNORM: case DXGI_FORMAT.DXGI_FORMAT_BC6H_UF16: case DXGI_FORMAT.DXGI_FORMAT_BC6H_SF16: case DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM: case DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM_SRGB: header.ddspf.flags = (uint)DDPF.FOURCC; header.ddspf.fourCC = FOURCC_DX10; if (DX10header == null) { DX10header = new DX10Header(); } IsDX10 = true; DX10header.DXGI_Format = Format; break; } }
/// <summary> /// Generates a DDS Header, and if requires, a DX10 Header /// </summary> /// <param name="metaData">Meta Data</param> /// <param name="flags">Flags</param> /// <param name="header">DDS Header Output</param> /// <param name="dx10Header">DX10 Header Output</param> public static void GenerateDDSHeader(TexMetadata metaData, DDSFlags flags, out DDSHeader header, out DX10Header dx10Header) { // Check array size if (metaData.ArraySize > 1) { // Check if we have an array and whether we're cube maps/non-2D if (metaData.ArraySize != 6 || metaData.Dimension != TexDimension.TEXTURE2D || !metaData.IsCubeMap()) { // Texture1D arrays, Texture2D arrays, and Cubemap arrays must be stored using 'DX10' extended header flags |= DDSFlags.FORCEDX10EXT; } } // Check for DX10 Ext if (flags.HasFlag(DDSFlags.FORCEDX10EXTMISC2)) { flags |= DDSFlags.FORCEDX10EXT; } // Create DDS Header header = new DDSHeader { // Set Data Size = (uint)Marshal.SizeOf <DDSHeader>(), Flags = DDSHeader.HeaderFlags.TEXTURE, Caps = (uint)DDSHeader.SurfaceFlags.TEXTURE, PixelFormat = new DDSHeader.DDSPixelFormat(0, 0, 0, 0, 0, 0, 0, 0) }; // Create DX10 Header dx10Header = new DX10Header(); // Switch format switch (metaData.Format) { case DXGIFormat.R8G8B8A8UNORM: header.PixelFormat = PixelFormats.A8B8G8R8; break; case DXGIFormat.R16G16UNORM: header.PixelFormat = PixelFormats.G16R16; break; case DXGIFormat.R8G8UNORM: header.PixelFormat = PixelFormats.A8L8; break; case DXGIFormat.R16UNORM: header.PixelFormat = PixelFormats.L16; break; case DXGIFormat.R8UNORM: header.PixelFormat = PixelFormats.L8; break; case DXGIFormat.A8UNORM: header.PixelFormat = PixelFormats.A8; break; case DXGIFormat.R8G8B8G8UNORM: header.PixelFormat = PixelFormats.R8G8B8G8; break; case DXGIFormat.G8R8G8B8UNORM: header.PixelFormat = PixelFormats.G8R8G8B8; break; case DXGIFormat.BC1UNORM: header.PixelFormat = PixelFormats.DXT1; break; case DXGIFormat.BC2UNORM: header.PixelFormat = metaData.IsPMAlpha() ? (PixelFormats.DXT2) : (PixelFormats.DXT3); break; case DXGIFormat.BC3UNORM: header.PixelFormat = metaData.IsPMAlpha() ? (PixelFormats.DXT4) : (PixelFormats.DXT5); break; case DXGIFormat.BC4UNORM: header.PixelFormat = PixelFormats.BC4UNORM; break; case DXGIFormat.BC4SNORM: header.PixelFormat = PixelFormats.BC4SNORM; break; case DXGIFormat.BC5UNORM: header.PixelFormat = PixelFormats.BC5UNORM; break; case DXGIFormat.BC5SNORM: header.PixelFormat = PixelFormats.BC5SNORM; break; case DXGIFormat.B5G6R5UNORM: header.PixelFormat = PixelFormats.R5G6B5; break; case DXGIFormat.B5G5R5A1UNORM: header.PixelFormat = PixelFormats.A1R5G5B5; break; case DXGIFormat.R8G8SNORM: header.PixelFormat = PixelFormats.V8U8; break; case DXGIFormat.R8G8B8A8SNORM: header.PixelFormat = PixelFormats.Q8W8V8U8; break; case DXGIFormat.R16G16SNORM: header.PixelFormat = PixelFormats.V16U16; break; case DXGIFormat.B8G8R8A8UNORM: header.PixelFormat = PixelFormats.A8R8G8B8; break; case DXGIFormat.B8G8R8X8UNORM: header.PixelFormat = PixelFormats.X8R8G8B8; break; case DXGIFormat.B4G4R4A4UNORM: header.PixelFormat = PixelFormats.A4R4G4B4; break; case DXGIFormat.YUY2: header.PixelFormat = PixelFormats.YUY2; break; // Legacy D3DX formats using D3DFMT enum value as FourCC case DXGIFormat.R32G32B32A32FLOAT: header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 116; // D3DFMTA32B32G32R32F break; case DXGIFormat.R16G16B16A16FLOAT: header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 113; // D3DFMTA16B16G16R16F break; case DXGIFormat.R16G16B16A16UNORM: header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 36; // D3DFMTA16B16G16R16 break; case DXGIFormat.R16G16B16A16SNORM: header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 110; // D3DFMTQ16W16V16U16 break; case DXGIFormat.R32G32FLOAT: header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 115; // D3DFMTG32R32F break; case DXGIFormat.R16G16FLOAT: header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 112; // D3DFMTG16R16F break; case DXGIFormat.R32FLOAT: header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 114; // D3DFMTR32F break; case DXGIFormat.R16FLOAT: header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 111; // D3DFMTR16F break; default: break; } // Check for mips if (metaData.MipLevels > 0) { // Set flag header.Flags |= DDSHeader.HeaderFlags.MIPMAP; // Check size if (metaData.MipLevels > UInt16.MaxValue) { throw new ArgumentException(String.Format("Too many mipmaps: {0}. Max: {1}", metaData.MipLevels, UInt16.MaxValue)); } // Set header.MipMapCount = (uint)metaData.MipLevels; // Check count if (header.MipMapCount > 1) { header.Caps |= (uint)DDSHeader.SurfaceFlags.MIPMAP; } } // Switch Dimension switch (metaData.Dimension) { case TexDimension.TEXTURE1D: { // Check size if (metaData.Width > Int32.MaxValue) { throw new ArgumentException(String.Format("Image Width too large: {0}. Max: {1}", metaData.Width, Int32.MaxValue)); } // Set header.Width = (uint)metaData.Width; header.Height = header.Depth = 1; // Check size break; } case TexDimension.TEXTURE2D: { // Check size if (metaData.Width > Int32.MaxValue || metaData.Height > Int32.MaxValue) { throw new ArgumentException(String.Format("Image Width and/or Height too large: {0}x{1}. Max: {2}", metaData.Width, metaData.Height, Int32.MaxValue)); } // Set header.Width = (uint)metaData.Width; header.Height = (uint)metaData.Height; header.Depth = 1; // Check size break; } case TexDimension.TEXTURE3D: { // Check size if (metaData.Width > Int32.MaxValue || metaData.Height > Int32.MaxValue) { throw new ArgumentException(String.Format("Image Width and/or Height too large: {0}x{1}. Max: {2}", metaData.Width, metaData.Height, Int32.MaxValue)); } // Check size if (metaData.Depth > UInt16.MaxValue) { throw new ArgumentException(String.Format("Image Depth too large: {0}. Max: {1}", metaData.Depth, UInt16.MaxValue)); } // Set header.Flags |= DDSHeader.HeaderFlags.VOLUME; header.Caps2 |= 0x00200000; header.Width = (uint)metaData.Width; header.Height = (uint)metaData.Height; header.Depth = (uint)metaData.Depth; // Check size break; } default: throw new ArgumentException("Invalid Texture Dimension."); } // Calculate the Pitch ComputePitch(metaData.Format, metaData.Width, metaData.Height, out long rowPitch, out long slicePitch, CPFLAGS.NONE); // Validate results if (slicePitch > UInt32.MaxValue || rowPitch > UInt32.MaxValue) { throw new ArgumentException("Failed to calculate row and/or slice pitch, values returned were too large"); } // Check is it compressed if (IsCompressed(metaData.Format)) { header.Flags |= DDSHeader.HeaderFlags.LINEARSIZE; header.PitchOrLinearSize = (uint)slicePitch; } else { header.Flags |= DDSHeader.HeaderFlags.PITCH; header.PitchOrLinearSize = (uint)rowPitch; } // Check for do we need to create the DX10 Header if (header.PixelFormat.Size == 0) { // Check size if (metaData.ArraySize > UInt16.MaxValue) { throw new ArgumentException(String.Format("Array Size too large: {0}. Max: {1}", metaData.ArraySize, UInt16.MaxValue)); } // Set Pixel format header.PixelFormat = PixelFormats.DX10; // Set Data dx10Header.Format = metaData.Format; dx10Header.ResourceDimension = metaData.Dimension; dx10Header.MiscFlag = metaData.MiscFlags & ~TexMiscFlags.TEXTURECUBE; dx10Header.ArraySize = (uint)metaData.ArraySize; // Check for Cube Maps if (metaData.MiscFlags.HasFlag(TexMiscFlags.TEXTURECUBE)) { // Check array size, must be a multiple of 6 for cube maps if ((metaData.ArraySize % 6) != 0) { throw new ArgumentException("Array size must be a multiple of 6"); } // Set Flag dx10Header.MiscFlag |= TexMiscFlags.TEXTURECUBE; dx10Header.ArraySize /= 6; } // Check for mist flags if (flags.HasFlag(DDSFlags.FORCEDX10EXTMISC2)) { // This was formerly 'reserved'. D3DX10 and D3DX11 will fail if this value is anything other than 0 dx10Header.MiscFlags2 = (uint)metaData.MiscFlags2; } } }
public DDS() { MainHeader = new Header(); PfHeader = new DDSPFHeader(); Dx10Header = new DX10Header(); }
// Methods public override void Load(Stream fileStream) { // Signature var reader = new ExtendedBinaryReader( fileStream, Encoding.ASCII, false); string sig = reader.ReadSignature(4); if (sig != Signature) { throw new InvalidSignatureException(Signature, sig); } // Header Header = new DDSHeader() { Size = reader.ReadUInt32(), Flags = reader.ReadUInt32() }; if (!Header.HasFlag(DDSHeader.FLAGS.CAPS) || !Header.HasFlag(DDSHeader.FLAGS.WIDTH) || !Header.HasFlag(DDSHeader.FLAGS.HEIGHT) || !Header.HasFlag(DDSHeader.FLAGS.PIXEL_FORMAT)) { throw new Exception( "Could not load DDS file. Required header flags are missing!"); } Height = reader.ReadUInt32(); Width = reader.ReadUInt32(); Header.PitchOrLinearSize = reader.ReadUInt32(); Header.Depth = reader.ReadUInt32(); Header.MipmapCount = reader.ReadUInt32(); reader.JumpAhead(44); // Skip past padding Header.PixelFormat = new DDSPixelFormat(reader); Header.Caps = reader.ReadUInt32(); Header.Caps2 = reader.ReadUInt32(); Header.Caps3 = reader.ReadUInt32(); Header.Caps4 = reader.ReadUInt32(); reader.JumpTo(Header.Size + 4, true); // Depth uint depth = 1; if (Header.HasFlag(DDSHeader.FLAGS.DEPTH) && Header.HasFlag(DDSHeader.CAPS2.VOLUME)) { depth = Header.Depth; // TODO throw new NotImplementedException( "Reading 3D textures from DDS files is not yet supported."); } else if (Header.HasFlag(DDSHeader.CAPS2.CUBEMAP)) { depth = 6; // TODO throw new NotImplementedException( "Reading DDS cubemaps is not yet supported."); } // MipMaps uint mipmapCount = 1; if (Header.HasFlag(DDSHeader.FLAGS.MIPMAP_COUNT) && Header.HasFlag(DDSHeader.CAPS.MIPMAP)) { mipmapCount = Header.MipmapCount; } MipmapCount = mipmapCount; // Caps if (!Header.HasFlag(DDSHeader.CAPS.TEXTURE)) { throw new Exception( "Could not load DDS file. Required CAPS flag is missing!"); } // TODO // Caps2 // TODO // DX10 Header/Pixel Format uint pixelsPerBlock = 16; byte blockSize; if (Header.PixelFormat.HasFlag(DDSPixelFormat.FLAGS.FOURCC)) { switch ((DDSPixelFormat.FOURCCS)Header.PixelFormat.FourCC) { // DX10 Header case DDSPixelFormat.FOURCCS.DX10: { var dx10Header = new DX10Header(reader); depth = dx10Header.ArraySize; switch ((DX10Header.DXGI_FORMATS)dx10Header.DXGIFormat) { // BC1 case DX10Header.DXGI_FORMATS.BC1_TYPELESS: case DX10Header.DXGI_FORMATS.BC1_UNORM: CompressionFormat = CompressionFormats.RGB_S3TC_DXT1_EXT; blockSize = 8; break; // BC3 case DX10Header.DXGI_FORMATS.BC3_TYPELESS: case DX10Header.DXGI_FORMATS.BC3_UNORM: CompressionFormat = CompressionFormats.RGBA_S3TC_DXT3_EXT; blockSize = 16; break; // BC5 case DX10Header.DXGI_FORMATS.BC5_TYPELESS: case DX10Header.DXGI_FORMATS.BC5_SNORM: case DX10Header.DXGI_FORMATS.BC5_UNORM: CompressionFormat = CompressionFormats.RGBA_S3TC_DXT5_EXT; blockSize = 16; break; // BC7 case DX10Header.DXGI_FORMATS.BC7_TYPELESS: case DX10Header.DXGI_FORMATS.BC7_UNORM: CompressionFormat = CompressionFormats.RGBA_BPTC_UNORM_EXT; blockSize = 16; break; case DX10Header.DXGI_FORMATS.BC7_UNORM_SRGB: CompressionFormat = CompressionFormats.SRGB_ALPHA_BPTC_UNORM_EXT; blockSize = 16; break; // TODO: Add support for BC1 SRGB, BC2, BC3 SRGB, BC4, and BC6 default: throw new NotImplementedException(string.Format( "Reading DX10 DXGI type \"{0}\" is not yet supported.", dx10Header.DXGIFormat)); } break; } // DXT1 case DDSPixelFormat.FOURCCS.DXT1: CompressionFormat = CompressionFormats.RGB_S3TC_DXT1_EXT; blockSize = 8; break; // DXT3 case DDSPixelFormat.FOURCCS.DXT3: CompressionFormat = CompressionFormats.RGBA_S3TC_DXT3_EXT; blockSize = 16; break; // DXT5 case DDSPixelFormat.FOURCCS.DXT5: case DDSPixelFormat.FOURCCS.ATI2: case DDSPixelFormat.FOURCCS.BC5S: CompressionFormat = CompressionFormats.RGBA_S3TC_DXT5_EXT; blockSize = 16; break; // TODO: Add support for DXT2 and DXT4 default: throw new NotImplementedException(string.Format("{0} \"{1}\" {2}", "Reading DDS files with FOURCC", Header.PixelFormat.FourCC, "is not yet supported.")); } } else { if (!Header.PixelFormat.HasFlag(DDSPixelFormat.FLAGS.RGB)) { throw new NotImplementedException( "Reading DDS files without RGB data is not yet supported."); } if (Header.PixelFormat.RGBBitCount % 8 != 0) { throw new InvalidDataException( "RGBBitCount must be divisible by 8."); } if (Header.PixelFormat.RGBBitCount > 32) { throw new InvalidDataException( "RGBBitCount must be less than or equal to 32."); } if (Header.PixelFormat.RGBBitCount != 32) { throw new NotImplementedException( "Reading DDS files with non 32-bit data is not yet supported."); } pixelsPerBlock = 1; CompressionFormat = CompressionFormats.None; blockSize = (byte)(Header.PixelFormat.RGBBitCount / 8); PixelFormat = PixelFormats.RGBA; } // Whether or not uncompressed pixels need to be re-arranged to RGBA bool isARGB = (CompressionFormat == CompressionFormats.None && Header.PixelFormat.RGBBitCount == 32 && Header.PixelFormat.ABitMask == 0xFF000000 && Header.PixelFormat.RBitMask == 0xFF0000 && Header.PixelFormat.GBitMask == 0xFF00 && Header.PixelFormat.BBitMask == 0xFF); // Data uint width = Width, height = Height; ColorData = new byte[mipmapCount * depth][]; for (uint slice = 0; slice < depth; ++slice) { for (uint level = 0; level < mipmapCount; ++level) { // Pad out width/height to 4x4 blocks if (CompressionFormat != CompressionFormats.None) { if (width % 4 != 0) { width = ((width / 4) + 1) * 4; } if (height % 4 != 0) { height = ((height / 4) + 1) * 4; } } // Compute size of this block uint size = ((width * height) / pixelsPerBlock) * blockSize; // Re-arrange uncompressed pixels to RGBA8 format if necessary if (isARGB) { uint p; ColorData[level] = new byte[size]; for (uint i = 0; i < size; i += 4) { // Convert from ARGB8 to RGBA8 p = reader.ReadUInt32(); ColorData[level][i] = (byte)((p & Header.PixelFormat.RBitMask) >> 16); ColorData[level][i + 1] = (byte)((p & Header.PixelFormat.GBitMask) >> 8); ColorData[level][i + 2] = (byte)(p & Header.PixelFormat.BBitMask); ColorData[level][i + 3] = (byte)((p & Header.PixelFormat.ABitMask) >> 24); } } // Otherwise, simply read the block else { ColorData[level] = reader.ReadBytes((int)size); } // Divide width/height by 2 for the next mipmap width /= 2; height /= 2; } } }
public void SetFlags(TexFormat format, bool isDX10, bool isCubemap) { var dxgiFormat = (DXGI_FORMAT)format; MainHeader.Flags = (uint)(DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PIXELFORMAT | DDSD.MIPMAPCOUNT | DDSD.LINEARSIZE); PfHeader.Caps1 = (uint)DDSCAPS.TEXTURE; if (MainHeader.MipCount > 1) { PfHeader.Caps1 |= (uint)(DDSCAPS.COMPLEX | DDSCAPS.MIPMAP); } if (isCubemap) { PfHeader.Caps2 |= (uint)(DDSCAPS2.CUBEMAP | DDSCAPS2.CUBEMAP_POSITIVEX | DDSCAPS2.CUBEMAP_NEGATIVEX | DDSCAPS2.CUBEMAP_POSITIVEY | DDSCAPS2.CUBEMAP_NEGATIVEY | DDSCAPS2.CUBEMAP_POSITIVEZ | DDSCAPS2.CUBEMAP_NEGATIVEZ); } if (isDX10) { PfHeader.Flags = (uint)DDPF.FOURCC; PfHeader.FourCC = FOURCC_DX10; Dx10Header.DxgiFormat = (uint)dxgiFormat; if (isCubemap) { Dx10Header.ArrayCount = (ArrayCount / 6); Dx10Header.MiscFlags1 = 0x4; } return; } var masks = DDS_RGBA.GetMasks(format); PfHeader.RBitMask = masks[0]; PfHeader.GBitMask = masks[1]; PfHeader.BBitMask = masks[2]; PfHeader.ABitMask = masks[3]; PfHeader.RgbBitCount = 0x8 * TextureFormatHelper.GetBytesPerPixel(format); PfHeader.Flags = (uint)(DDPF.RGB | DDPF.ALPHAPIXELS); switch (format) { case TexFormat.RGBA8_UNORM: case TexFormat.RGB8_SRGB: break; case TexFormat.RGB565_UNORM: PfHeader.Flags = (uint)(DDPF.RGB | DDPF.ALPHAPIXELS); break; case TexFormat.BC1_SRGB: case TexFormat.BC1_UNORM: PfHeader.Flags = (uint)DDPF.FOURCC; PfHeader.FourCC = FOURCC_DXT1; break; case TexFormat.BC2_SRGB: case TexFormat.BC2_UNORM: PfHeader.Flags = (uint)DDPF.FOURCC; PfHeader.FourCC = FOURCC_DXT3; break; case TexFormat.BC3_SRGB: case TexFormat.BC3_UNORM: PfHeader.Flags = (uint)DDPF.FOURCC; PfHeader.FourCC = FOURCC_DXT5; break; case TexFormat.BC4_UNORM: PfHeader.Flags = (uint)DDPF.FOURCC; PfHeader.FourCC = FOURCC_BC4U; break; case TexFormat.BC4_SNORM: PfHeader.Flags = (uint)DDPF.FOURCC; PfHeader.FourCC = FOURCC_BC4S; break; case TexFormat.BC5_UNORM: PfHeader.Flags = (uint)DDPF.FOURCC; PfHeader.FourCC = FOURCC_BC5U; break; case TexFormat.BC5_SNORM: PfHeader.Flags = (uint)DDPF.FOURCC; PfHeader.FourCC = FOURCC_BC5S; break; case TexFormat.BC6H_SF16: case TexFormat.BC6H_UF16: case TexFormat.BC7_UNORM: case TexFormat.BC7_SRGB: PfHeader.Flags = (uint)DDPF.FOURCC; PfHeader.FourCC = FOURCC_DX10; if (Dx10Header == null) { Dx10Header = new DX10Header(); } Dx10Header.DxgiFormat = (uint)dxgiFormat; break; } }