//--------------------------------------------------------------------------------------
// File: ddsdump.cpp
//
// DDS file content examination utility
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//--------------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include "DDS.h"
#include
using namespace DirectX;
namespace
{
//---------------------------------------------------------------------------------
struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } };
using ScopedHandle = std::unique_ptr;
inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
//--------------------------------------------------------------------------------------
struct DDPF
{
DDS_PIXELFORMAT ddpf;
const char* name;
};
const DDPF g_DDPF[] =
{
{ DDSPF_A8R8G8B8, "DXGI_FORMAT_B8G8R8A8_UNORM" },
{ DDSPF_X8R8G8B8, "DXGI_FORMAT_B8G8R8X8_UNORM" },
{ DDSPF_A8B8G8R8, "DXGI_FORMAT_R8G8B8A8_UNORM" },
{ DDSPF_X8B8G8R8, "D3DFMT_X8B8G8R8" },
{ DDSPF_G16R16, "DXGI_FORMAT_R16G16_UNORM" },
{ DDSPF_R5G6B5, "DXGI_FORMAT_B5G6R5_UNORM" },
{ DDSPF_A1R5G5B5, "DXGI_FORMAT_B5G5R5A1_UNORM" },
{ DDSPF_X1R5G5B5, "D3DFMT_X1R5G5B5" },
{ DDSPF_A4R4G4B4, "DXGI_FORMAT_B4G4R4A4_UNORM" },
{ DDSPF_X4R4G4B4, "D3DFMT_X4R4G4B4" },
{ DDSPF_R8G8B8, "D3DFMT_R8G8B8 (24bpp)" },
{ DDSPF_A8R3G3B2, "D3DFMT_A8R3G3B2" },
{ DDSPF_R3G3B2, "D3DFMT_R3G3B2" },
{ DDSPF_A4L4, "D3DFMT_A4L4" },
{ DDSPF_L8, "DXGI_FORMAT_R8_UNORM (D3DFMT_L8)" },
{ DDSPF_L8_NVTT1, "DXGI_FORMAT_R8_UNORM (D3DFMT_L8 NV)"},
{ DDSPF_L16, "DXGI_FORMAT_R16_UNORM (D3DFMT_L16)" },
{ DDSPF_L16_NVTT1, "DXGI_FORMAT_R16_UNORM (D3DFMT_L16 NV)" },
{ DDSPF_A8L8, "DXGI_FORMAT_R8G8_UNORM (D3DFMT_A8L8)" },
{ DDSPF_A8L8_ALT, "DXGI_FORMAT_R8G8_UNORM (D3DFMT_A8L8 Alt)" },
{ DDSPF_A8L8_NVTT1, "DXGI_FORMAT_R8G8_UNORM (D3DFMT_A8L8 NV)" },
{ DDSPF_A8, "DXGI_FORMAT_A8_UNORM" },
{ DDSPF_V8U8, "DXGI_FORMAT_R8G8_SNORM (D3DFMT_V8U8)" },
{ DDSPF_Q8W8V8U8, "DXGI_FORMAT_R8G8B8A8_SNORM (D3DFMT_Q8W8V8U8)" },
{ DDSPF_V16U16, "DXGI_FORMAT_R16G16_SNORM (D3DFMT_V16U16)" },
{ DDSPF_A2W10V10U10, "D3DFMT_A2W10V10U10 (mixed)" },
{ DDSPF_L6V5U5, "D3DFMT_L6V5U5 (mixed)" },
{ DDSPF_X8L8V8U8, "D3DFMT_X8L8V8U8 (mixed)"},
{ { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x3ff00000,0x000ffc00,0x000003ff,0xc0000000 }, "DXGI_FORMAT_R10G10B10A2_UNORM" },
{ { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000003ff,0x000ffc00,0x3ff00000,0xc0000000 }, "D3DFMT_A2R10G10B10" },
{ { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0xffffffff,0x00000000,0x00000000,0x00000000 }, "DXGI_FORMAT_R32_FLOAT" },
{ { sizeof(DDS_PIXELFORMAT), DDS_PAL8A, 0, 16, 0,0,0,0xff00 }, "D3DFMT_A8P8" },
{ { sizeof(DDS_PIXELFORMAT), DDS_PAL8, 0, 8, 0,0,0,0}, "D3DFMT_P8" },
{ {}, nullptr }
};
struct FOURCCPF
{
DWORD fourCC;
const char* name;
};
const FOURCCPF g_FOURCCPF[] =
{
{ MAKEFOURCC('D','X','T','1'), "DXGI_FORMAT_BC1_UNORM" },
{ MAKEFOURCC('D','X','T','3'), "DXGI_FORMAT_BC2_UNORM" },
{ MAKEFOURCC('D','X','T','5'), "DXGI_FORMAT_BC3_UNORM" },
{ MAKEFOURCC('D','X','T','2'), "D3DFMT_DXT2 (BC2)" },
{ MAKEFOURCC('D','X','T','4'), "D3DFMT_DXT4 (BC3)" },
{ MAKEFOURCC('B','C','4','U'), "DXGI_FORMAT_BC4_UNORM" },
{ MAKEFOURCC('B','C','4','S'), "DXGI_FORMAT_BC4_SNORM" },
{ MAKEFOURCC('B','C','5','U'), "DXGI_FORMAT_BC5_UNORM" },
{ MAKEFOURCC('B','C','5','S'), "DXGI_FORMAT_BC5_SNORM" },
{ MAKEFOURCC('R','G','B','G'), "DXGI_FORMAT_R8G8_B8G8_UNORM" },
{ MAKEFOURCC('G','R','G','B'), "DXGI_FORMAT_G8R8_G8B8_UNORM" },
{ MAKEFOURCC('A','T','I','1'), "DXGI_FORMAT_BC4_UNORM" },
{ MAKEFOURCC('A','T','I','2'), "DXGI_FORMAT_BC5_UNORM" },
{ MAKEFOURCC('A','2','X','Y'), "ATI2N_XY" },
{ MAKEFOURCC('A','2','D','5'), "ATI2N_DXT5" },
{ MAKEFOURCC('B','C','6','H'), "DXGI_FORMAT_BC6H_UF16" },
{ MAKEFOURCC('B','C','7','L'), "DXGI_FORMAT_BC7_UNORM" },
{ MAKEFOURCC('B','C','7','\0'), "DXGI_FORMAT_BC7_UNORM" },
{ MAKEFOURCC('U','Y','V','Y'), "D3DFMT_UYVY" },
{ MAKEFOURCC('Y','U','Y','2'), "D3DFMT_YUY2" },
{ MAKEFOURCC('x','G','B','R'), "DXT5_xGBR" },
{ MAKEFOURCC('R','x','B','G'), "DXT5_RxBG" },
{ MAKEFOURCC('R','B','x','G'), "DXT5_RBxG" },
{ MAKEFOURCC('x','R','B','G'), "DXT5_xRBG" },
{ MAKEFOURCC('R','G','x','B'), "DXT5_RGxB" },
{ MAKEFOURCC('x','G','x','R'), "DXT5_xGxR" },
{ MAKEFOURCC('G','X','R','B'), "DXT5_GXRB" },
{ MAKEFOURCC('G','R','X','B'), "DXT5_GRXB" },
{ MAKEFOURCC('R','X','G','B'), "DXT5_RXGB" },
{ MAKEFOURCC('B','R','G','X'), "DXT5_BRGX" },
{ 36, "DXGI_FORMAT_R16G16B16A16_UNORM" },
{ 110, "DXGI_FORMAT_R16G16B16A16_SNORM" },
{ 111, "DXGI_FORMAT_R16_FLOAT" },
{ 112, "DXGI_FORMAT_R16G16_FLOAT" },
{ 113, "DXGI_FORMAT_R16G16B16A16_FLOAT" },
{ 114, "DXGI_FORMAT_R32_FLOAT" },
{ 115, "DXGI_FORMAT_R32G32_FLOAT" },
{ 116, "DXGI_FORMAT_R32G32B32A32_FLOAT" },
{ 117, "D3DFMT_CxV8U8" },
{ 438304850, "D3DFMT_LIN_DXT1 (Xbox 360)" },
{ 2585788499, "D3DFMT_LIN_DXT2 (Xbox 360)" },
{ 438304851, "D3DFMT_LIN_DXT3 (Xbox 360)" },
{ 2585788500, "D3DFMT_LIN_DXT4 (Xbox 360)" },
{ 438304852, "D3DFMT_LIN_DXT5 (Xbox 360)" },
{ 438304890, "D3DFMT_LIN_DXT3A (Xbox 360)" },
{ 438304891, "D3DFMT_LIN_DXT5A (Xbox 360)" },
{ 438304881, "D3DFMT_LIN_DXN (Xbox 360)" },
{ 438304892, "D3DFMT_LIN_CTX1 (Xbox 360)" },
{ 405274700, "D3DFMT_LIN_G8R8_G8B8 (Xbox 360)" },
{ 1512046668, "D3DFMT_LIN_UYVY (Xbox 360)" },
{ 0, nullptr }
};
//--------------------------------------------------------------------------------------
HRESULT LoadTextureDataFromFile(_In_z_ const wchar_t* fileName,
std::unique_ptr& ddsData,
const DDS_HEADER** header,
uint8_t** bitData,
size_t* bitSize
)
{
// open the file
#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)
ScopedHandle hFile(safe_handle(CreateFile2(fileName,
GENERIC_READ,
FILE_SHARE_READ,
OPEN_EXISTING,
nullptr)));
#else
ScopedHandle hFile(safe_handle(CreateFileW(fileName,
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr)));
#endif
if (!hFile)
return HRESULT_FROM_WIN32(GetLastError());
// Get the file size
FILE_STANDARD_INFO fileInfo;
if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))
{
return HRESULT_FROM_WIN32(GetLastError());
}
// File is too big for 32-bit allocation, so reject read
if (fileInfo.EndOfFile.HighPart > 0)
{
return E_FAIL;
}
// Need at least enough data to fill the header and magic number to be a valid DDS
if (fileInfo.EndOfFile.LowPart (ddsData.get());
if (dwMagicNumber != DDS_MAGIC)
{
return E_FAIL;
}
auto hdr = reinterpret_cast(ddsData.get() + sizeof(uint32_t));
// Verify header to validate DDS file
if (hdr->size != 24 /* Known variant */
&& hdr->size != sizeof(DDS_HEADER))
{
return E_FAIL;
}
if (hdr->ddspf.size != 0 /* Known variant */
&& hdr->ddspf.size != 24 /* Known variant */
&& hdr->ddspf.size != sizeof(DDS_PIXELFORMAT))
{
return E_FAIL;
}
ptrdiff_t offset = DDS_MIN_HEADER_SIZE;
if (hdr->ddspf.flags & DDS_FOURCC)
{
// Check for DX10 extension
if (MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC)
{
if (hdr->ddspf.size != sizeof(DDS_PIXELFORMAT))
{
return E_FAIL;
}
// Must be long enough for both headers and magic value
if (fileInfo.EndOfFile.LowPart (ptrdiff_t(fileInfo.EndOfFile.LowPart) - offset);
return S_OK;
}
#define HEADER_FLAGS(x,y) if ( header->flags & (x)) { wprintf( y ); }
#define SURFACE_FLAGS(x,y) if ( header->caps & (x)) { wprintf( y ); }
#define CUBEMAP_FLAGS(x,y) if ( header->caps2 & (x)) { wprintf( y ); }
#define CAPS3_FLAGS(x,y) if ( header->caps3 & (x)) { wprintf( y ); }
#define PF_FLAGS(x,y) if ( header->ddspf.flags & (x)) { wprintf( y ); }
#define ENUM_CASE(x) case x: wprintf( L## #x ); break;
#define MISC_FLAGS(x,y) if ( ext->miscFlag & (x)) { wprintf( y ); }
void PrintDxgiFormat(DXGI_FORMAT format)
{
switch (static_cast(format))
{
ENUM_CASE(DXGI_FORMAT_R32G32B32A32_TYPELESS)
ENUM_CASE(DXGI_FORMAT_R32G32B32A32_FLOAT)
ENUM_CASE(DXGI_FORMAT_R32G32B32A32_UINT)
ENUM_CASE(DXGI_FORMAT_R32G32B32A32_SINT)
ENUM_CASE(DXGI_FORMAT_R32G32B32_TYPELESS)
ENUM_CASE(DXGI_FORMAT_R32G32B32_FLOAT)
ENUM_CASE(DXGI_FORMAT_R32G32B32_UINT)
ENUM_CASE(DXGI_FORMAT_R32G32B32_SINT)
ENUM_CASE(DXGI_FORMAT_R16G16B16A16_TYPELESS)
ENUM_CASE(DXGI_FORMAT_R16G16B16A16_FLOAT)
ENUM_CASE(DXGI_FORMAT_R16G16B16A16_UNORM)
ENUM_CASE(DXGI_FORMAT_R16G16B16A16_UINT)
ENUM_CASE(DXGI_FORMAT_R16G16B16A16_SNORM)
ENUM_CASE(DXGI_FORMAT_R16G16B16A16_SINT)
ENUM_CASE(DXGI_FORMAT_R32G32_TYPELESS)
ENUM_CASE(DXGI_FORMAT_R32G32_FLOAT)
ENUM_CASE(DXGI_FORMAT_R32G32_UINT)
ENUM_CASE(DXGI_FORMAT_R32G32_SINT)
ENUM_CASE(DXGI_FORMAT_R32G8X24_TYPELESS)
ENUM_CASE(DXGI_FORMAT_D32_FLOAT_S8X24_UINT)
ENUM_CASE(DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS)
ENUM_CASE(DXGI_FORMAT_X32_TYPELESS_G8X24_UINT)
ENUM_CASE(DXGI_FORMAT_R10G10B10A2_TYPELESS)
ENUM_CASE(DXGI_FORMAT_R10G10B10A2_UNORM)
ENUM_CASE(DXGI_FORMAT_R10G10B10A2_UINT)
ENUM_CASE(DXGI_FORMAT_R11G11B10_FLOAT)
ENUM_CASE(DXGI_FORMAT_R8G8B8A8_TYPELESS)
ENUM_CASE(DXGI_FORMAT_R8G8B8A8_UNORM)
ENUM_CASE(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB)
ENUM_CASE(DXGI_FORMAT_R8G8B8A8_UINT)
ENUM_CASE(DXGI_FORMAT_R8G8B8A8_SNORM)
ENUM_CASE(DXGI_FORMAT_R8G8B8A8_SINT)
ENUM_CASE(DXGI_FORMAT_R16G16_TYPELESS)
ENUM_CASE(DXGI_FORMAT_R16G16_FLOAT)
ENUM_CASE(DXGI_FORMAT_R16G16_UNORM)
ENUM_CASE(DXGI_FORMAT_R16G16_UINT)
ENUM_CASE(DXGI_FORMAT_R16G16_SNORM)
ENUM_CASE(DXGI_FORMAT_R16G16_SINT)
ENUM_CASE(DXGI_FORMAT_R32_TYPELESS)
ENUM_CASE(DXGI_FORMAT_D32_FLOAT)
ENUM_CASE(DXGI_FORMAT_R32_FLOAT)
ENUM_CASE(DXGI_FORMAT_R32_UINT)
ENUM_CASE(DXGI_FORMAT_R32_SINT)
ENUM_CASE(DXGI_FORMAT_R24G8_TYPELESS)
ENUM_CASE(DXGI_FORMAT_D24_UNORM_S8_UINT)
ENUM_CASE(DXGI_FORMAT_R24_UNORM_X8_TYPELESS)
ENUM_CASE(DXGI_FORMAT_X24_TYPELESS_G8_UINT)
ENUM_CASE(DXGI_FORMAT_R8G8_TYPELESS)
ENUM_CASE(DXGI_FORMAT_R8G8_UNORM)
ENUM_CASE(DXGI_FORMAT_R8G8_UINT)
ENUM_CASE(DXGI_FORMAT_R8G8_SNORM)
ENUM_CASE(DXGI_FORMAT_R8G8_SINT)
ENUM_CASE(DXGI_FORMAT_R16_TYPELESS)
ENUM_CASE(DXGI_FORMAT_R16_FLOAT)
ENUM_CASE(DXGI_FORMAT_D16_UNORM)
ENUM_CASE(DXGI_FORMAT_R16_UNORM)
ENUM_CASE(DXGI_FORMAT_R16_UINT)
ENUM_CASE(DXGI_FORMAT_R16_SNORM)
ENUM_CASE(DXGI_FORMAT_R16_SINT)
ENUM_CASE(DXGI_FORMAT_R8_TYPELESS)
ENUM_CASE(DXGI_FORMAT_R8_UNORM)
ENUM_CASE(DXGI_FORMAT_R8_UINT)
ENUM_CASE(DXGI_FORMAT_R8_SNORM)
ENUM_CASE(DXGI_FORMAT_R8_SINT)
ENUM_CASE(DXGI_FORMAT_A8_UNORM)
ENUM_CASE(DXGI_FORMAT_R1_UNORM)
ENUM_CASE(DXGI_FORMAT_R9G9B9E5_SHAREDEXP)
ENUM_CASE(DXGI_FORMAT_R8G8_B8G8_UNORM)
ENUM_CASE(DXGI_FORMAT_G8R8_G8B8_UNORM)
ENUM_CASE(DXGI_FORMAT_BC1_TYPELESS)
ENUM_CASE(DXGI_FORMAT_BC1_UNORM)
ENUM_CASE(DXGI_FORMAT_BC1_UNORM_SRGB)
ENUM_CASE(DXGI_FORMAT_BC2_TYPELESS)
ENUM_CASE(DXGI_FORMAT_BC2_UNORM)
ENUM_CASE(DXGI_FORMAT_BC2_UNORM_SRGB)
ENUM_CASE(DXGI_FORMAT_BC3_TYPELESS)
ENUM_CASE(DXGI_FORMAT_BC3_UNORM)
ENUM_CASE(DXGI_FORMAT_BC3_UNORM_SRGB)
ENUM_CASE(DXGI_FORMAT_BC4_TYPELESS)
ENUM_CASE(DXGI_FORMAT_BC4_UNORM)
ENUM_CASE(DXGI_FORMAT_BC4_SNORM)
ENUM_CASE(DXGI_FORMAT_BC5_TYPELESS)
ENUM_CASE(DXGI_FORMAT_BC5_UNORM)
ENUM_CASE(DXGI_FORMAT_BC5_SNORM)
ENUM_CASE(DXGI_FORMAT_B5G6R5_UNORM)
ENUM_CASE(DXGI_FORMAT_B5G5R5A1_UNORM)
ENUM_CASE(DXGI_FORMAT_B8G8R8A8_UNORM)
ENUM_CASE(DXGI_FORMAT_B8G8R8X8_UNORM)
ENUM_CASE(DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM)
ENUM_CASE(DXGI_FORMAT_B8G8R8A8_TYPELESS)
ENUM_CASE(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB)
ENUM_CASE(DXGI_FORMAT_B8G8R8X8_TYPELESS)
ENUM_CASE(DXGI_FORMAT_B8G8R8X8_UNORM_SRGB)
ENUM_CASE(DXGI_FORMAT_BC6H_TYPELESS)
ENUM_CASE(DXGI_FORMAT_BC6H_UF16)
ENUM_CASE(DXGI_FORMAT_BC6H_SF16)
ENUM_CASE(DXGI_FORMAT_BC7_TYPELESS)
ENUM_CASE(DXGI_FORMAT_BC7_UNORM)
ENUM_CASE(DXGI_FORMAT_BC7_UNORM_SRGB)
ENUM_CASE(DXGI_FORMAT_AYUV)
ENUM_CASE(DXGI_FORMAT_Y410)
ENUM_CASE(DXGI_FORMAT_Y416)
ENUM_CASE(DXGI_FORMAT_NV12)
ENUM_CASE(DXGI_FORMAT_P010)
ENUM_CASE(DXGI_FORMAT_P016)
ENUM_CASE(DXGI_FORMAT_420_OPAQUE)
ENUM_CASE(DXGI_FORMAT_YUY2)
ENUM_CASE(DXGI_FORMAT_Y210)
ENUM_CASE(DXGI_FORMAT_Y216)
ENUM_CASE(DXGI_FORMAT_NV11)
ENUM_CASE(DXGI_FORMAT_AI44)
ENUM_CASE(DXGI_FORMAT_IA44)
ENUM_CASE(DXGI_FORMAT_P8)
ENUM_CASE(DXGI_FORMAT_A8P8)
ENUM_CASE(DXGI_FORMAT_B4G4R4A4_UNORM)
case 116: wprintf(L"DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT [Xbox]"); break;
case 117: wprintf(L"DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT [Xbox]"); break;
case 118: wprintf(L"DXGI_FORMAT_D16_UNORM_S8_UINT [Xbox]"); break;
case 119: wprintf(L"DXGI_FORMAT_R16_UNORM_X8_TYPELESS [Xbox]"); break;
case 120: wprintf(L"DXGI_FORMAT_X16_TYPELESS_G8_UINT [Xbox]"); break;
case 130: wprintf(L"DXGI_FORMAT_P208"); break;
case 131: wprintf(L"DXGI_FORMAT_V208"); break;
case 132: wprintf(L"DXGI_FORMAT_V408"); break;
case 189: wprintf(L"DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM [Xbox]"); break;
case 190: wprintf(L"DXGI_FORMAT_R4G4_UNORM [Xbox]"); break;
case 191: wprintf(L"DXGI_FORMAT_A4B4G4R4_UNORM [D3D11on12]"); break;
default:
wprintf(L"UNKNOWN");
break;
}
}
void OutputHeader(const DDS_HEADER* header, const wchar_t* fname)
{
wprintf(L"DDS %ls\n(size: %u) Flags %08x: ", fname, header->size, header->flags);
HEADER_FLAGS(DDSD_CAPS, L"CAPS ")
HEADER_FLAGS(DDSD_HEIGHT, L"HEIGHT ")
HEADER_FLAGS(DDSD_WIDTH, L"WIDTH ")
HEADER_FLAGS(DDSD_PITCH, L"PITCH ")
HEADER_FLAGS(DDSD_PIXELFORMAT, L"PIXELFORMAT ")
HEADER_FLAGS(DDSD_MIPMAPCOUNT, L"MIPMAPCOUNT ")
HEADER_FLAGS(DDSD_LINEARSIZE, L"LINEARSIZE ")
HEADER_FLAGS(DDSD_DEPTH, L"DEPTH ")
HEADER_FLAGS(DDSD_BACKBUFFERCOUNT, L"BACKBUFFERCOUNT! ")
HEADER_FLAGS(DDSD_ZBUFFERBITDEPTH, L"ZBUFFERBITDEPTH! ")
HEADER_FLAGS(DDSD_ALPHABITDEPTH, L"ALPHABITDEPTH! ")
HEADER_FLAGS(DDSD_LPSURFACE, L"LPSURFACE! ")
HEADER_FLAGS(DDSD_CKDESTOVERLAY, L"CKDESTOVERLAY! ")
HEADER_FLAGS(DDSD_CKDESTBLT, L"CKDESTBLT! ")
HEADER_FLAGS(DDSD_CKSRCOVERLAY, L"CKSRCOVERLAY! ")
HEADER_FLAGS(DDSD_CKSRCBLT, L"CKSRCBLT! ")
HEADER_FLAGS(DDSD_REFRESHRATE, L"REFRESHRATE! ")
HEADER_FLAGS(DDSD_TEXTURESTAGE, L"TEXTURESTAGE! ")
HEADER_FLAGS(DDSD_FVF, L"FVF! ")
HEADER_FLAGS(DDSD_SRCVBHANDLE, L"SRCVBHANDLE! ")
wprintf(L"\n");
if (header->flags & DDSD_DEPTH)
wprintf(L"%u x %u x %u\n", header->width, header->height, header->depth);
else
wprintf(L"%u x %u\n", header->width, header->height);
wprintf(L"%ls: %u\n", (header->flags & DDSD_LINEARSIZE) ? L"Linear Size" : L"Pitch", header->pitchOrLinearSize);
wprintf(L"Mipmap count: %u\n", header->mipMapCount);
// Some DDS files are missing the DDSD_CAPS flag, so always dump these
{
// dwCaps
if (header->caps != 0)
{
wprintf(L"Surface flags: %08x: ", header->caps);
SURFACE_FLAGS(DDSCAPS_COMPLEX, L"COMPLEX ")
SURFACE_FLAGS(DDSCAPS_TEXTURE, L"TEXTURE ")
SURFACE_FLAGS(DDSCAPS_MIPMAP, L"MIPMAP ")
SURFACE_FLAGS(DDSCAPS_ALPHA, L"ALPHA ")
SURFACE_FLAGS(DDSCAPS_BACKBUFFER, L"BACKBUFFER! ")
SURFACE_FLAGS(DDSCAPS_FLIP, L"FLIP! ")
SURFACE_FLAGS(DDSCAPS_FRONTBUFFER, L"FRONTBUFFER! ")
SURFACE_FLAGS(DDSCAPS_OFFSCREENPLAIN, L"OFFSCREENPLAIN! ")
SURFACE_FLAGS(DDSCAPS_OVERLAY, L"OVERLAY! ")
SURFACE_FLAGS(DDSCAPS_PALETTE, L"PALETTE! ")
SURFACE_FLAGS(DDSCAPS_PRIMARYSURFACE, L"PRIMARYSURFACE! ")
SURFACE_FLAGS(DDSCAPS_SYSTEMMEMORY, L"SYSMEM! ")
SURFACE_FLAGS(DDSCAPS_3DDEVICE, L"3DDEVICE! ")
SURFACE_FLAGS(DDSCAPS_VIDEOMEMORY, L"VIDMEM! ")
SURFACE_FLAGS(DDSCAPS_VISIBLE, L"VISIBILE! ")
SURFACE_FLAGS(DDSCAPS_WRITEONLY, L"WRITEONLY! ")
SURFACE_FLAGS(DDSCAPS_ZBUFFER, L"ZBUFFER! ")
SURFACE_FLAGS(DDSCAPS_OWNDC, L"OWNDC! ")
SURFACE_FLAGS(DDSCAPS_LIVEVIDEO, L"LIVEVIDEO! ")
SURFACE_FLAGS(DDSCAPS_HWCODEC, L"HWCODEC! ")
SURFACE_FLAGS(DDSCAPS_MODEX, L"MODEX! ")
SURFACE_FLAGS(DDSCAPS_ALLOCONLOAD, L"ALLOCONLOAD! ")
SURFACE_FLAGS(DDSCAPS_VIDEOPORT, L"VIDEOPORT! ")
SURFACE_FLAGS(DDSCAPS_LOCALVIDMEM, L"LOCALVIDMEM! ")
SURFACE_FLAGS(DDSCAPS_NONLOCALVIDMEM, L"NONLOCALVIDMEM! ")
SURFACE_FLAGS(DDSCAPS_STANDARDVGAMODE, L"VGAMODE! ")
SURFACE_FLAGS(DDSCAPS_OPTIMIZED, L"OPTIMIZED! ")
SURFACE_FLAGS(DDSCAPS_RESERVED1, L"RESERVED1! ")
SURFACE_FLAGS(DDSCAPS_RESERVED2, L"RESERVED2! ")
#ifndef __MINGW32__
SURFACE_FLAGS(DDSCAPS_RESERVED3, L"RESERVED3! ")
#endif
wprintf(L"\n");
}
// dwCaps2
if (header->caps2 != 0)
{
wprintf(L"Cubemap flags: %08x: ", header->caps2);
CUBEMAP_FLAGS(DDSCAPS2_CUBEMAP, L"CUBEMAP ")
CUBEMAP_FLAGS(DDSCAPS2_CUBEMAP_POSITIVEX, L"POSX ")
CUBEMAP_FLAGS(DDSCAPS2_CUBEMAP_POSITIVEY, L"POSY ")
CUBEMAP_FLAGS(DDSCAPS2_CUBEMAP_POSITIVEZ, L"POSZ ")
CUBEMAP_FLAGS(DDSCAPS2_CUBEMAP_NEGATIVEX, L"NEGX ")
CUBEMAP_FLAGS(DDSCAPS2_CUBEMAP_NEGATIVEY, L"NEGY ")
CUBEMAP_FLAGS(DDSCAPS2_CUBEMAP_NEGATIVEZ, L"NEGZ ")
CUBEMAP_FLAGS(DDSCAPS2_VOLUME, L"VOLUME ")
CUBEMAP_FLAGS(DDSCAPS2_HINTDYNAMIC, L"HINTDYNAMIC! ")
CUBEMAP_FLAGS(DDSCAPS2_HINTSTATIC, L"HINTSTATIC! ")
CUBEMAP_FLAGS(DDSCAPS2_TEXTUREMANAGE, L"TEXTUREMANAGE! ")
CUBEMAP_FLAGS(DDSCAPS2_OPAQUE, L"OPAQUE! ")
CUBEMAP_FLAGS(DDSCAPS2_HINTANTIALIASING, L"HINTAA! ")
CUBEMAP_FLAGS(DDSCAPS2_MIPMAPSUBLEVEL, L"MIPMAPSUBLEVEL! ")
CUBEMAP_FLAGS(DDSCAPS2_D3DTEXTUREMANAGE, L"D3DTXTMANAGE! ")
CUBEMAP_FLAGS(DDSCAPS2_DONOTPERSIST, L"DONOTPERSIST! ")
CUBEMAP_FLAGS(DDSCAPS2_STEREOSURFACELEFT, L"STEREOL!")
CUBEMAP_FLAGS(DDSCAPS2_NOTUSERLOCKABLE, L"NOTUSERLOCKABLE! ")
CUBEMAP_FLAGS(DDSCAPS2_POINTS, L"POINTS! ")
CUBEMAP_FLAGS(DDSCAPS2_RTPATCHES, L"RTPATCHES! ")
CUBEMAP_FLAGS(DDSCAPS2_NPATCHES, L"NPATCHES! ")
CUBEMAP_FLAGS(DDSCAPS2_DISCARDBACKBUFFER, L"DISCARDBACKBUFFER! ")
CUBEMAP_FLAGS(DDSCAPS2_ENABLEALPHACHANNEL, L"ENABLEALPHA! ")
CUBEMAP_FLAGS(DDSCAPS2_EXTENDEDFORMATPRIMARY, L"EXTFMTPRIMARY! ")
CUBEMAP_FLAGS(DDSCAPS2_ADDITIONALPRIMARY, L"ADDITIONALPRIMARY! ")
CUBEMAP_FLAGS(DDSCAPS2_RESERVED1, L"RESERVED1! ")
CUBEMAP_FLAGS(DDSCAPS2_RESERVED2, L"RESERVED2! ")
CUBEMAP_FLAGS(DDSCAPS2_RESERVED3, L"RESERVED3! ")
#ifndef __MINGW32__
CUBEMAP_FLAGS(DDSCAPS2_RESERVED4, L"RESERVED4! ")
#endif
wprintf(L"\n");
}
if (header->caps3 != 0)
{
wprintf(L"Caps3 flags: %08x:", header->caps3);
CAPS3_FLAGS(DDSCAPS3_LIGHTWEIGHTMIPMAP, L"LWMIPMAP! ")
CAPS3_FLAGS(DDSCAPS3_AUTOGENMIPMAP, L"AUTOGEN! ")
CAPS3_FLAGS(DDSCAPS3_DMAP, L"DMAP! ")
CAPS3_FLAGS(DDSCAPS3_CREATESHAREDRESOURCE, L"CREATESHARED! ")
CAPS3_FLAGS(DDSCAPS3_READONLYRESOURCE, L"RO! ")
CAPS3_FLAGS(DDSCAPS3_OPENSHAREDRESOURCE, L"OPENSHARED! ")
CAPS3_FLAGS(DDSCAPS3_RESERVED1, L"RESERVED1! ")
CAPS3_FLAGS(DDSCAPS3_RESERVED2, L"RESERVED2! ")
wprintf(L"\n");
}
if (header->caps4 != 0)
wprintf(L"Caps4 flags: %08x\n", header->caps4);
}
bool dx10ext = false;
// Some DDS files are missing the DDSD_PIXELFORMAT flag, so always dump these
{
wprintf(L"PIXELFORMAT (size %u): %08x: ", header->ddspf.size, header->ddspf.flags);
PF_FLAGS(DDPF_ALPHAPIXELS, L"ALPHAPIXELS ")
PF_FLAGS(DDPF_ALPHA, L"ALPHA ")
PF_FLAGS(DDPF_FOURCC, L"FOURCC ")
PF_FLAGS(DDPF_RGB, L"RGB ")
PF_FLAGS(DDPF_LUMINANCE, L"LUMINANCE ")
PF_FLAGS(DDPF_PALETTEINDEXED8, L"PAL8 ")
PF_FLAGS(DDPF_YUV, L"YUV ")
PF_FLAGS(DDPF_PALETTEINDEXED4, L"PALI4! ")
PF_FLAGS(DDPF_PALETTEINDEXEDTO8, L"PALTO8! ")
PF_FLAGS(DDPF_COMPRESSED, L"COMPRESSED! ")
PF_FLAGS(DDPF_RGBTOYUV, L"RGB2YUV! ")
PF_FLAGS(DDPF_ZBUFFER, L"ZBUFFER! ")
PF_FLAGS(DDPF_PALETTEINDEXED1, L"PAL1! ")
PF_FLAGS(DDPF_PALETTEINDEXED2, L"PAL2! ")
PF_FLAGS(DDPF_ZPIXELS, L"ZPIXELS! ")
PF_FLAGS(DDPF_STENCILBUFFER, L"STENCIL! ")
PF_FLAGS(DDPF_ALPHAPREMULT, L"APREMULT! ")
PF_FLAGS(DDPF_BUMPLUMINANCE, L"BUMPLUMINANCE! ")
PF_FLAGS(DDPF_BUMPDUDV, L"BUMPDUDV! ")
wprintf(L"\n");
if ((header->ddspf.flags & DDPF_FOURCC)
|| (header->ddspf.flags == 0 && header->ddspf.fourCC != 0))
{
wprintf(L"FourCC = %u '%c%c%c%c'\n", header->ddspf.fourCC,
static_cast(header->ddspf.fourCC & 0xff),
static_cast((header->ddspf.fourCC >> 8) & 0xff),
static_cast((header->ddspf.fourCC >> 16) & 0xff),
static_cast((header->ddspf.fourCC >> 24) & 0xff));
if (header->ddspf.fourCC == MAKEFOURCC('D', 'X', '1', '0'))
dx10ext = true;
}
if (header->ddspf.RGBBitCount != 0)
{
wprintf(L"bitCount %u\nR: %08x G: %08x B: %08x A: %08x\n",
header->ddspf.RGBBitCount,
header->ddspf.RBitMask,
header->ddspf.GBitMask,
header->ddspf.BBitMask,
header->ddspf.ABitMask);
}
}
bool known = false;
if (dx10ext)
{
known = true;
auto ext = reinterpret_cast(reinterpret_cast(header) + sizeof(DDS_HEADER));
wprintf(L"dxgiFormat = %u: ", ext->dxgiFormat);
PrintDxgiFormat(ext->dxgiFormat);
wprintf(L"\nresourceDim = %u: ", ext->resourceDimension);
switch (ext->resourceDimension)
{
ENUM_CASE(DDS_DIMENSION_TEXTURE1D)
ENUM_CASE(DDS_DIMENSION_TEXTURE2D)
ENUM_CASE(DDS_DIMENSION_TEXTURE3D)
case 1:
wprintf(L"BUFFER!");
break;
default:
wprintf(L"UNKNOWN!");
break;
}
wprintf(L"\n");
if (ext->miscFlag != 0)
{
wprintf(L"miscFlag = %08x: ", ext->miscFlag);
// These match D3D11 and D3D10
MISC_FLAGS(D3D11_RESOURCE_MISC_GENERATE_MIPS, L"GENMIPS ")
MISC_FLAGS(D3D11_RESOURCE_MISC_SHARED, L"SHARED ")
MISC_FLAGS(D3D11_RESOURCE_MISC_TEXTURECUBE, L"TEXTURECUBE ")
// These are difference between D3D11 and D3D10
MISC_FLAGS(D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX, L"MISCKEYEDMUTEX! ")
MISC_FLAGS(D3D11_RESOURCE_MISC_GDI_COMPATIBLE, L"GDICOMPAT! ")
wprintf(L"\n");
}
wprintf(L"arraySize = %u\n", ext->arraySize);
if (ext->miscFlags2)
{
wprintf(L"miscFlags2 = %08x ", ext->miscFlags2);
switch (ext->miscFlags2 & DDS_MISC_FLAGS2_ALPHA_MODE_MASK)
{
case DDS_ALPHA_MODE_STRAIGHT: wprintf(L"ALPHASTRAIGHT "); break;
case DDS_ALPHA_MODE_PREMULTIPLIED: wprintf(L"PMALPHA "); break;
case DDS_ALPHA_MODE_OPAQUE: wprintf(L"ALPHAOPAQUE "); break;
case DDS_ALPHA_MODE_CUSTOM: wprintf(L"ALPHACUSTOM "); break;
}
wprintf(L"\n");
}
}
else if (header->ddspf.flags & DDPF_FOURCC)
{
for (size_t j = 0; j fourCC == header->ddspf.fourCC)
{
known = true;
wprintf(L"%hs\n", entry->name);
break;
}
}
}
else
{
for (size_t j = 0; j ddspf.flags == entry->ddpf.flags) && (header->ddspf.RGBBitCount == entry->ddpf.RGBBitCount))
{
if (header->ddspf.flags & DDS_PAL8)
{
known = true;
wprintf(L"%hs\n", entry->name);
break;
}
else if (header->ddspf.flags & DDS_LUMINANCE)
{
if (header->ddspf.flags & DDS_ALPHAPIXELS)
{
if (header->ddspf.RBitMask == entry->ddpf.RBitMask
&& header->ddspf.ABitMask == entry->ddpf.ABitMask)
{
known = true;
wprintf(L"%hs\n", entry->name);
break;
}
}
else if (header->ddspf.RBitMask == entry->ddpf.RBitMask)
{
known = true;
wprintf(L"%hs\n", entry->name);
break;
}
}
else if (header->ddspf.flags & DDS_ALPHAPIXELS)
{
if (header->ddspf.RBitMask == entry->ddpf.RBitMask
&& header->ddspf.GBitMask == entry->ddpf.GBitMask
&& header->ddspf.BBitMask == entry->ddpf.BBitMask
&& header->ddspf.ABitMask == entry->ddpf.ABitMask)
{
known = true;
wprintf(L"%hs\n", entry->name);
break;
}
}
else if (header->ddspf.RBitMask == entry->ddpf.RBitMask
&& header->ddspf.GBitMask == entry->ddpf.GBitMask
&& header->ddspf.BBitMask == entry->ddpf.BBitMask)
{
known = true;
wprintf(L"%hs\n", entry->name);
break;
}
}
}
}
if (!known)
{
wprintf(L"DXGI_FORMAT_UNKNOWN!\n");
}
bool reservedUsed = false;
for(size_t j = 0; j reserved1[j] != 0)
{
reservedUsed = true;
break;
}
}
if (header->reserved2 != 0)
{
reservedUsed = true;
}
if (reservedUsed)
{
wprintf(L"Reserved area:\n %08X %08X %08X %08X\n %08X %08X %08X %08X\n %08X %08X %08X\n %08X\n",
header->reserved1[0], header->reserved1[1], header->reserved1[2], header->reserved1[3],
header->reserved1[4], header->reserved1[5], header->reserved1[6], header->reserved1[7],
header->reserved1[8], header->reserved1[9], header->reserved1[10], header->reserved2);
if (((header->reserved1[9]) & 0xffffff) == MAKEFOURCC('N', 'V', 'T', 0))
{
wprintf(L"nVidia Texture Tool extension present '%c%c%c%c'\n",
static_cast(header->reserved1[9] & 0xff),
static_cast((header->reserved1[9] >> 8) & 0xff),
static_cast((header->reserved1[9] >> 16) & 0xff),
static_cast((header->reserved1[9] >> 24) & 0xff));
if (header->ddspf.flags & 0x80000000U)
{
wprintf(L" NVTT custom flag: DDPF_NORMAL\n");
}
if (header->ddspf.flags & 0x40000000U)
{
wprintf(L" NVTT custom flag: DDPF_SRGB\n");
}
}
}
}
}
int __cdecl wmain(int argc, wchar_t* argv[])
{
if (argc != 2)
{
wprintf(L"Usage: %ls [filename]\n", argv[0]);
return -1;
}
const DDS_HEADER* header = nullptr;
uint8_t* bitData = nullptr;
size_t bitSize = 0;
std::unique_ptr ddsData;
HRESULT hr = LoadTextureDataFromFile(argv[1], ddsData, &header, &bitData, &bitSize);
if (FAILED(hr))
{
wprintf(L"ERROR: failed to load %ls\n", argv[1]);
return -1;
}
OutputHeader(header, argv[1]);
return 0;
}