mirror of
https://github.com/Vita3K/Vita3K.git
synced 2025-04-02 11:02:10 -04:00
1055 lines
36 KiB
C++
1055 lines
36 KiB
C++
#pragma once
|
|
|
|
// Sources
|
|
// https://learn.microsoft.com/en-us/windows/uwp/gaming/complete-code-for-ddstextureloader
|
|
// https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-header
|
|
// https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-header-dxt10
|
|
// https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-pixelformat
|
|
|
|
#if (__cpp_constexpr == 201304) || (_MSC_VER > 1900)
|
|
#define ddspp_constexpr constexpr
|
|
#else
|
|
#define ddspp_constexpr const
|
|
#endif
|
|
|
|
namespace ddspp
|
|
{
|
|
namespace internal
|
|
{
|
|
static ddspp_constexpr unsigned int DDS_MAGIC = 0x20534444;
|
|
|
|
static ddspp_constexpr unsigned int DDS_ALPHAPIXELS = 0x00000001;
|
|
static ddspp_constexpr unsigned int DDS_ALPHA = 0x00000002; // DDPF_ALPHA
|
|
static ddspp_constexpr unsigned int DDS_FOURCC = 0x00000004; // DDPF_FOURCC
|
|
static ddspp_constexpr unsigned int DDS_RGB = 0x00000040; // DDPF_RGB
|
|
static ddspp_constexpr unsigned int DDS_RGBA = 0x00000041; // DDPF_RGB | DDPF_ALPHAPIXELS
|
|
static ddspp_constexpr unsigned int DDS_YUV = 0x00000200; // DDPF_YUV
|
|
static ddspp_constexpr unsigned int DDS_LUMINANCE = 0x00020000; // DDPF_LUMINANCE
|
|
static ddspp_constexpr unsigned int DDS_LUMINANCEA = 0x00020001; // DDPF_LUMINANCE | DDPF_ALPHAPIXELS
|
|
|
|
static ddspp_constexpr unsigned int DDS_PAL8 = 0x00000020; // DDPF_PALETTEINDEXED8
|
|
static ddspp_constexpr unsigned int DDS_BUMPDUDV = 0x00080000; // DDPF_BUMPDUDV
|
|
|
|
static ddspp_constexpr unsigned int DDS_HEADER_FLAGS_CAPS = 0x00000001; // DDSD_CAPS
|
|
static ddspp_constexpr unsigned int DDS_HEADER_FLAGS_HEIGHT = 0x00000002; // DDSD_HEIGHT
|
|
static ddspp_constexpr unsigned int DDS_HEADER_FLAGS_WIDTH = 0x00000004; // DDSD_WIDTH
|
|
static ddspp_constexpr unsigned int DDS_HEADER_FLAGS_PITCH = 0x00000008; // DDSD_PITCH
|
|
static ddspp_constexpr unsigned int DDS_HEADER_FLAGS_PIXELFORMAT = 0x00001000; // DDSD_PIXELFORMAT
|
|
static ddspp_constexpr unsigned int DDS_HEADER_FLAGS_MIPMAP = 0x00020000; // DDSD_MIPMAPCOUNT
|
|
static ddspp_constexpr unsigned int DDS_HEADER_FLAGS_LINEARSIZE = 0x00080000; // DDSD_LINEARSIZE
|
|
static ddspp_constexpr unsigned int DDS_HEADER_FLAGS_VOLUME = 0x00800000; // DDSD_DEPTH
|
|
|
|
static ddspp_constexpr unsigned int DDS_HEADER_CAPS_COMPLEX = 0x00000008; // DDSCAPS_COMPLEX
|
|
static ddspp_constexpr unsigned int DDS_HEADER_CAPS_MIPMAP = 0x00400000; // DDSCAPS_MIPMAP
|
|
static ddspp_constexpr unsigned int DDS_HEADER_CAPS_TEXTURE = 0x00001000; // DDSCAPS_TEXTURE
|
|
|
|
static ddspp_constexpr unsigned int DDS_HEADER_CAPS2_CUBEMAP = 0x00000200; // DDSCAPS2_CUBEMAP
|
|
static ddspp_constexpr unsigned int DDS_HEADER_CAPS2_CUBEMAP_POSITIVEX = 0x00000600; // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX
|
|
static ddspp_constexpr unsigned int DDS_HEADER_CAPS2_CUBEMAP_NEGATIVEX = 0x00000a00; // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX
|
|
static ddspp_constexpr unsigned int DDS_HEADER_CAPS2_CUBEMAP_POSITIVEY = 0x00001200; // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY
|
|
static ddspp_constexpr unsigned int DDS_HEADER_CAPS2_CUBEMAP_NEGATIVEY = 0x00002200; // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY
|
|
static ddspp_constexpr unsigned int DDS_HEADER_CAPS2_CUBEMAP_POSITIVEZ = 0x00004200; // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ
|
|
static ddspp_constexpr unsigned int DDS_HEADER_CAPS2_CUBEMAP_NEGATIVEZ = 0x00008200; // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ
|
|
static ddspp_constexpr unsigned int DDS_HEADER_CAPS2_VOLUME = 0x00200000; // DDSCAPS2_VOLUME
|
|
static ddspp_constexpr unsigned int DDS_HEADER_CAPS2_CUBEMAP_ALLFACES =
|
|
DDS_HEADER_CAPS2_CUBEMAP_POSITIVEX | DDS_HEADER_CAPS2_CUBEMAP_NEGATIVEX | DDS_HEADER_CAPS2_CUBEMAP_POSITIVEY |
|
|
DDS_HEADER_CAPS2_CUBEMAP_NEGATIVEY | DDS_HEADER_CAPS2_CUBEMAP_POSITIVEZ | DDS_HEADER_CAPS2_CUBEMAP_NEGATIVEZ;
|
|
|
|
static ddspp_constexpr unsigned int DXGI_MISC_FLAG_CUBEMAP = 0x2; // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_resource_misc_flag
|
|
static ddspp_constexpr unsigned int DDS_MISC_FLAGS2_ALPHA_MODE_MASK = 0x7;
|
|
|
|
#define ddspp_make_fourcc(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
|
|
|
|
// FOURCC constants
|
|
static ddspp_constexpr unsigned int FOURCC_DXT1 = ddspp_make_fourcc('D', 'X', 'T', '1'); // BC1_UNORM
|
|
static ddspp_constexpr unsigned int FOURCC_DXT2 = ddspp_make_fourcc('D', 'X', 'T', '2'); // BC2_UNORM
|
|
static ddspp_constexpr unsigned int FOURCC_DXT3 = ddspp_make_fourcc('D', 'X', 'T', '3'); // BC2_UNORM
|
|
static ddspp_constexpr unsigned int FOURCC_DXT4 = ddspp_make_fourcc('D', 'X', 'T', '4'); // BC3_UNORM
|
|
static ddspp_constexpr unsigned int FOURCC_DXT5 = ddspp_make_fourcc('D', 'X', 'T', '5'); // BC3_UNORM
|
|
static ddspp_constexpr unsigned int FOURCC_ATI1 = ddspp_make_fourcc('A', 'T', 'I', '1'); // BC4_UNORM
|
|
static ddspp_constexpr unsigned int FOURCC_BC4U = ddspp_make_fourcc('B', 'C', '4', 'U'); // BC4_UNORM
|
|
static ddspp_constexpr unsigned int FOURCC_BC4S = ddspp_make_fourcc('B', 'C', '4', 'S'); // BC4_SNORM
|
|
static ddspp_constexpr unsigned int FOURCC_ATI2 = ddspp_make_fourcc('A', 'T', 'I', '2'); // BC5_UNORM
|
|
static ddspp_constexpr unsigned int FOURCC_BC5U = ddspp_make_fourcc('B', 'C', '5', 'U'); // BC5_UNORM
|
|
static ddspp_constexpr unsigned int FOURCC_BC5S = ddspp_make_fourcc('B', 'C', '5', 'S'); // BC5_SNORM
|
|
static ddspp_constexpr unsigned int FOURCC_RGBG = ddspp_make_fourcc('R', 'G', 'B', 'G'); // R8G8_B8G8_UNORM
|
|
static ddspp_constexpr unsigned int FOURCC_GRBG = ddspp_make_fourcc('G', 'R', 'G', 'B'); // G8R8_G8B8_UNORM
|
|
static ddspp_constexpr unsigned int FOURCC_YUY2 = ddspp_make_fourcc('Y', 'U', 'Y', '2'); // YUY2
|
|
static ddspp_constexpr unsigned int FOURCC_DXT10 = ddspp_make_fourcc('D', 'X', '1', '0'); // DDS extension header
|
|
|
|
// These values come from the original D3D9 D3DFORMAT values https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dformat
|
|
static ddspp_constexpr unsigned int FOURCC_RGB8 = 20;
|
|
static ddspp_constexpr unsigned int FOURCC_A8R8G8B8 = 21;
|
|
static ddspp_constexpr unsigned int FOURCC_X8R8G8B8 = 22;
|
|
static ddspp_constexpr unsigned int FOURCC_R5G6B5 = 23; // B5G6R5_UNORM (needs swizzling)
|
|
static ddspp_constexpr unsigned int FOURCC_X1R5G5B5 = 24;
|
|
static ddspp_constexpr unsigned int FOURCC_RGB5A1 = 25; // B5G5R5A1_UNORM (needs swizzling)
|
|
static ddspp_constexpr unsigned int FOURCC_RGBA4 = 26; // B4G4R4A4_UNORM (needs swizzling)
|
|
static ddspp_constexpr unsigned int FOURCC_R3G3B2 = 27;
|
|
static ddspp_constexpr unsigned int FOURCC_A8 = 28;
|
|
static ddspp_constexpr unsigned int FOURCC_A8R3G3B2 = 29;
|
|
static ddspp_constexpr unsigned int FOURCC_X4R4G4B4 = 30;
|
|
static ddspp_constexpr unsigned int FOURCC_A2B10G10R10 = 31;
|
|
static ddspp_constexpr unsigned int FOURCC_A8B8G8R8 = 32;
|
|
static ddspp_constexpr unsigned int FOURCC_X8B8G8R8 = 33;
|
|
static ddspp_constexpr unsigned int FOURCC_G16R16 = 34;
|
|
static ddspp_constexpr unsigned int FOURCC_A2R10G10B10 = 35;
|
|
static ddspp_constexpr unsigned int FOURCC_RGBA16U = 36; // R16G16B16A16_UNORM
|
|
static ddspp_constexpr unsigned int FOURCC_RGBA16S = 110; // R16G16B16A16_SNORM
|
|
static ddspp_constexpr unsigned int FOURCC_R16F = 111; // R16_FLOAT
|
|
static ddspp_constexpr unsigned int FOURCC_RG16F = 112; // R16G16_FLOAT
|
|
static ddspp_constexpr unsigned int FOURCC_RGBA16F = 113; // R16G16B16A16_FLOAT
|
|
static ddspp_constexpr unsigned int FOURCC_R32F = 114; // R32_FLOAT
|
|
static ddspp_constexpr unsigned int FOURCC_RG32F = 115; // R32G32_FLOAT
|
|
static ddspp_constexpr unsigned int FOURCC_RGBA32F = 116; // R32G32B32A32_FLOAT
|
|
|
|
struct PixelFormat
|
|
{
|
|
unsigned int size;
|
|
unsigned int flags;
|
|
unsigned int fourCC;
|
|
unsigned int RGBBitCount;
|
|
unsigned int RBitMask;
|
|
unsigned int GBitMask;
|
|
unsigned int BBitMask;
|
|
unsigned int ABitMask;
|
|
};
|
|
|
|
static_assert(sizeof(PixelFormat) == 32, "PixelFormat size mismatch");
|
|
|
|
inline ddspp_constexpr bool is_rgba_mask(const PixelFormat& ddspf, unsigned int rmask, unsigned int gmask, unsigned int bmask, unsigned int amask)
|
|
{
|
|
return (ddspf.RBitMask == rmask) && (ddspf.GBitMask == gmask) && (ddspf.BBitMask == bmask) && (ddspf.ABitMask == amask);
|
|
}
|
|
|
|
inline ddspp_constexpr bool is_rgb_mask(const PixelFormat& ddspf, unsigned int rmask, unsigned int gmask, unsigned int bmask)
|
|
{
|
|
return (ddspf.RBitMask == rmask) && (ddspf.GBitMask == gmask) && (ddspf.BBitMask == bmask);
|
|
}
|
|
}
|
|
|
|
using namespace internal;
|
|
|
|
// https://docs.microsoft.com/en-us/windows/desktop/api/d3d11/ne-d3d11-d3d11_resource_dimension
|
|
enum DXGIResourceDimension : unsigned char
|
|
{
|
|
DXGI_Unknown,
|
|
DXGI_Buffer,
|
|
DXGI_Texture1D,
|
|
DXGI_Texture2D,
|
|
DXGI_Texture3D
|
|
};
|
|
|
|
// Matches DXGI_FORMAT https://docs.microsoft.com/en-us/windows/desktop/api/dxgiformat/ne-dxgiformat-dxgi_format
|
|
enum DXGIFormat : unsigned int
|
|
{
|
|
UNKNOWN = 0,
|
|
R32G32B32A32_TYPELESS = 1,
|
|
R32G32B32A32_FLOAT = 2,
|
|
R32G32B32A32_UINT = 3,
|
|
R32G32B32A32_SINT = 4,
|
|
R32G32B32_TYPELESS = 5,
|
|
R32G32B32_FLOAT = 6,
|
|
R32G32B32_UINT = 7,
|
|
R32G32B32_SINT = 8,
|
|
R16G16B16A16_TYPELESS = 9,
|
|
R16G16B16A16_FLOAT = 10,
|
|
R16G16B16A16_UNORM = 11,
|
|
R16G16B16A16_UINT = 12,
|
|
R16G16B16A16_SNORM = 13,
|
|
R16G16B16A16_SINT = 14,
|
|
R32G32_TYPELESS = 15,
|
|
R32G32_FLOAT = 16,
|
|
R32G32_UINT = 17,
|
|
R32G32_SINT = 18,
|
|
R32G8X24_TYPELESS = 19,
|
|
D32_FLOAT_S8X24_UINT = 20,
|
|
R32_FLOAT_X8X24_TYPELESS = 21,
|
|
X32_TYPELESS_G8X24_UINT = 22,
|
|
R10G10B10A2_TYPELESS = 23,
|
|
R10G10B10A2_UNORM = 24,
|
|
R10G10B10A2_UINT = 25,
|
|
R11G11B10_FLOAT = 26,
|
|
R8G8B8A8_TYPELESS = 27,
|
|
R8G8B8A8_UNORM = 28,
|
|
R8G8B8A8_UNORM_SRGB = 29,
|
|
R8G8B8A8_UINT = 30,
|
|
R8G8B8A8_SNORM = 31,
|
|
R8G8B8A8_SINT = 32,
|
|
R16G16_TYPELESS = 33,
|
|
R16G16_FLOAT = 34,
|
|
R16G16_UNORM = 35,
|
|
R16G16_UINT = 36,
|
|
R16G16_SNORM = 37,
|
|
R16G16_SINT = 38,
|
|
R32_TYPELESS = 39,
|
|
D32_FLOAT = 40,
|
|
R32_FLOAT = 41,
|
|
R32_UINT = 42,
|
|
R32_SINT = 43,
|
|
R24G8_TYPELESS = 44,
|
|
D24_UNORM_S8_UINT = 45,
|
|
R24_UNORM_X8_TYPELESS = 46,
|
|
X24_TYPELESS_G8_UINT = 47,
|
|
R8G8_TYPELESS = 48,
|
|
R8G8_UNORM = 49,
|
|
R8G8_UINT = 50,
|
|
R8G8_SNORM = 51,
|
|
R8G8_SINT = 52,
|
|
R16_TYPELESS = 53,
|
|
R16_FLOAT = 54,
|
|
D16_UNORM = 55,
|
|
R16_UNORM = 56,
|
|
R16_UINT = 57,
|
|
R16_SNORM = 58,
|
|
R16_SINT = 59,
|
|
R8_TYPELESS = 60,
|
|
R8_UNORM = 61,
|
|
R8_UINT = 62,
|
|
R8_SNORM = 63,
|
|
R8_SINT = 64,
|
|
A8_UNORM = 65,
|
|
R1_UNORM = 66,
|
|
R9G9B9E5_SHAREDEXP = 67,
|
|
R8G8_B8G8_UNORM = 68,
|
|
G8R8_G8B8_UNORM = 69,
|
|
BC1_TYPELESS = 70,
|
|
BC1_UNORM = 71,
|
|
BC1_UNORM_SRGB = 72,
|
|
BC2_TYPELESS = 73,
|
|
BC2_UNORM = 74,
|
|
BC2_UNORM_SRGB = 75,
|
|
BC3_TYPELESS = 76,
|
|
BC3_UNORM = 77,
|
|
BC3_UNORM_SRGB = 78,
|
|
BC4_TYPELESS = 79,
|
|
BC4_UNORM = 80,
|
|
BC4_SNORM = 81,
|
|
BC5_TYPELESS = 82,
|
|
BC5_UNORM = 83,
|
|
BC5_SNORM = 84,
|
|
B5G6R5_UNORM = 85,
|
|
B5G5R5A1_UNORM = 86,
|
|
B8G8R8A8_UNORM = 87,
|
|
B8G8R8X8_UNORM = 88,
|
|
R10G10B10_XR_BIAS_A2_UNORM = 89,
|
|
B8G8R8A8_TYPELESS = 90,
|
|
B8G8R8A8_UNORM_SRGB = 91,
|
|
B8G8R8X8_TYPELESS = 92,
|
|
B8G8R8X8_UNORM_SRGB = 93,
|
|
BC6H_TYPELESS = 94,
|
|
BC6H_UF16 = 95,
|
|
BC6H_SF16 = 96,
|
|
BC7_TYPELESS = 97,
|
|
BC7_UNORM = 98,
|
|
BC7_UNORM_SRGB = 99,
|
|
AYUV = 100,
|
|
Y410 = 101,
|
|
Y416 = 102,
|
|
NV12 = 103,
|
|
P010 = 104,
|
|
P016 = 105,
|
|
OPAQUE_420 = 106,
|
|
YUY2 = 107,
|
|
Y210 = 108,
|
|
Y216 = 109,
|
|
NV11 = 110,
|
|
AI44 = 111,
|
|
IA44 = 112,
|
|
P8 = 113,
|
|
A8P8 = 114,
|
|
B4G4R4A4_UNORM = 115,
|
|
|
|
P208 = 130,
|
|
V208 = 131,
|
|
V408 = 132,
|
|
ASTC_4X4_TYPELESS = 133,
|
|
ASTC_4X4_UNORM = 134,
|
|
ASTC_4X4_UNORM_SRGB = 135,
|
|
ASTC_5X4_TYPELESS = 137,
|
|
ASTC_5X4_UNORM = 138,
|
|
ASTC_5X4_UNORM_SRGB = 139,
|
|
ASTC_5X5_TYPELESS = 141,
|
|
ASTC_5X5_UNORM = 142,
|
|
ASTC_5X5_UNORM_SRGB = 143,
|
|
|
|
ASTC_6X5_TYPELESS = 145,
|
|
ASTC_6X5_UNORM = 146,
|
|
ASTC_6X5_UNORM_SRGB = 147,
|
|
|
|
ASTC_6X6_TYPELESS = 149,
|
|
ASTC_6X6_UNORM = 150,
|
|
ASTC_6X6_UNORM_SRGB = 151,
|
|
|
|
ASTC_8X5_TYPELESS = 153,
|
|
ASTC_8X5_UNORM = 154,
|
|
ASTC_8X5_UNORM_SRGB = 155,
|
|
|
|
ASTC_8X6_TYPELESS = 157,
|
|
ASTC_8X6_UNORM = 158,
|
|
ASTC_8X6_UNORM_SRGB = 159,
|
|
|
|
ASTC_8X8_TYPELESS = 161,
|
|
ASTC_8X8_UNORM = 162,
|
|
ASTC_8X8_UNORM_SRGB = 163,
|
|
|
|
ASTC_10X5_TYPELESS = 165,
|
|
ASTC_10X5_UNORM = 166,
|
|
ASTC_10X5_UNORM_SRGB = 167,
|
|
|
|
ASTC_10X6_TYPELESS = 169,
|
|
ASTC_10X6_UNORM = 170,
|
|
ASTC_10X6_UNORM_SRGB = 171,
|
|
|
|
ASTC_10X8_TYPELESS = 173,
|
|
ASTC_10X8_UNORM = 174,
|
|
ASTC_10X8_UNORM_SRGB = 175,
|
|
|
|
ASTC_10X10_TYPELESS = 177,
|
|
ASTC_10X10_UNORM = 178,
|
|
ASTC_10X10_UNORM_SRGB = 179,
|
|
|
|
ASTC_12X10_TYPELESS = 181,
|
|
ASTC_12X10_UNORM = 182,
|
|
ASTC_12X10_UNORM_SRGB = 183,
|
|
|
|
ASTC_12X12_TYPELESS = 185,
|
|
ASTC_12X12_UNORM = 186,
|
|
ASTC_12X12_UNORM_SRGB = 187,
|
|
|
|
FORCE_UINT = 0xffffffff
|
|
};
|
|
|
|
struct Header
|
|
{
|
|
unsigned int size;
|
|
unsigned int flags;
|
|
unsigned int height;
|
|
unsigned int width;
|
|
unsigned int pitchOrLinearSize;
|
|
unsigned int depth;
|
|
unsigned int mipMapCount;
|
|
unsigned int reserved1[11];
|
|
PixelFormat ddspf;
|
|
unsigned int caps;
|
|
unsigned int caps2;
|
|
unsigned int caps3;
|
|
unsigned int caps4;
|
|
unsigned int reserved2;
|
|
};
|
|
|
|
static_assert(sizeof(Header) == 124, "DDS Header size mismatch");
|
|
|
|
struct HeaderDXT10
|
|
{
|
|
DXGIFormat dxgiFormat;
|
|
DXGIResourceDimension resourceDimension;
|
|
unsigned int miscFlag;
|
|
unsigned int arraySize;
|
|
unsigned int reserved;
|
|
};
|
|
|
|
static_assert(sizeof(HeaderDXT10) == 20, "DDS DX10 Extended Header size mismatch");
|
|
|
|
// Maximum possible size of header. Use this to read in only the header, decode, seek to the real header size, then read in the rest of the image data
|
|
ddspp_constexpr int MAX_HEADER_SIZE = sizeof(DDS_MAGIC) + sizeof(Header) + sizeof(HeaderDXT10);
|
|
|
|
enum Result : unsigned char
|
|
{
|
|
Success,
|
|
Error
|
|
};
|
|
|
|
enum TextureType : unsigned char
|
|
{
|
|
Texture1D,
|
|
Texture2D,
|
|
Texture3D,
|
|
Cubemap,
|
|
};
|
|
|
|
struct Descriptor
|
|
{
|
|
DXGIFormat format;
|
|
TextureType type;
|
|
unsigned int width;
|
|
unsigned int height;
|
|
unsigned int depth;
|
|
unsigned int numMips;
|
|
unsigned int arraySize;
|
|
unsigned int rowPitch; // Row pitch for mip 0
|
|
unsigned int depthPitch; // Size of mip 0
|
|
unsigned int bitsPerPixelOrBlock; // If compressed bits per block, else bits per pixel
|
|
unsigned int blockWidth; // Width of block in pixels (1 if uncompressed)
|
|
unsigned int blockHeight;// Height of block in pixels (1 if uncompressed)
|
|
bool compressed;
|
|
bool srgb;
|
|
unsigned int headerSize; // Actual size of header, use this to get to image data
|
|
};
|
|
|
|
inline ddspp_constexpr bool is_dxt10(const Header& header)
|
|
{
|
|
const PixelFormat& ddspf = header.ddspf;
|
|
return (ddspf.flags & DDS_FOURCC) && (ddspf.fourCC == FOURCC_DXT10);
|
|
}
|
|
|
|
inline ddspp_constexpr bool is_compressed(DXGIFormat format)
|
|
{
|
|
return (format >= BC1_UNORM && format <= BC5_SNORM) ||
|
|
(format >= BC6H_TYPELESS && format <= BC7_UNORM_SRGB) ||
|
|
(format >= ASTC_4X4_TYPELESS && format <= ASTC_12X12_UNORM_SRGB);
|
|
}
|
|
|
|
inline ddspp_constexpr bool is_srgb(DXGIFormat format)
|
|
{
|
|
switch(format)
|
|
{
|
|
case R8G8B8A8_UNORM_SRGB:
|
|
case BC1_UNORM_SRGB:
|
|
case BC2_UNORM_SRGB:
|
|
case BC3_UNORM_SRGB:
|
|
case B8G8R8A8_UNORM_SRGB:
|
|
case B8G8R8X8_UNORM_SRGB:
|
|
case BC7_UNORM_SRGB:
|
|
case ASTC_4X4_UNORM_SRGB:
|
|
case ASTC_5X4_UNORM_SRGB:
|
|
case ASTC_5X5_UNORM_SRGB:
|
|
case ASTC_6X5_UNORM_SRGB:
|
|
case ASTC_6X6_UNORM_SRGB:
|
|
case ASTC_8X5_UNORM_SRGB:
|
|
case ASTC_8X6_UNORM_SRGB:
|
|
case ASTC_8X8_UNORM_SRGB:
|
|
case ASTC_10X5_UNORM_SRGB:
|
|
case ASTC_10X6_UNORM_SRGB:
|
|
case ASTC_10X8_UNORM_SRGB:
|
|
case ASTC_10X10_UNORM_SRGB:
|
|
case ASTC_12X10_UNORM_SRGB:
|
|
case ASTC_12X12_UNORM_SRGB:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
inline ddspp_constexpr unsigned int get_bits_per_pixel_or_block(DXGIFormat format)
|
|
{
|
|
if(format >= ASTC_4X4_TYPELESS && format <= ASTC_12X12_UNORM_SRGB)
|
|
{
|
|
return 128; // All ASTC blocks are the same size
|
|
}
|
|
|
|
switch(format)
|
|
{
|
|
case R1_UNORM:
|
|
return 1;
|
|
case R8_TYPELESS:
|
|
case R8_UNORM:
|
|
case R8_UINT:
|
|
case R8_SNORM:
|
|
case R8_SINT:
|
|
case A8_UNORM:
|
|
case AI44:
|
|
case IA44:
|
|
case P8:
|
|
return 8;
|
|
case NV12:
|
|
case OPAQUE_420:
|
|
case NV11:
|
|
return 12;
|
|
case R8G8_TYPELESS:
|
|
case R8G8_UNORM:
|
|
case R8G8_UINT:
|
|
case R8G8_SNORM:
|
|
case R8G8_SINT:
|
|
case R16_TYPELESS:
|
|
case R16_FLOAT:
|
|
case D16_UNORM:
|
|
case R16_UNORM:
|
|
case R16_UINT:
|
|
case R16_SNORM:
|
|
case R16_SINT:
|
|
case B5G6R5_UNORM:
|
|
case B5G5R5A1_UNORM:
|
|
case A8P8:
|
|
case B4G4R4A4_UNORM:
|
|
return 16;
|
|
case P010:
|
|
case P016:
|
|
return 24;
|
|
case BC1_UNORM:
|
|
case BC1_UNORM_SRGB:
|
|
case BC1_TYPELESS:
|
|
case BC4_UNORM:
|
|
case BC4_SNORM:
|
|
case BC4_TYPELESS:
|
|
case R16G16B16A16_TYPELESS:
|
|
case R16G16B16A16_FLOAT:
|
|
case R16G16B16A16_UNORM:
|
|
case R16G16B16A16_UINT:
|
|
case R16G16B16A16_SNORM:
|
|
case R16G16B16A16_SINT:
|
|
case R32G32_TYPELESS:
|
|
case R32G32_FLOAT:
|
|
case R32G32_UINT:
|
|
case R32G32_SINT:
|
|
case R32G8X24_TYPELESS:
|
|
case D32_FLOAT_S8X24_UINT:
|
|
case R32_FLOAT_X8X24_TYPELESS:
|
|
case X32_TYPELESS_G8X24_UINT:
|
|
case Y416:
|
|
case Y210:
|
|
case Y216:
|
|
return 64;
|
|
case R32G32B32_TYPELESS:
|
|
case R32G32B32_FLOAT:
|
|
case R32G32B32_UINT:
|
|
case R32G32B32_SINT:
|
|
return 96;
|
|
case BC2_UNORM:
|
|
case BC2_UNORM_SRGB:
|
|
case BC2_TYPELESS:
|
|
case BC3_UNORM:
|
|
case BC3_UNORM_SRGB:
|
|
case BC3_TYPELESS:
|
|
case BC5_UNORM:
|
|
case BC5_SNORM:
|
|
case BC6H_UF16:
|
|
case BC6H_SF16:
|
|
case BC7_UNORM:
|
|
case BC7_UNORM_SRGB:
|
|
case R32G32B32A32_TYPELESS:
|
|
case R32G32B32A32_FLOAT:
|
|
case R32G32B32A32_UINT:
|
|
case R32G32B32A32_SINT:
|
|
return 128;
|
|
default:
|
|
return 32; // Most formats are 32 bits per pixel
|
|
break;
|
|
}
|
|
}
|
|
|
|
inline ddspp_constexpr void get_block_size(DXGIFormat format, unsigned int& blockWidth, unsigned int& blockHeight)
|
|
{
|
|
switch(format)
|
|
{
|
|
case BC1_UNORM:
|
|
case BC1_UNORM_SRGB:
|
|
case BC1_TYPELESS:
|
|
case BC4_UNORM:
|
|
case BC4_SNORM:
|
|
case BC4_TYPELESS:
|
|
case BC2_UNORM:
|
|
case BC2_UNORM_SRGB:
|
|
case BC2_TYPELESS:
|
|
case BC3_UNORM:
|
|
case BC3_UNORM_SRGB:
|
|
case BC3_TYPELESS:
|
|
case BC5_UNORM:
|
|
case BC5_SNORM:
|
|
case BC6H_UF16:
|
|
case BC6H_SF16:
|
|
case BC7_UNORM:
|
|
case BC7_UNORM_SRGB:
|
|
case ASTC_4X4_TYPELESS:
|
|
case ASTC_4X4_UNORM:
|
|
case ASTC_4X4_UNORM_SRGB:
|
|
blockWidth = 4; blockHeight = 4;
|
|
break;
|
|
case ASTC_5X4_TYPELESS:
|
|
case ASTC_5X4_UNORM:
|
|
case ASTC_5X4_UNORM_SRGB:
|
|
blockWidth = 5; blockHeight = 4;
|
|
break;
|
|
case ASTC_5X5_TYPELESS:
|
|
case ASTC_5X5_UNORM:
|
|
case ASTC_5X5_UNORM_SRGB:
|
|
blockWidth = 5; blockHeight = 5;
|
|
break;
|
|
case ASTC_6X5_TYPELESS:
|
|
case ASTC_6X5_UNORM:
|
|
case ASTC_6X5_UNORM_SRGB:
|
|
blockWidth = 6; blockHeight = 5;
|
|
case ASTC_6X6_TYPELESS:
|
|
case ASTC_6X6_UNORM:
|
|
case ASTC_6X6_UNORM_SRGB:
|
|
blockWidth = 6; blockHeight = 6;
|
|
case ASTC_8X5_TYPELESS:
|
|
case ASTC_8X5_UNORM:
|
|
case ASTC_8X5_UNORM_SRGB:
|
|
blockWidth = 8; blockHeight = 5;
|
|
case ASTC_8X6_TYPELESS:
|
|
case ASTC_8X6_UNORM:
|
|
case ASTC_8X6_UNORM_SRGB:
|
|
blockWidth = 8; blockHeight = 6;
|
|
case ASTC_8X8_TYPELESS:
|
|
case ASTC_8X8_UNORM:
|
|
case ASTC_8X8_UNORM_SRGB:
|
|
blockWidth = 8; blockHeight = 8;
|
|
case ASTC_10X5_TYPELESS:
|
|
case ASTC_10X5_UNORM:
|
|
case ASTC_10X5_UNORM_SRGB:
|
|
blockWidth = 10; blockHeight = 5;
|
|
case ASTC_10X6_TYPELESS:
|
|
case ASTC_10X6_UNORM:
|
|
case ASTC_10X6_UNORM_SRGB:
|
|
blockWidth = 10; blockHeight = 6;
|
|
case ASTC_10X8_TYPELESS:
|
|
case ASTC_10X8_UNORM:
|
|
case ASTC_10X8_UNORM_SRGB:
|
|
blockWidth = 10; blockHeight = 8;
|
|
case ASTC_10X10_TYPELESS:
|
|
case ASTC_10X10_UNORM:
|
|
case ASTC_10X10_UNORM_SRGB:
|
|
blockWidth = 10; blockHeight = 10;
|
|
case ASTC_12X10_TYPELESS:
|
|
case ASTC_12X10_UNORM:
|
|
case ASTC_12X10_UNORM_SRGB:
|
|
blockWidth = 12; blockHeight = 10;
|
|
case ASTC_12X12_TYPELESS:
|
|
case ASTC_12X12_UNORM:
|
|
case ASTC_12X12_UNORM_SRGB:
|
|
blockWidth = 12; blockHeight = 12;
|
|
default:
|
|
blockWidth = 1; blockHeight = 1;
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
inline ddspp_constexpr unsigned int get_row_pitch(unsigned int width, unsigned int bitsPerPixelOrBlock, unsigned int blockWidth, unsigned int mip)
|
|
{
|
|
// Shift width by mipmap index, round to next block size and round to next byte (for the rare less than 1 byte per pixel formats)
|
|
// E.g. width = 119, mip = 3, BC1 compression
|
|
// ((((119 >> 2) + 4 - 1) / 4) * 64) / 8 = 64 bytes
|
|
return ((((width >> mip) + blockWidth - 1) / blockWidth) * bitsPerPixelOrBlock + 7) / 8;
|
|
}
|
|
|
|
// Returns number of bytes for each row of a given mip. Valid range is [0, desc.numMips)
|
|
inline ddspp_constexpr unsigned int get_row_pitch(const Descriptor& desc, unsigned int mip)
|
|
{
|
|
return get_row_pitch(desc.width, desc.bitsPerPixelOrBlock, desc.blockWidth, mip);
|
|
}
|
|
|
|
inline Result decode_header(unsigned char* sourceData, Descriptor& desc)
|
|
{
|
|
unsigned int magic = *reinterpret_cast<unsigned int*>(sourceData); // First 4 bytes are the magic DDS number
|
|
|
|
if (magic != DDS_MAGIC)
|
|
{
|
|
return ddspp::Error;
|
|
}
|
|
|
|
const Header header = *reinterpret_cast<const Header*>(sourceData + sizeof(DDS_MAGIC));
|
|
const PixelFormat& ddspf = header.ddspf;
|
|
bool dxt10Extension = is_dxt10(header);
|
|
const HeaderDXT10 dxt10Header = *reinterpret_cast<const HeaderDXT10*>(sourceData + sizeof(DDS_MAGIC) + sizeof(Header));
|
|
|
|
// Read basic data from the header
|
|
desc.width = header.width > 0 ? header.width : 1;
|
|
desc.height = header.height > 0 ? header.height : 1;
|
|
desc.depth = header.depth > 0 ? header.depth : 1;
|
|
desc.numMips = header.mipMapCount > 0 ? header.mipMapCount : 1;
|
|
|
|
// Set some sensible defaults
|
|
desc.arraySize = 1;
|
|
desc.srgb = false;
|
|
desc.type = Texture2D;
|
|
desc.format = UNKNOWN;
|
|
|
|
if (dxt10Extension)
|
|
{
|
|
desc.format = dxt10Header.dxgiFormat;
|
|
|
|
desc.arraySize = dxt10Header.arraySize;
|
|
|
|
switch(dxt10Header.resourceDimension)
|
|
{
|
|
case DXGI_Texture1D:
|
|
desc.depth = 1;
|
|
desc.type = Texture1D;
|
|
break;
|
|
case DXGI_Texture2D:
|
|
desc.depth = 1;
|
|
|
|
if(dxt10Header.miscFlag & DXGI_MISC_FLAG_CUBEMAP)
|
|
{
|
|
desc.type = Cubemap;
|
|
}
|
|
else
|
|
{
|
|
desc.type = Texture2D;
|
|
}
|
|
|
|
break;
|
|
case DXGI_Texture3D:
|
|
desc.type = Texture3D;
|
|
desc.arraySize = 1; // There are no 3D texture arrays
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(ddspf.flags & DDS_FOURCC)
|
|
{
|
|
unsigned int fourCC = ddspf.fourCC;
|
|
|
|
switch(fourCC)
|
|
{
|
|
// Compressed
|
|
case FOURCC_DXT1: desc.format = BC1_UNORM; break;
|
|
case FOURCC_DXT2: // fallthrough
|
|
case FOURCC_DXT3: desc.format = BC2_UNORM; break;
|
|
case FOURCC_DXT4: // fallthrough
|
|
case FOURCC_DXT5: desc.format = BC3_UNORM; break;
|
|
case FOURCC_ATI1: // fallthrough
|
|
case FOURCC_BC4U: desc.format = BC4_UNORM; break;
|
|
case FOURCC_BC4S: desc.format = BC4_SNORM; break;
|
|
case FOURCC_ATI2: // fallthrough
|
|
case FOURCC_BC5U: desc.format = BC5_UNORM; break;
|
|
case FOURCC_BC5S: desc.format = BC5_SNORM; break;
|
|
|
|
// Video
|
|
case FOURCC_RGBG: desc.format = R8G8_B8G8_UNORM; break;
|
|
case FOURCC_GRBG: desc.format = G8R8_G8B8_UNORM; break;
|
|
case FOURCC_YUY2: desc.format = YUY2; break;
|
|
|
|
// Packed
|
|
case FOURCC_R5G6B5: desc.format = B5G6R5_UNORM; break;
|
|
case FOURCC_RGB5A1: desc.format = B5G5R5A1_UNORM; break;
|
|
case FOURCC_RGBA4: desc.format = B4G4R4A4_UNORM; break;
|
|
|
|
// Uncompressed
|
|
case FOURCC_A8: desc.format = R8_UNORM; break;
|
|
case FOURCC_A2B10G10R10: desc.format = R10G10B10A2_UNORM; break;
|
|
case FOURCC_RGBA16U: desc.format = R16G16B16A16_UNORM; break;
|
|
case FOURCC_RGBA16S: desc.format = R16G16B16A16_SNORM; break;
|
|
case FOURCC_R16F: desc.format = R16_FLOAT; break;
|
|
case FOURCC_RG16F: desc.format = R16G16_FLOAT; break;
|
|
case FOURCC_RGBA16F: desc.format = R16G16B16A16_FLOAT; break;
|
|
case FOURCC_R32F: desc.format = R32_FLOAT; break;
|
|
case FOURCC_RG32F: desc.format = R32G32_FLOAT; break;
|
|
case FOURCC_RGBA32F: desc.format = R32G32B32A32_FLOAT; break;
|
|
default: break;
|
|
}
|
|
}
|
|
else if(ddspf.flags & DDS_RGB)
|
|
{
|
|
switch(ddspf.RGBBitCount)
|
|
{
|
|
case 32:
|
|
if(is_rgba_mask(ddspf, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000))
|
|
{
|
|
desc.format = R8G8B8A8_UNORM;
|
|
}
|
|
else if(is_rgba_mask(ddspf, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000))
|
|
{
|
|
desc.format = B8G8R8A8_UNORM;
|
|
}
|
|
else if(is_rgba_mask(ddspf, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000))
|
|
{
|
|
desc.format = B8G8R8X8_UNORM;
|
|
}
|
|
|
|
// No DXGI format maps to (0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000) aka D3DFMT_X8B8G8R8
|
|
// No DXGI format maps to (0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000) aka D3DFMT_A2R10G10B10
|
|
|
|
// 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
|
|
|
|
// For 'correct' writers, this should be 0x000003ff, 0x000ffc00, 0x3ff00000 for RGB data
|
|
else if (is_rgba_mask(ddspf, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000))
|
|
{
|
|
desc.format = R10G10B10A2_UNORM;
|
|
}
|
|
else if (is_rgba_mask(ddspf, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000))
|
|
{
|
|
desc.format = R16G16_UNORM;
|
|
}
|
|
else if (is_rgba_mask(ddspf, 0xffffffff, 0x00000000, 0x00000000, 0x00000000))
|
|
{
|
|
// The only 32-bit color channel format in D3D9 was R32F
|
|
desc.format = R32_FLOAT; // D3DX writes this out as a FourCC of 114
|
|
}
|
|
break;
|
|
case 24:
|
|
if(is_rgb_mask(ddspf, 0x00ff0000, 0x0000ff00, 0x000000ff))
|
|
{
|
|
desc.format = B8G8R8X8_UNORM;
|
|
}
|
|
break;
|
|
case 16:
|
|
if (is_rgba_mask(ddspf, 0x7c00, 0x03e0, 0x001f, 0x8000))
|
|
{
|
|
desc.format = B5G5R5A1_UNORM;
|
|
}
|
|
else if (is_rgba_mask(ddspf, 0xf800, 0x07e0, 0x001f, 0x0000))
|
|
{
|
|
desc.format = B5G6R5_UNORM;
|
|
}
|
|
else if (is_rgba_mask(ddspf, 0x0f00, 0x00f0, 0x000f, 0xf000))
|
|
{
|
|
desc.format = B4G4R4A4_UNORM;
|
|
}
|
|
// No DXGI format maps to (0x7c00, 0x03e0, 0x001f, 0x0000) aka D3DFMT_X1R5G5B5.
|
|
// No DXGI format maps to (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;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else if (ddspf.flags & DDS_LUMINANCE)
|
|
{
|
|
switch(ddspf.RGBBitCount)
|
|
{
|
|
case 16:
|
|
if (is_rgba_mask(ddspf, 0x0000ffff, 0x00000000, 0x00000000, 0x00000000))
|
|
{
|
|
desc.format = R16_UNORM; // D3DX10/11 writes this out as DX10 extension.
|
|
}
|
|
if (is_rgba_mask(ddspf, 0x000000ff, 0x00000000, 0x00000000, 0x0000ff00))
|
|
{
|
|
desc.format = R8G8_UNORM; // D3DX10/11 writes this out as DX10 extension.
|
|
}
|
|
break;
|
|
case 8:
|
|
if (is_rgba_mask(ddspf, 0x000000ff, 0x00000000, 0x00000000, 0x00000000))
|
|
{
|
|
desc.format = R8_UNORM; // D3DX10/11 writes this out as DX10 extension
|
|
}
|
|
|
|
// No DXGI format maps to (0x0f, 0x00, 0x00, 0xf0) aka D3DFMT_A4L4
|
|
|
|
if (is_rgba_mask(ddspf, 0x000000ff, 0x00000000, 0x00000000, 0x0000ff00))
|
|
{
|
|
desc.format = R8G8_UNORM; // Some DDS writers assume the bitcount should be 8 instead of 16
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (ddspf.flags & DDS_ALPHA)
|
|
{
|
|
if (ddspf.RGBBitCount == 8)
|
|
{
|
|
desc.format = A8_UNORM;
|
|
}
|
|
}
|
|
else if (ddspf.flags & DDS_BUMPDUDV)
|
|
{
|
|
if (ddspf.RGBBitCount == 32)
|
|
{
|
|
if (is_rgba_mask(ddspf, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000))
|
|
{
|
|
desc.format = R8G8B8A8_SNORM; // D3DX10/11 writes this out as DX10 extension
|
|
}
|
|
if (is_rgba_mask(ddspf, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000))
|
|
{
|
|
desc.format = R16G16_SNORM; // D3DX10/11 writes this out as DX10 extension
|
|
}
|
|
|
|
// No DXGI format maps to (0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000) aka D3DFMT_A2W10V10U10
|
|
}
|
|
else if (ddspf.RGBBitCount == 16)
|
|
{
|
|
if (is_rgba_mask(ddspf, 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000))
|
|
{
|
|
desc.format = R8G8_SNORM; // D3DX10/11 writes this out as DX10 extension
|
|
}
|
|
}
|
|
}
|
|
|
|
if((header.flags & DDS_HEADER_FLAGS_VOLUME) || (header.caps2 & DDS_HEADER_CAPS2_VOLUME))
|
|
{
|
|
desc.type = Texture3D;
|
|
}
|
|
else if (header.caps2 & DDS_HEADER_CAPS2_CUBEMAP)
|
|
{
|
|
if((header.caps2 & DDS_HEADER_CAPS2_CUBEMAP_ALLFACES) != DDS_HEADER_CAPS2_CUBEMAP_ALLFACES)
|
|
{
|
|
return ddspp::Error;
|
|
}
|
|
|
|
desc.type = Cubemap;
|
|
desc.arraySize = 1;
|
|
desc.depth = 1;
|
|
}
|
|
else
|
|
{
|
|
desc.type = Texture2D;
|
|
}
|
|
}
|
|
|
|
desc.compressed = is_compressed(desc.format);
|
|
desc.srgb = is_srgb(desc.format);
|
|
desc.bitsPerPixelOrBlock = get_bits_per_pixel_or_block(desc.format);
|
|
get_block_size(desc.format, desc.blockWidth, desc.blockHeight);
|
|
|
|
desc.rowPitch = get_row_pitch(desc.width, desc.bitsPerPixelOrBlock, desc.blockWidth, 0);
|
|
desc.depthPitch = desc.rowPitch * desc.height / desc.blockHeight;
|
|
desc.headerSize = sizeof(DDS_MAGIC) + sizeof(Header) + (dxt10Extension ? sizeof(HeaderDXT10) : 0);
|
|
|
|
return ddspp::Success;
|
|
}
|
|
|
|
inline void encode_header(const DXGIFormat format, const unsigned int width, const unsigned int height, const unsigned int depth,
|
|
const TextureType type, const unsigned int mipCount, const unsigned int arraySize,
|
|
Header& header, HeaderDXT10& dxt10Header)
|
|
{
|
|
header.size = sizeof(Header);
|
|
|
|
// Fill in header flags
|
|
header.flags = DDS_HEADER_FLAGS_CAPS | DDS_HEADER_FLAGS_HEIGHT | DDS_HEADER_FLAGS_WIDTH | DDS_HEADER_FLAGS_PIXELFORMAT;
|
|
header.caps = DDS_HEADER_CAPS_TEXTURE;
|
|
header.caps2 = 0;
|
|
|
|
if (mipCount > 1)
|
|
{
|
|
header.flags |= DDS_HEADER_FLAGS_MIPMAP;
|
|
header.caps |= DDS_HEADER_CAPS_COMPLEX | DDS_HEADER_CAPS_MIPMAP;
|
|
}
|
|
|
|
unsigned int bitsPerPixelOrBlock = get_bits_per_pixel_or_block(format);
|
|
|
|
if (is_compressed(format))
|
|
{
|
|
header.flags |= DDS_HEADER_FLAGS_LINEARSIZE;
|
|
unsigned int blockWidth, blockHeight;
|
|
get_block_size(format, blockWidth, blockHeight);
|
|
header.pitchOrLinearSize = width * height * bitsPerPixelOrBlock / (8 * blockWidth * blockHeight);
|
|
}
|
|
else
|
|
{
|
|
header.flags |= DDS_HEADER_FLAGS_PITCH;
|
|
header.pitchOrLinearSize = width * bitsPerPixelOrBlock / 8;
|
|
}
|
|
|
|
header.height = height;
|
|
header.width = width;
|
|
header.depth = depth;
|
|
header.mipMapCount = mipCount;
|
|
header.reserved1[0] = header.reserved1[1] = header.reserved1[2] = 0;
|
|
header.reserved1[3] = header.reserved1[4] = header.reserved1[5] = 0;
|
|
header.reserved1[6] = header.reserved1[7] = header.reserved1[8] = 0;
|
|
header.reserved1[9] = header.reserved1[10] = 0;
|
|
|
|
// Fill in pixel format
|
|
PixelFormat& ddspf = header.ddspf;
|
|
ddspf.size = sizeof(PixelFormat);
|
|
ddspf.fourCC = FOURCC_DXT10;
|
|
ddspf.flags = 0;
|
|
ddspf.flags |= DDS_FOURCC;
|
|
|
|
dxt10Header.dxgiFormat = format;
|
|
dxt10Header.arraySize = arraySize;
|
|
dxt10Header.miscFlag = 0;
|
|
|
|
if (type == Texture1D)
|
|
{
|
|
dxt10Header.resourceDimension = DXGI_Texture1D;
|
|
}
|
|
else if (type == Texture2D)
|
|
{
|
|
dxt10Header.resourceDimension = DXGI_Texture2D;
|
|
}
|
|
else if (type == Cubemap)
|
|
{
|
|
dxt10Header.resourceDimension = DXGI_Texture2D;
|
|
dxt10Header.miscFlag |= DXGI_MISC_FLAG_CUBEMAP;
|
|
header.caps |= DDS_HEADER_CAPS_COMPLEX;
|
|
header.caps2 |= DDS_HEADER_CAPS2_CUBEMAP | DDS_HEADER_CAPS2_CUBEMAP_ALLFACES;
|
|
}
|
|
else if (type == Texture3D)
|
|
{
|
|
dxt10Header.resourceDimension = DXGI_Texture3D;
|
|
header.flags |= DDS_HEADER_FLAGS_VOLUME;
|
|
header.caps2 |= DDS_HEADER_CAPS2_VOLUME;
|
|
}
|
|
|
|
// dxt10Header.miscFlag TODO Alpha Mode
|
|
|
|
// Unused
|
|
header.caps3 = 0;
|
|
header.caps4 = 0;
|
|
header.reserved2 = 0;
|
|
}
|
|
|
|
// Returns the offset from the base pointer to the desired mip and slice
|
|
// Slice is either a texture from an array, a face from a cubemap, or a 2D slice of a volume texture
|
|
inline ddspp_constexpr unsigned int get_offset(const Descriptor& desc, const unsigned int mip, const unsigned int slice)
|
|
{
|
|
// The mip/slice arrangement is different between texture arrays and volume textures
|
|
//
|
|
// Arrays
|
|
// __________ _____ __ __________ _____ __ __________ _____ __
|
|
// | || ||__|| || ||__|| || ||__|
|
|
// | ||_____| | ||_____| | ||_____|
|
|
// | | | | | |
|
|
// |__________| |__________| |__________|
|
|
//
|
|
// Volume
|
|
// __________ __________ __________ _____ _____ _____ __ __ __
|
|
// | || || || || || ||__||__||__|
|
|
// | || || ||_____||_____||_____|
|
|
// | || || |
|
|
// |__________||__________||__________|
|
|
//
|
|
|
|
unsigned long long offset = 0;
|
|
unsigned long long mip0Size = desc.depthPitch * 8; // Work in bits
|
|
|
|
if (desc.type == Texture3D)
|
|
{
|
|
for (unsigned int m = 0; m < mip; ++m)
|
|
{
|
|
unsigned long long mipSize = mip0Size >> 2 * m;
|
|
offset += mipSize * desc.numMips;
|
|
}
|
|
|
|
unsigned long long lastMip = mip0Size >> 2 * mip;
|
|
|
|
offset += lastMip * slice;
|
|
}
|
|
else
|
|
{
|
|
unsigned long long mipChainSize = 0;
|
|
unsigned int width = desc.width;
|
|
unsigned int height = desc.height;
|
|
|
|
for (unsigned int m = 0; m < desc.numMips; ++m)
|
|
{
|
|
unsigned long long blocksX = (width + desc.blockWidth - 1) / desc.blockWidth;
|
|
unsigned long long blocksY = (height + desc.blockHeight - 1) / desc.blockHeight;
|
|
unsigned long long mipSize = blocksX * blocksY * desc.bitsPerPixelOrBlock;
|
|
mipChainSize += mipSize;
|
|
|
|
width >>= 1;
|
|
height >>= 1;
|
|
}
|
|
|
|
offset += mipChainSize * slice;
|
|
|
|
width = desc.width;
|
|
height = desc.height;
|
|
for (unsigned int m = 0; m < mip; ++m)
|
|
{
|
|
unsigned long long blocksX = (width + desc.blockWidth - 1) / desc.blockWidth;
|
|
unsigned long long blocksY = (height + desc.blockHeight - 1) / desc.blockHeight;
|
|
unsigned long long mipSize = blocksX * blocksY * desc.bitsPerPixelOrBlock;
|
|
offset += mipSize > desc.bitsPerPixelOrBlock ? mipSize : desc.bitsPerPixelOrBlock;
|
|
|
|
width >>= 1;
|
|
height >>= 1;
|
|
}
|
|
}
|
|
|
|
offset /= 8; // Back to bytes
|
|
|
|
return (unsigned int)offset;
|
|
}
|
|
}
|