1
0
mirror of https://github.com/microsoft/DirectXTex synced 2024-11-21 12:00:06 +00:00

Convert command-line tools to use GNU-style long options (#541)

This commit is contained in:
Chuck Walbourn 2024-10-28 13:54:51 -07:00 committed by GitHub
parent b717c0f6da
commit b81e202ec4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 661 additions and 391 deletions

View File

@ -74,7 +74,7 @@ namespace DirectX
size_t __cdecl BytesPerBlock(_In_ DXGI_FORMAT fmt) noexcept; size_t __cdecl BytesPerBlock(_In_ DXGI_FORMAT fmt) noexcept;
enum FORMAT_TYPE enum FORMAT_TYPE : uint32_t
{ {
FORMAT_TYPE_TYPELESS, FORMAT_TYPE_TYPELESS,
FORMAT_TYPE_FLOAT, FORMAT_TYPE_FLOAT,
@ -136,7 +136,7 @@ namespace DirectX
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// Texture metadata // Texture metadata
enum TEX_DIMENSION enum TEX_DIMENSION : uint32_t
// Subset here matches D3D10_RESOURCE_DIMENSION and D3D11_RESOURCE_DIMENSION // Subset here matches D3D10_RESOURCE_DIMENSION and D3D11_RESOURCE_DIMENSION
{ {
TEX_DIMENSION_TEXTURE1D = 2, TEX_DIMENSION_TEXTURE1D = 2,
@ -155,7 +155,7 @@ namespace DirectX
TEX_MISC2_ALPHA_MODE_MASK = 0x7L, TEX_MISC2_ALPHA_MODE_MASK = 0x7L,
}; };
enum TEX_ALPHA_MODE enum TEX_ALPHA_MODE : uint32_t
// Matches DDS_ALPHA_MODE, encoded in MISC_FLAGS2 // Matches DDS_ALPHA_MODE, encoded in MISC_FLAGS2
{ {
TEX_ALPHA_MODE_UNKNOWN = 0, TEX_ALPHA_MODE_UNKNOWN = 0,
@ -934,7 +934,7 @@ namespace DirectX
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// WIC utility code // WIC utility code
#ifdef _WIN32 #ifdef _WIN32
enum WICCodecs enum WICCodecs : uint32_t
{ {
WIC_CODEC_BMP = 1, // Windows Bitmap (.bmp) WIC_CODEC_BMP = 1, // Windows Bitmap (.bmp)
WIC_CODEC_JPEG, // Joint Photographic Experts Group (.jpg, .jpeg) WIC_CODEC_JPEG, // Joint Photographic Experts Group (.jpg, .jpeg)

View File

@ -115,15 +115,6 @@ namespace
enum OPTIONS : uint32_t enum OPTIONS : uint32_t
{ {
OPT_RECURSIVE = 1, OPT_RECURSIVE = 1,
OPT_FILELIST,
OPT_WIDTH,
OPT_HEIGHT,
OPT_FORMAT,
OPT_FILTER,
OPT_SRGBI,
OPT_SRGBO,
OPT_SRGB,
OPT_OUTPUTFILE,
OPT_TOLOWER, OPT_TOLOWER,
OPT_OVERWRITE, OPT_OVERWRITE,
OPT_USE_DX10, OPT_USE_DX10,
@ -133,15 +124,26 @@ namespace
OPT_DEMUL_ALPHA, OPT_DEMUL_ALPHA,
OPT_TA_WRAP, OPT_TA_WRAP,
OPT_TA_MIRROR, OPT_TA_MIRROR,
OPT_FEATURE_LEVEL,
OPT_TONEMAP, OPT_TONEMAP,
OPT_GIF_BGCOLOR, OPT_GIF_BGCOLOR,
OPT_SWIZZLE,
OPT_STRIP_MIPS, OPT_STRIP_MIPS,
OPT_MAX OPT_FLAGS_MAX,
OPT_FILELIST,
OPT_WIDTH,
OPT_HEIGHT,
OPT_FORMAT,
OPT_FILTER,
OPT_SRGBI,
OPT_SRGBO,
OPT_SRGB,
OPT_OUTPUTFILE,
OPT_FEATURE_LEVEL,
OPT_SWIZZLE,
OPT_VERSION,
OPT_HELP,
}; };
static_assert(OPT_MAX <= 32, "dwOptions is a unsigned int bitfield"); static_assert(OPT_FLAGS_MAX <= 32, "dwOptions is a unsigned int bitfield");
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -194,13 +196,38 @@ namespace
{ L"wrap", OPT_TA_WRAP }, { L"wrap", OPT_TA_WRAP },
{ L"mirror", OPT_TA_MIRROR }, { L"mirror", OPT_TA_MIRROR },
{ L"fl", OPT_FEATURE_LEVEL }, { L"fl", OPT_FEATURE_LEVEL },
// Deprecated options (recommend using new -- alternatives)
{ L"tonemap", OPT_TONEMAP }, { L"tonemap", OPT_TONEMAP },
{ L"bgcolor", OPT_GIF_BGCOLOR }, { L"bgcolor", OPT_GIF_BGCOLOR },
{ L"swizzle", OPT_SWIZZLE }, { L"swizzle", OPT_SWIZZLE },
{ L"stripmips", OPT_STRIP_MIPS }, { L"stripmips", OPT_STRIP_MIPS },
{ nullptr, 0 } { nullptr, 0 }
}; };
const SValue<uint32_t> g_pOptionsLong[] =
{
{ L"feature-level", OPT_FEATURE_LEVEL },
{ L"file-list", OPT_FILELIST },
{ L"format", OPT_FORMAT },
{ L"gif-bg-color", OPT_GIF_BGCOLOR },
{ L"height", OPT_HEIGHT },
{ L"help", OPT_HELP },
{ L"image-filter", OPT_FILTER },
{ L"overwrite", OPT_OVERWRITE },
{ L"separate-alpha", OPT_SEPALPHA },
{ L"srgb-in", OPT_SRGBI },
{ L"srgb-out", OPT_SRGBO },
{ L"strip-mips", OPT_STRIP_MIPS },
{ L"swizzle", OPT_SWIZZLE },
{ L"to-lowercase", OPT_TOLOWER },
{ L"tonemap", OPT_TONEMAP },
{ L"version", OPT_VERSION },
{ L"width", OPT_WIDTH },
{ nullptr, 0 }
};
#define DEFFMT(fmt) { L## #fmt, DXGI_FORMAT_ ## fmt } #define DEFFMT(fmt) { L## #fmt, DXGI_FORMAT_ ## fmt }
const SValue<DXGI_FORMAT> g_pFormats[] = const SValue<DXGI_FORMAT> g_pFormats[] =
@ -317,18 +344,18 @@ namespace
{ nullptr, TEX_FILTER_DEFAULT } { nullptr, TEX_FILTER_DEFAULT }
}; };
#define CODEC_DDS 0xFFFF0001 constexpr uint32_t CODEC_DDS = 0xFFFF0001;
#define CODEC_TGA 0xFFFF0002 constexpr uint32_t CODEC_TGA = 0xFFFF0002;
#define CODEC_HDR 0xFFFF0005 constexpr uint32_t CODEC_HDR = 0xFFFF0005;
#ifdef USE_OPENEXR #ifdef USE_OPENEXR
#define CODEC_EXR 0xFFFF0006 constexpr uint32_t CODEC_EXR = 0xFFFF0008;
#endif #endif
#ifdef USE_LIBJPEG #ifdef USE_LIBJPEG
#define CODEC_JPEG 0xFFFF0007 constexpr uint32_t CODEC_JPEG = 0xFFFF0009;
#endif #endif
#ifdef USE_LIBPNG #ifdef USE_LIBPNG
#define CODEC_PNG 0xFFFF0008 constexpr uint32_t CODEC_PNG = 0xFFFF000A;
#endif #endif
const SValue<uint32_t> g_pExtFileTypes[] = const SValue<uint32_t> g_pExtFileTypes[] =
@ -500,7 +527,7 @@ namespace
static const wchar_t* const s_usage = static const wchar_t* const s_usage =
L"Usage: texassemble <command> <options> [--] <files>\n" L"Usage: texassemble <command> <options> [--] <files>\n"
L"\n" L"\nCOMMANDS\n"
L" cube create cubemap\n" L" cube create cubemap\n"
L" volume create volume map\n" L" volume create volume map\n"
L" array create texture array\n" L" array create texture array\n"
@ -518,34 +545,43 @@ namespace
L" cube-from-ht create cubemap from a h-tee image\n" L" cube-from-ht create cubemap from a h-tee image\n"
L" cube-from-hs create cubemap from a h-strip image\n" L" cube-from-hs create cubemap from a h-strip image\n"
L" cube-from-vs create cubemap from a v-strip image\n" L" cube-from-vs create cubemap from a v-strip image\n"
L"\n" L"\nOPTIONS\n"
L" -r wildcard filename search is recursive\n" L" -r wildcard filename search is recursive\n"
L" -flist <filename> use text file with a list of input files (one per line)\n" L" -flist <filename>, --file-list <filename>\n"
L" -w <n> width\n" L" use text file with a list of input files (one per line)\n"
L" -h <n> height\n" L"\n"
L" -f <format> format\n" L" -w <n>, --width <n> width for output\n"
L" -if <filter> image filtering\n" L" -h <n>, --height <n> height for output\n"
L" -srgb{i|o} sRGB {input, output}\n" L" -f <format>, --format <format> pixel format for output\n"
L" -o <filename> output filename\n" L"\n"
L" -l force output filename to lower case\n" L" -if <filter>, --image-filter <filter> image filtering\n"
L" -y overwrite existing output file (if any)\n" L" -srgb{i|o}, --srgb-in, --srgb-out sRGB {input, output}\n"
L" -sepalpha resize alpha channel separately from color channels\n" L"\n"
L" -o <filename> output filename\n"
L" -l, --to-lowercase force output filename to lower case\n"
L" -y, --overwrite overwrite existing output file (if any)\n"
L"\n"
L" -sepalpha, --separate-alpha resize/generate mips alpha channel separately from color channels\n"
L"\n"
L" -nowic Force non-WIC filtering\n" L" -nowic Force non-WIC filtering\n"
L" -wrap, -mirror texture addressing mode (wrap, mirror, or clamp)\n" L" -wrap, -mirror texture addressing mode (wrap, mirror, or clamp)\n"
L" -alpha convert premultiplied alpha to straight alpha\n" L" -alpha convert premultiplied alpha to straight alpha\n"
L" -dx10 Force use of 'DX10' extended header\n" L" -dx10 Force use of 'DX10' extended header\n"
L" -nologo suppress copyright message\n" L" -nologo suppress copyright message\n"
L" -fl <feature-level> Set maximum feature level target (defaults to 11.0)\n" L"\n"
L" -fl <feature-level>, --feature-level <feature-level>\n"
L" Set maximum feature level target (defaults to 11.0)\n"
L"\n"
L" -tonemap Apply a tonemap operator based on maximum luminance\n" L" -tonemap Apply a tonemap operator based on maximum luminance\n"
L"\n" L"\n"
L" (gif only)\n" L" (gif only)\n"
L" -bgcolor Use background color instead of transparency\n" L" --gif-bg-color Use background color instead of transparency\n"
L"\n" L"\n"
L" (merge only)\n" L" (merge only)\n"
L" -swizzle <rgba> Select channels for merge (defaults to rgbB)\n" L" --swizzle <rgba> Select channels for merge (defaults to rgbB)\n"
L"\n" L"\n"
L" (cube, volume, array, cubearray, merge only)\n" L" (cube, volume, array, cubearray, merge only)\n"
L" -stripmips Use only base image from input dds files\n" L" --strip-mips Use only base image from input dds files\n"
L"\n" L"\n"
L" '-- ' is needed if any input filepath starts with the '-' or '/' character\n"; L" '-- ' is needed if any input filepath starts with the '-' or '/' character\n";
@ -775,6 +811,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
return 0; return 0;
} }
// check for these before the command
if (('-' == argv[1][0]) && ('-' == argv[1][1])) if (('-' == argv[1][0]) && ('-' == argv[1][1]))
{ {
if (!_wcsicmp(argv[1], L"--version")) if (!_wcsicmp(argv[1], L"--version"))
@ -824,54 +861,94 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
std::list<SConversion> conversion; std::list<SConversion> conversion;
bool allowOpts = true; bool allowOpts = true;
for (int iArg = 2; iArg < argc; iArg++) for (int iArg = 2; iArg < argc; ++iArg)
{ {
PWSTR pArg = argv[iArg]; PWSTR pArg = argv[iArg];
if (allowOpts if (allowOpts && (('-' == pArg[0]) || ('/' == pArg[0])))
&& ('-' == pArg[0]) && ('-' == pArg[1]))
{ {
if (pArg[2] == 0) uint32_t dwOption = 0;
PWSTR pValue = nullptr;
if (('-' == pArg[0]) && ('-' == pArg[1]))
{ {
// "-- " is the POSIX standard for "end of options" marking to escape the '-' and '/' characters at the start of filepaths. if (pArg[2] == 0)
allowOpts = false; {
} // "-- " is the POSIX standard for "end of options" marking to escape the '-' and '/' characters at the start of filepaths.
else if (!_wcsicmp(pArg, L"--version")) allowOpts = false;
{ continue;
PrintLogo(true, g_ToolName, g_Description); }
return 0; else
} {
else if (!_wcsicmp(pArg, L"--help")) pArg += 2;
{
PrintUsage(); for (pValue = pArg; *pValue && (':' != *pValue) && ('=' != *pValue); ++pValue);
return 0;
if (*pValue)
*pValue++ = 0;
dwOption = LookupByName(pArg, g_pOptionsLong);
}
} }
else else
{ {
wprintf(L"Unknown option: %ls\n", pArg); pArg++;
return 1;
for (pValue = pArg; *pValue && (':' != *pValue) && ('=' != *pValue); ++pValue);
if (*pValue)
*pValue++ = 0;
dwOption = LookupByName(pArg, g_pOptions);
if (!dwOption)
{
if (LookupByName(pArg, g_pOptionsLong))
{
wprintf(L"ERROR: did you mean `--%ls` (with two dashes)?\n", pArg);
return 1;
}
}
} }
}
else if (allowOpts
&& (('-' == pArg[0]) || ('/' == pArg[0])))
{
pArg++;
PWSTR pValue;
for (pValue = pArg; *pValue && (':' != *pValue); pValue++); switch (dwOption)
if (*pValue)
*pValue++ = 0;
const uint32_t dwOption = LookupByName(pArg, g_pOptions);
if (!dwOption || (dwOptions & (1 << dwOption)))
{ {
PrintUsage(); case 0:
wprintf(L"ERROR: Unknown option: `%ls`\n\nUse %ls --help\n", pArg, g_ToolName);
return 1; return 1;
}
dwOptions |= 1 << dwOption; case OPT_FILELIST:
case OPT_WIDTH:
case OPT_HEIGHT:
case OPT_FORMAT:
case OPT_FILTER:
case OPT_SRGBI:
case OPT_SRGBO:
case OPT_SRGB:
case OPT_OUTPUTFILE:
case OPT_FEATURE_LEVEL:
case OPT_SWIZZLE:
// These don't use flag bits
break;
case OPT_VERSION:
PrintLogo(true, g_ToolName, g_Description);
return 0;
case OPT_HELP:
PrintUsage();
return 0;
default:
if (dwOptions & (UINT32_C(1) << dwOption))
{
wprintf(L"ERROR: Duplicate option: `%ls`\n\n", pArg);
return 1;
}
dwOptions |= (UINT32_C(1) << dwOption);
break;
}
// Handle options with additional value parameter // Handle options with additional value parameter
switch (dwOption) switch (dwOption)
@ -1034,8 +1111,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
maxVolume = LookupByName(pValue, g_pFeatureLevelsVolume); maxVolume = LookupByName(pValue, g_pFeatureLevelsVolume);
if (!maxSize || !maxCube || !maxArray || !maxVolume) if (!maxSize || !maxCube || !maxArray || !maxVolume)
{ {
wprintf(L"Invalid value specified with -fl (%ls)\n", pValue); wprintf(L"Invalid value specified with -fl (%ls)\n\n", pValue);
wprintf(L"\n");
PrintUsage(); PrintUsage();
return 1; return 1;
} }
@ -1092,7 +1168,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
{ {
const size_t count = conversion.size(); const size_t count = conversion.size();
std::filesystem::path path(pArg); std::filesystem::path path(pArg);
SearchForFiles(path.make_preferred(), conversion, (dwOptions & (1 << OPT_RECURSIVE)) != 0, nullptr); SearchForFiles(path.make_preferred(), conversion, (dwOptions & (UINT32_C(1) << OPT_RECURSIVE)) != 0, nullptr);
if (conversion.size() <= count) if (conversion.size() <= count)
{ {
wprintf(L"No matching files found for %ls\n", pArg); wprintf(L"No matching files found for %ls\n", pArg);
@ -1114,7 +1190,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
return 0; return 0;
} }
if (~dwOptions & (1 << OPT_NOLOGO)) if (~dwOptions & (UINT32_C(1) << OPT_NOLOGO))
PrintLogo(false, g_ToolName, g_Description); PrintLogo(false, g_ToolName, g_Description);
switch (dwCommand) switch (dwCommand)
@ -1169,7 +1245,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
outputFile = curpath.stem().concat(L".dds").native(); outputFile = curpath.stem().concat(L".dds").native();
} }
hr = LoadAnimatedGif(curpath.c_str(), loadedImages, (dwOptions & (1 << OPT_GIF_BGCOLOR)) != 0); hr = LoadAnimatedGif(curpath.c_str(), loadedImages, (dwOptions & (UINT32_C(1) << OPT_GIF_BGCOLOR)) != 0);
if (FAILED(hr)) if (FAILED(hr))
{ {
wprintf(L" FAILED (%08X%ls)\n", static_cast<unsigned int>(hr), GetErrorDesc(hr)); wprintf(L" FAILED (%08X%ls)\n", static_cast<unsigned int>(hr), GetErrorDesc(hr));
@ -1296,7 +1372,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wprintf(L"\nERROR: Can't assemble complex surfaces\n"); wprintf(L"\nERROR: Can't assemble complex surfaces\n");
return 1; return 1;
} }
else if ((info.mipLevels > 1) && ((dwOptions & (1 << OPT_STRIP_MIPS)) == 0)) else if ((info.mipLevels > 1) && ((dwOptions & (UINT32_C(1) << OPT_STRIP_MIPS)) == 0))
{ {
switch (dwCommand) switch (dwCommand)
{ {
@ -1476,7 +1552,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
// --- Strip Mips (if requested) ----------------------------------------------- // --- Strip Mips (if requested) -----------------------------------------------
if ((info.mipLevels > 1) && (dwOptions & (1 << OPT_STRIP_MIPS))) if ((info.mipLevels > 1) && (dwOptions & (UINT32_C(1) << OPT_STRIP_MIPS)))
{ {
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage); std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage) if (!timage)
@ -1526,7 +1602,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
// --- Undo Premultiplied Alpha (if requested) --------------------------------- // --- Undo Premultiplied Alpha (if requested) ---------------------------------
if ((dwOptions & (1 << OPT_DEMUL_ALPHA)) if ((dwOptions & (UINT32_C(1) << OPT_DEMUL_ALPHA))
&& HasAlpha(info.format) && HasAlpha(info.format)
&& info.format != DXGI_FORMAT_A8_UNORM) && info.format != DXGI_FORMAT_A8_UNORM)
{ {
@ -1633,7 +1709,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
// --- Tonemap (if requested) -------------------------------------------------- // --- Tonemap (if requested) --------------------------------------------------
if (dwOptions & (1 << OPT_TONEMAP)) if (dwOptions & (UINT32_C(1) << OPT_TONEMAP))
{ {
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage); std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage) if (!timage)
@ -1973,12 +2049,12 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wprintf(L"\n"); wprintf(L"\n");
fflush(stdout); fflush(stdout);
if (dwOptions & (1 << OPT_TOLOWER)) if (dwOptions & (UINT32_C(1) << OPT_TOLOWER))
{ {
std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower); std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower);
} }
if (~dwOptions & (1 << OPT_OVERWRITE)) if (~dwOptions & (UINT32_C(1) << OPT_OVERWRITE))
{ {
if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES) if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES)
{ {
@ -2041,12 +2117,12 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wprintf(L"\n"); wprintf(L"\n");
fflush(stdout); fflush(stdout);
if (dwOptions & (1 << OPT_TOLOWER)) if (dwOptions & (UINT32_C(1) << OPT_TOLOWER))
{ {
std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower); std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower);
} }
if (~dwOptions & (1 << OPT_OVERWRITE)) if (~dwOptions & (UINT32_C(1) << OPT_OVERWRITE))
{ {
if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES) if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES)
{ {
@ -2110,12 +2186,12 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wprintf(L"\n"); wprintf(L"\n");
fflush(stdout); fflush(stdout);
if (dwOptions & (1 << OPT_TOLOWER)) if (dwOptions & (UINT32_C(1) << OPT_TOLOWER))
{ {
std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower); std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower);
} }
if (~dwOptions & (1 << OPT_OVERWRITE)) if (~dwOptions & (UINT32_C(1) << OPT_OVERWRITE))
{ {
if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES) if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES)
{ {
@ -2309,12 +2385,12 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wprintf(L"\n"); wprintf(L"\n");
fflush(stdout); fflush(stdout);
if (dwOptions & (1 << OPT_TOLOWER)) if (dwOptions & (UINT32_C(1) << OPT_TOLOWER))
{ {
std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower); std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower);
} }
if (~dwOptions & (1 << OPT_OVERWRITE)) if (~dwOptions & (UINT32_C(1) << OPT_OVERWRITE))
{ {
if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES) if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES)
{ {
@ -2324,7 +2400,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
hr = SaveToDDSFile(result.GetImages(), result.GetImageCount(), result.GetMetadata(), hr = SaveToDDSFile(result.GetImages(), result.GetImageCount(), result.GetMetadata(),
(dwOptions & (1 << OPT_USE_DX10)) ? (DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2) : DDS_FLAGS_NONE, (dwOptions & (UINT32_C(1) << OPT_USE_DX10)) ? (DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2) : DDS_FLAGS_NONE,
outputFile.c_str()); outputFile.c_str());
if (FAILED(hr)) if (FAILED(hr))
{ {
@ -2367,12 +2443,12 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wprintf(L"\n"); wprintf(L"\n");
fflush(stdout); fflush(stdout);
if (dwOptions & (1 << OPT_TOLOWER)) if (dwOptions & (UINT32_C(1) << OPT_TOLOWER))
{ {
std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower); std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower);
} }
if (~dwOptions & (1 << OPT_OVERWRITE)) if (~dwOptions & (UINT32_C(1) << OPT_OVERWRITE))
{ {
if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES) if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES)
{ {
@ -2382,7 +2458,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
hr = SaveToDDSFile(result.GetImages(), result.GetImageCount(), result.GetMetadata(), hr = SaveToDDSFile(result.GetImages(), result.GetImageCount(), result.GetMetadata(),
(dwOptions & (1 << OPT_USE_DX10)) ? (DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2) : DDS_FLAGS_NONE, (dwOptions & (UINT32_C(1) << OPT_USE_DX10)) ? (DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2) : DDS_FLAGS_NONE,
outputFile.c_str()); outputFile.c_str());
if (FAILED(hr)) if (FAILED(hr))
{ {
@ -2456,7 +2532,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case CMD_ARRAY: case CMD_ARRAY:
case CMD_GIF: case CMD_GIF:
hr = result.InitializeArrayFromImages(&imageArray[0], imageArray.size(), (dwOptions & (1 << OPT_USE_DX10)) != 0); hr = result.InitializeArrayFromImages(&imageArray[0], imageArray.size(), (dwOptions & (UINT32_C(1) << OPT_USE_DX10)) != 0);
break; break;
case CMD_CUBE: case CMD_CUBE:
@ -2480,12 +2556,12 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wprintf(L"\n"); wprintf(L"\n");
fflush(stdout); fflush(stdout);
if (dwOptions & (1 << OPT_TOLOWER)) if (dwOptions & (UINT32_C(1) << OPT_TOLOWER))
{ {
std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower); std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower);
} }
if (~dwOptions & (1 << OPT_OVERWRITE)) if (~dwOptions & (UINT32_C(1) << OPT_OVERWRITE))
{ {
if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES) if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES)
{ {
@ -2495,7 +2571,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
hr = SaveToDDSFile(result.GetImages(), result.GetImageCount(), result.GetMetadata(), hr = SaveToDDSFile(result.GetImages(), result.GetImageCount(), result.GetMetadata(),
(dwOptions & (1 << OPT_USE_DX10)) ? (DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2) : DDS_FLAGS_NONE, (dwOptions & (UINT32_C(1) << OPT_USE_DX10)) ? (DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2) : DDS_FLAGS_NONE,
outputFile.c_str()); outputFile.c_str());
if (FAILED(hr)) if (FAILED(hr))
{ {

View File

@ -103,21 +103,8 @@ namespace
enum OPTIONS : uint64_t enum OPTIONS : uint64_t
{ {
OPT_RECURSIVE = 1, OPT_RECURSIVE = 1,
OPT_FILELIST,
OPT_WIDTH,
OPT_HEIGHT,
OPT_MIPLEVELS,
OPT_FORMAT,
OPT_FILTER,
OPT_SRGBI,
OPT_SRGBO,
OPT_SRGB,
OPT_PREFIX,
OPT_SUFFIX,
OPT_OUTPUTDIR,
OPT_TOLOWER, OPT_TOLOWER,
OPT_OVERWRITE, OPT_OVERWRITE,
OPT_FILETYPE,
OPT_HFLIP, OPT_HFLIP,
OPT_VFLIP, OPT_VFLIP,
OPT_DDS_DWORD_ALIGN, OPT_DDS_DWORD_ALIGN,
@ -128,7 +115,6 @@ namespace
OPT_USE_DX9, OPT_USE_DX9,
OPT_TGA20, OPT_TGA20,
OPT_TGAZEROALPHA, OPT_TGAZEROALPHA,
OPT_WIC_QUALITY,
OPT_WIC_LOSSLESS, OPT_WIC_LOSSLESS,
OPT_WIC_MULTIFRAME, OPT_WIC_MULTIFRAME,
OPT_NOLOGO, OPT_NOLOGO,
@ -145,28 +131,44 @@ namespace
OPT_FORCE_SINGLEPROC, OPT_FORCE_SINGLEPROC,
OPT_GPU, OPT_GPU,
OPT_NOGPU, OPT_NOGPU,
OPT_FEATURE_LEVEL,
OPT_FIT_POWEROF2, OPT_FIT_POWEROF2,
OPT_ALPHA_THRESHOLD,
OPT_ALPHA_WEIGHT,
OPT_NORMAL_MAP, OPT_NORMAL_MAP,
OPT_NORMAL_MAP_AMPLITUDE,
OPT_BC_COMPRESS,
OPT_COLORKEY, OPT_COLORKEY,
OPT_TONEMAP, OPT_TONEMAP,
OPT_X2_BIAS, OPT_X2_BIAS,
OPT_PRESERVE_ALPHA_COVERAGE, OPT_PRESERVE_ALPHA_COVERAGE,
OPT_INVERT_Y, OPT_INVERT_Y,
OPT_RECONSTRUCT_Z, OPT_RECONSTRUCT_Z,
OPT_ROTATE_COLOR,
OPT_PAPER_WHITE_NITS,
OPT_BCNONMULT4FIX, OPT_BCNONMULT4FIX,
OPT_SWIZZLE,
#ifdef USE_XBOX_EXTS #ifdef USE_XBOX_EXTS
OPT_USE_XBOX, OPT_USE_XBOX,
OPT_XGMODE, OPT_XGMODE,
#endif #endif
OPT_MAX OPT_FLAGS_MAX,
OPT_FILELIST,
OPT_WIDTH,
OPT_HEIGHT,
OPT_MIPLEVELS,
OPT_FORMAT,
OPT_FILTER,
OPT_SRGBI,
OPT_SRGBO,
OPT_SRGB,
OPT_PREFIX,
OPT_SUFFIX,
OPT_OUTPUTDIR,
OPT_FILETYPE,
OPT_WIC_QUALITY,
OPT_FEATURE_LEVEL,
OPT_ALPHA_THRESHOLD,
OPT_ALPHA_WEIGHT,
OPT_NORMAL_MAP_AMPLITUDE,
OPT_BC_COMPRESS,
OPT_ROTATE_COLOR,
OPT_PAPER_WHITE_NITS,
OPT_SWIZZLE,
OPT_VERSION,
OPT_HELP,
}; };
enum enum
@ -187,7 +189,7 @@ namespace
FORMAT_DXT5_RXGB, FORMAT_DXT5_RXGB,
}; };
static_assert(OPT_MAX <= 64, "dwOptions is a unsigned int bitfield"); static_assert(OPT_FLAGS_MAX <= 64, "dwOptions is a unsigned int bitfield");
const SValue<uint64_t> g_pOptions[] = const SValue<uint64_t> g_pOptions[] =
{ {
@ -210,20 +212,12 @@ namespace
{ L"hflip", OPT_HFLIP }, { L"hflip", OPT_HFLIP },
{ L"vflip", OPT_VFLIP }, { L"vflip", OPT_VFLIP },
{ L"dword", OPT_DDS_DWORD_ALIGN }, { L"dword", OPT_DDS_DWORD_ALIGN },
{ L"badtails", OPT_DDS_BAD_DXTN_TAILS },
{ L"permissive", OPT_DDS_PERMISSIVE },
{ L"ignoremips", OPT_DDS_IGNORE_MIPS },
{ L"dx10", OPT_USE_DX10 }, { L"dx10", OPT_USE_DX10 },
{ L"dx9", OPT_USE_DX9 }, { L"dx9", OPT_USE_DX9 },
{ L"tga20", OPT_TGA20 }, { L"tga20", OPT_TGA20 },
{ L"tgazeroalpha", OPT_TGAZEROALPHA },
{ L"wicq", OPT_WIC_QUALITY }, { L"wicq", OPT_WIC_QUALITY },
{ L"wiclossless", OPT_WIC_LOSSLESS },
{ L"wicmulti", OPT_WIC_MULTIFRAME },
{ L"nologo", OPT_NOLOGO }, { L"nologo", OPT_NOLOGO },
{ L"timing", OPT_TIMING },
{ L"sepalpha", OPT_SEPALPHA }, { L"sepalpha", OPT_SEPALPHA },
{ L"keepcoverage", OPT_PRESERVE_ALPHA_COVERAGE },
{ L"nowic", OPT_NO_WIC }, { L"nowic", OPT_NO_WIC },
{ L"tu", OPT_TYPELESS_UNORM }, { L"tu", OPT_TYPELESS_UNORM },
{ L"tf", OPT_TYPELESS_FLOAT }, { L"tf", OPT_TYPELESS_FLOAT },
@ -232,7 +226,6 @@ namespace
{ L"xlum", OPT_EXPAND_LUMINANCE }, { L"xlum", OPT_EXPAND_LUMINANCE },
{ L"wrap", OPT_TA_WRAP }, { L"wrap", OPT_TA_WRAP },
{ L"mirror", OPT_TA_MIRROR }, { L"mirror", OPT_TA_MIRROR },
{ L"singleproc", OPT_FORCE_SINGLEPROC },
{ L"gpu", OPT_GPU }, { L"gpu", OPT_GPU },
{ L"nogpu", OPT_NOGPU }, { L"nogpu", OPT_NOGPU },
{ L"fl", OPT_FEATURE_LEVEL }, { L"fl", OPT_FEATURE_LEVEL },
@ -243,21 +236,90 @@ namespace
{ L"nmapamp", OPT_NORMAL_MAP_AMPLITUDE }, { L"nmapamp", OPT_NORMAL_MAP_AMPLITUDE },
{ L"bc", OPT_BC_COMPRESS }, { L"bc", OPT_BC_COMPRESS },
{ L"c", OPT_COLORKEY }, { L"c", OPT_COLORKEY },
{ L"nits", OPT_PAPER_WHITE_NITS },
#ifdef USE_XBOX_EXTS
{ L"xbox", OPT_USE_XBOX },
{ L"xgmode", OPT_XGMODE },
#endif
// Deprecated options (recommend using new -- alternatives)
{ L"badtails", OPT_DDS_BAD_DXTN_TAILS },
{ L"permissive", OPT_DDS_PERMISSIVE },
{ L"ignoremips", OPT_DDS_IGNORE_MIPS },
{ L"tgazeroalpha", OPT_TGAZEROALPHA },
{ L"wiclossless", OPT_WIC_LOSSLESS },
{ L"wicmulti", OPT_WIC_MULTIFRAME },
{ L"timing", OPT_TIMING },
{ L"keepcoverage", OPT_PRESERVE_ALPHA_COVERAGE },
{ L"singleproc", OPT_FORCE_SINGLEPROC },
{ L"tonemap", OPT_TONEMAP }, { L"tonemap", OPT_TONEMAP },
{ L"x2bias", OPT_X2_BIAS }, { L"x2bias", OPT_X2_BIAS },
{ L"inverty", OPT_INVERT_Y }, { L"inverty", OPT_INVERT_Y },
{ L"reconstructz", OPT_RECONSTRUCT_Z }, { L"reconstructz", OPT_RECONSTRUCT_Z },
{ L"rotatecolor", OPT_ROTATE_COLOR }, { L"rotatecolor", OPT_ROTATE_COLOR },
{ L"nits", OPT_PAPER_WHITE_NITS },
{ L"fixbc4x4", OPT_BCNONMULT4FIX }, { L"fixbc4x4", OPT_BCNONMULT4FIX },
{ L"swizzle", OPT_SWIZZLE }, { L"swizzle", OPT_SWIZZLE },
#ifdef USE_XBOX_EXTS
{ L"xbox", OPT_USE_XBOX },
{ L"xgmode", OPT_XGMODE },
#endif
{ nullptr, 0 } { nullptr, 0 }
}; };
const SValue<uint64_t> g_pOptionsLong[] =
{
{ L"alpha-threshold", OPT_ALPHA_THRESHOLD },
{ L"alpha-weight", OPT_ALPHA_WEIGHT },
{ L"bad-tails", OPT_DDS_BAD_DXTN_TAILS },
{ L"block-compress", OPT_BC_COMPRESS },
{ L"color-key", OPT_COLORKEY },
{ L"dword-alignment", OPT_DDS_DWORD_ALIGN },
{ L"expand-luminance", OPT_EXPAND_LUMINANCE },
{ L"feature-level", OPT_FEATURE_LEVEL },
{ L"file-list", OPT_FILELIST },
{ L"file-type", OPT_FILETYPE },
{ L"fit-power-of-2", OPT_FIT_POWEROF2 },
{ L"fix-bc-4x4", OPT_BCNONMULT4FIX },
{ L"format", OPT_FORMAT },
{ L"height", OPT_HEIGHT },
{ L"help", OPT_HELP },
{ L"horizontal-flip", OPT_HFLIP },
{ L"ignore-mips", OPT_DDS_IGNORE_MIPS },
{ L"image-filter", OPT_FILTER },
{ L"invert-y", OPT_INVERT_Y },
{ L"keep-coverage", OPT_PRESERVE_ALPHA_COVERAGE },
{ L"mip-levels", OPT_MIPLEVELS },
{ L"normal-map-amplitude", OPT_NORMAL_MAP_AMPLITUDE },
{ L"normal-map", OPT_NORMAL_MAP },
{ L"overwrite", OPT_OVERWRITE },
{ L"paper-white-nits", OPT_PAPER_WHITE_NITS },
{ L"permissive", OPT_DDS_PERMISSIVE },
{ L"prefix", OPT_PREFIX },
{ L"premultiplied-alpha", OPT_PREMUL_ALPHA },
{ L"reconstruct-z", OPT_RECONSTRUCT_Z },
{ L"rotate-color", OPT_ROTATE_COLOR },
{ L"separate-alpha", OPT_SEPALPHA },
{ L"single-proc", OPT_FORCE_SINGLEPROC },
{ L"srgb-in", OPT_SRGBI },
{ L"srgb-out", OPT_SRGBO },
{ L"suffix", OPT_SUFFIX },
{ L"swizzle", OPT_SWIZZLE },
{ L"tga-zero-alpha", OPT_TGAZEROALPHA },
{ L"timing", OPT_TIMING },
{ L"to-lowercase", OPT_TOLOWER },
{ L"tonemap", OPT_TONEMAP },
{ L"typeless-unorm", OPT_TYPELESS_UNORM },
{ L"typeless-float", OPT_TYPELESS_FLOAT },
{ L"version", OPT_VERSION },
{ L"vertical-flip", OPT_VFLIP },
{ L"wic-lossless", OPT_WIC_LOSSLESS },
{ L"wic-multiframe", OPT_WIC_MULTIFRAME },
{ L"wic-quality", OPT_WIC_QUALITY },
{ L"width", OPT_WIDTH },
{ L"x2-bias", OPT_X2_BIAS },
#ifdef USE_XBOX_EXTS
{ L"xbox-mode", OPT_XGMODE },
#endif
{ nullptr, 0 }
};
#define DEFFMT(fmt) { L## #fmt, DXGI_FORMAT_ ## fmt } #define DEFFMT(fmt) { L## #fmt, DXGI_FORMAT_ ## fmt }
const SValue<DXGI_FORMAT> g_pFormats[] = const SValue<DXGI_FORMAT> g_pFormats[] =
@ -482,22 +544,22 @@ namespace
{ nullptr, 0 }, { nullptr, 0 },
}; };
#define CODEC_DDS 0xFFFF0001 constexpr uint32_t CODEC_DDS = 0xFFFF0001;
#define CODEC_TGA 0xFFFF0002 constexpr uint32_t CODEC_TGA = 0xFFFF0002;
#define CODEC_HDP 0xFFFF0003 constexpr uint32_t CODEC_HDP = 0xFFFF0003;
#define CODEC_JXR 0xFFFF0004 constexpr uint32_t CODEC_JXR = 0xFFFF0004;
#define CODEC_HDR 0xFFFF0005 constexpr uint32_t CODEC_HDR = 0xFFFF0005;
#define CODEC_PPM 0xFFFF0006 constexpr uint32_t CODEC_PPM = 0xFFFF0006;
#define CODEC_PFM 0xFFFF0007 constexpr uint32_t CODEC_PFM = 0xFFFF0007;
#ifdef USE_OPENEXR #ifdef USE_OPENEXR
#define CODEC_EXR 0xFFFF0008 constexpr uint32_t CODEC_EXR = 0xFFFF0008;
#endif #endif
#ifdef USE_LIBJPEG #ifdef USE_LIBJPEG
#define CODEC_JPEG 0xFFFF0009 constexpr uint32_t CODEC_JPEG = 0xFFFF0009;
#endif #endif
#ifdef USE_LIBPNG #ifdef USE_LIBPNG
#define CODEC_PNG 0xFFFF000A constexpr uint32_t CODEC_PNG = 0xFFFF000A;
#endif #endif
const SValue<uint32_t> g_pSaveFileTypes[] = // valid formats to write to const SValue<uint32_t> g_pSaveFileTypes[] = // valid formats to write to
@ -693,96 +755,108 @@ namespace
L" -r wildcard filename search is recursive\n" L" -r wildcard filename search is recursive\n"
L" -r:flatten flatten the directory structure (default)\n" L" -r:flatten flatten the directory structure (default)\n"
L" -r:keep keep the directory structure\n" L" -r:keep keep the directory structure\n"
L" -flist <filename> use text file with a list of input files (one per line)\n" L" -flist <filename>, --file-list <filename>\n"
L" use text file with a list of input files (one per line)\n"
L"\n" L"\n"
L" -w <n> width\n" L" -w <n>, --width <n> width for output\n"
L" -h <n> height\n" L" -h <n>, --height <n> height for output\n"
L" -m <n> miplevels\n" L" -m <n>, --mip-levels <n> miplevels for output\n"
L" -f <format> format\n" L" -f <format>, --format <format> pixel format for output\n"
L"\n" L"\n"
L" -if <filter> image filtering\n" L" -if <filter>, --image-filter <filter> image filtering\n"
L" -srgb{i|o} sRGB {input, output}\n" L" -srgb{i|o}, --srgb-in, --srgb-out sRGB {input, output}\n"
L"\n" L"\n"
L" -px <string> name prefix\n" L" -px <string>, --prefix <string> name prefix\n"
L" -sx <string> name suffix\n" L" -sx <string>, --suffix <string> name suffix\n"
L" -o <directory> output directory\n" L" -o <directory> output directory\n"
L" -l force output filename to lower case\n" L" -l, --to-lowercase force output filename to lower case\n"
L" -y overwrite existing output file (if any)\n" L" -y, --overwrite overwrite existing output file (if any)\n"
L" -ft <filetype> output file type\n" L" -ft <filetype>, --file-type <filetype> output file type\n"
L"\n" L"\n"
L" -hflip horizonal flip of source image\n" L" -hflip, --horizontal-flip horizonal flip of source image\n"
L" -vflip vertical flip of source image\n" L" -vflip, --vertical-flip vertical flip of source image\n"
L"\n" L"\n"
L" -sepalpha resize/generate mips alpha channel separately\n" L" -sepalpha, --separate-alpha resize/generate mips alpha channel separately from color channels\n"
L" from color channels\n" L" --keep-coverage <ref> Preserve alpha coverage in mips for alpha test ref\n"
L" -keepcoverage <ref> Preserve alpha coverage in mips for alpha test ref\n"
L"\n" L"\n"
L" -nowic Force non-WIC filtering\n" L" -nowic Force non-WIC filtering\n"
L" -wrap, -mirror texture addressing mode (wrap, mirror, or clamp)\n" L" -wrap, -mirror texture addressing mode (wrap, mirror, or clamp)\n"
L" -pmalpha convert final texture to use premultiplied alpha\n" L" -pmalpha, --premultiplied-alpha convert final texture to use premultiplied alpha\n"
L" -alpha convert premultiplied alpha to straight alpha\n" L" -alpha convert premultiplied alpha to straight alpha\n"
L" -at <threshold> Alpha threshold used for BC1, RGBA5551, and WIC\n" L" -at <threshold>, --alpha-threshold <threshold>\n"
L" (defaults to 0.5)\n" L" Alpha threshold used for BC1, RGBA5551, and WIC\n"
L" (defaults to 0.5)\n"
L"\n" L"\n"
L" -fl <feature-level> Set maximum feature level target (defaults to 11.0)\n" L" -fl <feature-level>, --feature-level <feature-level>\n"
L" -pow2 resize to fit a power-of-2, respecting aspect ratio\n" L" Set maximum feature level target (defaults to 11.0)\n"
L" -pow2, --fit-power-of-2\n"
L" resize to fit a power-of-2, respecting aspect ratio\n"
L"\n" L"\n"
L" -nmap <options> converts height-map to normal-map\n" L" -nmap <options>, --normal-map <options>\n"
L" converts height-map to normal-map\n"
L" options must be one or more of\n" L" options must be one or more of\n"
L" r, g, b, a, l, m, u, v, i, o\n" L" r, g, b, a, l, m, u, v, i, o\n"
L" -nmapamp <weight> normal map amplitude (defaults to 1.0)\n" L" -nmapamp <weight>, --normal-map-amplitude <weight>\n"
L" normal map amplitude (defaults to 1.0)\n"
L"\n" L"\n"
L" (DDS input only)\n" L" (DDS input only)\n"
L" -t{u|f} TYPELESS format is treated as UNORM or FLOAT\n" L" -tu, --typeless-unorm TYPELESS format is treated as UNORM\n"
L" -dword Use DWORD instead of BYTE alignment\n" L" -tf, --typeless-float TYPELESS format is treated as FLOAT\n"
L" -badtails Fix for older DXTn with bad mipchain tails\n" L" -dword, --dword-alignment Use DWORD instead of BYTE alignment\n"
L" -permissive Allow some DX9 variants with unusual header values\n" L" --bad-tails Fix for older DXTn with bad mipchain tails\n"
L" -ignoremips Reads just the top-level mip which reads some invalid files\n" L" --permissive Allow some DX9 variants with unusual header values\n"
L" -fixbc4x4 Fix for odd-sized BC files that Direct3D can't load\n" L" --ignore-mips Reads just the top-level mip which reads some invalid files\n"
L" -xlum expand legacy L8, L16, and A8P8 formats\n" L" --fix-bc-4x4 Fix for odd-sized BC files that Direct3D can't load\n"
L" -xlum, --expand-luminance Expand legacy L8, L16, and A8P8 formats\n"
L"\n" L"\n"
L" (DDS output only)\n" L" (DDS output only)\n"
L" -dx10 Force use of 'DX10' extended header\n" L" -dx10 Force use of 'DX10' extended header\n"
L" -dx9 Force use of legacy DX9 header\n" L" -dx9 Force use of legacy DX9 header\n"
#ifdef USE_XBOX_EXTS #ifdef USE_XBOX_EXTS
L" -xbox Tile/swizzle and use 'XBOX' variant of DDS\n" L" -xbox Tile/swizzle and use 'XBOX' variant of DDS\n"
L" -xgmode <mode> Tile/swizzle using provided memory layout mode\n" L" -xgmode <mode>, --xbox-mode <mode>\n"\
L" Tile/swizzle using provided memory layout mode\n"
#endif #endif
L"\n" L"\n"
L" (TGA input only)\n" L" (TGA input only)\n"
L" -tgazeroalpha Allow all zero alpha channel files to be loaded 'as is'\n" L" --tga-zero-alpha Allow all zero alpha channel files to be loaded 'as is'\n"
L"\n" L"\n"
L" (TGA output only)\n" L" (TGA output only)\n"
L" -tga20 Write file including TGA 2.0 extension area\n" L" -tga20 Write file including TGA 2.0 extension area\n"
L"\n" L"\n"
L" (BMP, PNG, JPG, TIF, WDP output only)\n" L" (BMP, PNG, JPG, TIF, WDP output only)\n"
L" -wicq <quality> When writing images with WIC use quality (0.0 to 1.0)\n" L" -wicq <quality>, --wic-quality <quality>\n"
L" -wiclossless When writing images with WIC use lossless mode\n" L" When writing images with WIC use quality (0.0 to 1.0)\n"
L" -wicmulti When writing images with WIC encode multiframe images\n" L" --wic-lossless When writing images with WIC use lossless mode\n"
L" --wic-multiframe When writing images with WIC encode multiframe images\n"
L"\n" L"\n"
L" -nologo suppress copyright message\n" L" -nologo suppress copyright message\n"
L" -timing Display elapsed processing time\n" L" --timing display elapsed processing time\n"
L"\n" L"\n"
#ifdef _OPENMP #ifdef _OPENMP
L" -singleproc Do not use multi-threaded compression\n" L" --single-proc Do not use multi-threaded compression\n"
#endif #endif
L" -gpu <adapter> Select GPU for DirectCompute-based codecs (0 is default)\n" L" -gpu <adapter> Select GPU for DirectCompute-based codecs (0 is default)\n"
L" -nogpu Do not use DirectCompute-based codecs\n" L" -nogpu Do not use DirectCompute-based codecs\n"
L"\n" L"\n"
L" -bc <options> Sets options for BC compression\n" L" -bc <options>, --block-compress <options>\n"
L" Sets options for BC compression\n"
L" options must be one or more of\n" L" options must be one or more of\n"
L" d, u, q, x\n" L" d, u, q, x\n"
L" -aw <weight> BC7 GPU compressor weighting for alpha error metric\n" L" -aw <weight>, --alpha-weight <weight>\n"
L" BC7 GPU compressor weighting for alpha error metric\n"
L" (defaults to 1.0)\n" L" (defaults to 1.0)\n"
L"\n" L"\n"
L" -c <hex-RGB> colorkey (a.k.a. chromakey) transparency\n" L" -c <hex-RGB>, --color-key <hex-RGB> colorkey (a.k.a. chromakey) transparency\n"
L" -rotatecolor <rot> rotates color primaries and/or applies a curve\n" L" --rotate-color <rot> rotates color primaries and/or applies a curve\n"
L" -nits <value> paper-white value in nits to use for HDR10 (def: 200.0)\n" L"\n"
L" -tonemap Apply a tonemap operator based on maximum luminance\n" L" -nits <value>, --paper-white-nits <value>\n"
L" -x2bias Enable *2 - 1 conversion cases for unorm/pos-only-float\n" L" paper-white value in nits to use for HDR10 (def: 200.0)\n"
L" -inverty Invert Y (i.e. green) channel values\n" L" --tonemap Apply a tonemap operator based on maximum luminance\n"
L" -reconstructz Rebuild Z (blue) channel assuming X/Y are normals\n" L" --x2-bias Enable *2 - 1 conversion cases for unorm/pos-only-float\n"
L" -swizzle <rgba> Swizzle image channels using HLSL-style mask\n" L" --invert-y Invert Y (i.e. green) channel values\n"
L" --reconstruct-z Rebuild Z (blue) channel assuming X/Y are normals\n"
L" --swizzle <rgba> Swizzle image channels using HLSL-style mask\n"
L"\n" L"\n"
L" '-- ' is needed if any input filepath starts with the '-' or '/' character\n"; L" '-- ' is needed if any input filepath starts with the '-' or '/' character\n";
@ -1214,54 +1288,105 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
std::list<SConversion> conversion; std::list<SConversion> conversion;
bool allowOpts = true; bool allowOpts = true;
for (int iArg = 1; iArg < argc; iArg++) for (int iArg = 1; iArg < argc; ++iArg)
{ {
PWSTR pArg = argv[iArg]; PWSTR pArg = argv[iArg];
if (allowOpts if (allowOpts && (('-' == pArg[0]) || ('/' == pArg[0])))
&& ('-' == pArg[0]) && ('-' == pArg[1]))
{ {
if (pArg[2] == 0) uint64_t dwOption = 0;
PWSTR pValue = nullptr;
if (('-' == pArg[0]) && ('-' == pArg[1]))
{ {
// "-- " is the POSIX standard for "end of options" marking to escape the '-' and '/' characters at the start of filepaths. if (pArg[2] == 0)
allowOpts = false; {
} // "-- " is the POSIX standard for "end of options" marking to escape the '-' and '/' characters at the start of filepaths.
else if (!_wcsicmp(pArg,L"--version")) allowOpts = false;
{ continue;
PrintLogo(true, g_ToolName, g_Description); }
return 0; else
} {
else if (!_wcsicmp(pArg, L"--help")) pArg += 2;
{
PrintUsage(); for (pValue = pArg; *pValue && (':' != *pValue) && ('=' != *pValue); ++pValue);
return 0;
if (*pValue)
*pValue++ = 0;
dwOption = LookupByName(pArg, g_pOptionsLong);
}
} }
else else
{ {
wprintf(L"Unknown option: %ls\n", pArg); pArg++;
return 1;
for (pValue = pArg; *pValue && (':' != *pValue) && ('=' != *pValue); ++pValue);
if (*pValue)
*pValue++ = 0;
dwOption = LookupByName(pArg, g_pOptions);
if (!dwOption)
{
if (LookupByName(pArg, g_pOptionsLong))
{
wprintf(L"ERROR: did you mean `--%ls` (with two dashes)?\n", pArg);
return 1;
}
}
} }
}
else if (allowOpts
&& (('-' == pArg[0]) || ('/' == pArg[0])))
{
pArg++;
PWSTR pValue;
for (pValue = pArg; *pValue && (':' != *pValue); pValue++); switch (dwOption)
if (*pValue)
*pValue++ = 0;
const uint64_t dwOption = LookupByName(pArg, g_pOptions);
if (!dwOption || (dwOptions & (uint64_t(1) << dwOption)))
{ {
PrintUsage(); case 0:
wprintf(L"ERROR: Unknown option: `%ls`\n\nUse %ls --help\n", pArg, g_ToolName);
return 1; return 1;
}
dwOptions |= (uint64_t(1) << dwOption); case OPT_FILELIST:
case OPT_WIDTH:
case OPT_HEIGHT:
case OPT_MIPLEVELS:
case OPT_FORMAT:
case OPT_FILTER:
case OPT_SRGBI:
case OPT_SRGBO:
case OPT_SRGB:
case OPT_PREFIX:
case OPT_SUFFIX:
case OPT_OUTPUTDIR:
case OPT_FILETYPE:
case OPT_WIC_QUALITY:
case OPT_FEATURE_LEVEL:
case OPT_ALPHA_THRESHOLD:
case OPT_ALPHA_WEIGHT:
case OPT_NORMAL_MAP_AMPLITUDE:
case OPT_BC_COMPRESS:
case OPT_ROTATE_COLOR:
case OPT_PAPER_WHITE_NITS:
case OPT_SWIZZLE:
// These don't use flag bits
break;
case OPT_VERSION:
PrintLogo(true, g_ToolName, g_Description);
return 0;
case OPT_HELP:
PrintUsage();
return 0;
default:
if (dwOptions & (UINT64_C(1) << dwOption))
{
wprintf(L"ERROR: Duplicate option: `%ls`\n\n", pArg);
return 1;
}
dwOptions |= (UINT64_C(1) << dwOption);
break;
}
// Handle options with additional value parameter // Handle options with additional value parameter
switch (dwOption) switch (dwOption)
@ -1312,8 +1437,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case OPT_WIDTH: case OPT_WIDTH:
if (swscanf_s(pValue, L"%zu", &width) != 1) if (swscanf_s(pValue, L"%zu", &width) != 1)
{ {
wprintf(L"Invalid value specified with -w (%ls)\n", pValue); wprintf(L"Invalid value specified with -w (%ls)\n\n", pValue);
wprintf(L"\n");
PrintUsage(); PrintUsage();
return 1; return 1;
} }
@ -1332,8 +1456,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case OPT_MIPLEVELS: case OPT_MIPLEVELS:
if (swscanf_s(pValue, L"%zu", &mipLevels) != 1) if (swscanf_s(pValue, L"%zu", &mipLevels) != 1)
{ {
wprintf(L"Invalid value specified with -m (%ls)\n", pValue); wprintf(L"Invalid value specified with -m (%ls)\n\n", pValue);
wprintf(L"\n");
PrintUsage(); PrintUsage();
return 1; return 1;
} }
@ -1359,8 +1482,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
break; break;
default: default:
wprintf(L"Invalid value specified with -f (%ls)\n", pValue); wprintf(L"Invalid value specified with -f (%ls)\n\n", pValue);
wprintf(L"\n");
PrintUsage(); PrintUsage();
return 1; return 1;
} }
@ -1372,8 +1494,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
dwFilter = static_cast<TEX_FILTER_FLAGS>(LookupByName(pValue, g_pFilters)); dwFilter = static_cast<TEX_FILTER_FLAGS>(LookupByName(pValue, g_pFilters));
if (!dwFilter) if (!dwFilter)
{ {
wprintf(L"Invalid value specified with -if (%ls)\n", pValue); wprintf(L"Invalid value specified with -if (%ls)\n\n", pValue);
wprintf(L"\n");
PrintUsage(); PrintUsage();
return 1; return 1;
} }
@ -1383,8 +1504,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
dwRotateColor = LookupByName(pValue, g_pRotateColor); dwRotateColor = LookupByName(pValue, g_pRotateColor);
if (!dwRotateColor) if (!dwRotateColor)
{ {
wprintf(L"Invalid value specified with -rotatecolor (%ls)\n", pValue); wprintf(L"Invalid value specified with -rotatecolor (%ls)\n\n", pValue);
wprintf(L"\n");
PrintUsage(); PrintUsage();
return 1; return 1;
} }
@ -1429,15 +1549,14 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
FileType = LookupByName(pValue, g_pSaveFileTypes); FileType = LookupByName(pValue, g_pSaveFileTypes);
if (!FileType) if (!FileType)
{ {
wprintf(L"Invalid value specified with -ft (%ls)\n", pValue); wprintf(L"Invalid value specified with -ft (%ls)\n\n", pValue);
wprintf(L"\n");
PrintUsage(); PrintUsage();
return 1; return 1;
} }
break; break;
case OPT_PREMUL_ALPHA: case OPT_PREMUL_ALPHA:
if (dwOptions & (uint64_t(1) << OPT_DEMUL_ALPHA)) if (dwOptions & (UINT64_C(1) << OPT_DEMUL_ALPHA))
{ {
wprintf(L"Can't use -pmalpha and -alpha at same time\n\n"); wprintf(L"Can't use -pmalpha and -alpha at same time\n\n");
PrintUsage(); PrintUsage();
@ -1446,7 +1565,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
break; break;
case OPT_DEMUL_ALPHA: case OPT_DEMUL_ALPHA:
if (dwOptions & (uint64_t(1) << OPT_PREMUL_ALPHA)) if (dwOptions & (UINT64_C(1) << OPT_PREMUL_ALPHA))
{ {
wprintf(L"Can't use -pmalpha and -alpha at same time\n\n"); wprintf(L"Can't use -pmalpha and -alpha at same time\n\n");
PrintUsage(); PrintUsage();
@ -1571,8 +1690,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
maxSize = LookupByName(pValue, g_pFeatureLevels); maxSize = LookupByName(pValue, g_pFeatureLevels);
if (!maxSize) if (!maxSize)
{ {
wprintf(L"Invalid value specified with -fl (%ls)\n", pValue); wprintf(L"Invalid value specified with -fl (%ls)\n\n", pValue);
wprintf(L"\n");
PrintUsage(); PrintUsage();
return 1; return 1;
} }
@ -1581,15 +1699,13 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case OPT_ALPHA_THRESHOLD: case OPT_ALPHA_THRESHOLD:
if (swscanf_s(pValue, L"%f", &alphaThreshold) != 1) if (swscanf_s(pValue, L"%f", &alphaThreshold) != 1)
{ {
wprintf(L"Invalid value specified with -at (%ls)\n", pValue); wprintf(L"Invalid value specified with -at (%ls)\n\n", pValue);
wprintf(L"\n");
PrintUsage(); PrintUsage();
return 1; return 1;
} }
else if (alphaThreshold < 0.f) else if (alphaThreshold < 0.f)
{ {
wprintf(L"-at (%ls) parameter must be positive\n", pValue); wprintf(L"-at (%ls) parameter must be positive\n\n", pValue);
wprintf(L"\n");
return 1; return 1;
} }
break; break;
@ -1597,15 +1713,13 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case OPT_ALPHA_WEIGHT: case OPT_ALPHA_WEIGHT:
if (swscanf_s(pValue, L"%f", &alphaWeight) != 1) if (swscanf_s(pValue, L"%f", &alphaWeight) != 1)
{ {
wprintf(L"Invalid value specified with -aw (%ls)\n", pValue); wprintf(L"Invalid value specified with -aw (%ls)\n\n", pValue);
wprintf(L"\n");
PrintUsage(); PrintUsage();
return 1; return 1;
} }
else if (alphaWeight < 0.f) else if (alphaWeight < 0.f)
{ {
wprintf(L"-aw (%ls) parameter must be positive\n", pValue); wprintf(L"-aw (%ls) parameter must be positive\n\n", pValue);
wprintf(L"\n");
return 1; return 1;
} }
break; break;
@ -1682,7 +1796,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
break; break;
case OPT_USE_DX10: case OPT_USE_DX10:
if (dwOptions & (uint64_t(1) << OPT_USE_DX9)) if (dwOptions & (UINT64_C(1) << OPT_USE_DX9))
{ {
wprintf(L"Can't use -dx9 and -dx10 at same time\n\n"); wprintf(L"Can't use -dx9 and -dx10 at same time\n\n");
PrintUsage(); PrintUsage();
@ -1691,7 +1805,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
break; break;
case OPT_USE_DX9: case OPT_USE_DX9:
if (dwOptions & (uint64_t(1) << OPT_USE_DX10)) if (dwOptions & (UINT64_C(1) << OPT_USE_DX10))
{ {
wprintf(L"Can't use -dx9 and -dx10 at same time\n\n"); wprintf(L"Can't use -dx9 and -dx10 at same time\n\n");
PrintUsage(); PrintUsage();
@ -1813,7 +1927,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
{ {
const size_t count = conversion.size(); const size_t count = conversion.size();
std::filesystem::path path(pArg); std::filesystem::path path(pArg);
SearchForFiles(path.make_preferred(), conversion, (dwOptions & (uint64_t(1) << OPT_RECURSIVE)) != 0, nullptr); SearchForFiles(path.make_preferred(), conversion, (dwOptions & (UINT64_C(1) << OPT_RECURSIVE)) != 0, nullptr);
if (conversion.size() <= count) if (conversion.size() <= count)
{ {
wprintf(L"No matching files found for %ls\n", pArg); wprintf(L"No matching files found for %ls\n", pArg);
@ -1835,7 +1949,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
return 0; return 0;
} }
if (~dwOptions & (uint64_t(1) << OPT_NOLOGO)) if (~dwOptions & (UINT64_C(1) << OPT_NOLOGO))
PrintLogo(false, g_ToolName, g_Description); PrintLogo(false, g_ToolName, g_Description);
auto fileTypeName = LookupByValue(FileType, g_pSaveFileTypes); auto fileTypeName = LookupByValue(FileType, g_pSaveFileTypes);
@ -1920,15 +2034,15 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
#endif // USE_XBOX_EXTS #endif // USE_XBOX_EXTS
{ {
DDS_FLAGS ddsFlags = DDS_FLAGS_ALLOW_LARGE_FILES; DDS_FLAGS ddsFlags = DDS_FLAGS_ALLOW_LARGE_FILES;
if (dwOptions & (uint64_t(1) << OPT_DDS_DWORD_ALIGN)) if (dwOptions & (UINT64_C(1) << OPT_DDS_DWORD_ALIGN))
ddsFlags |= DDS_FLAGS_LEGACY_DWORD; ddsFlags |= DDS_FLAGS_LEGACY_DWORD;
if (dwOptions & (uint64_t(1) << OPT_EXPAND_LUMINANCE)) if (dwOptions & (UINT64_C(1) << OPT_EXPAND_LUMINANCE))
ddsFlags |= DDS_FLAGS_EXPAND_LUMINANCE; ddsFlags |= DDS_FLAGS_EXPAND_LUMINANCE;
if (dwOptions & (uint64_t(1) << OPT_DDS_BAD_DXTN_TAILS)) if (dwOptions & (UINT64_C(1) << OPT_DDS_BAD_DXTN_TAILS))
ddsFlags |= DDS_FLAGS_BAD_DXTN_TAILS; ddsFlags |= DDS_FLAGS_BAD_DXTN_TAILS;
if (dwOptions & (uint64_t(1) << OPT_DDS_PERMISSIVE)) if (dwOptions & (UINT64_C(1) << OPT_DDS_PERMISSIVE))
ddsFlags |= DDS_FLAGS_PERMISSIVE; ddsFlags |= DDS_FLAGS_PERMISSIVE;
if (dwOptions & (uint64_t(1) << OPT_DDS_IGNORE_MIPS)) if (dwOptions & (UINT64_C(1) << OPT_DDS_IGNORE_MIPS))
ddsFlags |= DDS_FLAGS_IGNORE_MIPS; ddsFlags |= DDS_FLAGS_IGNORE_MIPS;
hr = LoadFromDDSFile(curpath.c_str(), ddsFlags, &info, *image); hr = LoadFromDDSFile(curpath.c_str(), ddsFlags, &info, *image);
@ -1942,11 +2056,11 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
if (IsTypeless(info.format)) if (IsTypeless(info.format))
{ {
if (dwOptions & (uint64_t(1) << OPT_TYPELESS_UNORM)) if (dwOptions & (UINT64_C(1) << OPT_TYPELESS_UNORM))
{ {
info.format = MakeTypelessUNORM(info.format); info.format = MakeTypelessUNORM(info.format);
} }
else if (dwOptions & (uint64_t(1) << OPT_TYPELESS_FLOAT)) else if (dwOptions & (UINT64_C(1) << OPT_TYPELESS_FLOAT))
{ {
info.format = MakeTypelessFLOAT(info.format); info.format = MakeTypelessFLOAT(info.format);
} }
@ -1974,7 +2088,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
else if (_wcsicmp(ext.c_str(), L".tga") == 0) else if (_wcsicmp(ext.c_str(), L".tga") == 0)
{ {
TGA_FLAGS tgaFlags = (IsBGR(format)) ? TGA_FLAGS_BGR : TGA_FLAGS_NONE; TGA_FLAGS tgaFlags = (IsBGR(format)) ? TGA_FLAGS_BGR : TGA_FLAGS_NONE;
if (dwOptions & (uint64_t(1) << OPT_TGAZEROALPHA)) if (dwOptions & (UINT64_C(1) << OPT_TGAZEROALPHA))
{ {
tgaFlags |= TGA_FLAGS_ALLOW_ALL_ZERO_ALPHA; tgaFlags |= TGA_FLAGS_ALLOW_ALL_ZERO_ALPHA;
} }
@ -2142,7 +2256,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
// Direct3D can only create BC resources with multiple-of-4 top levels // Direct3D can only create BC resources with multiple-of-4 top levels
if ((info.width % 4) != 0 || (info.height % 4) != 0) if ((info.width % 4) != 0 || (info.height % 4) != 0)
{ {
if (dwOptions & (uint64_t(1) << OPT_BCNONMULT4FIX)) if (dwOptions & (UINT64_C(1) << OPT_BCNONMULT4FIX))
{ {
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage); std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage) if (!timage)
@ -2246,7 +2360,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
// --- Undo Premultiplied Alpha (if requested) --------------------------------- // --- Undo Premultiplied Alpha (if requested) ---------------------------------
if ((dwOptions & (uint64_t(1) << OPT_DEMUL_ALPHA)) if ((dwOptions & (UINT64_C(1) << OPT_DEMUL_ALPHA))
&& HasAlpha(info.format) && HasAlpha(info.format)
&& info.format != DXGI_FORMAT_A8_UNORM) && info.format != DXGI_FORMAT_A8_UNORM)
{ {
@ -2297,7 +2411,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
// --- Flip/Rotate ------------------------------------------------------------- // --- Flip/Rotate -------------------------------------------------------------
if (dwOptions & ((uint64_t(1) << OPT_HFLIP) | (uint64_t(1) << OPT_VFLIP))) if (dwOptions & ((UINT64_C(1) << OPT_HFLIP) | (UINT64_C(1) << OPT_VFLIP)))
{ {
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage); std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage) if (!timage)
@ -2308,10 +2422,10 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
TEX_FR_FLAGS dwFlags = TEX_FR_ROTATE0; TEX_FR_FLAGS dwFlags = TEX_FR_ROTATE0;
if (dwOptions & (uint64_t(1) << OPT_HFLIP)) if (dwOptions & (UINT64_C(1) << OPT_HFLIP))
dwFlags |= TEX_FR_FLIP_HORIZONTAL; dwFlags |= TEX_FR_FLIP_HORIZONTAL;
if (dwOptions & (uint64_t(1) << OPT_VFLIP)) if (dwOptions & (UINT64_C(1) << OPT_VFLIP))
dwFlags |= TEX_FR_FLIP_VERTICAL; dwFlags |= TEX_FR_FLIP_VERTICAL;
assert(dwFlags != 0); assert(dwFlags != 0);
@ -2358,7 +2472,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
sizewarn = true; sizewarn = true;
} }
if (dwOptions & (uint64_t(1) << OPT_FIT_POWEROF2)) if (dwOptions & (UINT64_C(1) << OPT_FIT_POWEROF2))
{ {
FitPowerOf2(info.width, info.height, twidth, theight, maxSize); FitPowerOf2(info.width, info.height, twidth, theight, maxSize);
} }
@ -2730,7 +2844,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
// --- Tonemap (if requested) -------------------------------------------------- // --- Tonemap (if requested) --------------------------------------------------
if (dwOptions & uint64_t(1) << OPT_TONEMAP) if (dwOptions & UINT64_C(1) << OPT_TONEMAP)
{ {
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage); std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage) if (!timage)
@ -2810,7 +2924,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
// --- Convert ----------------------------------------------------------------- // --- Convert -----------------------------------------------------------------
if (dwOptions & (uint64_t(1) << OPT_NORMAL_MAP)) if (dwOptions & (UINT64_C(1) << OPT_NORMAL_MAP))
{ {
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage); std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage) if (!timage)
@ -2898,7 +3012,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
// --- ColorKey/ChromaKey ------------------------------------------------------ // --- ColorKey/ChromaKey ------------------------------------------------------
if ((dwOptions & (uint64_t(1) << OPT_COLORKEY)) if ((dwOptions & (UINT64_C(1) << OPT_COLORKEY))
&& HasAlpha(info.format)) && HasAlpha(info.format))
{ {
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage); std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
@ -2957,7 +3071,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
// --- Invert Y Channel -------------------------------------------------------- // --- Invert Y Channel --------------------------------------------------------
if (dwOptions & (uint64_t(1) << OPT_INVERT_Y)) if (dwOptions & (UINT64_C(1) << OPT_INVERT_Y))
{ {
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage); std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage) if (!timage)
@ -3006,7 +3120,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
// --- Reconstruct Z Channel --------------------------------------------------- // --- Reconstruct Z Channel ---------------------------------------------------
if (dwOptions & (uint64_t(1) << OPT_RECONSTRUCT_Z)) if (dwOptions & (UINT64_C(1) << OPT_RECONSTRUCT_Z))
{ {
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage); std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage) if (!timage)
@ -3268,7 +3382,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
// --- Premultiplied alpha (if requested) -------------------------------------- // --- Premultiplied alpha (if requested) --------------------------------------
if ((dwOptions & (uint64_t(1) << OPT_PREMUL_ALPHA)) if ((dwOptions & (UINT64_C(1) << OPT_PREMUL_ALPHA))
&& HasAlpha(info.format) && HasAlpha(info.format)
&& info.format != DXGI_FORMAT_A8_UNORM) && info.format != DXGI_FORMAT_A8_UNORM)
{ {
@ -3438,7 +3552,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
{ {
s_tryonce = true; s_tryonce = true;
if (!(dwOptions & (uint64_t(1) << OPT_NOGPU))) if (!(dwOptions & (UINT64_C(1) << OPT_NOGPU)))
{ {
if (!CreateDevice(adapter, pDevice.GetAddressOf())) if (!CreateDevice(adapter, pDevice.GetAddressOf()))
wprintf(L"\nWARNING: DirectCompute is not available, using BC6H / BC7 CPU codec\n"); wprintf(L"\nWARNING: DirectCompute is not available, using BC6H / BC7 CPU codec\n");
@ -3457,7 +3571,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
TEX_COMPRESS_FLAGS cflags = dwCompress; TEX_COMPRESS_FLAGS cflags = dwCompress;
#ifdef _OPENMP #ifdef _OPENMP
if (!(dwOptions & (uint64_t(1) << OPT_FORCE_SINGLEPROC))) if (!(dwOptions & (UINT64_C(1) << OPT_FORCE_SINGLEPROC)))
{ {
cflags |= TEX_COMPRESS_PARALLEL; cflags |= TEX_COMPRESS_PARALLEL;
} }
@ -3517,7 +3631,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
{ {
// Aleady set TEX_ALPHA_MODE_PREMULTIPLIED // Aleady set TEX_ALPHA_MODE_PREMULTIPLIED
} }
else if (dwOptions & (uint64_t(1) << OPT_SEPALPHA)) else if (dwOptions & (UINT64_C(1) << OPT_SEPALPHA))
{ {
info.SetAlphaMode(TEX_ALPHA_MODE_CUSTOM); info.SetAlphaMode(TEX_ALPHA_MODE_CUSTOM);
} }
@ -3538,7 +3652,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
const size_t nimg = image->GetImageCount(); const size_t nimg = image->GetImageCount();
#ifdef USE_XBOX_EXTS #ifdef USE_XBOX_EXTS
const bool isXboxOut = ((FileType == CODEC_DDS) && (dwOptions & (uint64_t(1) << OPT_USE_XBOX))) != 0; const bool isXboxOut = ((FileType == CODEC_DDS) && (dwOptions & (UINT64_C(1) << OPT_USE_XBOX))) != 0;
#else #else
constexpr bool isXboxOut = false; constexpr bool isXboxOut = false;
#endif #endif
@ -3585,7 +3699,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
std::wstring destName = dest.c_str(); std::wstring destName = dest.c_str();
if (dwOptions & (uint64_t(1) << OPT_TOLOWER)) if (dwOptions & (UINT64_C(1) << OPT_TOLOWER))
{ {
std::transform(destName.begin(), destName.end(), destName.begin(), towlower); std::transform(destName.begin(), destName.end(), destName.begin(), towlower);
} }
@ -3594,7 +3708,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wprintf(L"writing %ls", destName.c_str()); wprintf(L"writing %ls", destName.c_str());
fflush(stdout); fflush(stdout);
if (~dwOptions & (uint64_t(1) << OPT_OVERWRITE)) if (~dwOptions & (UINT64_C(1) << OPT_OVERWRITE))
{ {
if (GetFileAttributesW(destName.c_str()) != INVALID_FILE_ATTRIBUTES) if (GetFileAttributesW(destName.c_str()) != INVALID_FILE_ATTRIBUTES)
{ {
@ -3622,11 +3736,11 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
#endif // USE_XBOX_EXTS #endif // USE_XBOX_EXTS
{ {
DDS_FLAGS ddsFlags = DDS_FLAGS_NONE; DDS_FLAGS ddsFlags = DDS_FLAGS_NONE;
if (dwOptions & (uint64_t(1) << OPT_USE_DX10)) if (dwOptions & (UINT64_C(1) << OPT_USE_DX10))
{ {
ddsFlags |= DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2; ddsFlags |= DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2;
} }
else if (dwOptions & (uint64_t(1) << OPT_USE_DX9)) else if (dwOptions & (UINT64_C(1) << OPT_USE_DX9))
{ {
if (dxt5rxgb) if (dxt5rxgb)
{ {
@ -3641,7 +3755,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
break; break;
case CODEC_TGA: case CODEC_TGA:
hr = SaveToTGAFile(img[0], TGA_FLAGS_NONE, destName.c_str(), (dwOptions & (uint64_t(1) << OPT_TGA20)) ? &info : nullptr); hr = SaveToTGAFile(img[0], TGA_FLAGS_NONE, destName.c_str(), (dwOptions & (UINT64_C(1) << OPT_TGA20)) ? &info : nullptr);
break; break;
case CODEC_HDR: case CODEC_HDR:
@ -3675,11 +3789,11 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
default: default:
{ {
const WICCodecs codec = (FileType == CODEC_HDP || FileType == CODEC_JXR) ? WIC_CODEC_WMP : static_cast<WICCodecs>(FileType); const WICCodecs codec = (FileType == CODEC_HDP || FileType == CODEC_JXR) ? WIC_CODEC_WMP : static_cast<WICCodecs>(FileType);
const size_t nimages = (dwOptions & (uint64_t(1) << OPT_WIC_MULTIFRAME)) ? nimg : 1; const size_t nimages = (dwOptions & (UINT64_C(1) << OPT_WIC_MULTIFRAME)) ? nimg : 1;
hr = SaveToWICFile(img, nimages, WIC_FLAGS_NONE, GetWICCodec(codec), destName.c_str(), nullptr, hr = SaveToWICFile(img, nimages, WIC_FLAGS_NONE, GetWICCodec(codec), destName.c_str(), nullptr,
[&](IPropertyBag2* props) [&](IPropertyBag2* props)
{ {
const bool wicLossless = (dwOptions & (uint64_t(1) << OPT_WIC_LOSSLESS)) != 0; const bool wicLossless = (dwOptions & (UINT64_C(1) << OPT_WIC_LOSSLESS)) != 0;
switch (FileType) switch (FileType)
{ {
@ -3770,7 +3884,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
if (non4bc) if (non4bc)
wprintf(L"\nWARNING: Direct3D requires BC image to be multiple of 4 in width & height\n"); wprintf(L"\nWARNING: Direct3D requires BC image to be multiple of 4 in width & height\n");
if (dwOptions & (uint64_t(1) << OPT_TIMING)) if (dwOptions & (UINT64_C(1) << OPT_TIMING))
{ {
LARGE_INTEGER qpcEnd = {}; LARGE_INTEGER qpcEnd = {};
std::ignore = QueryPerformanceCounter(&qpcEnd); std::ignore = QueryPerformanceCounter(&qpcEnd);

View File

@ -96,29 +96,31 @@ namespace
enum OPTIONS : uint32_t enum OPTIONS : uint32_t
{ {
OPT_RECURSIVE = 1, OPT_RECURSIVE = 1,
OPT_FORMAT,
OPT_FILTER,
OPT_DDS_DWORD_ALIGN, OPT_DDS_DWORD_ALIGN,
OPT_DDS_BAD_DXTN_TAILS, OPT_DDS_BAD_DXTN_TAILS,
OPT_DDS_PERMISSIVE, OPT_DDS_PERMISSIVE,
OPT_DDS_IGNORE_MIPS, OPT_DDS_IGNORE_MIPS,
OPT_OUTPUTFILE,
OPT_TOLOWER, OPT_TOLOWER,
OPT_OVERWRITE, OPT_OVERWRITE,
OPT_FILETYPE,
OPT_NOLOGO, OPT_NOLOGO,
OPT_TYPELESS_UNORM, OPT_TYPELESS_UNORM,
OPT_TYPELESS_FLOAT, OPT_TYPELESS_FLOAT,
OPT_EXPAND_LUMINANCE, OPT_EXPAND_LUMINANCE,
OPT_FLAGS_MAX,
OPT_FORMAT,
OPT_FILTER,
OPT_OUTPUTFILE,
OPT_FILETYPE,
OPT_TARGET_PIXELX, OPT_TARGET_PIXELX,
OPT_TARGET_PIXELY, OPT_TARGET_PIXELY,
OPT_DIFF_COLOR, OPT_DIFF_COLOR,
OPT_THRESHOLD, OPT_THRESHOLD,
OPT_FILELIST, OPT_FILELIST,
OPT_MAX OPT_VERSION,
OPT_HELP,
}; };
static_assert(OPT_MAX <= 32, "dwOptions is a unsigned int bitfield"); static_assert(OPT_FLAGS_MAX <= 32, "dwOptions is a unsigned int bitfield");
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -141,9 +143,6 @@ namespace
{ L"f", OPT_FORMAT }, { L"f", OPT_FORMAT },
{ L"if", OPT_FILTER }, { L"if", OPT_FILTER },
{ L"dword", OPT_DDS_DWORD_ALIGN }, { L"dword", OPT_DDS_DWORD_ALIGN },
{ L"badtails", OPT_DDS_BAD_DXTN_TAILS },
{ L"permissive", OPT_DDS_PERMISSIVE },
{ L"ignoremips", OPT_DDS_IGNORE_MIPS },
{ L"nologo", OPT_NOLOGO }, { L"nologo", OPT_NOLOGO },
{ L"o", OPT_OUTPUTFILE }, { L"o", OPT_OUTPUTFILE },
{ L"l", OPT_TOLOWER }, { L"l", OPT_TOLOWER },
@ -152,14 +151,44 @@ namespace
{ L"tu", OPT_TYPELESS_UNORM }, { L"tu", OPT_TYPELESS_UNORM },
{ L"tf", OPT_TYPELESS_FLOAT }, { L"tf", OPT_TYPELESS_FLOAT },
{ L"xlum", OPT_EXPAND_LUMINANCE }, { L"xlum", OPT_EXPAND_LUMINANCE },
{ L"targetx", OPT_TARGET_PIXELX },
{ L"targety", OPT_TARGET_PIXELY },
{ L"c", OPT_DIFF_COLOR }, { L"c", OPT_DIFF_COLOR },
{ L"t", OPT_THRESHOLD }, { L"t", OPT_THRESHOLD },
{ L"flist", OPT_FILELIST }, { L"flist", OPT_FILELIST },
// Deprecated options (recommend using new -- alternatives)
{ L"badtails", OPT_DDS_BAD_DXTN_TAILS },
{ L"permissive", OPT_DDS_PERMISSIVE },
{ L"ignoremips", OPT_DDS_IGNORE_MIPS },
{ L"targetx", OPT_TARGET_PIXELX },
{ L"targety", OPT_TARGET_PIXELY },
{ nullptr, 0 } { nullptr, 0 }
}; };
const SValue<uint32_t> g_pOptionsLong[] =
{
{ L"bad-tails", OPT_DDS_BAD_DXTN_TAILS },
{ L"dword-alignment", OPT_DDS_DWORD_ALIGN },
{ L"expand-luminance", OPT_EXPAND_LUMINANCE },
{ L"file-list", OPT_FILELIST },
{ L"file-type", OPT_FILETYPE },
{ L"format", OPT_FORMAT },
{ L"help", OPT_HELP },
{ L"ignore-mips", OPT_DDS_IGNORE_MIPS },
{ L"image-filter", OPT_FILTER },
{ L"overwrite", OPT_OVERWRITE },
{ L"permissive", OPT_DDS_PERMISSIVE },
{ L"target-x", OPT_TARGET_PIXELX },
{ L"target-y", OPT_TARGET_PIXELY },
{ L"to-lowercase", OPT_TOLOWER },
{ L"typeless-unorm", OPT_TYPELESS_UNORM },
{ L"typeless-float", OPT_TYPELESS_FLOAT },
{ L"version", OPT_VERSION },
{ L"diff-color", OPT_DIFF_COLOR },
{ L"threshold", OPT_THRESHOLD },
{ nullptr, 0 }
};
#define DEFFMT(fmt) { L## #fmt, DXGI_FORMAT_ ## fmt } #define DEFFMT(fmt) { L## #fmt, DXGI_FORMAT_ ## fmt }
const SValue<DXGI_FORMAT> g_pFormats[] = const SValue<DXGI_FORMAT> g_pFormats[] =
@ -350,18 +379,18 @@ namespace
{ nullptr, TEX_FILTER_DEFAULT } { nullptr, TEX_FILTER_DEFAULT }
}; };
#define CODEC_DDS 0xFFFF0001 constexpr uint32_t CODEC_DDS = 0xFFFF0001;
#define CODEC_TGA 0xFFFF0002 constexpr uint32_t CODEC_TGA = 0xFFFF0002;
#define CODEC_HDR 0xFFFF0005 constexpr uint32_t CODEC_HDR = 0xFFFF0005;
#ifdef USE_OPENEXR #ifdef USE_OPENEXR
#define CODEC_EXR 0xFFFF0006 constexpr uint32_t CODEC_EXR = 0xFFFF0008;
#endif #endif
#ifdef USE_LIBJPEG #ifdef USE_LIBJPEG
#define CODEC_JPEG 0xFFFF0007 constexpr uint32_t CODEC_JPEG = 0xFFFF0009;
#endif #endif
#ifdef USE_LIBPNG #ifdef USE_LIBPNG
#define CODEC_PNG 0xFFFF0008 constexpr uint32_t CODEC_PNG = 0xFFFF000A;
#endif #endif
const SValue<uint32_t> g_pDumpFileTypes[] = const SValue<uint32_t> g_pDumpFileTypes[] =
@ -425,42 +454,49 @@ namespace
static const wchar_t* const s_usage = static const wchar_t* const s_usage =
L"Usage: texdiag <command> <options> [--] <files>\n" L"Usage: texdiag <command> <options> [--] <files>\n"
L"\n" L"\nCOMMANDS\n"
L" info Output image metadata\n" L" info Output image metadata\n"
L" analyze Analyze and summarize image information\n" L" analyze Analyze and summarize image information\n"
L" compare Compare two images with MSE error metric\n" L" compare Compare two images with MSE error metric\n"
L" diff Generate difference image from two images\n" L" diff Generate difference image from two images\n"
L" dumpbc Dump out compressed blocks (DDS BC only)\n" L" dumpbc Dump out compressed blocks (DDS BC only)\n"
L" dumpdds Dump out all the images in a complex DDS\n" L" dumpdds Dump out all the images in a complex DDS\n"
L"\n" L"\nOPTIONS\n"
L" -r wildcard filename search is recursive\n" L" -r wildcard filename search is recursive\n"
L" -if <filter> image filtering\n" L" -flist <filename>, --file-list <filename>\n"
L" use text file with a list of input files (one per line)\n"
L"\n" L"\n"
L" (DDS input only)\n" L" -if <filter>, --image-filter <filter> image filtering\n"
L" -t{u|f} TYPELESS format is treated as UNORM or FLOAT\n"
L" -dword Use DWORD instead of BYTE alignment\n"
L" -badtails Fix for older DXTn with bad mipchain tails\n"
L" -permissive Allow some DX9 variants with unusual header values\n"
L" -ignoremips Reads just the top-level mip which reads some invalid files\n"
L" -xlum expand legacy L8, L16, and A8P8 formats\n"
L"\n" L"\n"
L" (diff only)\n" L" (DDS input only)\n"
L" -f <format> format\n" L" -tu, --typeless-unorm TYPELESS format is treated as UNORM\n"
L" -o <filename> output filename\n" L" -tf, --typeless-float TYPELESS format is treated as FLOAT\n"
L" -l force output filename to lower case\n" L" -dword, --dword-alignment Use DWORD instead of BYTE alignment\n"
L" -y overwrite existing output file (if any)\n" L" --bad-tails Fix for older DXTn with bad mipchain tails\n"
L" -c <hex-RGB> highlight difference color (defaults to off)\n" L" --permissive Allow some DX9 variants with unusual header values\n"
L" -t <threshold> highlight threshold (defaults to 0.25)\n" L" --ignore-mips Reads just the top-level mip which reads some invalid files\n"
L" -xlum, --expand-luminance Expand legacy L8, L16, and A8P8 formats\n"
L"\n"
L" (diff only)\n"
L" -f <format>, --format <format> pixel format for output\n"
L" -o <filename> output filename for diff\n"
L" -l, --to-lowercase force output filename to lower case\n"
L" -y, --overwrite overwrite existing output file (if any)\n"
L" -c <hex-RGB>, --diff-color <hex-RGB>\n"
L" highlight difference color (defaults to off)\n"
L" -t <threshold>, --threshold <threshold>\n"
L" highlight threshold (defaults to 0.25)\n"
L"\n" L"\n"
L" (dumpbc only)\n" L" (dumpbc only)\n"
L" -targetx <num> dump pixels at location x (defaults to all)\n" L" --target-x <num> dump pixels at location x (defaults to all)\n"
L" -targety <num> dump pixels at location y (defaults to all)\n" L" --target-y <num> dump pixels at location y (defaults to all)\n"
L"\n" L"\n"
L" (dumpdds only)\n" L" (dumpdds only)\n"
L" -ft <filetype> output file type\n" L" -o <path> output path for dumpdds\n"
L" -ft <filetype>, --file-type <filetype>\n"
" output file type\n"
L"\n" L"\n"
L" -nologo suppress copyright message\n" L" -nologo suppress copyright message\n"
L" -flist <filename> use text file with a list of input files (one per line)\n"
L"\n" L"\n"
L" '-- ' is needed if any input filepath starts with the '-' or '/' character\n"; L" '-- ' is needed if any input filepath starts with the '-' or '/' character\n";
@ -498,15 +534,15 @@ namespace
if (_wcsicmp(ext.c_str(), L".dds") == 0) if (_wcsicmp(ext.c_str(), L".dds") == 0)
{ {
DDS_FLAGS ddsFlags = DDS_FLAGS_ALLOW_LARGE_FILES; DDS_FLAGS ddsFlags = DDS_FLAGS_ALLOW_LARGE_FILES;
if (dwOptions & (1 << OPT_DDS_DWORD_ALIGN)) if (dwOptions & (UINT32_C(1) << OPT_DDS_DWORD_ALIGN))
ddsFlags |= DDS_FLAGS_LEGACY_DWORD; ddsFlags |= DDS_FLAGS_LEGACY_DWORD;
if (dwOptions & (1 << OPT_EXPAND_LUMINANCE)) if (dwOptions & (UINT32_C(1) << OPT_EXPAND_LUMINANCE))
ddsFlags |= DDS_FLAGS_EXPAND_LUMINANCE; ddsFlags |= DDS_FLAGS_EXPAND_LUMINANCE;
if (dwOptions & (1 << OPT_DDS_BAD_DXTN_TAILS)) if (dwOptions & (UINT32_C(1) << OPT_DDS_BAD_DXTN_TAILS))
ddsFlags |= DDS_FLAGS_BAD_DXTN_TAILS; ddsFlags |= DDS_FLAGS_BAD_DXTN_TAILS;
if (dwOptions & (1 << OPT_DDS_PERMISSIVE)) if (dwOptions & (UINT32_C(1) << OPT_DDS_PERMISSIVE))
ddsFlags |= DDS_FLAGS_PERMISSIVE; ddsFlags |= DDS_FLAGS_PERMISSIVE;
if (dwOptions & (1 << OPT_DDS_IGNORE_MIPS)) if (dwOptions & (UINT32_C(1) << OPT_DDS_IGNORE_MIPS))
ddsFlags |= DDS_FLAGS_IGNORE_MIPS; ddsFlags |= DDS_FLAGS_IGNORE_MIPS;
HRESULT hr = LoadFromDDSFile(fileName, ddsFlags, &info, *image); HRESULT hr = LoadFromDDSFile(fileName, ddsFlags, &info, *image);
@ -515,11 +551,11 @@ namespace
if (IsTypeless(info.format)) if (IsTypeless(info.format))
{ {
if (dwOptions & (1 << OPT_TYPELESS_UNORM)) if (dwOptions & (UINT32_C(1) << OPT_TYPELESS_UNORM))
{ {
info.format = MakeTypelessUNORM(info.format); info.format = MakeTypelessUNORM(info.format);
} }
else if (dwOptions & (1 << OPT_TYPELESS_FLOAT)) else if (dwOptions & (UINT32_C(1) << OPT_TYPELESS_FLOAT))
{ {
info.format = MakeTypelessFLOAT(info.format); info.format = MakeTypelessFLOAT(info.format);
} }
@ -1352,7 +1388,7 @@ namespace
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
#define SIGN_EXTEND(x,nb) ((((x)&(1<<((nb)-1)))?((~0)^((1<<(nb))-1)):0)|(x)) #define SIGN_EXTEND(x,nb) ((((x)&(1<<((nb)-1)))?((~0)^((1<<(nb))-1)):0)|(x))
#define NUM_PIXELS_PER_BLOCK 16 constexpr size_t NUM_PIXELS_PER_BLOCK = 16;
void Print565(uint16_t rgb) void Print565(uint16_t rgb)
{ {
@ -3062,54 +3098,92 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
std::list<SConversion> conversion; std::list<SConversion> conversion;
bool allowOpts = true; bool allowOpts = true;
for (int iArg = 2; iArg < argc; iArg++) for (int iArg = 2; iArg < argc; ++iArg)
{ {
PWSTR pArg = argv[iArg]; PWSTR pArg = argv[iArg];
if (allowOpts if (allowOpts && (('-' == pArg[0]) || ('/' == pArg[0])))
&& ('-' == pArg[0]) && ('-' == pArg[1]))
{ {
if (pArg[2] == 0) uint32_t dwOption = 0;
PWSTR pValue = nullptr;
if (('-' == pArg[0]) && ('-' == pArg[1]))
{ {
// "-- " is the POSIX standard for "end of options" marking to escape the '-' and '/' characters at the start of filepaths. if (pArg[2] == 0)
allowOpts = false; {
} // "-- " is the POSIX standard for "end of options" marking to escape the '-' and '/' characters at the start of filepaths.
else if (!_wcsicmp(pArg, L"--version")) allowOpts = false;
{ continue;
PrintLogo(true, g_ToolName, g_Description); }
return 0; else
} {
else if (!_wcsicmp(pArg, L"--help")) pArg += 2;
{
PrintUsage(); for (pValue = pArg; *pValue && (':' != *pValue) && ('=' != *pValue); ++pValue);
return 0;
if (*pValue)
*pValue++ = 0;
dwOption = LookupByName(pArg, g_pOptionsLong);
}
} }
else else
{ {
wprintf(L"Unknown option: %ls\n", pArg); pArg++;
return 1;
for (pValue = pArg; *pValue && (':' != *pValue) && ('=' != *pValue); ++pValue);
if (*pValue)
*pValue++ = 0;
dwOption = LookupByName(pArg, g_pOptions);
if (!dwOption)
{
if (LookupByName(pArg, g_pOptionsLong))
{
wprintf(L"ERROR: did you mean `--%ls` (with two dashes)?\n", pArg);
return 1;
}
}
} }
}
else if (allowOpts
&& (('-' == pArg[0]) || ('/' == pArg[0])))
{
pArg++;
PWSTR pValue;
for (pValue = pArg; *pValue && (':' != *pValue); pValue++); switch (dwOption)
if (*pValue)
*pValue++ = 0;
const uint32_t dwOption = LookupByName(pArg, g_pOptions);
if (!dwOption || (dwOptions & (1 << dwOption)))
{ {
PrintUsage(); case 0:
wprintf(L"ERROR: Unknown option: `%ls`\n\nUse %ls --help\n", pArg, g_ToolName);
return 1; return 1;
}
dwOptions |= 1 << dwOption; case OPT_FORMAT:
case OPT_FILTER:
case OPT_OUTPUTFILE:
case OPT_FILETYPE:
case OPT_TARGET_PIXELX:
case OPT_TARGET_PIXELY:
case OPT_DIFF_COLOR:
case OPT_THRESHOLD:
case OPT_FILELIST:
// These don't use flag bits
break;
case OPT_VERSION:
PrintLogo(true, g_ToolName, g_Description);
return 0;
case OPT_HELP:
PrintUsage();
return 0;
default:
if (dwOptions & (UINT32_C(1) << dwOption))
{
wprintf(L"ERROR: Duplicate option: `%ls`\n\n", pArg);
return 1;
}
dwOptions |= (UINT32_C(1) << dwOption);
break;
}
// Handle options with additional value parameter // Handle options with additional value parameter
switch (dwOption) switch (dwOption)
@ -3173,9 +3247,9 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
break; break;
case OPT_OUTPUTFILE: case OPT_OUTPUTFILE:
if (dwCommand != CMD_DIFF) if (dwCommand != CMD_DIFF && dwCommand != CMD_DUMPDDS)
{ {
wprintf(L"-o only valid for use with diff command\n"); wprintf(L"-o only valid for use with diff or dumpdds commands\n");
return 1; return 1;
} }
else else
@ -3183,7 +3257,10 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
std::filesystem::path path(pValue); std::filesystem::path path(pValue);
outputFile = path.make_preferred().native(); outputFile = path.make_preferred().native();
fileType = LookupByName(path.extension().c_str(), g_pExtFileTypes); if (dwCommand == CMD_DIFF)
{
fileType = LookupByName(path.extension().c_str(), g_pExtFileTypes);
}
} }
break; break;
@ -3198,8 +3275,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
fileType = LookupByName(pValue, g_pDumpFileTypes); fileType = LookupByName(pValue, g_pDumpFileTypes);
if (!fileType) if (!fileType)
{ {
wprintf(L"Invalid value specified with -ft (%ls)\n", pValue); wprintf(L"Invalid value specified with -ft (%ls)\n\n", pValue);
wprintf(L"\n");
PrintUsage(); PrintUsage();
return 1; return 1;
} }
@ -3277,7 +3353,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
{ {
const size_t count = conversion.size(); const size_t count = conversion.size();
std::filesystem::path path(pArg); std::filesystem::path path(pArg);
SearchForFiles(path.make_preferred(), conversion, (dwOptions & (1 << OPT_RECURSIVE)) != 0, nullptr); SearchForFiles(path.make_preferred(), conversion, (dwOptions & (UINT32_C(1) << OPT_RECURSIVE)) != 0, nullptr);
if (conversion.size() <= count) if (conversion.size() <= count)
{ {
wprintf(L"No matching files found for %ls\n", pArg); wprintf(L"No matching files found for %ls\n", pArg);
@ -3299,7 +3375,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
return 0; return 0;
} }
if (~dwOptions & (1 << OPT_NOLOGO)) if (~dwOptions & (UINT32_C(1) << OPT_NOLOGO))
PrintLogo(false, g_ToolName, g_Description); PrintLogo(false, g_ToolName, g_Description);
switch (dwCommand) switch (dwCommand)
@ -3380,12 +3456,12 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
return 1; return 1;
} }
if (dwOptions & (1 << OPT_TOLOWER)) if (dwOptions & (UINT32_C(1) << OPT_TOLOWER))
{ {
std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower); std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower);
} }
if (~dwOptions & (1 << OPT_OVERWRITE)) if (~dwOptions & (UINT32_C(1) << OPT_OVERWRITE))
{ {
if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES) if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES)
{ {
@ -3656,6 +3732,8 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
auto const ext = LookupByValue(fileType, g_pDumpFileTypes); auto const ext = LookupByValue(fileType, g_pDumpFileTypes);
std::filesystem::path basePath(outputFile);
if (info.depth > 1) if (info.depth > 1)
{ {
wprintf(L"Writing by mip (%3zu) and slice (%3zu)...", info.mipLevels, info.depth); wprintf(L"Writing by mip (%3zu) and slice (%3zu)...", info.mipLevels, info.depth);
@ -3684,10 +3762,11 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
swprintf_s(subFname, L"%ls_slice%03zu", curpath.stem().c_str(), slice); swprintf_s(subFname, L"%ls_slice%03zu", curpath.stem().c_str(), slice);
} }
outputFile.assign(subFname); std::filesystem::path output(basePath);
outputFile.append(ext); output.append(subFname);
output.replace_extension(ext);
hr = SaveImage(img, outputFile.c_str(), fileType); hr = SaveImage(img, output.c_str(), fileType);
if (FAILED(hr)) if (FAILED(hr))
{ {
wprintf(L" FAILED (%08X%ls)\n", static_cast<unsigned int>(hr), GetErrorDesc(hr)); wprintf(L" FAILED (%08X%ls)\n", static_cast<unsigned int>(hr), GetErrorDesc(hr));
@ -3728,10 +3807,11 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
swprintf_s(subFname, L"%ls_item%03zu", curpath.stem().c_str(), item); swprintf_s(subFname, L"%ls_item%03zu", curpath.stem().c_str(), item);
} }
outputFile.assign(subFname); std::filesystem::path output(basePath);
outputFile.append(ext); output.append(subFname);
output.replace_extension(ext);
hr = SaveImage(img, outputFile.c_str(), fileType); hr = SaveImage(img, output.c_str(), fileType);
if (FAILED(hr)) if (FAILED(hr))
{ {
wprintf(L" FAILED (%08X%ls)\n", static_cast<unsigned int>(hr), GetErrorDesc(hr)); wprintf(L" FAILED (%08X%ls)\n", static_cast<unsigned int>(hr), GetErrorDesc(hr));