//-------------------------------------------------------------------------------------- // 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_A4R4G4B4, "DXGI_FORMAT_B4G4R4A4_UNORM" }, { DDSPF_R8G8B8, "D3DFMT_R8G8B8 (24bpp)" }, { DDSPF_A8, "DXGI_FORMAT_A8_UNORM" }, { DDSPF_V8U8, "DXGI_FORMAT_R8G8_SNORM" }, { DDSPF_Q8W8V8U8, "DXGI_FORMAT_R8G8B8A8_SNORM" }, { DDSPF_V16U16, "DXGI_FORMAT_R16G16_SNORM" }, { { 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_RGB, 0, 16, 0x7c00,0x03e0,0x001f,0x0000 }, "D3DFMT_X1R5G5B5" }, { { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0f00,0x00f0,0x000f,0x0000 }, "D3DFMT_X4R4G4B4" }, { { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x00e0,0x001c,0x0003,0xff00 }, "D3DFMT_A8R3G3B2" }, { { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 8, 0xe0,0x1c,0x03,0x00 }, "D3DFMT_R3G3B2" }, { DDSPF_L8, "DXGI_FORMAT_R8_UNORM (L8)" }, { DDSPF_L16, "DXGI_FORMAT_R16_UNORM (L16)" }, { DDSPF_A8L8, "DXGI_FORMAT_R8G8_UNORM (A8L8)" }, { { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 8, 0x0f, 0x00, 0x00, 0xf0 }, "D3DFMT_A4L4" }, { { sizeof(DDS_PIXELFORMAT), DDS_PAL8, 0, 16, 0,0,0,0}, "D3DFMT_A8P8" }, { { sizeof(DDS_PIXELFORMAT), DDS_PAL8, 0, 8, 0,0,0,0}, "D3DFMT_P8" }, { {}, nullptr } }; // TODO - DDPF_BUMPDUDV D3DFMT_A2W10V10U10 // TODO - DDPF_BUMPLUMINANCE D3DFMT_L6V5U5, D3DFMT_X8L8V8U8 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 < (sizeof(DDS_HEADER) + sizeof(DWORD))) { return E_FAIL; } // create enough space for the file data ddsData.reset(new uint8_t[fileInfo.EndOfFile.LowPart]); if (!ddsData) { return E_OUTOFMEMORY; } // read the data in DWORD BytesRead = 0; if (!ReadFile(hFile.get(), ddsData.get(), fileInfo.EndOfFile.LowPart, &BytesRead, nullptr)) { return HRESULT_FROM_WIN32(GetLastError()); } if (BytesRead < fileInfo.EndOfFile.LowPart) { return E_FAIL; } // DDS files always start with the same magic number ("DDS ") auto dwMagicNumber = *reinterpret_cast(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 = sizeof(uint32_t) + sizeof(DDS_HEADER); 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 < (sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_DXT10))) { return E_FAIL; } offset += sizeof(DDS_HEADER_DXT10); } } // setup the pointers in the process request *header = hdr; *bitData = ddsData.get() + offset; *bitSize = static_cast(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); } } if (dx10ext) { 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 < std::size(g_FOURCCPF); ++j) { const FOURCCPF* entry = &g_FOURCCPF[j]; if (entry->fourCC == header->ddspf.fourCC) { wprintf(L"%hs\n", entry->name); break; } } } else { for (size_t j = 0; j < std::size(g_DDPF); ++j) { const DDPF* entry = &g_DDPF[j]; if (header->ddspf.flags & entry->ddpf.flags) { if (header->ddspf.flags & DDS_PAL8) { if (header->ddspf.RGBBitCount == entry->ddpf.RGBBitCount) { 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 && header->ddspf.ABitMask == entry->ddpf.ABitMask) { wprintf(L"%hs\n", entry->name); break; } } } } } bool reservedUsed = false; for(size_t j = 0; j < 11; ++j) { if (header->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; }