Last active
August 29, 2015 14:26
-
-
Save legends2k/97584e4c576d7b5e0dcf to your computer and use it in GitHub Desktop.
Prints DDS file information
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <fstream> | |
| #include <iostream> | |
| #include <array> | |
| #include <bitset> | |
| #include <iomanip> | |
| #include <type_traits> | |
| #include <stdexcept> | |
| #include <cstdint> | |
| using DWORD = uint32_t; | |
| using UINT = unsigned int; | |
| #define DDPF_ALPHAPIXELS 0x00000001 | |
| #define DDPF_ALPHA 0x00000002 | |
| #define DDPF_FOURCC 0x00000004 | |
| #define DDPF_RGB 0x00000040 | |
| #define DDPF_RGBA 0x00000041 | |
| #define DDPF_YUV 0x00000200 | |
| #define DDPF_LUMINANCE 0x00020000 | |
| #define DDSCAPS2_CUBEMAP 0x200 | |
| #define DDSCAPS2_CUBEMAP_POSITIVEX 0x400 | |
| #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x800 | |
| #define DDSCAPS2_CUBEMAP_POSITIVEY 0x1000 | |
| #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x2000 | |
| #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x4000 | |
| #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x8000 | |
| #define DDSCAPS2_VOLUME 0x200000 | |
| #define DDS_CUBEMAP_ALLFACES (DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_POSITIVEY | DDSCAPS2_CUBEMAP_POSITIVEZ | \ | |
| DDSCAPS2_CUBEMAP_NEGATIVEZ | DDSCAPS2_CUBEMAP_NEGATIVEY | DDSCAPS2_CUBEMAP_NEGATIVEZ) | |
| enum class D3D10_RESOURCE_DIMENSION : uint8_t { | |
| D3D10_RESOURCE_DIMENSION_UNKNOWN = 0, | |
| D3D10_RESOURCE_DIMENSION_BUFFER = 1, | |
| D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2, | |
| D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3, | |
| D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4, | |
| Total | |
| }; | |
| enum class DXGI_FORMAT : uint32_t { | |
| DXGI_FORMAT_UNKNOWN = 0, | |
| DXGI_FORMAT_R32G32B32A32_TYPELESS = 1, | |
| DXGI_FORMAT_R32G32B32A32_FLOAT = 2, | |
| DXGI_FORMAT_R32G32B32A32_UINT = 3, | |
| DXGI_FORMAT_R32G32B32A32_SINT = 4, | |
| DXGI_FORMAT_R32G32B32_TYPELESS = 5, | |
| DXGI_FORMAT_R32G32B32_FLOAT = 6, | |
| DXGI_FORMAT_R32G32B32_UINT = 7, | |
| DXGI_FORMAT_R32G32B32_SINT = 8, | |
| DXGI_FORMAT_R16G16B16A16_TYPELESS = 9, | |
| DXGI_FORMAT_R16G16B16A16_FLOAT = 10, | |
| DXGI_FORMAT_R16G16B16A16_UNORM = 11, | |
| DXGI_FORMAT_R16G16B16A16_UINT = 12, | |
| DXGI_FORMAT_R16G16B16A16_SNORM = 13, | |
| DXGI_FORMAT_R16G16B16A16_SINT = 14, | |
| DXGI_FORMAT_R32G32_TYPELESS = 15, | |
| DXGI_FORMAT_R32G32_FLOAT = 16, | |
| DXGI_FORMAT_R32G32_UINT = 17, | |
| DXGI_FORMAT_R32G32_SINT = 18, | |
| DXGI_FORMAT_R32G8X24_TYPELESS = 19, | |
| DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20, | |
| DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, | |
| DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22, | |
| DXGI_FORMAT_R10G10B10A2_TYPELESS = 23, | |
| DXGI_FORMAT_R10G10B10A2_UNORM = 24, | |
| DXGI_FORMAT_R10G10B10A2_UINT = 25, | |
| DXGI_FORMAT_R11G11B10_FLOAT = 26, | |
| DXGI_FORMAT_R8G8B8A8_TYPELESS = 27, | |
| DXGI_FORMAT_R8G8B8A8_UNORM = 28, | |
| DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29, | |
| DXGI_FORMAT_R8G8B8A8_UINT = 30, | |
| DXGI_FORMAT_R8G8B8A8_SNORM = 31, | |
| DXGI_FORMAT_R8G8B8A8_SINT = 32, | |
| DXGI_FORMAT_R16G16_TYPELESS = 33, | |
| DXGI_FORMAT_R16G16_FLOAT = 34, | |
| DXGI_FORMAT_R16G16_UNORM = 35, | |
| DXGI_FORMAT_R16G16_UINT = 36, | |
| DXGI_FORMAT_R16G16_SNORM = 37, | |
| DXGI_FORMAT_R16G16_SINT = 38, | |
| DXGI_FORMAT_R32_TYPELESS = 39, | |
| DXGI_FORMAT_D32_FLOAT = 40, | |
| DXGI_FORMAT_R32_FLOAT = 41, | |
| DXGI_FORMAT_R32_UINT = 42, | |
| DXGI_FORMAT_R32_SINT = 43, | |
| DXGI_FORMAT_R24G8_TYPELESS = 44, | |
| DXGI_FORMAT_D24_UNORM_S8_UINT = 45, | |
| DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46, | |
| DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47, | |
| DXGI_FORMAT_R8G8_TYPELESS = 48, | |
| DXGI_FORMAT_R8G8_UNORM = 49, | |
| DXGI_FORMAT_R8G8_UINT = 50, | |
| DXGI_FORMAT_R8G8_SNORM = 51, | |
| DXGI_FORMAT_R8G8_SINT = 52, | |
| DXGI_FORMAT_R16_TYPELESS = 53, | |
| DXGI_FORMAT_R16_FLOAT = 54, | |
| DXGI_FORMAT_D16_UNORM = 55, | |
| DXGI_FORMAT_R16_UNORM = 56, | |
| DXGI_FORMAT_R16_UINT = 57, | |
| DXGI_FORMAT_R16_SNORM = 58, | |
| DXGI_FORMAT_R16_SINT = 59, | |
| DXGI_FORMAT_R8_TYPELESS = 60, | |
| DXGI_FORMAT_R8_UNORM = 61, | |
| DXGI_FORMAT_R8_UINT = 62, | |
| DXGI_FORMAT_R8_SNORM = 63, | |
| DXGI_FORMAT_R8_SINT = 64, | |
| DXGI_FORMAT_A8_UNORM = 65, | |
| DXGI_FORMAT_R1_UNORM = 66, | |
| DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67, | |
| DXGI_FORMAT_R8G8_B8G8_UNORM = 68, | |
| DXGI_FORMAT_G8R8_G8B8_UNORM = 69, | |
| DXGI_FORMAT_BC1_TYPELESS = 70, | |
| DXGI_FORMAT_BC1_UNORM = 71, | |
| DXGI_FORMAT_BC1_UNORM_SRGB = 72, | |
| DXGI_FORMAT_BC2_TYPELESS = 73, | |
| DXGI_FORMAT_BC2_UNORM = 74, | |
| DXGI_FORMAT_BC2_UNORM_SRGB = 75, | |
| DXGI_FORMAT_BC3_TYPELESS = 76, | |
| DXGI_FORMAT_BC3_UNORM = 77, | |
| DXGI_FORMAT_BC3_UNORM_SRGB = 78, | |
| DXGI_FORMAT_BC4_TYPELESS = 79, | |
| DXGI_FORMAT_BC4_UNORM = 80, | |
| DXGI_FORMAT_BC4_SNORM = 81, | |
| DXGI_FORMAT_BC5_TYPELESS = 82, | |
| DXGI_FORMAT_BC5_UNORM = 83, | |
| DXGI_FORMAT_BC5_SNORM = 84, | |
| DXGI_FORMAT_B5G6R5_UNORM = 85, | |
| DXGI_FORMAT_B5G5R5A1_UNORM = 86, | |
| DXGI_FORMAT_B8G8R8A8_UNORM = 87, | |
| DXGI_FORMAT_B8G8R8X8_UNORM = 88, | |
| DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89, | |
| DXGI_FORMAT_B8G8R8A8_TYPELESS = 90, | |
| DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91, | |
| DXGI_FORMAT_B8G8R8X8_TYPELESS = 92, | |
| DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93, | |
| DXGI_FORMAT_BC6H_TYPELESS = 94, | |
| DXGI_FORMAT_BC6H_UF16 = 95, | |
| DXGI_FORMAT_BC6H_SF16 = 96, | |
| DXGI_FORMAT_BC7_TYPELESS = 97, | |
| DXGI_FORMAT_BC7_UNORM = 98, | |
| DXGI_FORMAT_BC7_UNORM_SRGB = 99, | |
| DXGI_FORMAT_AYUV = 100, | |
| DXGI_FORMAT_Y410 = 101, | |
| DXGI_FORMAT_Y416 = 102, | |
| DXGI_FORMAT_NV12 = 103, | |
| DXGI_FORMAT_P010 = 104, | |
| DXGI_FORMAT_P016 = 105, | |
| DXGI_FORMAT_420_OPAQUE = 106, | |
| DXGI_FORMAT_YUY2 = 107, | |
| DXGI_FORMAT_Y210 = 108, | |
| DXGI_FORMAT_Y216 = 109, | |
| DXGI_FORMAT_NV11 = 110, | |
| DXGI_FORMAT_AI44 = 111, | |
| DXGI_FORMAT_IA44 = 112, | |
| DXGI_FORMAT_P8 = 113, | |
| DXGI_FORMAT_A8P8 = 114, | |
| DXGI_FORMAT_B4G4R4A4_UNORM = 115, | |
| DXGI_FORMAT_FORCE_UINT = 0xffffffffU, | |
| Total = DXGI_FORMAT_B4G4R4A4_UNORM + 2 | |
| }; | |
| #pragma pack(push) | |
| struct DDS_PIXELFORMAT { | |
| DWORD dwSize; | |
| DWORD dwFlags; | |
| DWORD dwFourCC; | |
| DWORD dwRGBBitCount; | |
| DWORD dwRBitMask; | |
| DWORD dwGBitMask; | |
| DWORD dwBBitMask; | |
| DWORD dwABitMask; | |
| }; | |
| struct DDS_HEADER { | |
| DWORD dwSize; | |
| DWORD dwFlags; | |
| DWORD dwHeight; | |
| DWORD dwWidth; | |
| DWORD dwPitchOrLinearSize; | |
| DWORD dwDepth; | |
| DWORD dwMipMapCount; | |
| DWORD dwReserved1[11]; | |
| DDS_PIXELFORMAT ddspf; | |
| DWORD dwCaps; | |
| DWORD dwCaps2; | |
| DWORD dwCaps3; | |
| DWORD dwCaps4; | |
| DWORD dwReserved2; | |
| }; | |
| struct DDS_HEADER_DXT10 { | |
| DXGI_FORMAT dxgiFormat; | |
| D3D10_RESOURCE_DIMENSION resourceDimension; | |
| UINT miscFlag; | |
| UINT arraySize; | |
| UINT reserved; | |
| }; | |
| #pragma pack(pop) | |
| char const *resource_dim_string[] = { "Unknown", "N/A (Buffer)", "1D", "2D", "3D" }; | |
| char const *dxgi_format_string[] = { | |
| "UNKNOWN", | |
| "R32G32B32A32_TYPELESS", | |
| "R32G32B32A32_FLOAT", | |
| "R32G32B32A32_UINT", | |
| "R32G32B32A32_SINT", | |
| "R32G32B32_TYPELESS", | |
| "R32G32B32_FLOAT", | |
| "R32G32B32_UINT", | |
| "R32G32B32_SINT", | |
| "R16G16B16A16_TYPELESS", | |
| "R16G16B16A16_FLOAT", | |
| "R16G16B16A16_UNORM", | |
| "R16G16B16A16_UINT", | |
| "R16G16B16A16_SNORM", | |
| "R16G16B16A16_SINT", | |
| "R32G32_TYPELESS", | |
| "R32G32_FLOAT", | |
| "R32G32_UINT", | |
| "R32G32_SINT", | |
| "R32G8X24_TYPELESS", | |
| "D32_FLOAT_S8X24_UINT", | |
| "R32_FLOAT_X8X24_TYPELESS", | |
| "X32_TYPELESS_G8X24_UINT", | |
| "R10G10B10A2_TYPELESS", | |
| "R10G10B10A2_UNORM", | |
| "R10G10B10A2_UINT", | |
| "R11G11B10_FLOAT", | |
| "R8G8B8A8_TYPELESS", | |
| "R8G8B8A8_UNORM", | |
| "R8G8B8A8_UNORM_SRGB", | |
| "R8G8B8A8_UINT", | |
| "R8G8B8A8_SNORM", | |
| "R8G8B8A8_SINT", | |
| "R16G16_TYPELESS", | |
| "R16G16_FLOAT", | |
| "R16G16_UNORM", | |
| "R16G16_UINT", | |
| "R16G16_SNORM", | |
| "R16G16_SINT", | |
| "R32_TYPELESS", | |
| "D32_FLOAT", | |
| "R32_FLOAT", | |
| "R32_UINT", | |
| "R32_SINT", | |
| "R24G8_TYPELESS", | |
| "D24_UNORM_S8_UINT", | |
| "R24_UNORM_X8_TYPELESS", | |
| "X24_TYPELESS_G8_UINT", | |
| "R8G8_TYPELESS", | |
| "R8G8_UNORM", | |
| "R8G8_UINT", | |
| "R8G8_SNORM", | |
| "R8G8_SINT", | |
| "R16_TYPELESS", | |
| "R16_FLOAT", | |
| "D16_UNORM", | |
| "R16_UNORM", | |
| "R16_UINT", | |
| "R16_SNORM", | |
| "R16_SINT", | |
| "R8_TYPELESS", | |
| "R8_UNORM", | |
| "R8_UINT", | |
| "R8_SNORM", | |
| "R8_SINT", | |
| "A8_UNORM", | |
| "R1_UNORM", | |
| "R9G9B9E5_SHAREDEXP", | |
| "R8G8_B8G8_UNORM", | |
| "G8R8_G8B8_UNORM", | |
| "BC1_TYPELESS", | |
| "BC1_UNORM", | |
| "BC1_UNORM_SRGB", | |
| "BC2_TYPELESS", | |
| "BC2_UNORM", | |
| "BC2_UNORM_SRGB", | |
| "BC3_TYPELESS", | |
| "BC3_UNORM", | |
| "BC3_UNORM_SRGB", | |
| "BC4_TYPELESS", | |
| "BC4_UNORM", | |
| "BC4_SNORM", | |
| "BC5_TYPELESS", | |
| "BC5_UNORM", | |
| "BC5_SNORM", | |
| "B5G6R5_UNORM", | |
| "B5G5R5A1_UNORM", | |
| "B8G8R8A8_UNORM", | |
| "B8G8R8X8_UNORM", | |
| "R10G10B10_XR_BIAS_A2_UNORM", | |
| "B8G8R8A8_TYPELESS", | |
| "B8G8R8A8_UNORM_SRGB", | |
| "B8G8R8X8_TYPELESS", | |
| "B8G8R8X8_UNORM_SRGB", | |
| "BC6H_TYPELESS", | |
| "BC6H_UF16", | |
| "BC6H_SF16", | |
| "BC7_TYPELESS", | |
| "BC7_UNORM", | |
| "BC7_UNORM_SRGB", | |
| "AYUV", | |
| "Y410", | |
| "Y416", | |
| "NV12", | |
| "P010", | |
| "P016", | |
| "420_OPAQUE", | |
| "YUY2", | |
| "Y210", | |
| "Y216", | |
| "NV11", | |
| "AI44", | |
| "IA44", | |
| "P8", | |
| "A8P8", | |
| "B4G4R4A4_UNORM", | |
| "FORCE_UINT" | |
| }; | |
| char const *str_old_style = "Old-style"; | |
| char const *str_compressed = "Compressed"; | |
| char const *str_uncompressed = "Uncompressed"; | |
| char const *str_cube_map = "Cube Map"; | |
| char const *str_vol_tex = "Volume"; | |
| char const *str_tex = "Texture"; | |
| char const *str_pixels = "pixels"; | |
| char const *str_bytes = "bytes"; | |
| char const *str_rgb = "RGB"; | |
| char const *str_yuv = "YUV"; | |
| char const *str_alpha = "Alpha"; | |
| char const *str_luminance = "Luminance"; | |
| // fields are retained as arrays to be able to find length at compile-time | |
| char const str_field_size[] = "Size: "; | |
| char const str_field_top_level[] = "Top-level Texture: "; | |
| char const str_field_pitch[] = "Stride/Pitch: "; | |
| char const str_field_channels[] = "Channels: "; | |
| char const str_field_fourcc[] = "FourCC: "; | |
| char const str_field_bit_cnt[] = "Bit Count: "; | |
| char const str_field_r_mask[] = "R Mask: "; | |
| char const str_field_g_mask[] = "G Mask: "; | |
| char const str_field_b_mask[] = "B Mask: "; | |
| char const str_field_y_mask[] = "Y Mask: "; | |
| char const str_field_u_mask[] = "U Mask: "; | |
| char const str_field_v_mask[] = "V Mask: "; | |
| char const str_field_alpha_mask[] = "Alpha Mask: "; | |
| char const str_field_luminance_mask[] = "Luminance Mask: "; | |
| char const str_field_dxgi_fmt[] = "DXGI Format: "; | |
| char const str_field_dim[] = "Dimensions: "; | |
| char const str_field_array_cnt[] = "Array Size: "; | |
| char const str_field_mipmaps[] = "Mipmaps: "; | |
| char const str_field_depth[] = "Depth: "; | |
| const uint32_t DDS_ASCII = 0x20534444; // Equivalent to "DDS " | |
| const uint32_t FOURCC_DX10 = 0x30315844; // Equivalent to "DX10" in ASCII | |
| struct DDSHeaders { | |
| DDS_HEADER header; | |
| DDS_HEADER_DXT10 header10; | |
| }; | |
| enum class ChannelData : uint8_t { | |
| Alpha = 1 << 0, | |
| YUV = 1 << 1, | |
| RGB = 1 << 2, | |
| Luminance = 1 << 3, | |
| Total = 4 | |
| }; | |
| // http://stackoverflow.com/a/1448478/183120 | |
| // enum class operator | |
| ChannelData operator|(ChannelData a, ChannelData b) { | |
| using UT = typename std::underlying_type<ChannelData>::type; | |
| return static_cast<ChannelData>(static_cast<UT>(a) | static_cast<UT>(b)); | |
| } | |
| bool operator&(ChannelData a, ChannelData b) { | |
| using UT = typename std::underlying_type<ChannelData>::type; | |
| return static_cast<UT>(a) & static_cast<UT>(b); | |
| } | |
| void operator|=(ChannelData &a, ChannelData b) { | |
| a = a | b; | |
| } | |
| template <typename T, size_t N> | |
| char const *get_enum_string(T o, char const* (&strings) [N]) { | |
| using UT = typename std::underlying_type<T>::type; | |
| static_assert(N == static_cast<UT>(T::Total), "Update strings to match all enum members!"); | |
| auto const i = static_cast<UT>(o); | |
| return strings[i]; | |
| } | |
| std::ostream& operator<<(std::ostream &os, ChannelData d) { | |
| bool started = false; | |
| if (d & ChannelData::RGB) { | |
| os << str_rgb; | |
| started = true; | |
| } | |
| if (d & ChannelData::YUV) { | |
| os << (started ? ", " : "") << str_yuv; | |
| started = true; | |
| } | |
| if (d & ChannelData::Alpha) { | |
| os << (started ? ", " : "") << str_alpha; | |
| started = true; | |
| } | |
| if (d & ChannelData::Luminance) { | |
| os << (started ? ", " : "") << str_luminance; | |
| } | |
| return os; | |
| } | |
| std::ostream& operator<<(std::ostream& os, D3D10_RESOURCE_DIMENSION d) { | |
| return os << get_enum_string(d, resource_dim_string); | |
| } | |
| std::ostream& operator<<(std::ostream& os, DXGI_FORMAT f) { | |
| return os << get_enum_string(f, dxgi_format_string); | |
| } | |
| struct DDSFlagInfo { | |
| // 0 - old | |
| // 1 - fourCC (also implies compressed texture) | |
| std::bitset<3> bits; | |
| ChannelData type; | |
| uint32_t bit_count; | |
| std::array<uint32_t, 4> masks; | |
| }; | |
| // dummy structs for printing | |
| struct fourcc { | |
| uint32_t f; | |
| explicit fourcc(uint32_t data) : f{data} { } | |
| }; | |
| struct mask { | |
| uint32_t m; | |
| explicit mask(uint32_t data) : m{data} { } | |
| }; | |
| std::ostream& operator<<(std::ostream &os, fourcc fcc) { | |
| return os << static_cast<char>((fcc.f & 0x000000FF)) | |
| << static_cast<char>((fcc.f & 0x0000FF00) >> 8) | |
| << static_cast<char>((fcc.f & 0x00FF0000) >> 16) | |
| << static_cast<char>((fcc.f & 0xFF000000) >> 24); | |
| } | |
| std::ostream& operator<<(std::ostream &os, mask m) { | |
| return os << std::hex << std::showbase << std::setfill('0') << std::internal | |
| << std::setw(2 + sizeof(uint32_t) * 2u) // two for the base "0x" | |
| << m.m << std::setfill(' ') << std::noshowbase << std::dec; | |
| } | |
| DDSFlagInfo parse_flags(DDS_HEADER const &header) { | |
| DDSFlagInfo f = { }; | |
| if (DDPF_ALPHAPIXELS & header.ddspf.dwFlags) { | |
| f.type |= ChannelData::Alpha; | |
| } | |
| if (DDPF_ALPHA & header.ddspf.dwFlags) { | |
| f.bits[0] = true; | |
| f.type |= ChannelData::Alpha; | |
| } | |
| if (DDPF_FOURCC & header.ddspf.dwFlags) { | |
| f.bits[1] = true; | |
| f.type |= ChannelData::RGB; | |
| } | |
| if (DDPF_RGB & header.ddspf.dwFlags) | |
| f.type |= ChannelData::RGB; | |
| if (DDPF_YUV & header.ddspf.dwFlags) { | |
| f.bits[0] = true; | |
| f.type |= ChannelData::YUV; | |
| } | |
| if (DDPF_LUMINANCE & header.ddspf.dwFlags) { | |
| f.bits[0] = true; | |
| f.type |= ChannelData::Luminance; | |
| } | |
| f.bit_count = header.ddspf.dwRGBBitCount; | |
| f.masks[0] = header.ddspf.dwRBitMask; | |
| f.masks[1] = header.ddspf.dwGBitMask; | |
| f.masks[2] = header.ddspf.dwBBitMask; | |
| f.masks[3] = header.ddspf.dwABitMask; | |
| return f; | |
| } | |
| DDSHeaders read_dds(const std::string &file_path) { | |
| std::ifstream ddsfile{file_path, std::ios::binary | std::ios::in | std::ios::ate }; | |
| auto const file_size = ddsfile.tellg(); | |
| auto const chunk_size = sizeof(DDS_HEADER) + sizeof(uint32_t); | |
| if (file_size < chunk_size) | |
| throw std::runtime_error(file_path + " isn't a valid DDS file"); | |
| ddsfile.seekg(0); | |
| uint32_t magicNo; | |
| if (!(ddsfile.read(reinterpret_cast<char*>(&magicNo), sizeof(magicNo)) && (magicNo == DDS_ASCII))) | |
| throw std::runtime_error(file_path + " isn't a valid DDS file"); | |
| DDS_HEADER header = { }; | |
| ddsfile.read(reinterpret_cast<char*>(&header), sizeof(DDS_HEADER)); | |
| // read the additional DX10 header, if applicable and available | |
| DDS_HEADER_DXT10 ddsDX10Header = { }; | |
| if ((header.ddspf.dwFourCC == FOURCC_DX10) && (file_size >= (chunk_size + sizeof(DDS_HEADER_DXT10)))) { | |
| ddsfile.read(reinterpret_cast<char*>(&ddsDX10Header), sizeof(ddsDX10Header)); | |
| } | |
| return {header, ddsDX10Header}; | |
| } | |
| bool isVolumeTexture(DWORD caps) { | |
| return caps & DDSCAPS2_VOLUME; | |
| } | |
| bool isCubeTexture(DWORD caps) { | |
| return (caps & DDS_CUBEMAP_ALLFACES) || (caps & DDSCAPS2_CUBEMAP); | |
| } | |
| struct field { | |
| int n; | |
| explicit field(size_t align) : n(align) { } | |
| }; | |
| std::ostream& operator<<(std::ostream &os, field f) { | |
| return os << std::left << std::setw(f.n); | |
| } | |
| template <typename T> | |
| inline constexpr size_t str_literal_len(const T&) { | |
| return std::extent<T>::value - 1; | |
| } | |
| void print_dds(DDSHeaders const &headers) { | |
| auto const h = headers.header; | |
| auto const f = parse_flags(h); | |
| if (f.bits[0]) | |
| std::cout << str_old_style << ' '; | |
| std::cout << (f.bits[1] ? str_compressed : str_uncompressed) << ' '; | |
| if (isCubeTexture(h.dwCaps2)) | |
| std::cout << str_cube_map << ' '; | |
| else if (isVolumeTexture(h.dwCaps2)) | |
| std::cout << str_vol_tex << ' '; | |
| std::cout << str_tex << '\n'; | |
| // use the longest field length as the field width | |
| auto constexpr fw = str_literal_len(str_field_top_level); | |
| std::cout << field(fw) << str_field_size << h.dwWidth << " × " << h.dwHeight << ' ' << str_pixels << '\n' | |
| << field(fw) << (f.bits[1] ? str_field_top_level : str_field_pitch) | |
| << h.dwPitchOrLinearSize << ' ' << str_bytes << '\n'; | |
| std::cout << field(fw) << str_field_channels << f.type << '\n'; | |
| if (f.bits[1]) | |
| std::cout << field(fw) << str_field_fourcc << fourcc(h.ddspf.dwFourCC) << '\n'; | |
| else { | |
| std::cout << field(fw) << str_field_bit_cnt << f.bit_count << '\n'; | |
| // http://stackoverflow.com/q/1532640/183120 | |
| // http://stackoverflow.com/a/1449923/183120 | |
| // 12 for "Alpha Mask: ", 16 for "Luminance Mask: " | |
| char const *col[][3] = { { str_field_r_mask, str_field_g_mask, str_field_b_mask }, | |
| { str_field_y_mask, str_field_u_mask, str_field_v_mask }}; | |
| auto const i = (f.type & ChannelData::RGB) ? 0 : 1; | |
| if ((f.type & ChannelData::RGB) || (f.type & ChannelData::YUV)) | |
| std::cout << field(fw) << col[i][0] << mask(f.masks[0]) << '\n' | |
| << field(fw) << col[i][1] << mask(f.masks[1]) << '\n' | |
| << field(fw) << col[i][2] << mask(f.masks[2]) << '\n'; | |
| if ((f.type & ChannelData::Alpha) || (f.type & ChannelData::Luminance)) | |
| std::cout << field(fw) << ((f.type & ChannelData::Alpha) ? str_field_alpha_mask : str_field_luminance_mask) | |
| << mask(f.masks[3]) << '\n'; | |
| std::cout << std::dec; | |
| } | |
| if (h.ddspf.dwFourCC == FOURCC_DX10) { | |
| auto const &h10 = headers.header10; | |
| std::cout << field(fw) << str_field_dxgi_fmt << h10.dxgiFormat << '\n'; | |
| std::cout << field(fw) << str_field_dim << h10.resourceDimension << '\n'; | |
| std::cout << field(fw) << str_field_array_cnt << h10.arraySize << '\n'; | |
| } | |
| std::cout << field(fw) << str_field_mipmaps << h.dwMipMapCount << '\n'; | |
| if (isVolumeTexture(h.dwCaps2)) | |
| std::cout << field(fw) << str_field_depth << h.dwDepth << ' '<< str_pixels << '\n'; | |
| } | |
| int main(int argc, char *argv[]) { | |
| if (argc < 2) { | |
| std::cout << "Usage: ddsnfo FILE\n"; | |
| return -1; | |
| } | |
| DDSHeaders head; | |
| try { | |
| head = read_dds(argv[1]); | |
| } | |
| catch (std::runtime_error &e) { | |
| std::cout << "Read failed: " << argv[1]; | |
| return -1; | |
| } | |
| print_dds(head); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment