Files
UnrealEngine/Engine/Source/ThirdParty/Windows/glTF-Toolkit/WindowsMRAssetConverter/CommandLine.cpp
2025-05-18 13:04:45 +08:00

292 lines
12 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
#include "stdafx.h"
#include "CommandLine.h"
#include "FileSystem.h"
// Constants
const wchar_t * PARAM_OUTFILE = L"-o";
const wchar_t * PARAM_TMPDIR = L"-temp-directory";
const wchar_t * PARAM_LOD = L"-lod";
const wchar_t * PARAM_SCREENCOVERAGE = L"-screen-coverage";
const wchar_t * PARAM_MAXTEXTURESIZE = L"-max-texture-size";
const wchar_t * PARAM_SHARE_MATERIALS = L"-share-materials";
const wchar_t * PARAM_MIN_VERSION = L"-min-version";
const wchar_t * PARAM_PLATFORM = L"-platform";
const wchar_t * PARAM_REPLACE_TEXTURES = L"-replace-textures";
const wchar_t * PARAM_COMPRESS_MESHES = L"-compress-meshes";
const wchar_t * PARAM_VALUE_VERSION_1709 = L"1709";
const wchar_t * PARAM_VALUE_VERSION_1803 = L"1803";
const wchar_t * PARAM_VALUE_VERSION_1809 = L"1809";
const wchar_t * PARAM_VALUE_VERSION_RS3 = L"rs3";
const wchar_t * PARAM_VALUE_VERSION_RS4 = L"rs4";
const wchar_t * PARAM_VALUE_VERSION_RS5 = L"rs5";
const wchar_t * PARAM_VALUE_VERSION_LATEST = L"latest";
const wchar_t * PARAM_VALUE_HOLOGRAPHIC = L"holographic";
const wchar_t * PARAM_VALUE_HOLOLENS= L"hololens";
const wchar_t * PARAM_VALUE_DESKTOP = L"desktop";
const wchar_t * PARAM_VALUE_PC = L"pc";
const wchar_t * PARAM_VALUE_ALL = L"all";
const wchar_t * SUFFIX_CONVERTED = L"_converted";
const wchar_t * CLI_INDENT = L" ";
const size_t MAXTEXTURESIZE_DEFAULT = 512;
const size_t MAXTEXTURESIZE_MAX = 4096;
const CommandLine::Version MIN_VERSION_DEFAULT = CommandLine::Version::Version1709;
const CommandLine::Platform PLATFORM_DEFAULT = CommandLine::Platform::Desktop;
enum class CommandLineParsingState
{
Initial,
InputRead,
ReadOutFile,
ReadTmpDir,
ReadLods,
ReadScreenCoverage,
ReadMaxTextureSize,
ReadMinVersion,
ReadPlatform
};
void CommandLine::PrintHelp()
{
auto indent = std::wstring(CLI_INDENT);
std::wcerr << std::endl
<< L"Windows Mixed Reality Asset Converter" << std::endl
<< L"=====================================" << std::endl
<< std::endl
<< L"A command line tool to convert core GLTF 2.0 assets for use in "
<< L"the Windows Mixed Reality home, with the proper texture packing, compression and merged LODs." << std::endl << std::endl
<< L"Usage: WindowsMRAssetConverter <path to GLTF/GLB>" << std::endl
<< std::endl
<< L"Optional arguments:" << std::endl
<< indent << "[" << std::wstring(PARAM_OUTFILE) << L" <output file path>]" << std::endl
<< indent << "[" << std::wstring(PARAM_TMPDIR) << L" <temporary folder>] - default is the system temp folder for the user" << std::endl
<< indent << "[" << std::wstring(PARAM_PLATFORM) << " <" << PARAM_VALUE_ALL << " | " << PARAM_VALUE_HOLOGRAPHIC << " | " << PARAM_VALUE_DESKTOP << ">] - defaults to " << PARAM_VALUE_DESKTOP << std::endl
<< indent << "[" << std::wstring(PARAM_MIN_VERSION) << " <" << PARAM_VALUE_VERSION_1709 << " | " << PARAM_VALUE_VERSION_1803 << " | " << PARAM_VALUE_VERSION_1809 << " | " << PARAM_VALUE_VERSION_LATEST << ">] - defaults to " << PARAM_VALUE_VERSION_1709 << std::endl
<< indent << "[" << std::wstring(PARAM_LOD) << " <path to each lower LOD asset in descending order of quality>]" << std::endl
<< indent << "[" << std::wstring(PARAM_SCREENCOVERAGE) << " <LOD screen coverage values>]" << std::endl
<< indent << "[" << std::wstring(PARAM_SHARE_MATERIALS) << "] - disabled if not present" << std::endl
<< indent << "[" << std::wstring(PARAM_MAXTEXTURESIZE) << " <Max texture size in pixels>] - defaults to 512" << std::endl
<< indent << "[" << std::wstring(PARAM_REPLACE_TEXTURES) << "] - disabled if not present" << std::endl
<< indent << "[" << std::wstring(PARAM_COMPRESS_MESHES) << "] - compress meshes with Draco" << std::endl
<< std::endl
<< "Example:" << std::endl
<< indent << "WindowsMRAssetConverter FileToConvert.gltf "
<< std::wstring(PARAM_OUTFILE) << " ConvertedFile.glb "
<< std::wstring(PARAM_LOD) << " Lod1.gltf Lod2.gltf "
<< std::wstring(PARAM_SCREENCOVERAGE) << " 0.5 0.2 0.01" << std::endl
<< std::endl
<< "The above will convert \"FileToConvert.gltf\" into \"ConvertedFile.glb\" in the "
<< "current directory." << std::endl
<< std::endl
<< "If the file is a GLB and the output name is not specified, defaults to the same name as input "
<< "+ \"_converted.glb\"." << std::endl
<< std::endl;
}
void CommandLine::ParseCommandLineArguments(
int argc, wchar_t *argv[],
std::wstring& inputFilePath, AssetType& inputAssetType, std::wstring& outFilePath, std::wstring& tempDirectory,
std::vector<std::wstring>& lodFilePaths, std::vector<double>& screenCoveragePercentages, size_t& maxTextureSize,
bool& shareMaterials, Version& minVersion, Platform& targetPlatforms, bool& replaceTextures, bool& compressMeshes)
{
CommandLineParsingState state = CommandLineParsingState::Initial;
inputFilePath = FileSystem::GetFullPath(std::wstring(argv[1]));
inputAssetType = AssetTypeUtils::AssetTypeFromFilePath(inputFilePath);
// Reset input parameters
outFilePath = L"";
tempDirectory = L"";
lodFilePaths.clear();
screenCoveragePercentages.clear();
maxTextureSize = MAXTEXTURESIZE_DEFAULT;
shareMaterials = false;
minVersion = MIN_VERSION_DEFAULT;
targetPlatforms = PLATFORM_DEFAULT;
replaceTextures = false;
compressMeshes = false;
state = CommandLineParsingState::InputRead;
std::wstring outFile;
std::wstring tmpDir;
for (int i = 2; i < argc; i++)
{
std::wstring param = argv[i];
if (param == PARAM_OUTFILE)
{
outFile = L"";
state = CommandLineParsingState::ReadOutFile;
}
else if (param == PARAM_TMPDIR)
{
tmpDir = L"";
state = CommandLineParsingState::ReadTmpDir;
}
else if (param == PARAM_LOD)
{
lodFilePaths.clear();
state = CommandLineParsingState::ReadLods;
}
else if (param == PARAM_SCREENCOVERAGE)
{
screenCoveragePercentages.clear();
state = CommandLineParsingState::ReadScreenCoverage;
}
else if (param == PARAM_MAXTEXTURESIZE)
{
maxTextureSize = MAXTEXTURESIZE_DEFAULT;
state = CommandLineParsingState::ReadMaxTextureSize;
}
else if (param == PARAM_SHARE_MATERIALS)
{
shareMaterials = true;
state = CommandLineParsingState::InputRead;
}
else if (param == PARAM_MIN_VERSION)
{
minVersion = MIN_VERSION_DEFAULT;
state = CommandLineParsingState::ReadMinVersion;
}
else if (param == PARAM_PLATFORM)
{
targetPlatforms = PLATFORM_DEFAULT;
state = CommandLineParsingState::ReadPlatform;
}
else if (param == PARAM_REPLACE_TEXTURES)
{
replaceTextures = true;
state = CommandLineParsingState::InputRead;
}
else if (param == PARAM_COMPRESS_MESHES)
{
if (minVersion >= CommandLine::Version::Version1809)
{
compressMeshes = true;
}
else
{
throw std::invalid_argument("Invalid min version specified with mesh compression; must be at least 1809.");
}
state = CommandLineParsingState::InputRead;
}
else
{
switch (state)
{
case CommandLineParsingState::ReadOutFile:
outFile = FileSystem::GetFullPath(param);
state = CommandLineParsingState::InputRead;
break;
case CommandLineParsingState::ReadTmpDir:
tmpDir = FileSystem::GetFullPath(param);
state = CommandLineParsingState::InputRead;
break;
case CommandLineParsingState::ReadLods:
lodFilePaths.push_back(FileSystem::GetFullPath(param));
break;
case CommandLineParsingState::ReadScreenCoverage:
{
auto paramA = std::string(param.begin(), param.end());
screenCoveragePercentages.push_back(std::atof(paramA.c_str()));
break;
}
case CommandLineParsingState::ReadMaxTextureSize:
maxTextureSize = std::min(static_cast<size_t>(std::stoul(param.c_str())), MAXTEXTURESIZE_MAX);
break;
case CommandLineParsingState::ReadMinVersion:
if (_wcsicmp(param.c_str(), PARAM_VALUE_VERSION_1709) == 0 || _wcsicmp(param.c_str(), PARAM_VALUE_VERSION_RS3) == 0)
{
minVersion = Version::Version1709;
}
else if (_wcsicmp(param.c_str(), PARAM_VALUE_VERSION_1803) == 0 || _wcsicmp(param.c_str(), PARAM_VALUE_VERSION_RS4) == 0)
{
minVersion = Version::Version1803;
}
else if (_wcsicmp(param.c_str(), PARAM_VALUE_VERSION_1809) == 0 || _wcsicmp(param.c_str(), PARAM_VALUE_VERSION_RS5) == 0)
{
minVersion = Version::Version1809;
}
else if (_wcsicmp(param.c_str(), PARAM_VALUE_VERSION_LATEST) == 0)
{
minVersion = Version::Latest;
}
else
{
throw std::invalid_argument("Invalid min version specified. For help, try the command again without parameters.");
}
state = CommandLineParsingState::InputRead;
break;
case CommandLineParsingState::ReadPlatform:
if (_wcsicmp(param.c_str(), PARAM_VALUE_ALL) == 0)
{
targetPlatforms = (Platform) (Platform::Desktop | Platform::Holographic);
}
else if (_wcsicmp(param.c_str(), PARAM_VALUE_HOLOGRAPHIC) == 0 || _wcsicmp(param.c_str(), PARAM_VALUE_HOLOLENS) == 0)
{
targetPlatforms = Platform::Holographic;
}
else if (_wcsicmp(param.c_str(), PARAM_VALUE_DESKTOP) == 0 || _wcsicmp(param.c_str(), PARAM_VALUE_PC) == 0)
{
targetPlatforms = Platform::Desktop;
}
else
{
throw std::invalid_argument("Invalid platform specified. For help, try the command again without parameters.");
}
state = CommandLineParsingState::InputRead;
break;
case CommandLineParsingState::Initial:
case CommandLineParsingState::InputRead:
default:
// Invalid argument detected
throw std::invalid_argument("Invalid usage. For help, try the command again without parameters.");
}
}
}
if (!std::experimental::filesystem::exists(inputFilePath))
{
throw std::invalid_argument("Input file not found.");
}
for (auto& lodFilePath : lodFilePaths)
{
if (!std::experimental::filesystem::exists(lodFilePath))
{
throw std::invalid_argument("Lod file not found.");
}
}
if (outFile.empty())
{
std::wstring inputFilePathWithoutExtension = inputFilePath;
if (FAILED(PathCchRemoveExtension(&inputFilePathWithoutExtension[0], inputFilePathWithoutExtension.length() + 1)))
{
throw std::invalid_argument("Invalid input file extension.");
}
outFile = std::wstring(&inputFilePathWithoutExtension[0]);
if (inputAssetType == AssetType::GLB)
{
outFile += SUFFIX_CONVERTED;
}
outFile += EXTENSION_GLB;
}
outFilePath = outFile;
if (tmpDir.empty())
{
tmpDir = FileSystem::CreateTempFolder();
}
tempDirectory = tmpDir;
}