From e35e84f6e10245ebe4e3805bafd761ad2583ef14 Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Mon, 12 Sep 2016 21:54:08 -0700 Subject: [PATCH] texassemble/texconv: added wildcard support --- Texassemble/texassemble.cpp | 99 ++++++++++++++++++++++++++++++++++++- Texconv/texconv.cpp | 97 +++++++++++++++++++++++++++++++++++- 2 files changed, 194 insertions(+), 2 deletions(-) diff --git a/Texassemble/texassemble.cpp b/Texassemble/texassemble.cpp index a5be525..b4575c3 100644 --- a/Texassemble/texassemble.cpp +++ b/Texassemble/texassemble.cpp @@ -34,7 +34,8 @@ using namespace DirectX; enum OPTIONS { - OPT_CUBE = 1, + OPT_RECURSIVE = 1, + OPT_CUBE, OPT_VOLUME, OPT_ARRAY, OPT_CUBEARRAY, @@ -68,6 +69,7 @@ struct SValue SValue g_pOptions[] = { + { L"r", OPT_RECURSIVE }, { L"cube", OPT_CUBE }, { L"volume", OPT_VOLUME }, { L"array", OPT_ARRAY }, @@ -181,6 +183,12 @@ SValue g_pFilters[] = namespace { + inline HANDLE safe_handle(HANDLE h) { return (h == INVALID_HANDLE_VALUE) ? 0 : h; } + + struct find_closer { void operator()(HANDLE h) { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } }; + + typedef public std::unique_ptr ScopedFindHandle; + #pragma prefast(disable : 26018, "Only used with static internal arrays") DWORD LookupByName(const wchar_t *pName, const SValue *pArray) @@ -196,6 +204,7 @@ namespace return 0; } + const wchar_t* LookupByValue(DWORD pValue, const SValue *pArray) { while (pArray->pName) @@ -209,6 +218,82 @@ namespace return L""; } + + void SearchForFiles(const wchar_t* path, std::list& files, bool recursive) + { + // Process files + WIN32_FIND_DATA findData = {}; + ScopedFindHandle hFile(safe_handle(FindFirstFileExW(path, + FindExInfoBasic, &findData, + FindExSearchNameMatch, nullptr, + FIND_FIRST_EX_LARGE_FETCH))); + if (hFile) + { + for (;;) + { + if (!(findData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY))) + { + wchar_t drive[_MAX_DRIVE] = {}; + wchar_t dir[_MAX_DIR] = {}; + _wsplitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0); + + SConversion conv; + _wmakepath_s(conv.szSrc, drive, dir, findData.cFileName, nullptr); + files.push_back(conv); + } + + if (!FindNextFile(hFile.get(), &findData)) + break; + } + } + + // Process directories + if (recursive) + { + wchar_t searchDir[MAX_PATH] = {}; + { + wchar_t drive[_MAX_DRIVE] = {}; + wchar_t dir[_MAX_DIR] = {}; + _wsplitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0); + _wmakepath_s(searchDir, drive, dir, L"*", nullptr); + } + + hFile.reset(safe_handle(FindFirstFileExW(searchDir, + FindExInfoBasic, &findData, + FindExSearchLimitToDirectories, nullptr, + FIND_FIRST_EX_LARGE_FETCH))); + if (!hFile) + return; + + for (;;) + { + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (findData.cFileName[0] != L'.') + { + wchar_t subdir[MAX_PATH] = {}; + + { + wchar_t drive[_MAX_DRIVE] = {}; + wchar_t dir[_MAX_DIR] = {}; + wchar_t fname[_MAX_FNAME] = {}; + wchar_t ext[_MAX_FNAME] = {}; + _wsplitpath_s(path, drive, dir, fname, ext); + wcscat_s(dir, findData.cFileName); + _wmakepath_s(subdir, drive, dir, fname, ext); + } + + SearchForFiles(subdir, files, recursive); + } + } + + if (!FindNextFile(hFile.get(), &findData)) + break; + } + } + } + + void PrintFormat(DXGI_FORMAT Format) { for (SValue *pFormat = g_pFormats; pFormat->pName; pFormat++) @@ -221,6 +306,7 @@ namespace } } + void PrintInfo(const TexMetadata& info) { wprintf(L" (%Iux%Iu", info.width, info.height); @@ -298,6 +384,7 @@ namespace wprintf(L"Usage: texassemble [-cube | - volume | -array | -cubearray] \n"); wprintf(L"\n"); + wprintf(L" -r wildcard filename search is recursive\n"); wprintf(L" -cube create cubemap\n"); wprintf(L" -volume create volume map\n"); wprintf(L" -array create texture array\n"); @@ -441,6 +528,16 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) break; } } + else if (wcspbrk(pArg, L"?*") != nullptr) + { + size_t count = conversion.size(); + SearchForFiles(pArg, conversion, (dwOptions & (1 << OPT_RECURSIVE)) != 0); + if (conversion.size() <= count) + { + wprintf(L"No matching files found for %ls\n", pArg); + return 1; + } + } else { SConversion conv; diff --git a/Texconv/texconv.cpp b/Texconv/texconv.cpp index b8310de..9e99456 100644 --- a/Texconv/texconv.cpp +++ b/Texconv/texconv.cpp @@ -40,7 +40,8 @@ using Microsoft::WRL::ComPtr; enum OPTIONS { - OPT_WIDTH = 1, + OPT_RECURSIVE = 1, + OPT_WIDTH, OPT_HEIGHT, OPT_MIPLEVELS, OPT_FORMAT, @@ -96,12 +97,14 @@ struct SValue DWORD dwValue; }; + ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// SValue g_pOptions[] = { + { L"r", OPT_RECURSIVE }, { L"w", OPT_WIDTH }, { L"h", OPT_HEIGHT }, { L"m", OPT_MIPLEVELS }, @@ -345,6 +348,12 @@ SValue g_pFeatureLevels[] = // valid feature levels for -fl for maximimum si namespace { + inline HANDLE safe_handle(HANDLE h) { return (h == INVALID_HANDLE_VALUE) ? 0 : h; } + + struct find_closer { void operator()(HANDLE h) { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } }; + + typedef public std::unique_ptr ScopedFindHandle; + inline static bool ispow2(size_t x) { return ((x != 0) && !(x & (x - 1))); @@ -380,6 +389,81 @@ namespace } + void SearchForFiles(const wchar_t* path, std::list& files, bool recursive) + { + // Process files + WIN32_FIND_DATA findData = {}; + ScopedFindHandle hFile(safe_handle(FindFirstFileExW(path, + FindExInfoBasic, &findData, + FindExSearchNameMatch, nullptr, + FIND_FIRST_EX_LARGE_FETCH))); + if (hFile) + { + for (;;) + { + if (!(findData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY))) + { + wchar_t drive[_MAX_DRIVE] = {}; + wchar_t dir[_MAX_DIR] = {}; + _wsplitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0); + + SConversion conv; + _wmakepath_s(conv.szSrc, drive, dir, findData.cFileName, nullptr); + files.push_back(conv); + } + + if (!FindNextFile(hFile.get(), &findData)) + break; + } + } + + // Process directories + if (recursive) + { + wchar_t searchDir[MAX_PATH] = {}; + { + wchar_t drive[_MAX_DRIVE] = {}; + wchar_t dir[_MAX_DIR] = {}; + _wsplitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0); + _wmakepath_s(searchDir, drive, dir, L"*", nullptr); + } + + hFile.reset(safe_handle(FindFirstFileExW(searchDir, + FindExInfoBasic, &findData, + FindExSearchLimitToDirectories, nullptr, + FIND_FIRST_EX_LARGE_FETCH))); + if (!hFile) + return; + + for (;;) + { + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (findData.cFileName[0] != L'.') + { + wchar_t subdir[MAX_PATH] = {}; + + { + wchar_t drive[_MAX_DRIVE] = {}; + wchar_t dir[_MAX_DIR] = {}; + wchar_t fname[_MAX_FNAME] = {}; + wchar_t ext[_MAX_FNAME] = {}; + _wsplitpath_s(path, drive, dir, fname, ext); + wcscat_s(dir, findData.cFileName); + _wmakepath_s(subdir, drive, dir, fname, ext); + } + + SearchForFiles(subdir, files, recursive); + } + } + + if (!FindNextFile(hFile.get(), &findData)) + break; + } + } + } + + void PrintFormat(DXGI_FORMAT Format) { for (SValue *pFormat = g_pFormats; pFormat->pName; pFormat++) @@ -511,6 +595,7 @@ namespace wprintf(L"Usage: texconv \n"); wprintf(L"\n"); + wprintf(L" -r wildcard filename search is recursive\n"); wprintf(L" -w width\n"); wprintf(L" -h height\n"); wprintf(L" -m miplevels\n"); @@ -1096,6 +1181,16 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) break; } } + else if (wcspbrk(pArg, L"?*") != nullptr) + { + size_t count = conversion.size(); + SearchForFiles(pArg, conversion, (dwOptions & (1 << OPT_RECURSIVE)) != 0); + if (conversion.size() <= count) + { + wprintf(L"No matching files found for %ls\n", pArg); + return 1; + } + } else { SConversion conv;