diff --git a/DirectXTex/DirectXTex.h b/DirectXTex/DirectXTex.h index eeed9cb..fe285a4 100644 --- a/DirectXTex/DirectXTex.h +++ b/DirectXTex/DirectXTex.h @@ -168,6 +168,10 @@ namespace DirectX DDS_FLAGS_FORCE_DX10_EXT_MISC2 = 0x20000, // DDS_FLAGS_FORCE_DX10_EXT including miscFlags2 information (result may not be compatible with D3DX10 or D3DX11) + + DDS_FLAGS_FORCE_DX9_LEGACY = 0x40000, + // Force use of legacy header for DDS writer (will fail if unable to write as such) + }; enum WIC_FLAGS diff --git a/DirectXTex/DirectXTexDDS.cpp b/DirectXTex/DirectXTexDDS.cpp index 03bad7c..5af201f 100644 --- a/DirectXTex/DirectXTexDDS.cpp +++ b/DirectXTex/DirectXTexDDS.cpp @@ -550,6 +550,9 @@ HRESULT DirectX::_EncodeDDSHeader( if ((metadata.arraySize != 6) || (metadata.dimension != TEX_DIMENSION_TEXTURE2D) || !(metadata.IsCubemap())) { // Texture1D arrays, Texture2D arrays, and Cubemap arrays must be stored using 'DX10' extended header + if (flags & DDS_FLAGS_FORCE_DX9_LEGACY) + return HRESULT_FROM_WIN32(ERROR_CANNOT_MAKE); + flags |= DDS_FLAGS_FORCE_DX10_EXT; } } @@ -575,9 +578,7 @@ HRESULT DirectX::_EncodeDDSHeader( case DXGI_FORMAT_BC1_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_DXT1, sizeof(DDS_PIXELFORMAT)); break; case DXGI_FORMAT_BC2_UNORM: memcpy_s(&ddpf, sizeof(ddpf), metadata.IsPMAlpha() ? (&DDSPF_DXT2) : (&DDSPF_DXT3), sizeof(DDS_PIXELFORMAT)); break; case DXGI_FORMAT_BC3_UNORM: memcpy_s(&ddpf, sizeof(ddpf), metadata.IsPMAlpha() ? (&DDSPF_DXT4) : (&DDSPF_DXT5), sizeof(DDS_PIXELFORMAT)); break; - case DXGI_FORMAT_BC4_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_BC4_UNORM, sizeof(DDS_PIXELFORMAT)); break; case DXGI_FORMAT_BC4_SNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_BC4_SNORM, sizeof(DDS_PIXELFORMAT)); break; - case DXGI_FORMAT_BC5_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_BC5_UNORM, sizeof(DDS_PIXELFORMAT)); break; case DXGI_FORMAT_BC5_SNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_BC5_SNORM, sizeof(DDS_PIXELFORMAT)); break; case DXGI_FORMAT_B5G6R5_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_R5G6B5, sizeof(DDS_PIXELFORMAT)); break; case DXGI_FORMAT_B5G5R5A1_UNORM: memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_A1R5G5B5, sizeof(DDS_PIXELFORMAT)); break; @@ -615,6 +616,73 @@ HRESULT DirectX::_EncodeDDSHeader( ddpf.size = sizeof(DDS_PIXELFORMAT); ddpf.flags = DDS_FOURCC; ddpf.fourCC = 111; // D3DFMT_R16F break; + // DX9 legacy pixel formats + case DXGI_FORMAT_R10G10B10A2_UNORM: + if (flags & DDS_FLAGS_FORCE_DX9_LEGACY) + { + // Write using the 'incorrect' mask version to match D3DX bug + memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_A2B10G10R10, sizeof(DDS_PIXELFORMAT)); + } + break; + + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + if (flags & DDS_FLAGS_FORCE_DX9_LEGACY) + { + memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_A8B8G8R8, sizeof(DDS_PIXELFORMAT)); + } + break; + + case DXGI_FORMAT_BC1_UNORM_SRGB: + if (flags & DDS_FLAGS_FORCE_DX9_LEGACY) + { + memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_DXT1, sizeof(DDS_PIXELFORMAT)); + } + break; + + case DXGI_FORMAT_BC2_UNORM_SRGB: + if (flags & DDS_FLAGS_FORCE_DX9_LEGACY) + { + memcpy_s(&ddpf, sizeof(ddpf), metadata.IsPMAlpha() ? (&DDSPF_DXT2) : (&DDSPF_DXT3), sizeof(DDS_PIXELFORMAT)); + } + break; + + case DXGI_FORMAT_BC3_UNORM_SRGB: + if (flags & DDS_FLAGS_FORCE_DX9_LEGACY) + { + memcpy_s(&ddpf, sizeof(ddpf), metadata.IsPMAlpha() ? (&DDSPF_DXT4) : (&DDSPF_DXT5), sizeof(DDS_PIXELFORMAT)); + } + break; + + case DXGI_FORMAT_BC4_UNORM: + memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_BC4_UNORM, sizeof(DDS_PIXELFORMAT)); + if (flags & DDS_FLAGS_FORCE_DX9_LEGACY) + { + ddpf.fourCC = MAKEFOURCC('A', 'T', 'I', '1'); + } + break; + + case DXGI_FORMAT_BC5_UNORM: + memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_BC5_UNORM, sizeof(DDS_PIXELFORMAT)); + if (flags & DDS_FLAGS_FORCE_DX9_LEGACY) + { + ddpf.fourCC = MAKEFOURCC('A', 'T', 'I', '2'); + } + break; + + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + if (flags & DDS_FLAGS_FORCE_DX9_LEGACY) + { + memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_A8R8G8B8, sizeof(DDS_PIXELFORMAT)); + } + break; + + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + if (flags & DDS_FLAGS_FORCE_DX9_LEGACY) + { + memcpy_s(&ddpf, sizeof(ddpf), &DDSPF_X8R8G8B8, sizeof(DDS_PIXELFORMAT)); + } + break; + default: break; } @@ -623,7 +691,12 @@ HRESULT DirectX::_EncodeDDSHeader( required = sizeof(uint32_t) + sizeof(DDS_HEADER); if (ddpf.size == 0) + { + if (flags & DDS_FLAGS_FORCE_DX9_LEGACY) + return HRESULT_FROM_WIN32(ERROR_CANNOT_MAKE); + required += sizeof(DDS_HEADER_DXT10); + } if (!pDestination) return S_OK; diff --git a/Texconv/texconv.cpp b/Texconv/texconv.cpp index 1a553cc..14128d0 100644 --- a/Texconv/texconv.cpp +++ b/Texconv/texconv.cpp @@ -76,6 +76,7 @@ enum OPTIONS OPT_DDS_DWORD_ALIGN, OPT_DDS_BAD_DXTN_TAILS, OPT_USE_DX10, + OPT_USE_DX9, OPT_TGA20, OPT_WIC_QUALITY, OPT_WIC_LOSSLESS, @@ -100,10 +101,7 @@ enum OPTIONS OPT_ALPHA_WEIGHT, OPT_NORMAL_MAP, OPT_NORMAL_MAP_AMPLITUDE, - OPT_COMPRESS_UNIFORM, - OPT_COMPRESS_MAX, - OPT_COMPRESS_QUICK, - OPT_COMPRESS_DITHER, + OPT_BC_COMPRESS, OPT_COLORKEY, OPT_TONEMAP, OPT_X2_BIAS, @@ -166,6 +164,7 @@ const SValue g_pOptions[] = { L"dword", OPT_DDS_DWORD_ALIGN }, { L"badtails", OPT_DDS_BAD_DXTN_TAILS }, { L"dx10", OPT_USE_DX10 }, + { L"dx9", OPT_USE_DX9 }, { L"tga20", OPT_TGA20 }, { L"wicq", OPT_WIC_QUALITY }, { L"wiclossless", OPT_WIC_LOSSLESS }, @@ -191,10 +190,7 @@ const SValue g_pOptions[] = { L"aw", OPT_ALPHA_WEIGHT }, { L"nmap", OPT_NORMAL_MAP }, { L"nmapamp", OPT_NORMAL_MAP_AMPLITUDE }, - { L"bcuniform", OPT_COMPRESS_UNIFORM }, - { L"bcmax", OPT_COMPRESS_MAX }, - { L"bcquick", OPT_COMPRESS_QUICK }, - { L"bcdither", OPT_COMPRESS_DITHER }, + { L"bc", OPT_BC_COMPRESS }, { L"c", OPT_COLORKEY }, { L"tonemap", OPT_TONEMAP }, { L"x2bias", OPT_X2_BIAS }, @@ -752,6 +748,7 @@ namespace wprintf(L" -xlum expand legacy L8, L16, and A8P8 formats\n"); wprintf(L"\n (DDS output only)\n"); wprintf(L" -dx10 Force use of 'DX10' extended header\n"); + wprintf(L" -dx9 Force use of legacy DX9 header\n"); wprintf(L"\n (TGA output only)\n"); wprintf(L" -tga20 Write file including TGA 2.0 extension area\n"); wprintf(L"\n (BMP, PNG, JPG, TIF, WDP output only)\n"); @@ -765,10 +762,10 @@ namespace #endif wprintf(L" -gpu Select GPU for DirectCompute-based codecs (0 is default)\n"); wprintf(L" -nogpu Do not use DirectCompute-based codecs\n"); - wprintf(L" -bcuniform Use uniform rather than perceptual weighting for BC1-3\n"); - wprintf(L" -bcdither Use dithering for BC1-3\n"); - wprintf(L" -bcmax Use exhaustive compression (BC7 only)\n"); - wprintf(L" -bcquick Use quick compression (BC7 only)\n"); + wprintf( + L"\n -bc Sets options for BC compression\n" + L" options must be one or more of\n" + L" d, u, q, x\n"); wprintf( L" -aw BC7 GPU compressor weighting for alpha error metric\n" L" (defaults to 1.0)\n"); @@ -1201,6 +1198,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) case OPT_NORMAL_MAP: case OPT_NORMAL_MAP_AMPLITUDE: case OPT_WIC_QUALITY: + case OPT_BC_COMPRESS: case OPT_COLORKEY: case OPT_FILELIST: case OPT_ROTATE_COLOR: @@ -1508,33 +1506,50 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) } break; - case OPT_COMPRESS_UNIFORM: - dwCompress |= TEX_COMPRESS_UNIFORM; - break; + case OPT_BC_COMPRESS: + { + dwCompress = TEX_COMPRESS_DEFAULT; - case OPT_COMPRESS_MAX: - if (dwCompress & TEX_COMPRESS_BC7_QUICK) + bool found = false; + if (wcschr(pValue, L'u')) { - wprintf(L"Can't use -bcmax and -bcquick at same time\n\n"); + dwCompress |= TEX_COMPRESS_UNIFORM; + found = true; + } + + if (wcschr(pValue, L'd')) + { + dwCompress |= TEX_COMPRESS_DITHER; + found = true; + } + + if (wcschr(pValue, L'q')) + { + dwCompress |= TEX_COMPRESS_BC7_QUICK; + found = true; + } + + if (wcschr(pValue, L'x')) + { + dwCompress |= TEX_COMPRESS_BC7_USE_3SUBSETS; + found = true; + } + + if ((dwCompress & (TEX_COMPRESS_BC7_QUICK | TEX_COMPRESS_BC7_USE_3SUBSETS)) == (TEX_COMPRESS_BC7_QUICK | TEX_COMPRESS_BC7_USE_3SUBSETS)) + { + wprintf(L"Can't use -bc x (max) and -bc q (quick) at same time\n\n"); PrintUsage(); return 1; } - dwCompress |= TEX_COMPRESS_BC7_USE_3SUBSETS; - break; - case OPT_COMPRESS_QUICK: - if (dwCompress & TEX_COMPRESS_BC7_USE_3SUBSETS) + if (!found) { - wprintf(L"Can't use -bcmax and -bcquick at same time\n\n"); + wprintf(L"Invalid value specified for -bc (%ls), missing d, u, q, or x\n\n", pValue); PrintUsage(); return 1; } - dwCompress |= TEX_COMPRESS_BC7_QUICK; - break; - - case OPT_COMPRESS_DITHER: - dwCompress |= TEX_COMPRESS_DITHER; - break; + } + break; case OPT_WIC_QUALITY: if (swscanf_s(pValue, L"%f", &wicQuality) != 1 @@ -1563,6 +1578,24 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) dwConvert |= TEX_FILTER_FLOAT_X2BIAS; break; + case OPT_USE_DX10: + if (dwOptions & (DWORD64(1) << OPT_USE_DX9)) + { + wprintf(L"Can't use -dx9 and -dx10 at same time\n\n"); + PrintUsage(); + return 1; + } + break; + + case OPT_USE_DX9: + if (dwOptions & (DWORD64(1) << OPT_USE_DX10)) + { + wprintf(L"Can't use -dx9 and -dx10 at same time\n\n"); + PrintUsage(); + return 1; + } + break; + case OPT_FILELIST: { std::wifstream inFile(pValue); @@ -3090,10 +3123,20 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) switch (FileType) { case CODEC_DDS: - hr = SaveToDDSFile(img, nimg, info, - (dwOptions & (DWORD64(1) << OPT_USE_DX10)) ? (DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2) : DDS_FLAGS_NONE, - pConv->szDest); + { + DWORD ddsFlags = DDS_FLAGS_NONE; + if (dwOptions & (DWORD64(1) << OPT_USE_DX10)) + { + ddsFlags |= DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2; + } + else if (dwOptions & (DWORD64(1) << OPT_USE_DX9)) + { + ddsFlags |= DDS_FLAGS_FORCE_DX9_LEGACY; + } + + hr = SaveToDDSFile(img, nimg, info, ddsFlags, pConv->szDest); break; + } case CODEC_TGA: hr = SaveToTGAFile(img[0], pConv->szDest, (dwOptions & (DWORD64(1) << OPT_TGA20)) ? &info : nullptr);