Refactor command-line tools to use shared header (#514)
Some checks failed
MSBuild / build (Debug, ARM64, 2019) (push) Has been cancelled
CodeQL / Analyze (C/C++) (push) Has been cancelled
MSBuild / build (Debug, ARM64, 2022) (push) Has been cancelled
CMake (Windows) / build (amd64, x64-Debug, windows-2019) (push) Has been cancelled
CMake (Windows) / build (amd64, x64-Debug, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64, x64-Debug-Clang, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64, x64-Release, windows-2019) (push) Has been cancelled
CMake (Windows) / build (amd64, x64-Release, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64, x64-Release-Clang, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_arm64, arm64-Debug, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_arm64, arm64-Release, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_arm64, arm64ec-Debug, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_arm64, arm64ec-Release, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_x86, x86-Debug, windows-2019) (push) Has been cancelled
CMake (Windows) / build (amd64_x86, x86-Debug, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_x86, x86-Debug-Clang, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_x86, x86-Release, windows-2019) (push) Has been cancelled
CMake (Windows) / build (amd64_x86, x86-Release, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_x86, x86-Release-Clang, windows-2022) (push) Has been cancelled
MSBuild / build (Debug, x64, 2019) (push) Has been cancelled
MSBuild / build (Debug, x64, 2022) (push) Has been cancelled
MSBuild / build (Debug, x86, 2019) (push) Has been cancelled
MSBuild / build (Debug, x86, 2022) (push) Has been cancelled
MSBuild / build (Release, ARM64, 2019) (push) Has been cancelled
MSBuild / build (Release, ARM64, 2022) (push) Has been cancelled
MSBuild / build (Release, x64, 2019) (push) Has been cancelled
MSBuild / build (Release, x64, 2022) (push) Has been cancelled
MSBuild / build (Release, x86, 2019) (push) Has been cancelled
MSBuild / build (Release, x86, 2022) (push) Has been cancelled
Microsoft C++ Code Analysis / Analyze (push) Has been cancelled
CTest (Windows) / build (amd64, x64-Debug, windows-2019) (push) Has been cancelled
CTest (Windows) / build (amd64, x64-Debug, windows-2022) (push) Has been cancelled
CMake (Windows using VCPKG) / build (amd64_arm64, arm64-Debug-VCPKG, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64, x64-Debug-Clang, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64, x64-Release, windows-2019) (push) Has been cancelled
CTest (Windows) / build (amd64, x64-Release, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64, x64-Release-Clang, windows-2022) (push) Has been cancelled
CMake (Windows using VCPKG) / build (amd64_x86, x86-Debug-VCPKG, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_arm64, arm64-Debug, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_arm64, arm64-Release, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_arm64, arm64ec-Debug, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_arm64, arm64ec-Release, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_x86, x86-Debug, windows-2019) (push) Has been cancelled
CTest (Windows) / build (amd64_x86, x86-Debug, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_x86, x86-Debug-Clang, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_x86, x86-Release, windows-2019) (push) Has been cancelled
CTest (Windows) / build (amd64_x86, x86-Release, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_x86, x86-Release-Clang, windows-2022) (push) Has been cancelled
CMake (Windows using VCPKG) / build (amd64, x64-Debug-Clang-VCPKG, windows-2022) (push) Has been cancelled
CMake (Windows using VCPKG) / build (amd64, x64-Debug-VCPKG, windows-2019) (push) Has been cancelled
CMake (Windows using VCPKG) / build (amd64, x64-Debug-VCPKG, windows-2022) (push) Has been cancelled
CMake (WSL) / build (x64-Debug-Linux, 10) (push) Has been cancelled
CMake (WSL) / build (x64-Debug-Linux, 11) (push) Has been cancelled
CMake (WSL) / build (x64-Debug-Linux, 12) (push) Has been cancelled
CMake (WSL) / build (x64-Release-Linux, 10) (push) Has been cancelled
CMake (WSL) / build (x64-Release-Linux, 11) (push) Has been cancelled
CMake (WSL) / build (x64-Release-Linux, 12) (push) Has been cancelled

This commit is contained in:
Chuck Walbourn
2024-09-17 13:45:12 -07:00
committed by GitHub
parent 1deadd38ed
commit 73aa2f3c34
67 changed files with 1134 additions and 1605 deletions

View File

@@ -44,7 +44,6 @@
#include <locale>
#include <memory>
#include <new>
#include <set>
#include <string>
#include <tuple>
#include <utility>
@@ -76,11 +75,18 @@
#include "DirectXTexPNG.h"
#endif
#define TOOL_VERSION DIRECTX_TEX_VERSION
#include "CmdLineHelpers.h"
using namespace Helpers;
using namespace DirectX;
using Microsoft::WRL::ComPtr;
namespace
{
const wchar_t* g_ToolName = L"texassemble";
const wchar_t* g_Description = L"Microsoft (R) DirectX Texture Assembler [DirectXTex]";
enum COMMANDS : uint32_t
{
CMD_CUBE = 1,
@@ -137,22 +143,11 @@ namespace
static_assert(OPT_MAX <= 32, "dwOptions is a unsigned int bitfield");
struct SConversion
{
std::wstring szSrc;
};
struct SValue
{
const wchar_t* name;
uint32_t value;
};
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
const SValue g_pCommands[] =
const SValue<uint32_t> g_pCommands[] =
{
{ L"cube", CMD_CUBE },
{ L"volume", CMD_VOLUME },
@@ -177,7 +172,7 @@ namespace
{ nullptr, 0 }
};
const SValue g_pOptions[] =
const SValue<uint32_t> g_pOptions[] =
{
{ L"r", OPT_RECURSIVE },
{ L"flist", OPT_FILELIST },
@@ -206,9 +201,9 @@ namespace
{ nullptr, 0 }
};
#define DEFFMT(fmt) { L## #fmt, DXGI_FORMAT_ ## fmt }
#define DEFFMT(fmt) { L## #fmt, DXGI_FORMAT_ ## fmt }
const SValue g_pFormats[] =
const SValue<DXGI_FORMAT> g_pFormats[] =
{
// List does not include _TYPELESS or depth/stencil formats
DEFFMT(R32G32B32A32_FLOAT),
@@ -285,7 +280,9 @@ namespace
{ nullptr, DXGI_FORMAT_UNKNOWN }
};
const SValue g_pFormatAliases[] =
#undef DEFFMT
const SValue<DXGI_FORMAT> g_pFormatAliases[] =
{
{ L"RGBA", DXGI_FORMAT_R8G8B8A8_UNORM },
{ L"BGRA", DXGI_FORMAT_B8G8R8A8_UNORM },
@@ -297,7 +294,7 @@ namespace
{ nullptr, DXGI_FORMAT_UNKNOWN }
};
const SValue g_pFilters[] =
const SValue<uint32_t> g_pFilters[] =
{
{ L"POINT", TEX_FILTER_POINT },
{ L"LINEAR", TEX_FILTER_LINEAR },
@@ -320,21 +317,21 @@ namespace
{ nullptr, TEX_FILTER_DEFAULT }
};
#define CODEC_DDS 0xFFFF0001
#define CODEC_TGA 0xFFFF0002
#define CODEC_HDR 0xFFFF0005
#define CODEC_DDS 0xFFFF0001
#define CODEC_TGA 0xFFFF0002
#define CODEC_HDR 0xFFFF0005
#ifdef USE_OPENEXR
#define CODEC_EXR 0xFFFF0006
#endif
#ifdef USE_LIBJPEG
#define CODEC_JPEG 0xFFFF0007
#endif
#ifdef USE_LIBPNG
#define CODEC_PNG 0xFFFF0008
#endif
#ifdef USE_OPENEXR
#define CODEC_EXR 0xFFFF0006
#endif
#ifdef USE_LIBJPEG
#define CODEC_JPEG 0xFFFF0007
#endif
#ifdef USE_LIBPNG
#define CODEC_PNG 0xFFFF0008
#endif
const SValue g_pExtFileTypes[] =
const SValue<uint32_t> g_pExtFileTypes[] =
{
{ L".BMP", WIC_CODEC_BMP },
#ifdef USE_LIBJPEG
@@ -363,7 +360,7 @@ namespace
{ nullptr, CODEC_DDS }
};
const SValue g_pFeatureLevels[] = // valid feature levels for -fl for maximimum size
const SValue<uint32_t> g_pFeatureLevels[] = // valid feature levels for -fl for maximimum size
{
{ L"9.1", 2048 },
{ L"9.2", 2048 },
@@ -378,7 +375,7 @@ namespace
{ nullptr, 0 },
};
const SValue g_pFeatureLevelsCube[] = // valid feature levels for -fl for maximum cubemap size
const SValue<uint32_t> g_pFeatureLevelsCube[] = // valid feature levels for -fl for maximum cubemap size
{
{ L"9.1", 512 },
{ L"9.2", 512 },
@@ -393,7 +390,7 @@ namespace
{ nullptr, 0 },
};
const SValue g_pFeatureLevelsArray[] = // valid feature levels for -fl for maximum array size
const SValue<uint32_t> g_pFeatureLevelsArray[] = // valid feature levels for -fl for maximum array size
{
{ L"9.1", 1 },
{ L"9.2", 1 },
@@ -408,7 +405,7 @@ namespace
{ nullptr, 0 },
};
const SValue g_pFeatureLevelsVolume[] = // valid feature levels for -fl for maximum depth size
const SValue<uint32_t> g_pFeatureLevelsVolume[] = // valid feature levels for -fl for maximum depth size
{
{ L"9.1", 256 },
{ L"9.2", 256 },
@@ -438,183 +435,6 @@ HRESULT LoadAnimatedGif(const wchar_t* szFile,
namespace
{
inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
struct find_closer { void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };
using ScopedFindHandle = std::unique_ptr<void, find_closer>;
#ifdef _PREFAST_
#pragma prefast(disable : 26018, "Only used with static internal arrays")
#endif
uint32_t LookupByName(const wchar_t *pName, const SValue *pArray)
{
while (pArray->name)
{
if (!_wcsicmp(pName, pArray->name))
return pArray->value;
pArray++;
}
return 0;
}
void SearchForFiles(const std::filesystem::path& path, std::list<SConversion>& files, bool recursive)
{
// Process files
WIN32_FIND_DATAW findData = {};
ScopedFindHandle hFile(safe_handle(FindFirstFileExW(path.c_str(),
FindExInfoBasic, &findData,
FindExSearchNameMatch, nullptr,
FIND_FIRST_EX_LARGE_FETCH)));
if (hFile)
{
for (;;)
{
if (!(findData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)))
{
SConversion conv = {};
conv.szSrc = path.parent_path().append(findData.cFileName).native();
files.push_back(conv);
}
if (!FindNextFileW(hFile.get(), &findData))
break;
}
}
// Process directories
if (recursive)
{
auto searchDir = path.parent_path().append(L"*");
hFile.reset(safe_handle(FindFirstFileExW(searchDir.c_str(),
FindExInfoBasic, &findData,
FindExSearchLimitToDirectories, nullptr,
FIND_FIRST_EX_LARGE_FETCH)));
if (!hFile)
return;
for (;;)
{
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (findData.cFileName[0] != L'.')
{
auto subdir = path.parent_path().append(findData.cFileName).append(path.filename().c_str());
SearchForFiles(subdir, files, recursive);
}
}
if (!FindNextFileW(hFile.get(), &findData))
break;
}
}
}
void ProcessFileList(std::wifstream& inFile, std::list<SConversion>& files)
{
std::list<SConversion> flist;
std::set<std::wstring> excludes;
for (;;)
{
std::wstring fname;
std::getline(inFile, fname);
if (!inFile)
break;
if (fname[0] == L'#')
{
// Comment
}
else if (fname[0] == L'-')
{
if (flist.empty())
{
wprintf(L"WARNING: Ignoring the line '%ls' in -flist\n", fname.c_str());
}
else
{
std::filesystem::path path(fname.c_str() + 1);
auto& npath = path.make_preferred();
if (wcspbrk(fname.c_str(), L"?*") != nullptr)
{
std::list<SConversion> removeFiles;
SearchForFiles(npath, removeFiles, false);
for (auto& it : removeFiles)
{
std::wstring name = it.szSrc;
std::transform(name.begin(), name.end(), name.begin(), towlower);
excludes.insert(name);
}
}
else
{
std::wstring name = npath.c_str();
std::transform(name.begin(), name.end(), name.begin(), towlower);
excludes.insert(name);
}
}
}
else if (wcspbrk(fname.c_str(), L"?*") != nullptr)
{
std::filesystem::path path(fname.c_str());
SearchForFiles(path.make_preferred(), flist, false);
}
else
{
SConversion conv = {};
std::filesystem::path path(fname.c_str());
conv.szSrc = path.make_preferred().native();
flist.push_back(conv);
}
}
inFile.close();
if (!excludes.empty())
{
// Remove any excluded files
for (auto it = flist.begin(); it != flist.end();)
{
std::wstring name = it->szSrc;
std::transform(name.begin(), name.end(), name.begin(), towlower);
auto item = it;
++it;
if (excludes.find(name) != excludes.end())
{
flist.erase(item);
}
}
}
if (flist.empty())
{
wprintf(L"WARNING: No file names found in -flist\n");
}
else
{
files.splice(files.end(), flist);
}
}
void PrintFormat(DXGI_FORMAT Format)
{
for (auto pFormat = g_pFormats; pFormat->name; pFormat++)
{
if (static_cast<DXGI_FORMAT>(pFormat->value) == Format)
{
wprintf(L"%ls", pFormat->name);
break;
}
}
}
void PrintInfo(const TexMetadata& info)
{
wprintf(L" (%zux%zu", info.width, info.height);
@@ -629,7 +449,7 @@ namespace
wprintf(L",%zu", info.arraySize);
wprintf(L" ");
PrintFormat(info.format);
PrintFormat(info.format, g_pFormats);
switch (info.dimension)
{
@@ -674,109 +494,9 @@ namespace
wprintf(L")");
}
void PrintList(size_t cch, const SValue *pValue)
{
while (pValue->name)
{
const size_t cchName = wcslen(pValue->name);
if (cch + cchName + 2 >= 80)
{
wprintf(L"\n ");
cch = 6;
}
wprintf(L"%ls ", pValue->name);
cch += cchName + 2;
pValue++;
}
wprintf(L"\n");
}
void PrintLogo(bool versionOnly)
{
wchar_t version[32] = {};
wchar_t appName[_MAX_PATH] = {};
if (GetModuleFileNameW(nullptr, appName, _MAX_PATH))
{
const DWORD size = GetFileVersionInfoSizeW(appName, nullptr);
if (size > 0)
{
auto verInfo = std::make_unique<uint8_t[]>(size);
if (GetFileVersionInfoW(appName, 0, size, verInfo.get()))
{
LPVOID lpstr = nullptr;
UINT strLen = 0;
if (VerQueryValueW(verInfo.get(), L"\\StringFileInfo\\040904B0\\ProductVersion", &lpstr, &strLen))
{
wcsncpy_s(version, reinterpret_cast<const wchar_t*>(lpstr), strLen);
}
}
}
}
if (!*version || wcscmp(version, L"1.0.0.0") == 0)
{
swprintf_s(version, L"%03d (library)", DIRECTX_TEX_VERSION);
}
if (versionOnly)
{
wprintf(L"texassemble version %ls\n", version);
}
else
{
wprintf(L"Microsoft (R) DirectX Texture Assembler [DirectXTex] Version %ls\n", version);
wprintf(L"Copyright (C) Microsoft Corp.\n");
#ifdef _DEBUG
wprintf(L"*** Debug build ***\n");
#endif
wprintf(L"\n");
}
}
const wchar_t* GetErrorDesc(HRESULT hr)
{
static wchar_t desc[1024] = {};
LPWSTR errorText = nullptr;
const DWORD result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
nullptr, static_cast<DWORD>(hr),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&errorText), 0, nullptr);
*desc = 0;
if (result > 0 && errorText)
{
swprintf_s(desc, L": %ls", errorText);
size_t len = wcslen(desc);
if (len >= 1)
{
desc[len - 1] = 0;
}
if (errorText)
LocalFree(errorText);
for (wchar_t* ptr = desc; *ptr != 0; ++ptr)
{
if (*ptr == L'\r' || *ptr == L'\n')
{
*ptr = L' ';
}
}
}
return desc;
}
void PrintUsage()
{
PrintLogo(false);
PrintLogo(false, g_ToolName, g_Description);
static const wchar_t* const s_usage =
L"Usage: texassemble <command> <options> [--] <files>\n"
@@ -1059,7 +779,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
{
if (!_wcsicmp(argv[1], L"--version"))
{
PrintLogo(true);
PrintLogo(true, g_ToolName, g_Description);
return 0;
}
else if (!_wcsicmp(argv[1], L"--help"))
@@ -1118,7 +838,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
}
else if (!_wcsicmp(pArg, L"--version"))
{
PrintLogo(true);
PrintLogo(true, g_ToolName, g_Description);
return 0;
}
else if (!_wcsicmp(pArg, L"--help"))
@@ -1372,7 +1092,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
{
const size_t count = conversion.size();
std::filesystem::path path(pArg);
SearchForFiles(path.make_preferred(), conversion, (dwOptions & (1 << OPT_RECURSIVE)) != 0);
SearchForFiles(path.make_preferred(), conversion, (dwOptions & (1 << OPT_RECURSIVE)) != 0, nullptr);
if (conversion.size() <= count)
{
wprintf(L"No matching files found for %ls\n", pArg);
@@ -1395,7 +1115,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
}
if (~dwOptions & (1 << OPT_NOLOGO))
PrintLogo(false);
PrintLogo(false, g_ToolName, g_Description);
switch (dwCommand)
{