/// <summary> /// Creates a DDS header from a set of information. /// </summary> /// <param name="Mips">Number of mipmaps.</param> /// <param name="Height">Height of top mipmap.</param> /// <param name="Width">Width of top mipmap.</param> /// <param name="surfaceformat">Format header represents.</param> public DDS_Header(int Mips, int Height, int Width, ImageEngineFormat surfaceformat, DXGI_FORMAT dx10Format = DXGI_FORMAT.DXGI_FORMAT_UNKNOWN) { dwSize = 124; dwFlags = DDSdwFlags.DDSD_CAPS | DDSdwFlags.DDSD_HEIGHT | DDSdwFlags.DDSD_WIDTH | DDSdwFlags.DDSD_PIXELFORMAT | (Mips != 1 ? DDSdwFlags.DDSD_MIPMAPCOUNT : 0); this.Width = Width; this.Height = Height; dwCaps = DDSdwCaps.DDSCAPS_TEXTURE | (Mips == 1 ? 0 : DDSdwCaps.DDSCAPS_COMPLEX | DDSdwCaps.DDSCAPS_MIPMAP); dwMipMapCount = Mips == 1 ? 1 : Mips; ddspf = new DDS_PIXELFORMAT(surfaceformat); if (surfaceformat == ImageEngineFormat.DDS_DX10 || surfaceformat == ImageEngineFormat.DDS_ARGB_32F) { if (surfaceformat == ImageEngineFormat.DDS_ARGB_32F) { dx10Format = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT; } DX10_DXGI_AdditionalHeader = new DDS_DXGI_DX10_Additional { dxgiFormat = dx10Format, resourceDimension = D3D10_RESOURCE_DIMENSION.DDS_DIMENSION_TEXTURE2D, miscFlag = DDS_DXGI_DX10_Additional.D3D10_RESOURCE_MISC_FLAGS.D3D10_RESOURCE_MISC_GENERATE_MIPS, miscFlags2 = DXGI_MiscFlags.DDS_ALPHA_MODE_UNKNOWN, arraySize = 1 }; } }
/// <summary> /// Creates a DDS header from a set of information. /// </summary> /// <param name="Mips">Number of mipmaps.</param> /// <param name="Height">Height of top mipmap.</param> /// <param name="Width">Width of top mipmap.</param> /// <param name="surfaceformat">Format header represents.</param> /// <param name="customMasks">Custom user defined masks for colours.</param> public DDS_Header(int Mips, int Height, int Width, ImageEngineFormat surfaceformat, List<uint> customMasks = null) { dwSize = 124; dwFlags = DDSdwFlags.DDSD_CAPS | DDSdwFlags.DDSD_HEIGHT | DDSdwFlags.DDSD_WIDTH | DDSdwFlags.DDSD_PIXELFORMAT | (Mips != 1 ? DDSdwFlags.DDSD_MIPMAPCOUNT : 0); this.Width = Width; this.Height = Height; dwCaps = DDSdwCaps.DDSCAPS_TEXTURE | (Mips == 1 ? 0 : DDSdwCaps.DDSCAPS_COMPLEX | DDSdwCaps.DDSCAPS_MIPMAP); dwMipMapCount = Mips == 1 ? 1 : Mips; ddspf = new DDS_PIXELFORMAT(surfaceformat, customMasks); }
public static void DDSPF_DX10(ref DDS_PIXELFORMAT _PIXELFORMAT) { _PIXELFORMAT.dwSize = 0x20; _PIXELFORMAT.dwFlags = DDS_TYPE.FOURCC; _PIXELFORMAT.dwFourCC = MAKEFOURCC_R('D', 'X', '1', '0'); _PIXELFORMAT.dwRGBBitCount = 0; _PIXELFORMAT.dwRBitMask = 0; _PIXELFORMAT.dwGBitMask = 0; _PIXELFORMAT.dwBBitMask = 0; _PIXELFORMAT.dwABitMask = 0; }
/// <summary> /// Reads DDS pixel format. /// </summary> /// <param name="p">Pixel format struct.</param> /// <param name="r">File reader.</param> private static void Read_DDS_PIXELFORMAT(DDS_PIXELFORMAT p, BinaryReader r) { p.dwSize = r.ReadInt32(); p.dwFlags = r.ReadInt32(); p.dwFourCC = r.ReadInt32(); p.dwRGBBitCount = r.ReadInt32(); p.dwRBitMask = r.ReadInt32(); p.dwGBitMask = r.ReadInt32(); p.dwBBitMask = r.ReadInt32(); p.dwABitMask = r.ReadInt32(); }
public static void DDSPF_Q8W8V8U8(ref DDS_PIXELFORMAT _PIXELFORMAT) { _PIXELFORMAT.dwSize = 0x20; _PIXELFORMAT.dwFlags = DDS_TYPE.BUMPDUDV; _PIXELFORMAT.dwFourCC = 0; _PIXELFORMAT.dwRGBBitCount = 32; _PIXELFORMAT.dwRBitMask = 0x000000FF; _PIXELFORMAT.dwGBitMask = 0x0000FF00; _PIXELFORMAT.dwBBitMask = 0x00FF0000; _PIXELFORMAT.dwABitMask = 0xFF000000; }
public static void DDSPF_A8(ref DDS_PIXELFORMAT _PIXELFORMAT) { _PIXELFORMAT.dwSize = 0x20; _PIXELFORMAT.dwFlags = DDS_TYPE.ALPHA; _PIXELFORMAT.dwFourCC = 0; _PIXELFORMAT.dwRGBBitCount = 8; _PIXELFORMAT.dwRBitMask = 0; _PIXELFORMAT.dwGBitMask = 0; _PIXELFORMAT.dwBBitMask = 0; _PIXELFORMAT.dwABitMask = 0x00FF; }
public static void DDSPF_A8L8_ALT(ref DDS_PIXELFORMAT _PIXELFORMAT) { _PIXELFORMAT.dwSize = 0x20; _PIXELFORMAT.dwFlags = DDS_TYPE.LUMINANCEA; _PIXELFORMAT.dwFourCC = 0; _PIXELFORMAT.dwRGBBitCount = 8; _PIXELFORMAT.dwRBitMask = 0x00FF; _PIXELFORMAT.dwGBitMask = 0; _PIXELFORMAT.dwBBitMask = 0; _PIXELFORMAT.dwABitMask = 0xFF00; }
public static void DDSPF_L16(ref DDS_PIXELFORMAT _PIXELFORMAT) { _PIXELFORMAT.dwSize = 0x20; _PIXELFORMAT.dwFlags = DDS_TYPE.LUMINANCE; _PIXELFORMAT.dwFourCC = 0; _PIXELFORMAT.dwRGBBitCount = 16; _PIXELFORMAT.dwRBitMask = 0xFFFF; _PIXELFORMAT.dwGBitMask = 0; _PIXELFORMAT.dwBBitMask = 0; _PIXELFORMAT.dwABitMask = 0; }
public static void DDSPF_R8G8B8(ref DDS_PIXELFORMAT _PIXELFORMAT) { _PIXELFORMAT.dwSize = 0x20; _PIXELFORMAT.dwFlags = DDS_TYPE.RGB; _PIXELFORMAT.dwFourCC = 0; _PIXELFORMAT.dwRGBBitCount = 24; _PIXELFORMAT.dwRBitMask = 0x00FF0000; _PIXELFORMAT.dwGBitMask = 0x0000FF00; _PIXELFORMAT.dwBBitMask = 0x000000FF; _PIXELFORMAT.dwABitMask = 0; }
public static void DDSPF_A1R5G5B5(ref DDS_PIXELFORMAT _PIXELFORMAT) { _PIXELFORMAT.dwSize = 0x20; _PIXELFORMAT.dwFlags = DDS_TYPE.RGBA; _PIXELFORMAT.dwFourCC = 0; _PIXELFORMAT.dwRGBBitCount = 16; _PIXELFORMAT.dwRBitMask = 0x00007C00; _PIXELFORMAT.dwGBitMask = 0x000003E0; _PIXELFORMAT.dwBBitMask = 0x0000001F; _PIXELFORMAT.dwABitMask = 0x00008000; }
public static void DDSPF_YUY2(ref DDS_PIXELFORMAT _PIXELFORMAT) { _PIXELFORMAT.dwSize = 0x20; _PIXELFORMAT.dwFlags = DDS_TYPE.FOURCC; _PIXELFORMAT.dwFourCC = MAKEFOURCC_R('Y', 'U', 'Y', '2'); _PIXELFORMAT.dwRGBBitCount = 0; _PIXELFORMAT.dwRBitMask = 0; _PIXELFORMAT.dwGBitMask = 0; _PIXELFORMAT.dwBBitMask = 0; _PIXELFORMAT.dwABitMask = 0; }
public static void DDSPF_G8R8_G8B8(ref DDS_PIXELFORMAT _PIXELFORMAT) { _PIXELFORMAT.dwSize = 0x20; _PIXELFORMAT.dwFlags = DDS_TYPE.FOURCC; _PIXELFORMAT.dwFourCC = MAKEFOURCC_R('G', 'R', 'G', 'B'); _PIXELFORMAT.dwRGBBitCount = 0; _PIXELFORMAT.dwRBitMask = 0; _PIXELFORMAT.dwGBitMask = 0; _PIXELFORMAT.dwBBitMask = 0; _PIXELFORMAT.dwABitMask = 0; }
public static void DDSPF_BC5_SNORM(ref DDS_PIXELFORMAT _PIXELFORMAT) { _PIXELFORMAT.dwSize = 0x20; _PIXELFORMAT.dwFlags = DDS_TYPE.FOURCC; _PIXELFORMAT.dwFourCC = MAKEFOURCC_R('B', 'C', '5', 'S'); _PIXELFORMAT.dwRGBBitCount = 0; _PIXELFORMAT.dwRBitMask = 0; _PIXELFORMAT.dwGBitMask = 0; _PIXELFORMAT.dwBBitMask = 0; _PIXELFORMAT.dwABitMask = 0; }
private DDS_PIXELFORMAT ReadPixelFormat(Stream s) { DDS_PIXELFORMAT r = new DDS_PIXELFORMAT(); r.dwSize = ReadUInt(s); r.dwFlags = ReadUInt(s); r.dwFourCC = ReadUInt(s); r.dwRGBBitCount = ReadUInt(s); r.dwRBitMask = ReadUInt(s); r.dwGBitMask = ReadUInt(s); r.dwBBitMask = ReadUInt(s); r.dwABitMask = ReadUInt(s); return(r); }
DDS_PIXELFORMAT ReadPixelFormat() { DDS_PIXELFORMAT pf = new DDS_PIXELFORMAT(); pf.dwSize = ReadInt(); pf.dwFlags = ReadEnumFlags <DDS_PIXELFORMAT.DWFlags>(); pf.dwFourCC = ReadString(4); pf.dwRGBBitCount = ReadInt(); pf.dwRBitMask = ReadInt(); pf.dwGBitMask = ReadInt(); pf.dwBBitMask = ReadInt(); pf.dwABitMask = ReadInt(); return(pf); }
public static DDS_PIXELFORMAT make(DDS_PIXELFORMAT_FLAGS flags, FourCC fourCC, uint RGBBitCount, uint RBitMask, uint GBitMask, uint BBitMask, uint ABitMask) { DDS_PIXELFORMAT result = new DDS_PIXELFORMAT(); result.size = (uint)Marshal.SizeOf <DDS_PIXELFORMAT>(); result.flags = flags; result.fourCC = fourCC; result.RGBBitCount = RGBBitCount; result.RBitMask = RBitMask; result.GBitMask = GBitMask; result.BBitMask = BBitMask; result.ABitMask = ABitMask; return(result); }
/// <summary> /// Edits .dds pixelformat based on compression passed. /// </summary> /// <param name="_PIXELFORMAT">.dds pixelformat of the .dds header passed as a reference type.</param> /// <param name="compression">EA compression byte of the image.</param> public static void GetPixelFormat(ref DDS_PIXELFORMAT _PIXELFORMAT, byte compression) { switch (compression) { case EAComp.DXT1_08: DDS_CONST.DDSPF_DXT1(ref _PIXELFORMAT); break; case EAComp.DXT3_08: DDS_CONST.DDSPF_DXT3(ref _PIXELFORMAT); break; case EAComp.DXT5_08: DDS_CONST.DDSPF_DXT5(ref _PIXELFORMAT); break; default: // set to be RGB in case of mismatch DDS_CONST.DDSPF_A8R8G8B8(ref _PIXELFORMAT); break; } }
/// <summary> /// Reads DDS header from stream. /// </summary> /// <param name="stream">Fully formatted DDS image.</param> /// <returns>Header length.</returns> protected override long Load(Stream stream) { base.Load(stream); var temp = stream.ReadBytes(MaxHeaderSize); if (!CheckIdentifier(temp)) { throw new FormatException("Stream is not a recognised DDS image."); } // Start header dwSize = BitConverter.ToInt32(temp, 4); dwFlags = (DDSdwFlags)BitConverter.ToInt32(temp, 8); Height = BitConverter.ToInt32(temp, 12); Width = BitConverter.ToInt32(temp, 16); dwPitchOrLinearSize = BitConverter.ToInt32(temp, 20); dwDepth = BitConverter.ToInt32(temp, 24); dwMipMapCount = BitConverter.ToInt32(temp, 28); for (int i = 0; i < 11; ++i) { dwReserved1[i] = BitConverter.ToInt32(temp, 32 + (i * 4)); } // DDS PixelFormat ddspf = new DDS_PIXELFORMAT(temp); dwCaps = (DDSdwCaps)BitConverter.ToInt32(temp, 108); dwCaps2 = BitConverter.ToInt32(temp, 112); dwCaps3 = BitConverter.ToInt32(temp, 116); dwCaps4 = BitConverter.ToInt32(temp, 120); dwReserved2 = BitConverter.ToInt32(temp, 124); // DX10 Additional header if (ddspf.dwFourCC == FourCC.DX10) { DX10_DXGI_AdditionalHeader = new DDS_DXGI_DX10_Additional(temp); } return(MaxHeaderSize); }
/// <summary> /// Writes V8U8 DDS header to binary stream. /// </summary> /// <param name="header">Header to write.</param> /// <param name="writer">BinaryWriter wrapped stream to write to.</param> private static void Write_V8U8_DDS_Header(DDS_HEADER header, BinaryWriter writer) { // KFreon: Write magic number ("DDS") writer.Write(0x20534444); // KFreon: Write all header fields regardless of filled or not writer.Write(header.dwSize); writer.Write(header.dwFlags); writer.Write(header.dwHeight); writer.Write(header.dwWidth); writer.Write(header.dwPitchOrLinearSize); writer.Write(header.dwDepth); writer.Write(header.dwMipMapCount); // KFreon: Write reserved1 for (int i = 0; i < 11; i++) { writer.Write(0); } // KFreon: Write PIXELFORMAT DDS_PIXELFORMAT px = header.ddspf; writer.Write(px.dwSize); writer.Write(px.dwFlags); writer.Write(px.dwFourCC); writer.Write(px.dwRGBBitCount); writer.Write(px.dwRBitMask); writer.Write(px.dwGBitMask); writer.Write(px.dwBBitMask); writer.Write(px.dwABitMask); writer.Write(header.dwCaps); writer.Write(header.dwCaps2); writer.Write(header.dwCaps3); writer.Write(header.dwCaps4); writer.Write(header.dwReserved2); }
/// <summary> /// Builds a V8U8 DDS header from certain details. /// </summary> /// <param name="Mips">Number of mipmaps.</param> /// <param name="height">Height of image.</param> /// <param name="width">Width of image.</param> /// <returns>DDS_HEADER struct from details.</returns> private static DDS_HEADER Build_V8U8_DDS_Header(int Mips, int height, int width) { DDS_HEADER header = new DDS_HEADER(); header.dwSize = 124; header.dwFlags = 0x1 | 0x2 | 0x4 | 0x1000 | (Mips != 0 ? 0x20000 : 0x0); // Flags to denote valid fields: DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT header.dwWidth = width; header.dwHeight = height; header.dwCaps = 0x1000 | 0x8 | (Mips == 0 ? 0 : 0x400000); header.dwMipMapCount = Mips == 0 ? 1 : Mips; //header.dwPitchOrLinearSize = ((width + 1) >> 1)*4; DDS_PIXELFORMAT px = new DDS_PIXELFORMAT(); px.dwSize = 32; //px.dwFlags = 0x200; px.dwFlags = 0x80000; px.dwRGBBitCount = 16; px.dwRBitMask = 255; px.dwGBitMask = 0x0000FF00; header.ddspf = px; return(header); }
private DDS_PIXELFORMAT ReadPixelFormat(Stream s) { DDS_PIXELFORMAT r = new DDS_PIXELFORMAT(); r.dwSize = ReadUInt(s); r.dwFlags = ReadUInt(s); r.dwFourCC = ReadUInt(s); r.dwRGBBitCount = ReadUInt(s); r.dwRBitMask = ReadUInt(s); r.dwGBitMask = ReadUInt(s); r.dwBBitMask = ReadUInt(s); r.dwABitMask = ReadUInt(s); return r; }
/// <summary> /// Create a DDS file from a D3DTX /// </summary> /// <param name="d3dtx"></param> public DDS_Master(D3DTX_Master d3dtx) { header = DDS_Functions.GetPresetHeader(); T3SurfaceFormat surfaceFormat = T3SurfaceFormat.eSurface_DXT1; if (d3dtx.d3dtx4 != null) { header.dwWidth = d3dtx.d3dtx4.mWidth; header.dwHeight = d3dtx.d3dtx4.mHeight; header.dwMipMapCount = d3dtx.d3dtx4.mNumMipLevels; surfaceFormat = d3dtx.d3dtx4.mSurfaceFormat; } else if (d3dtx.d3dtx5 != null) { header.dwWidth = d3dtx.d3dtx5.mWidth; header.dwHeight = d3dtx.d3dtx5.mHeight; header.dwMipMapCount = d3dtx.d3dtx5.mNumMipLevels; surfaceFormat = d3dtx.d3dtx5.mSurfaceFormat; } else if (d3dtx.d3dtx6 != null) { header.dwWidth = d3dtx.d3dtx6.mWidth; header.dwHeight = d3dtx.d3dtx6.mHeight; header.dwMipMapCount = d3dtx.d3dtx6.mNumMipLevels; surfaceFormat = d3dtx.d3dtx6.mSurfaceFormat; } else if (d3dtx.d3dtx7 != null) { header.dwWidth = d3dtx.d3dtx7.mWidth; header.dwHeight = d3dtx.d3dtx7.mHeight; header.dwMipMapCount = d3dtx.d3dtx7.mNumMipLevels; //header.dwDepth = d3dtx.d3dtx7.mDepth; surfaceFormat = d3dtx.d3dtx7.mSurfaceFormat; } else if (d3dtx.d3dtx8 != null) { header.dwWidth = d3dtx.d3dtx8.mWidth; header.dwHeight = d3dtx.d3dtx8.mHeight; header.dwMipMapCount = d3dtx.d3dtx8.mNumMipLevels; header.dwDepth = d3dtx.d3dtx8.mDepth; surfaceFormat = d3dtx.d3dtx8.mSurfaceFormat; } else if (d3dtx.d3dtx9 != null) { header.dwWidth = d3dtx.d3dtx9.mWidth; header.dwHeight = d3dtx.d3dtx9.mHeight; header.dwMipMapCount = d3dtx.d3dtx9.mNumMipLevels; header.dwDepth = d3dtx.d3dtx9.mDepth; surfaceFormat = d3dtx.d3dtx9.mSurfaceFormat; } DDS_PIXELFORMAT new_ddspf = new DDS_PIXELFORMAT(); new_ddspf.dwFourCC = DDS_Functions.Get_FourCC_FromTellale(surfaceFormat); switch (surfaceFormat) { case Telltale.T3SurfaceFormat.eSurface_A8: new_ddspf.dwABitMask = 255; header.dwCaps = 4198408; //DDSCAPS_COMPLEX | DDSCAPS_TEXTURE | DDSCAPS_MIPMAP break; case Telltale.T3SurfaceFormat.eSurface_ARGB8: new_ddspf.dwABitMask = 255; new_ddspf.dwRBitMask = 255; new_ddspf.dwGBitMask = 255; new_ddspf.dwBBitMask = 255; header.dwCaps = 4198408; //DDSCAPS_COMPLEX | DDSCAPS_TEXTURE | DDSCAPS_MIPMAP break; } header.ddspf = new_ddspf; }
/// <summary> /// Builds a V8U8 DDS header from certain details. /// </summary> /// <param name="Mips">Number of mipmaps.</param> /// <param name="height">Height of image.</param> /// <param name="width">Width of image.</param> /// <returns>DDS_HEADER struct from details.</returns> private static DDS_HEADER Build_V8U8_DDS_Header(int Mips, int height, int width) { DDS_HEADER header = new DDS_HEADER(); header.dwSize = 124; header.dwFlags = 0x1 | 0x2 | 0x4 | 0x1000 | (Mips != 0 ? 0x20000 : 0x0); // Flags to denote valid fields: DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT header.dwWidth = width; header.dwHeight = height; header.dwCaps = 0x1000 | 0x8 | (Mips == 0 ? 0 : 0x400000); header.dwMipMapCount = Mips == 0 ? 1 : Mips; //header.dwPitchOrLinearSize = ((width + 1) >> 1)*4; DDS_PIXELFORMAT px = new DDS_PIXELFORMAT(); px.dwSize = 32; //px.dwFlags = 0x200; px.dwFlags = 0x80000; px.dwRGBBitCount = 16; px.dwRBitMask = 255; px.dwGBitMask = 0x0000FF00; header.ddspf = px; return header; }
/// <summary> /// Reads DDS header from stream. /// </summary> /// <param name="stream">Fully formatted DDS image.</param> /// <returns>Header length.</returns> protected override long Load(Stream stream) { base.Load(stream); var temp = stream.ReadBytes(HeaderSize); if (!CheckIdentifier(temp)) throw new FormatException("Stream is not a recognised DDS image."); // Start header dwSize = BitConverter.ToInt32(temp, 4); dwFlags = (DDSdwFlags)BitConverter.ToInt32(temp, 8); Height = BitConverter.ToInt32(temp, 12); Width = BitConverter.ToInt32(temp, 16); dwPitchOrLinearSize = BitConverter.ToInt32(temp, 20); dwDepth = BitConverter.ToInt32(temp, 24); dwMipMapCount = BitConverter.ToInt32(temp, 28); for (int i = 0; i < 11; ++i) dwReserved1[i] = BitConverter.ToInt32(temp, 32 + (i * 4)); // DDS PixelFormat ddspf = new DDS_PIXELFORMAT(temp); dwCaps = (DDSdwCaps)BitConverter.ToInt32(temp, 108); dwCaps2 = BitConverter.ToInt32(temp, 112); dwCaps3 = BitConverter.ToInt32(temp, 116); dwCaps4 = BitConverter.ToInt32(temp, 120); dwReserved2 = BitConverter.ToInt32(temp, 124); // DX10 Additional header if (ddspf.dwFourCC == FourCC.DX10) DX10_DXGI_AdditionalHeader = new DDS_DXGI_DX10_Additional(temp); return HeaderSize; }
static bool ISBITMASK(DDS_PIXELFORMAT ddpf, uint r, uint g, uint b, uint a) { return(ddpf.RBitMask == r && ddpf.GBitMask == g && ddpf.BBitMask == b && ddpf.ABitMask == a); }
static Format GetDXGIFormat(DDS_PIXELFORMAT ddpf) { if ((ddpf.flags & DDS_RGB) > 0) { // Note that sRGB formats are written using the "DX10" extended header switch (ddpf.RGBBitCount) { case 32: if (ISBITMASK(ddpf, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000)) { return(Format.R8G8B8A8_UNorm); } if (ISBITMASK(ddpf, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000)) { return(Format.B8G8R8A8_UNorm); } if (ISBITMASK(ddpf, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000)) { return(Format.B8G8R8X8_UNorm); } // No DXGI format maps to ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000) aka D3DFMT_X8B8G8R8 // Note that many common DDS reader/writers (including D3DX) swap the // the RED/BLUE masks for 10:10:10:2 formats. We assumme // 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 // For 'correct' writers, this should be 0x000003ff, 0x000ffc00, 0x3ff00000 for RGB data if (ISBITMASK(ddpf, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000)) { return(Format.R10G10B10A2_UNorm); } // No DXGI format maps to ISBITMASK(0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000) aka D3DFMT_A2R10G10B10 if (ISBITMASK(ddpf, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000)) { return(Format.R16G16_UNorm); } if (ISBITMASK(ddpf, 0xffffffff, 0x00000000, 0x00000000, 0x00000000)) { // Only 32-bit color channel format in D3D9 was R32F return(Format.R32_Float); // D3DX writes this out as a FourCC of 114 } break; case 24: // No 24bpp DXGI formats aka D3DFMT_R8G8B8 break; case 16: if (ISBITMASK(ddpf, 0x7c00, 0x03e0, 0x001f, 0x8000)) { return(Format.B5G5R5A1_UNorm); } if (ISBITMASK(ddpf, 0xf800, 0x07e0, 0x001f, 0x0000)) { return(Format.B5G6R5_UNorm); } // No DXGI format maps to ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x0000) aka D3DFMT_X1R5G5B5 if (ISBITMASK(ddpf, 0x0f00, 0x00f0, 0x000f, 0xf000)) { return(Format.B4G4R4A4_UNorm); } // No DXGI format maps to ISBITMASK(0x0f00, 0x00f0, 0x000f, 0x0000) aka D3DFMT_X4R4G4B4 // No 3:3:2, 3:3:2:8, or paletted DXGI formats aka D3DFMT_A8R3G3B2, D3DFMT_R3G3B2, D3DFMT_P8, D3DFMT_A8P8, etc. break; } } else if ((ddpf.flags & DDS_LUMINANCE) > 0) { if (8 == ddpf.RGBBitCount) { if (ISBITMASK(ddpf, 0x000000ff, 0x00000000, 0x00000000, 0x00000000)) { return(Format.R8_UNorm); // D3DX10/11 writes this out as DX10 extension } // No DXGI format maps to ISBITMASK(0x0f, 0x00, 0x00, 0xf0) aka D3DFMT_A4L4 } if (16 == ddpf.RGBBitCount) { if (ISBITMASK(ddpf, 0x0000ffff, 0x00000000, 0x00000000, 0x00000000)) { return(Format.R16_UNorm); // D3DX10/11 writes this out as DX10 extension } if (ISBITMASK(ddpf, 0x000000ff, 0x00000000, 0x00000000, 0x0000ff00)) { return(Format.R8G8_UNorm); // D3DX10/11 writes this out as DX10 extension } } } else if ((ddpf.flags & DDS_ALPHA) > 0) { if (8 == ddpf.RGBBitCount) { return(Format.A8_UNorm); } } else if ((ddpf.flags & DDS_FOURCC) > 0) { if (MAKEFOURCC('D', 'X', 'T', '1') == ddpf.fourCC) { return(Format.BC1_UNorm); } if (MAKEFOURCC('D', 'X', 'T', '3') == ddpf.fourCC) { return(Format.BC2_UNorm); } if (MAKEFOURCC('D', 'X', 'T', '5') == ddpf.fourCC) { return(Format.BC3_UNorm); } // While pre-mulitplied alpha isn't directly supported by the DXGI formats, // they are basically the same as these BC formats so they can be mapped if (MAKEFOURCC('D', 'X', 'T', '2') == ddpf.fourCC) { return(Format.BC2_UNorm); } if (MAKEFOURCC('D', 'X', 'T', '4') == ddpf.fourCC) { return(Format.BC3_UNorm); } if (MAKEFOURCC('A', 'T', 'I', '1') == ddpf.fourCC) { return(Format.BC4_UNorm); } if (MAKEFOURCC('B', 'C', '4', 'U') == ddpf.fourCC) { return(Format.BC4_UNorm); } if (MAKEFOURCC('B', 'C', '4', 'S') == ddpf.fourCC) { return(Format.BC4_SNorm); } if (MAKEFOURCC('A', 'T', 'I', '2') == ddpf.fourCC) { return(Format.BC5_UNorm); } if (MAKEFOURCC('B', 'C', '5', 'U') == ddpf.fourCC) { return(Format.BC5_UNorm); } if (MAKEFOURCC('B', 'C', '5', 'S') == ddpf.fourCC) { return(Format.BC5_SNorm); } // BC6H and BC7 are written using the "DX10" extended header if (MAKEFOURCC('R', 'G', 'B', 'G') == ddpf.fourCC) { return(Format.R8G8_B8G8_UNorm); } if (MAKEFOURCC('G', 'R', 'G', 'B') == ddpf.fourCC) { return(Format.G8R8_G8B8_UNorm); } // Check for D3DFORMAT enums being set here switch (ddpf.fourCC) { case 36: // D3DFMT_A16B16G16R16 return(Format.R16G16B16A16_UNorm); case 110: // D3DFMT_Q16W16V16U16 return(Format.R16G16B16A16_SNorm); case 111: // D3DFMT_R16F return(Format.R16_Float); case 112: // D3DFMT_G16R16F return(Format.R16G16_Float); case 113: // D3DFMT_A16B16G16R16F return(Format.R16G16B16A16_Float); case 114: // D3DFMT_R32F return(Format.R32_Float); case 115: // D3DFMT_G32R32F return(Format.R32G32_Float); case 116: // D3DFMT_A32B32G32R32F return(Format.R32G32B32A32_Float); } } return(Format.Unknown); }
internal static string ExportDDSTexture(Texture2D texture, string directory, bool overwrite = false) { if (texture.Format != TextureFormat.Alpha8 && texture.Format != TextureFormat.ARGB4444 && texture.Format != TextureFormat.RGB24 && texture.Format != TextureFormat.RGBA32 && texture.Format != TextureFormat.ARGB32 && texture.Format != TextureFormat.RGB565 && texture.Format != TextureFormat.R16 && texture.Format != TextureFormat.DXT1 && texture.Format != TextureFormat.DXT5 && texture.Format != TextureFormat.RGBA4444 && texture.Format != TextureFormat.BGRA32 && texture.Format != TextureFormat.RG16 && texture.Format != TextureFormat.R8) { throw new UnsupportedFormatException($"Cannot export {texture.Format.ToString()} to DDS format."); } string exportPath = Path.Combine(directory, $"{texture.m_Name}.dds"); if (File.Exists(exportPath) && !overwrite) { throw new IOException($"File {exportPath} already exist and overwrite argument is not set true."); } byte[] textureData = Texture2DExporter.GetTextureData(texture); DDS_HEADER ddsHeader = new DDS_HEADER() { dwSize = 0x7C, dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT, dwHeight = (uint)texture.m_Height, dwWidth = (uint)texture.m_Width, dwPitchOrLinearSize = (uint)texture.m_CompleteImageSize, dwDepth = 0, dwMipMapCount = (uint)texture.m_MipCount, dwReserved = DDS_GENERATOR_DATA, dwCaps = DDSCAPS_TEXTURE, dwCaps2 = 0, dwCaps3 = 0, dwCaps4 = 0, dwReserved2 = 0, }; DDS_PIXELFORMAT ddspf = new DDS_PIXELFORMAT() { dwSize = 0x20, dwFlags = 0, dwFourCC = 0, dwRGBBitCount = 0, dwRBitMask = 0, dwGBitMask = 0, dwBBitMask = 0, dwABitMask = 0, }; if (texture.HasMips) { ddsHeader.dwFlags |= DDSD_MIPMAPCOUNT; ddsHeader.dwCaps |= DDSCAPS_MIPMAP; } int blocksize = 0; switch (texture.Format) { case TextureFormat.Alpha8: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_ALPHAPIXELS; ddspf.dwRGBBitCount = 0x8; ddspf.dwABitMask = 0xF; blocksize = 8; break; } case TextureFormat.ARGB4444: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB; ddspf.dwRGBBitCount = 0x10; ddspf.dwRBitMask = 0xFu << 8; ddspf.dwGBitMask = 0xFu << 4; ddspf.dwBBitMask = 0xFu; ddspf.dwABitMask = 0xFu << 12; blocksize = 16; break; } case TextureFormat.RGB24: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_RGB; ddspf.dwRGBBitCount = 0x18; ddspf.dwRBitMask = 0xFFu << 16; ddspf.dwGBitMask = 0xFFu << 8; ddspf.dwBBitMask = 0xFFu; blocksize = 24; break; } case TextureFormat.RGBA32: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB; ddspf.dwRGBBitCount = 0x20; ddspf.dwRBitMask = 0xFFu << 24; ddspf.dwGBitMask = 0xFFu << 16; ddspf.dwBBitMask = 0xFFu << 8; ddspf.dwABitMask = 0xFFu; blocksize = 32; break; } case TextureFormat.ARGB32: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB; ddspf.dwRGBBitCount = 0x20; ddspf.dwRBitMask = 0xFFu << 16; ddspf.dwGBitMask = 0xFFu << 8; ddspf.dwBBitMask = 0xFFu; ddspf.dwABitMask = 0xFFu << 24; blocksize = 32; break; } case TextureFormat.RGB565: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_RGB; ddspf.dwRGBBitCount = 0x10; ddspf.dwRBitMask = 0b1111_1000_0000_0000; ddspf.dwGBitMask = 0b0000_0111_1110_0000; ddspf.dwBBitMask = 0b0000_0000_0001_1111; blocksize = 16; break; } case TextureFormat.R16: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_RGB; ddspf.dwRGBBitCount = 0x10; ddspf.dwRBitMask = 0xFFFF; blocksize = 16; break; } case TextureFormat.DXT1: { ddsHeader.dwFlags |= DDSD_LINEARSIZE; ddspf.dwFlags = DDPF_FOURCC; ddspf.dwFourCC = 0x31545844; // DXT1 blocksize = 16; break; } case TextureFormat.DXT5: { ddsHeader.dwFlags |= DDSD_LINEARSIZE; ddspf.dwFlags = DDPF_FOURCC; ddspf.dwFourCC = 0x35545844; // DXT5 break; } case TextureFormat.RGBA4444: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB; ddspf.dwRGBBitCount = 0x10; ddspf.dwRBitMask = 0xFu << 12; ddspf.dwGBitMask = 0xFu << 8; ddspf.dwBBitMask = 0xFu << 4; ddspf.dwABitMask = 0xFu; break; } case TextureFormat.BGRA32: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB; ddspf.dwRGBBitCount = 0x20; ddspf.dwRBitMask = 0xFFu << 8; ddspf.dwGBitMask = 0xFFu << 16; ddspf.dwBBitMask = 0xFFu << 24; ddspf.dwABitMask = 0xFFu; break; } case TextureFormat.RG16: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_RGB; ddspf.dwRGBBitCount = 0x10; ddspf.dwRBitMask = 0xFF00; ddspf.dwGBitMask = 0x00FF; break; } case TextureFormat.R8: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_RGB; ddspf.dwRGBBitCount = 0x8; ddspf.dwRBitMask = 0xF; break; } default: throw new UnsupportedFormatException($"Cannot export {texture.Format} to DDS format."); } ddsHeader.ddspf = ddspf; using (var writer = new BinaryWriter(File.OpenWrite(exportPath))) { writer.Write(0x20534444u); // 'DDS ' writer.Write(ddsHeader.dwSize); writer.Write(ddsHeader.dwFlags); writer.Write(ddsHeader.dwHeight); writer.Write(ddsHeader.dwWidth); writer.Write(ddsHeader.dwPitchOrLinearSize); writer.Write(ddsHeader.dwDepth); writer.Write(ddsHeader.dwMipMapCount); for (int i = 0; i < ddsHeader.dwReserved.Length; i++) { writer.Write(ddsHeader.dwReserved[i]); } writer.Write(ddsHeader.ddspf.dwSize); writer.Write(ddsHeader.ddspf.dwFlags); writer.Write(ddsHeader.ddspf.dwFourCC); writer.Write(ddsHeader.ddspf.dwRGBBitCount); writer.Write(ddsHeader.ddspf.dwRBitMask); writer.Write(ddsHeader.ddspf.dwGBitMask); writer.Write(ddsHeader.ddspf.dwBBitMask); writer.Write(ddsHeader.ddspf.dwABitMask); writer.Write(ddsHeader.dwCaps); writer.Write(ddsHeader.dwCaps2); writer.Write(ddsHeader.dwCaps3); writer.Write(ddsHeader.dwCaps4); writer.Write(ddsHeader.dwReserved2); writer.Write(textureData); } return(exportPath); }