mirror of https://github.com/AxioDL/metaforce.git
Merge branch 'master' of ssh://git.axiodl.com:6431/AxioDL/hecl
This commit is contained in:
commit
c180cbd529
|
@ -88,7 +88,7 @@ protected:
|
|||
}
|
||||
|
||||
public:
|
||||
ToolBase(const ToolPassInfo& info) : m_info(info) {
|
||||
explicit ToolBase(const ToolPassInfo& info) : m_info(info) {
|
||||
hecl::VerbosityLevel = info.verbosityLevel;
|
||||
hecl::GuiMode = info.gui;
|
||||
}
|
||||
|
@ -96,15 +96,15 @@ public:
|
|||
virtual hecl::SystemString toolName() const = 0;
|
||||
virtual int run() = 0;
|
||||
virtual void cancel() {}
|
||||
inline operator bool() const { return m_good; }
|
||||
explicit operator bool() const { return m_good; }
|
||||
};
|
||||
|
||||
class HelpOutput {
|
||||
public:
|
||||
typedef void (*HelpFunc)(HelpOutput&);
|
||||
using HelpFunc = void (*)(HelpOutput&);
|
||||
|
||||
private:
|
||||
FILE* m_sout;
|
||||
FILE* m_sout = nullptr;
|
||||
HelpFunc m_helpFunc;
|
||||
int m_lineWidth;
|
||||
hecl::SystemString m_wrapBuffer;
|
||||
|
@ -156,8 +156,8 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
HelpOutput(HelpFunc helpFunc)
|
||||
: m_sout(NULL), m_helpFunc(helpFunc), m_lineWidth(hecl::GuiMode ? 120 : hecl::ConsoleWidth()) {}
|
||||
explicit HelpOutput(HelpFunc helpFunc)
|
||||
: m_helpFunc(helpFunc), m_lineWidth(hecl::GuiMode ? 120 : hecl::ConsoleWidth()) {}
|
||||
|
||||
void go() {
|
||||
#if _WIN32
|
||||
|
|
|
@ -13,7 +13,7 @@ class ToolCook final : public ToolBase {
|
|||
bool m_fast = false;
|
||||
|
||||
public:
|
||||
ToolCook(const ToolPassInfo& info) : ToolBase(info), m_useProj(info.project) {
|
||||
explicit ToolCook(const ToolPassInfo& info) : ToolBase(info), m_useProj(info.project) {
|
||||
/* Check for recursive flag */
|
||||
for (hecl::SystemChar arg : info.flags)
|
||||
if (arg == _SYS_STR('r'))
|
||||
|
@ -145,9 +145,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
hecl::SystemString toolName() const { return _SYS_STR("cook"); }
|
||||
hecl::SystemString toolName() const override { return _SYS_STR("cook"); }
|
||||
|
||||
int run() {
|
||||
int run() override {
|
||||
hecl::MultiProgressPrinter printer(true);
|
||||
hecl::ClientProcess cp(&printer);
|
||||
for (const hecl::ProjectPath& path : m_selectedItems)
|
||||
|
@ -156,5 +156,5 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
void cancel() { m_useProj->interruptCook(); }
|
||||
void cancel() override { m_useProj->interruptCook(); }
|
||||
};
|
||||
|
|
|
@ -27,7 +27,7 @@ class ToolExtract final : public ToolBase {
|
|||
hecl::Database::Project* m_useProj = nullptr;
|
||||
|
||||
public:
|
||||
ToolExtract(const ToolPassInfo& info) : ToolBase(info) {
|
||||
explicit ToolExtract(const ToolPassInfo& info) : ToolBase(info) {
|
||||
if (!m_info.args.size())
|
||||
LogModule.report(logvisor::Fatal, fmt("hecl extract needs a source path as its first argument"));
|
||||
|
||||
|
@ -112,7 +112,7 @@ public:
|
|||
help.endWrap();
|
||||
}
|
||||
|
||||
hecl::SystemString toolName() const { return _SYS_STR("extract"); }
|
||||
hecl::SystemString toolName() const override { return _SYS_STR("extract"); }
|
||||
|
||||
static void _recursivePrint(int level, hecl::Database::IDataSpec::ExtractReport& rep) {
|
||||
for (int l = 0; l < level; ++l)
|
||||
|
@ -129,7 +129,7 @@ public:
|
|||
_recursivePrint(level + 1, child);
|
||||
}
|
||||
|
||||
int run() {
|
||||
int run() override {
|
||||
if (m_specPasses.empty()) {
|
||||
if (XTERM_COLOR)
|
||||
fmt::print(fmt(_SYS_STR("" RED BOLD "NOTHING TO EXTRACT" NORMAL "\n")));
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
class ToolHelp final : public ToolBase {
|
||||
|
||||
public:
|
||||
ToolHelp(const ToolPassInfo& info) : ToolBase(info) {
|
||||
explicit ToolHelp(const ToolPassInfo& info) : ToolBase(info) {
|
||||
if (m_info.args.empty()) {
|
||||
LogModule.report(logvisor::Error, fmt("help requires a tool name argument"));
|
||||
return;
|
||||
|
@ -15,7 +15,7 @@ public:
|
|||
m_good = true;
|
||||
}
|
||||
|
||||
~ToolHelp() {}
|
||||
~ToolHelp() override = default;
|
||||
|
||||
static void Help(HelpOutput& help) {
|
||||
help.printBold(
|
||||
|
@ -50,7 +50,7 @@ public:
|
|||
|
||||
static void ShowHelp(const hecl::SystemString& toolName) {
|
||||
/* Select tool's help-text streamer */
|
||||
HelpOutput::HelpFunc helpFunc = NULL;
|
||||
HelpOutput::HelpFunc helpFunc = nullptr;
|
||||
if (toolName == _SYS_STR("init"))
|
||||
helpFunc = ToolInit::Help;
|
||||
else if (toolName == _SYS_STR("spec"))
|
||||
|
@ -72,9 +72,9 @@ public:
|
|||
ho.go();
|
||||
}
|
||||
|
||||
hecl::SystemString toolName() const { return _SYS_STR("help"); }
|
||||
hecl::SystemString toolName() const override { return _SYS_STR("help"); }
|
||||
|
||||
int run() {
|
||||
int run() override {
|
||||
ShowHelp(m_info.args.front());
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ class ToolImage final : public ToolBase {
|
|||
hecl::Database::Project* m_useProj;
|
||||
|
||||
public:
|
||||
ToolImage(const ToolPassInfo& info) : ToolBase(info), m_useProj(info.project) {
|
||||
explicit ToolImage(const ToolPassInfo& info) : ToolBase(info), m_useProj(info.project) {
|
||||
if (!info.project)
|
||||
LogModule.report(logvisor::Fatal, fmt("hecl image must be ran within a project directory"));
|
||||
|
||||
|
@ -44,7 +44,7 @@ public:
|
|||
"provided a path within a project"));
|
||||
}
|
||||
|
||||
~ToolImage() {}
|
||||
~ToolImage() override = default;
|
||||
|
||||
static void Help(HelpOutput& help) {
|
||||
help.secHead(_SYS_STR("NAME"));
|
||||
|
@ -71,9 +71,9 @@ public:
|
|||
help.endWrap();
|
||||
}
|
||||
|
||||
hecl::SystemString toolName() const { return _SYS_STR("image"); }
|
||||
hecl::SystemString toolName() const override { return _SYS_STR("image"); }
|
||||
|
||||
int run() {
|
||||
int run() override {
|
||||
if (XTERM_COLOR)
|
||||
fmt::print(fmt(_SYS_STR("" GREEN BOLD "ABOUT TO IMAGE:" NORMAL "\n")));
|
||||
else
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
#include <cstdio>
|
||||
|
||||
class ToolInit final : public ToolBase {
|
||||
const hecl::SystemString* m_dir = NULL;
|
||||
const hecl::SystemString* m_dir = nullptr;
|
||||
|
||||
public:
|
||||
ToolInit(const ToolPassInfo& info) : ToolBase(info) {
|
||||
explicit ToolInit(const ToolPassInfo& info) : ToolBase(info) {
|
||||
hecl::Sstat theStat;
|
||||
const hecl::SystemString* dir;
|
||||
if (info.args.size())
|
||||
|
@ -36,7 +36,7 @@ public:
|
|||
m_dir = dir;
|
||||
}
|
||||
|
||||
int run() {
|
||||
int run() override {
|
||||
if (!m_dir)
|
||||
return 1;
|
||||
size_t ErrorRef = logvisor::ErrorCount;
|
||||
|
@ -73,5 +73,5 @@ public:
|
|||
help.endWrap();
|
||||
}
|
||||
|
||||
hecl::SystemString toolName() const { return _SYS_STR("init"); }
|
||||
hecl::SystemString toolName() const override { return _SYS_STR("init"); }
|
||||
};
|
||||
|
|
|
@ -59,7 +59,7 @@ class ToolPackage final : public ToolBase {
|
|||
}
|
||||
|
||||
public:
|
||||
ToolPackage(const ToolPassInfo& info) : ToolBase(info), m_useProj(info.project) {
|
||||
explicit ToolPackage(const ToolPassInfo& info) : ToolBase(info), m_useProj(info.project) {
|
||||
if (!info.project)
|
||||
LogModule.report(logvisor::Fatal, fmt("hecl package must be ran within a project directory"));
|
||||
|
||||
|
@ -156,9 +156,9 @@ public:
|
|||
help.endWrap();
|
||||
}
|
||||
|
||||
hecl::SystemString toolName() const { return _SYS_STR("package"); }
|
||||
hecl::SystemString toolName() const override { return _SYS_STR("package"); }
|
||||
|
||||
int run() {
|
||||
int run() override {
|
||||
if (XTERM_COLOR)
|
||||
fmt::print(fmt(_SYS_STR("" GREEN BOLD "ABOUT TO PACKAGE:" NORMAL "\n")));
|
||||
else
|
||||
|
@ -181,5 +181,5 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
void cancel() { m_useProj->interruptCook(); }
|
||||
void cancel() override { m_useProj->interruptCook(); }
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ class ToolSpec final : public ToolBase {
|
|||
enum Mode { MLIST = 0, MENABLE, MDISABLE } mode = MLIST;
|
||||
|
||||
public:
|
||||
ToolSpec(const ToolPassInfo& info) : ToolBase(info) {
|
||||
explicit ToolSpec(const ToolPassInfo& info) : ToolBase(info) {
|
||||
if (info.args.empty())
|
||||
return;
|
||||
|
||||
|
@ -71,9 +71,9 @@ public:
|
|||
help.endWrap();
|
||||
}
|
||||
|
||||
hecl::SystemString toolName() const { return _SYS_STR("spec"); }
|
||||
hecl::SystemString toolName() const override { return _SYS_STR("spec"); }
|
||||
|
||||
int run() {
|
||||
int run() override {
|
||||
if (!m_info.project) {
|
||||
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
|
||||
if (XTERM_COLOR)
|
||||
|
|
|
@ -77,14 +77,196 @@ static void SIGINTHandler(int sig) {
|
|||
}
|
||||
|
||||
static logvisor::Module AthenaLog("Athena");
|
||||
static void AthenaExc(athena::error::Level level, const char* file, const char*, int line,
|
||||
fmt::string_view fmt, fmt::format_args args) {
|
||||
static void AthenaExc(athena::error::Level level, const char* file, const char*, int line, fmt::string_view fmt,
|
||||
fmt::format_args args) {
|
||||
AthenaLog.vreport(logvisor::Level(level), fmt, args);
|
||||
}
|
||||
|
||||
static hecl::SystemChar cwdbuf[1024];
|
||||
hecl::SystemString ExeDir;
|
||||
|
||||
#if _WIN32
|
||||
static ToolPassInfo CreateInfo(int argc, const wchar_t** argv) {
|
||||
#else
|
||||
static ToolPassInfo CreateInfo(int argc, const char** argv) {
|
||||
#endif
|
||||
hecl::SystemChar cwdbuf[1024];
|
||||
|
||||
ToolPassInfo info;
|
||||
info.pname = argv[0];
|
||||
|
||||
if (hecl::Getcwd(cwdbuf, static_cast<int>(std::size(cwdbuf)))) {
|
||||
info.cwd = cwdbuf;
|
||||
if (info.cwd.size() && info.cwd.back() != _SYS_STR('/') && info.cwd.back() != _SYS_STR('\\')) {
|
||||
#if _WIN32
|
||||
info.cwd += _SYS_STR('\\');
|
||||
#else
|
||||
info.cwd += _SYS_STR('/');
|
||||
#endif
|
||||
}
|
||||
|
||||
if (hecl::PathRelative(argv[0])) {
|
||||
ExeDir = hecl::SystemString(cwdbuf) + _SYS_STR('/');
|
||||
}
|
||||
hecl::SystemString Argv0(argv[0]);
|
||||
hecl::SystemString::size_type lastIdx = Argv0.find_last_of(_SYS_STR("/\\"));
|
||||
if (lastIdx != hecl::SystemString::npos) {
|
||||
ExeDir.insert(ExeDir.end(), Argv0.begin(), Argv0.begin() + lastIdx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Concatenate args */
|
||||
std::vector<hecl::SystemString> args;
|
||||
args.reserve(argc - 2);
|
||||
for (int i = 2; i < argc; ++i) {
|
||||
args.emplace_back(argv[i]);
|
||||
}
|
||||
|
||||
if (!args.empty()) {
|
||||
/* Extract output argument */
|
||||
for (auto it = args.cbegin(); it != args.cend();) {
|
||||
const hecl::SystemString& arg = *it;
|
||||
hecl::SystemRegexMatch oMatch;
|
||||
|
||||
if (std::regex_search(arg, oMatch, regOPEN)) {
|
||||
const hecl::SystemString& token = oMatch[1].str();
|
||||
|
||||
if (token.size()) {
|
||||
if (info.output.empty()) {
|
||||
info.output = oMatch[1].str();
|
||||
}
|
||||
|
||||
it = args.erase(it);
|
||||
} else {
|
||||
it = args.erase(it);
|
||||
|
||||
if (it == args.end()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (info.output.empty()) {
|
||||
info.output = *it;
|
||||
}
|
||||
|
||||
it = args.erase(it);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
/* Iterate flags */
|
||||
bool threadArg = false;
|
||||
for (auto it = args.cbegin(); it != args.cend();) {
|
||||
const hecl::SystemString& arg = *it;
|
||||
if (threadArg) {
|
||||
threadArg = false;
|
||||
hecl::CpuCountOverride = int(hecl::StrToUl(arg.c_str(), nullptr, 0));
|
||||
it = args.erase(it);
|
||||
continue;
|
||||
}
|
||||
if (arg.size() < 2 || arg[0] != _SYS_STR('-') || arg[1] == _SYS_STR('-')) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto chit = arg.cbegin() + 1; chit != arg.cend(); ++chit) {
|
||||
if (*chit == _SYS_STR('v'))
|
||||
++info.verbosityLevel;
|
||||
else if (*chit == _SYS_STR('f'))
|
||||
info.force = true;
|
||||
else if (*chit == _SYS_STR('y'))
|
||||
info.yes = true;
|
||||
else if (*chit == _SYS_STR('g'))
|
||||
info.gui = true;
|
||||
else if (*chit == _SYS_STR('j')) {
|
||||
++chit;
|
||||
if (*chit)
|
||||
hecl::CpuCountOverride = int(hecl::StrToUl(&*chit, nullptr, 0));
|
||||
else
|
||||
threadArg = true;
|
||||
break;
|
||||
} else
|
||||
info.flags.push_back(*chit);
|
||||
}
|
||||
|
||||
it = args.erase(it);
|
||||
}
|
||||
|
||||
/* Gather remaining args */
|
||||
info.args.reserve(args.size());
|
||||
for (const hecl::SystemString& arg : args)
|
||||
info.args.push_back(arg);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static std::unique_ptr<hecl::Database::Project> FindProject(hecl::SystemStringView cwd) {
|
||||
const hecl::ProjectRootPath rootPath = hecl::SearchForProject(cwd);
|
||||
if (!rootPath) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const size_t ErrorRef = logvisor::ErrorCount;
|
||||
auto newProj = std::make_unique<hecl::Database::Project>(rootPath);
|
||||
if (logvisor::ErrorCount > ErrorRef) {
|
||||
#if WIN_PAUSE
|
||||
system("PAUSE");
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return newProj;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ToolBase> MakeSelectedTool(hecl::SystemString toolName, ToolPassInfo& info) {
|
||||
hecl::SystemString toolNameLower = toolName;
|
||||
hecl::ToLower(toolNameLower);
|
||||
|
||||
if (toolNameLower == _SYS_STR("init")) {
|
||||
return std::make_unique<ToolInit>(info);
|
||||
}
|
||||
|
||||
if (toolNameLower == _SYS_STR("spec")) {
|
||||
return std::make_unique<ToolSpec>(info);
|
||||
}
|
||||
|
||||
if (toolNameLower == _SYS_STR("extract")) {
|
||||
return std::make_unique<ToolExtract>(info);
|
||||
}
|
||||
|
||||
if (toolNameLower == _SYS_STR("cook")) {
|
||||
return std::make_unique<ToolCook>(info);
|
||||
}
|
||||
|
||||
if (toolNameLower == _SYS_STR("package") || toolNameLower == _SYS_STR("pack")) {
|
||||
return std::make_unique<ToolPackage>(info);
|
||||
}
|
||||
|
||||
#if HECL_HAS_NOD
|
||||
if (toolNameLower == _SYS_STR("image")) {
|
||||
return std::make_unique<ToolImage>(info);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (toolNameLower == _SYS_STR("help")) {
|
||||
return std::make_unique<ToolHelp>(info);
|
||||
}
|
||||
|
||||
auto fp = hecl::FopenUnique(toolName.c_str(), _SYS_STR("rb"));
|
||||
if (fp == nullptr) {
|
||||
LogModule.report(logvisor::Error, fmt(_SYS_STR("unrecognized tool '{}'")), toolNameLower);
|
||||
return nullptr;
|
||||
}
|
||||
fp.reset();
|
||||
|
||||
/* Shortcut-case: implicit extract */
|
||||
info.args.insert(info.args.begin(), std::move(toolName));
|
||||
return std::make_unique<ToolExtract>(info);
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
int wmain(int argc, const wchar_t** argv)
|
||||
#else
|
||||
|
@ -140,167 +322,34 @@ int main(int argc, const char** argv)
|
|||
HECLRegisterDataSpecs();
|
||||
|
||||
/* Assemble common tool pass info */
|
||||
ToolPassInfo info;
|
||||
info.pname = argv[0];
|
||||
if (hecl::Getcwd(cwdbuf, 1024)) {
|
||||
info.cwd = cwdbuf;
|
||||
if (info.cwd.size() && info.cwd.back() != _SYS_STR('/') && info.cwd.back() != _SYS_STR('\\'))
|
||||
#if _WIN32
|
||||
info.cwd += _SYS_STR('\\');
|
||||
#else
|
||||
info.cwd += _SYS_STR('/');
|
||||
#endif
|
||||
|
||||
if (hecl::PathRelative(argv[0]))
|
||||
ExeDir = hecl::SystemString(cwdbuf) + _SYS_STR('/');
|
||||
hecl::SystemString Argv0(argv[0]);
|
||||
hecl::SystemString::size_type lastIdx = Argv0.find_last_of(_SYS_STR("/\\"));
|
||||
if (lastIdx != hecl::SystemString::npos)
|
||||
ExeDir.insert(ExeDir.end(), Argv0.begin(), Argv0.begin() + lastIdx);
|
||||
}
|
||||
|
||||
/* Concatenate args */
|
||||
std::vector<hecl::SystemString> args;
|
||||
args.reserve(argc - 2);
|
||||
for (int i = 2; i < argc; ++i)
|
||||
args.push_back(hecl::SystemString(argv[i]));
|
||||
|
||||
if (!args.empty()) {
|
||||
/* Extract output argument */
|
||||
for (auto it = args.cbegin(); it != args.cend();) {
|
||||
const hecl::SystemString& arg = *it;
|
||||
hecl::SystemRegexMatch oMatch;
|
||||
if (std::regex_search(arg, oMatch, regOPEN)) {
|
||||
const hecl::SystemString& token = oMatch[1].str();
|
||||
if (token.size()) {
|
||||
if (info.output.empty())
|
||||
info.output = oMatch[1].str();
|
||||
it = args.erase(it);
|
||||
} else {
|
||||
it = args.erase(it);
|
||||
if (it == args.end())
|
||||
break;
|
||||
if (info.output.empty())
|
||||
info.output = *it;
|
||||
it = args.erase(it);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
/* Iterate flags */
|
||||
bool threadArg = false;
|
||||
for (auto it = args.cbegin(); it != args.cend();) {
|
||||
const hecl::SystemString& arg = *it;
|
||||
if (threadArg) {
|
||||
threadArg = false;
|
||||
hecl::CpuCountOverride = int(hecl::StrToUl(arg.c_str(), nullptr, 0));
|
||||
it = args.erase(it);
|
||||
continue;
|
||||
}
|
||||
if (arg.size() < 2 || arg[0] != _SYS_STR('-') || arg[1] == _SYS_STR('-')) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto chit = arg.cbegin() + 1; chit != arg.cend(); ++chit) {
|
||||
if (*chit == _SYS_STR('v'))
|
||||
++info.verbosityLevel;
|
||||
else if (*chit == _SYS_STR('f'))
|
||||
info.force = true;
|
||||
else if (*chit == _SYS_STR('y'))
|
||||
info.yes = true;
|
||||
else if (*chit == _SYS_STR('g'))
|
||||
info.gui = true;
|
||||
else if (*chit == _SYS_STR('j')) {
|
||||
++chit;
|
||||
if (*chit)
|
||||
hecl::CpuCountOverride = int(hecl::StrToUl(&*chit, nullptr, 0));
|
||||
else
|
||||
threadArg = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
info.flags.push_back(*chit);
|
||||
}
|
||||
|
||||
it = args.erase(it);
|
||||
}
|
||||
|
||||
/* Gather remaining args */
|
||||
info.args.reserve(args.size());
|
||||
for (const hecl::SystemString& arg : args)
|
||||
info.args.push_back(arg);
|
||||
}
|
||||
ToolPassInfo info = CreateInfo(argc, argv);
|
||||
|
||||
/* Attempt to find hecl project */
|
||||
hecl::ProjectRootPath rootPath = hecl::SearchForProject(info.cwd);
|
||||
std::unique_ptr<hecl::Database::Project> project;
|
||||
if (rootPath) {
|
||||
size_t ErrorRef = logvisor::ErrorCount;
|
||||
hecl::Database::Project* newProj = new hecl::Database::Project(rootPath);
|
||||
if (logvisor::ErrorCount > ErrorRef) {
|
||||
#if WIN_PAUSE
|
||||
system("PAUSE");
|
||||
#endif
|
||||
delete newProj;
|
||||
return 1;
|
||||
}
|
||||
project.reset(newProj);
|
||||
info.project = newProj;
|
||||
auto project = FindProject(info.cwd);
|
||||
if (project != nullptr) {
|
||||
info.project = project.get();
|
||||
}
|
||||
|
||||
/* Construct selected tool */
|
||||
hecl::SystemString toolName(argv[1]);
|
||||
hecl::ToLower(toolName);
|
||||
std::unique_ptr<ToolBase> tool;
|
||||
|
||||
size_t ErrorRef = logvisor::ErrorCount;
|
||||
if (toolName == _SYS_STR("init"))
|
||||
tool.reset(new ToolInit(info));
|
||||
else if (toolName == _SYS_STR("spec"))
|
||||
tool.reset(new ToolSpec(info));
|
||||
else if (toolName == _SYS_STR("extract"))
|
||||
tool.reset(new ToolExtract(info));
|
||||
else if (toolName == _SYS_STR("cook"))
|
||||
tool.reset(new ToolCook(info));
|
||||
else if (toolName == _SYS_STR("package") || toolName == _SYS_STR("pack"))
|
||||
tool.reset(new ToolPackage(info));
|
||||
#if HECL_HAS_NOD
|
||||
else if (toolName == _SYS_STR("image"))
|
||||
tool.reset(new ToolImage(info));
|
||||
#endif
|
||||
else if (toolName == _SYS_STR("help"))
|
||||
tool.reset(new ToolHelp(info));
|
||||
else {
|
||||
FILE* fp = hecl::Fopen(argv[1], _SYS_STR("rb"));
|
||||
if (!fp)
|
||||
LogModule.report(logvisor::Error, fmt(_SYS_STR("unrecognized tool '{}'")), toolName);
|
||||
else {
|
||||
/* Shortcut-case: implicit extract */
|
||||
fclose(fp);
|
||||
info.args.insert(info.args.begin(), argv[1]);
|
||||
tool.reset(new ToolExtract(info));
|
||||
}
|
||||
}
|
||||
|
||||
if (logvisor::ErrorCount > ErrorRef) {
|
||||
const size_t MakeToolErrorRef = logvisor::ErrorCount;
|
||||
auto tool = MakeSelectedTool(argv[1], info);
|
||||
if (logvisor::ErrorCount > MakeToolErrorRef) {
|
||||
#if WIN_PAUSE
|
||||
system("PAUSE");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (info.verbosityLevel)
|
||||
LogModule.report(logvisor::Info, fmt(_SYS_STR("Constructed tool '{}' {}\n")), tool->toolName(), info.verbosityLevel);
|
||||
if (info.verbosityLevel) {
|
||||
LogModule.report(logvisor::Info, fmt(_SYS_STR("Constructed tool '{}' {}\n")), tool->toolName(),
|
||||
info.verbosityLevel);
|
||||
}
|
||||
|
||||
/* Run tool */
|
||||
ErrorRef = logvisor::ErrorCount;
|
||||
const size_t RunToolErrorRef = logvisor::ErrorCount;
|
||||
ToolPtr = tool.get();
|
||||
int retval = tool->run();
|
||||
const int retval = tool->run();
|
||||
ToolPtr = nullptr;
|
||||
if (logvisor::ErrorCount > ErrorRef) {
|
||||
if (logvisor::ErrorCount > RunToolErrorRef) {
|
||||
hecl::blender::Connection::Shutdown();
|
||||
#if WIN_PAUSE
|
||||
system("PAUSE");
|
||||
|
|
|
@ -67,7 +67,7 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const { return ((*WordRef) & (BitWord(1) << BitPos)) != 0; }
|
||||
explicit operator bool() const { return ((*WordRef) & (BitWord(1) << BitPos)) != 0; }
|
||||
};
|
||||
|
||||
/// BitVector default ctor - Creates an empty bitvector.
|
||||
|
|
|
@ -12,32 +12,37 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cfloat>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "hecl/hecl.hpp"
|
||||
#include "hecl/Backend.hpp"
|
||||
#include "hecl/HMDLMeta.hpp"
|
||||
#include "hecl/TypedVariant.hpp"
|
||||
#include "hecl/Backend.hpp"
|
||||
#include "athena/Types.hpp"
|
||||
#include "athena/MemoryWriter.hpp"
|
||||
#include <optional>
|
||||
#include "Token.hpp"
|
||||
|
||||
#include <athena/Types.hpp>
|
||||
#include <fmt/ostream.h>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
namespace hecl::blender {
|
||||
using namespace std::literals;
|
||||
|
||||
extern logvisor::Module BlenderLog;
|
||||
class HMDLBuffers;
|
||||
class Connection;
|
||||
class HMDLBuffers;
|
||||
|
||||
extern logvisor::Module BlenderLog;
|
||||
|
||||
struct PoolSkinIndex {
|
||||
size_t m_poolSz = 0;
|
||||
|
@ -76,7 +81,7 @@ class PyOutStream : public std::ostream {
|
|||
StreamBuf(PyOutStream& parent, bool deleteOnError) : m_parent(parent), m_deleteOnError(deleteOnError) {}
|
||||
StreamBuf(const StreamBuf& other) = delete;
|
||||
StreamBuf(StreamBuf&& other) = default;
|
||||
int_type overflow(int_type ch);
|
||||
int_type overflow(int_type ch) override;
|
||||
} m_sbuf;
|
||||
PyOutStream(Connection* parent, bool deleteOnError);
|
||||
|
||||
|
@ -85,7 +90,7 @@ public:
|
|||
PyOutStream(PyOutStream&& other) : std::ostream(&m_sbuf), m_parent(other.m_parent), m_sbuf(std::move(other.m_sbuf)) {
|
||||
other.m_parent = nullptr;
|
||||
}
|
||||
~PyOutStream() { close(); }
|
||||
~PyOutStream() override { close(); }
|
||||
void close();
|
||||
template <typename S, typename... Args, typename Char = fmt::char_t<S>>
|
||||
void format(const S& format, Args&&... args);
|
||||
|
@ -136,15 +141,15 @@ struct Vector4f {
|
|||
}
|
||||
};
|
||||
struct Matrix3f {
|
||||
atVec3f m[3];
|
||||
inline atVec3f& operator[](size_t idx) { return m[idx]; }
|
||||
inline const atVec3f& operator[](size_t idx) const { return m[idx]; }
|
||||
std::array<atVec3f, 3> m;
|
||||
atVec3f& operator[](size_t idx) { return m[idx]; }
|
||||
const atVec3f& operator[](size_t idx) const { return m[idx]; }
|
||||
};
|
||||
struct Matrix4f {
|
||||
atVec4f val[4];
|
||||
std::array<atVec4f, 4> val;
|
||||
Matrix4f() = default;
|
||||
void read(Connection& conn);
|
||||
Matrix4f(Connection& conn) { read(conn); }
|
||||
void read(Connection& conn);
|
||||
const atVec4f& operator[](size_t idx) const { return val[idx]; }
|
||||
};
|
||||
struct Index {
|
||||
|
@ -343,8 +348,8 @@ struct Mesh {
|
|||
struct Vert {
|
||||
uint32_t iPos = 0xffffffff;
|
||||
uint32_t iNorm = 0xffffffff;
|
||||
uint32_t iColor[4] = {0xffffffff};
|
||||
uint32_t iUv[8] = {0xffffffff};
|
||||
std::array<uint32_t, 4> iColor = {0xffffffff};
|
||||
std::array<uint32_t, 8> iUv = {0xffffffff};
|
||||
uint32_t iSkin = 0xffffffff;
|
||||
uint32_t iBankSkin = 0xffffffff;
|
||||
|
||||
|
@ -433,14 +438,14 @@ struct ColMesh {
|
|||
std::vector<Vector3f> verts;
|
||||
|
||||
struct Edge {
|
||||
uint32_t verts[2];
|
||||
std::array<uint32_t, 2> verts;
|
||||
bool seam;
|
||||
Edge(Connection& conn);
|
||||
};
|
||||
std::vector<Edge> edges;
|
||||
|
||||
struct Triangle {
|
||||
uint32_t edges[3];
|
||||
std::array<uint32_t, 3> edges;
|
||||
uint32_t matIdx;
|
||||
bool flip;
|
||||
Triangle(Connection& conn);
|
||||
|
@ -454,10 +459,10 @@ struct ColMesh {
|
|||
struct World {
|
||||
struct Area {
|
||||
ProjectPath path;
|
||||
Vector3f aabb[2];
|
||||
std::array<Vector3f, 2> aabb;
|
||||
Matrix4f transform;
|
||||
struct Dock {
|
||||
Vector3f verts[4];
|
||||
std::array<Vector3f, 4> verts;
|
||||
Index targetArea;
|
||||
Index targetDock;
|
||||
Dock(Connection& conn);
|
||||
|
@ -666,30 +671,30 @@ public:
|
|||
};
|
||||
|
||||
class Connection {
|
||||
friend class ANIMOutStream;
|
||||
friend class DataStream;
|
||||
friend class PyOutStream;
|
||||
friend class ANIMOutStream;
|
||||
friend struct PyOutStream::StreamBuf;
|
||||
friend struct Mesh;
|
||||
friend struct Material;
|
||||
friend struct Action;
|
||||
friend struct Actor;
|
||||
friend struct Armature;
|
||||
friend struct Bone;
|
||||
friend struct Boolean;
|
||||
friend struct ColMesh;
|
||||
friend struct World;
|
||||
friend struct Float;
|
||||
friend struct Index;
|
||||
friend struct Light;
|
||||
friend struct MapArea;
|
||||
friend struct MapUniverse;
|
||||
friend struct Actor;
|
||||
friend struct Armature;
|
||||
friend struct Action;
|
||||
friend struct Bone;
|
||||
friend struct Material;
|
||||
friend struct Matrix3f;
|
||||
friend struct Matrix4f;
|
||||
friend struct Mesh;
|
||||
friend struct PathMesh;
|
||||
friend struct PyOutStream::StreamBuf;
|
||||
friend struct Vector2f;
|
||||
friend struct Vector3f;
|
||||
friend struct Vector4f;
|
||||
friend struct Matrix3f;
|
||||
friend struct Matrix4f;
|
||||
friend struct Index;
|
||||
friend struct Float;
|
||||
friend struct Boolean;
|
||||
friend struct World;
|
||||
|
||||
std::atomic_bool m_lock = {false};
|
||||
bool m_pyStreamActive = false;
|
||||
|
@ -701,8 +706,8 @@ class Connection {
|
|||
#else
|
||||
pid_t m_blenderProc = 0;
|
||||
#endif
|
||||
int m_readpipe[2];
|
||||
int m_writepipe[2];
|
||||
std::array<int, 2> m_readpipe{};
|
||||
std::array<int, 2> m_writepipe{};
|
||||
BlendType m_loadedType = BlendType::None;
|
||||
bool m_loadedRigged = false;
|
||||
ProjectPath m_loadedBlend;
|
||||
|
@ -710,8 +715,7 @@ class Connection {
|
|||
uint32_t _readStr(char* buf, uint32_t bufSz);
|
||||
uint32_t _writeStr(const char* str, uint32_t len, int wpipe);
|
||||
uint32_t _writeStr(const char* str, uint32_t len) { return _writeStr(str, len, m_writepipe[1]); }
|
||||
uint32_t _writeStr(const char* str) { return _writeStr(str, strlen(str)); }
|
||||
uint32_t _writeStr(const std::string& str) { return _writeStr(str.c_str(), str.size()); }
|
||||
uint32_t _writeStr(std::string_view view) { return _writeStr(view.data(), view.size()); }
|
||||
size_t _readBuf(void* buf, size_t len);
|
||||
size_t _writeBuf(const void* buf, size_t len);
|
||||
void _closePipe();
|
||||
|
|
|
@ -57,7 +57,7 @@ class SDNARead {
|
|||
|
||||
public:
|
||||
explicit SDNARead(SystemStringView path);
|
||||
operator bool() const { return !m_data.empty(); }
|
||||
explicit operator bool() const { return !m_data.empty(); }
|
||||
const SDNABlock& sdnaBlock() const { return m_sdnaBlock; }
|
||||
void enumerate(const std::function<bool(const FileBlock& block, athena::io::MemoryReader& r)>& func) const;
|
||||
};
|
||||
|
|
|
@ -70,8 +70,8 @@ public:
|
|||
float toFloat(bool* isValid = nullptr) const;
|
||||
bool toBoolean(bool* isValid = nullptr) const;
|
||||
int toInteger(bool* isValid = nullptr) const;
|
||||
const std::wstring toWideLiteral(bool* isValid = nullptr) const;
|
||||
const std::string toLiteral(bool* isValid = nullptr) const;
|
||||
std::wstring toWideLiteral(bool* isValid = nullptr) const;
|
||||
std::string toLiteral(bool* isValid = nullptr) const;
|
||||
|
||||
bool fromVec4f(const atVec4f& val);
|
||||
bool fromFloat(float val);
|
||||
|
@ -117,7 +117,7 @@ public:
|
|||
*/
|
||||
void lock();
|
||||
|
||||
void addListener(ListenerFunc func) { m_listeners.push_back(func); }
|
||||
void addListener(ListenerFunc func) { m_listeners.push_back(std::move(func)); }
|
||||
|
||||
private:
|
||||
void dispatch();
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
void* m_targetBuf;
|
||||
size_t m_maxLen;
|
||||
size_t m_offset;
|
||||
void run(blender::Token& btok);
|
||||
void run(blender::Token& btok) override;
|
||||
BufferTransaction(ClientProcess& parent, const ProjectPath& path, void* target, size_t maxLen, size_t offset)
|
||||
: Transaction(parent, Type::Buffer), m_path(path), m_targetBuf(target), m_maxLen(maxLen), m_offset(offset) {}
|
||||
};
|
||||
|
@ -46,13 +46,13 @@ public:
|
|||
bool m_returnResult = false;
|
||||
bool m_force;
|
||||
bool m_fast;
|
||||
void run(blender::Token& btok);
|
||||
void run(blender::Token& btok) override;
|
||||
CookTransaction(ClientProcess& parent, const ProjectPath& path, bool force, bool fast, Database::IDataSpec* spec)
|
||||
: Transaction(parent, Type::Cook), m_path(path), m_dataSpec(spec), m_force(force), m_fast(fast) {}
|
||||
};
|
||||
struct LambdaTransaction final : Transaction {
|
||||
std::function<void(blender::Token&)> m_func;
|
||||
void run(blender::Token& btok);
|
||||
void run(blender::Token& btok) override;
|
||||
LambdaTransaction(ClientProcess& parent, std::function<void(blender::Token&)>&& func)
|
||||
: Transaction(parent, Type::Lambda), m_func(std::move(func)) {}
|
||||
};
|
||||
|
|
|
@ -12,35 +12,35 @@ using PlatformEnum = boo::IGraphicsDataFactory::Platform;
|
|||
struct Null {};
|
||||
struct OpenGL {
|
||||
static constexpr PlatformEnum Enum = PlatformEnum::OpenGL;
|
||||
static const char* Name;
|
||||
static constexpr char Name[] = "OpenGL";
|
||||
#if BOO_HAS_GL
|
||||
using Context = boo::GLDataFactory::Context;
|
||||
#endif
|
||||
};
|
||||
struct D3D11 {
|
||||
static constexpr PlatformEnum Enum = PlatformEnum::D3D11;
|
||||
static const char* Name;
|
||||
static constexpr char Name[] = "D3D11";
|
||||
#if _WIN32
|
||||
using Context = boo::D3D11DataFactory::Context;
|
||||
#endif
|
||||
};
|
||||
struct Metal {
|
||||
static constexpr PlatformEnum Enum = PlatformEnum::Metal;
|
||||
static const char* Name;
|
||||
static constexpr char Name[] = "Metal";
|
||||
#if BOO_HAS_METAL
|
||||
using Context = boo::MetalDataFactory::Context;
|
||||
#endif
|
||||
};
|
||||
struct Vulkan {
|
||||
static constexpr PlatformEnum Enum = PlatformEnum::Vulkan;
|
||||
static const char* Name;
|
||||
static constexpr char Name[] = "Vulkan";
|
||||
#if BOO_HAS_VULKAN
|
||||
using Context = boo::VulkanDataFactory::Context;
|
||||
#endif
|
||||
};
|
||||
struct NX {
|
||||
static constexpr PlatformEnum Enum = PlatformEnum::NX;
|
||||
static const char* Name;
|
||||
static constexpr char Name[] = "NX";
|
||||
#if BOO_HAS_NX
|
||||
using Context = boo::NXDataFactory::Context;
|
||||
#endif
|
||||
|
@ -51,27 +51,27 @@ namespace PipelineStage {
|
|||
using StageEnum = boo::PipelineStage;
|
||||
struct Null {
|
||||
static constexpr StageEnum Enum = StageEnum::Null;
|
||||
static const char* Name;
|
||||
static constexpr char Name[] = "Null";
|
||||
};
|
||||
struct Vertex {
|
||||
static constexpr StageEnum Enum = StageEnum::Vertex;
|
||||
static const char* Name;
|
||||
static constexpr char Name[] = "Vertex";
|
||||
};
|
||||
struct Fragment {
|
||||
static constexpr StageEnum Enum = StageEnum::Fragment;
|
||||
static const char* Name;
|
||||
static constexpr char Name[] = "Fragment";
|
||||
};
|
||||
struct Geometry {
|
||||
static constexpr StageEnum Enum = StageEnum::Geometry;
|
||||
static const char* Name;
|
||||
static constexpr char Name[] = "Geometry";
|
||||
};
|
||||
struct Control {
|
||||
static constexpr StageEnum Enum = StageEnum::Control;
|
||||
static const char* Name;
|
||||
static constexpr char Name[] = "Control";
|
||||
};
|
||||
struct Evaluation {
|
||||
static constexpr StageEnum Enum = StageEnum::Evaluation;
|
||||
static const char* Name;
|
||||
static constexpr char Name[] = "Evaluation";
|
||||
};
|
||||
} // namespace PipelineStage
|
||||
|
||||
|
|
|
@ -26,13 +26,14 @@ class Console {
|
|||
Console* m_con;
|
||||
LogVisorAdapter(Console* con) : m_con(con) {}
|
||||
|
||||
~LogVisorAdapter() = default;
|
||||
void report(const char* modName, logvisor::Level severity, fmt::string_view format, fmt::format_args args);
|
||||
void report(const char* modName, logvisor::Level severity, fmt::wstring_view format, fmt::wformat_args args);
|
||||
~LogVisorAdapter() override = default;
|
||||
void report(const char* modName, logvisor::Level severity, fmt::string_view format, fmt::format_args args) override;
|
||||
void report(const char* modName, logvisor::Level severity, fmt::wstring_view format,
|
||||
fmt::wformat_args args) override;
|
||||
void reportSource(const char* modName, logvisor::Level severity, const char* file, unsigned linenum,
|
||||
fmt::string_view format, fmt::format_args args);
|
||||
fmt::string_view format, fmt::format_args args) override;
|
||||
void reportSource(const char* modName, logvisor::Level severity, const char* file, unsigned linenum,
|
||||
fmt::wstring_view format, fmt::wformat_args args);
|
||||
fmt::wstring_view format, fmt::wformat_args args) override;
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <fstream>
|
||||
#include <stdint.h>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
#include "athena/IStreamReader.hpp"
|
||||
#include "logvisor/logvisor.hpp"
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
#include "hecl.hpp"
|
||||
|
||||
|
@ -62,7 +58,7 @@ class IDataSpec {
|
|||
|
||||
public:
|
||||
IDataSpec(const DataSpecEntry* specEntry) : m_specEntry(specEntry) {}
|
||||
virtual ~IDataSpec() {}
|
||||
virtual ~IDataSpec() = default;
|
||||
using FCookProgress = std::function<void(const SystemChar*)>;
|
||||
|
||||
/**
|
||||
|
@ -91,43 +87,33 @@ public:
|
|||
|
||||
virtual void setThreadProject() {}
|
||||
|
||||
virtual bool canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps) {
|
||||
(void)info;
|
||||
(void)reps;
|
||||
virtual bool canExtract([[maybe_unused]] const ExtractPassInfo& info,
|
||||
[[maybe_unused]] std::vector<ExtractReport>& reps) {
|
||||
LogModule.report(logvisor::Error, fmt("not implemented"));
|
||||
return false;
|
||||
}
|
||||
virtual void doExtract(const ExtractPassInfo& info, const MultiProgressPrinter& progress) {
|
||||
(void)info;
|
||||
(void)progress;
|
||||
}
|
||||
virtual void doExtract([[maybe_unused]] const ExtractPassInfo& info,
|
||||
[[maybe_unused]] const MultiProgressPrinter& progress) {}
|
||||
|
||||
virtual bool canCook(const ProjectPath& path, blender::Token& btok) {
|
||||
(void)path;
|
||||
virtual bool canCook([[maybe_unused]] const ProjectPath& path, [[maybe_unused]] blender::Token& btok) {
|
||||
LogModule.report(logvisor::Error, fmt("not implemented"));
|
||||
return false;
|
||||
}
|
||||
virtual const DataSpecEntry* overrideDataSpec(const ProjectPath& path,
|
||||
const Database::DataSpecEntry* oldEntry) const {
|
||||
(void)path;
|
||||
virtual const DataSpecEntry* overrideDataSpec([[maybe_unused]] const ProjectPath& path,
|
||||
const DataSpecEntry* oldEntry) const {
|
||||
return oldEntry;
|
||||
}
|
||||
virtual void doCook(const ProjectPath& path, const ProjectPath& cookedPath, bool fast, blender::Token& btok,
|
||||
FCookProgress progress) {
|
||||
(void)path;
|
||||
(void)cookedPath;
|
||||
(void)fast;
|
||||
(void)progress;
|
||||
}
|
||||
virtual void doCook([[maybe_unused]] const ProjectPath& path, [[maybe_unused]] const ProjectPath& cookedPath,
|
||||
[[maybe_unused]] bool fast, [[maybe_unused]] blender::Token& btok,
|
||||
[[maybe_unused]] FCookProgress progress) {}
|
||||
|
||||
virtual bool canPackage(const ProjectPath& path) {
|
||||
(void)path;
|
||||
virtual bool canPackage([[maybe_unused]] const ProjectPath& path) {
|
||||
return false;
|
||||
}
|
||||
virtual void doPackage(const ProjectPath& path, const Database::DataSpecEntry* entry, bool fast, blender::Token& btok,
|
||||
const MultiProgressPrinter& progress, ClientProcess* cp = nullptr) {
|
||||
(void)path;
|
||||
}
|
||||
virtual void doPackage([[maybe_unused]] const ProjectPath& path, [[maybe_unused]] const DataSpecEntry* entry,
|
||||
[[maybe_unused]] bool fast, [[maybe_unused]] blender::Token& btok,
|
||||
[[maybe_unused]] const MultiProgressPrinter& progress,
|
||||
[[maybe_unused]] ClientProcess* cp = nullptr) {}
|
||||
|
||||
virtual void interruptCook() {}
|
||||
|
||||
|
@ -190,7 +176,7 @@ protected:
|
|||
Cafe /**< Swizzled textures and R700 shader objects */
|
||||
};
|
||||
|
||||
typedef std::function<void(const void* data, size_t len)> FDataAppender;
|
||||
using FDataAppender = std::function<void(const void* data, size_t len)>;
|
||||
|
||||
/**
|
||||
* @brief Optional private method implemented by subclasses to cook objects
|
||||
|
@ -203,14 +189,12 @@ protected:
|
|||
* Part of the cooking process may include embedding database-refs to dependencies.
|
||||
* This method should store the 64-bit value provided by IDataObject::id() when doing this.
|
||||
*/
|
||||
virtual bool cookObject(FDataAppender dataAppender, DataEndianness endianness, DataPlatform platform) {
|
||||
(void)dataAppender;
|
||||
(void)endianness;
|
||||
(void)platform;
|
||||
virtual bool cookObject([[maybe_unused]] FDataAppender dataAppender, [[maybe_unused]] DataEndianness endianness,
|
||||
[[maybe_unused]] DataPlatform platform) {
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef std::function<void(ObjectBase*)> FDepAdder;
|
||||
using FDepAdder = std::function<void(ObjectBase*)>;
|
||||
|
||||
/**
|
||||
* @brief Optional private method implemented by CProjectObject subclasses to resolve dependencies
|
||||
|
@ -220,7 +204,7 @@ protected:
|
|||
* Dependencies registered via this method will eventually have this method called on themselves
|
||||
* as well. This is a non-recursive operation, no need for subclasses to implement recursion-control.
|
||||
*/
|
||||
virtual void gatherDeps(FDepAdder depAdder) { (void)depAdder; }
|
||||
virtual void gatherDeps([[maybe_unused]] FDepAdder depAdder) {}
|
||||
|
||||
/**
|
||||
* @brief Get a packagable FourCC representation of the object's type
|
||||
|
@ -262,7 +246,7 @@ private:
|
|||
|
||||
public:
|
||||
Project(const ProjectRootPath& rootPath);
|
||||
operator bool() const { return m_valid; }
|
||||
explicit operator bool() const { return m_valid; }
|
||||
|
||||
/**
|
||||
* @brief Configuration file handle
|
||||
|
@ -273,7 +257,7 @@ public:
|
|||
class ConfigFile {
|
||||
SystemString m_filepath;
|
||||
std::vector<std::string> m_lines;
|
||||
FILE* m_lockedFile = NULL;
|
||||
UniqueFilePtr m_lockedFile;
|
||||
|
||||
public:
|
||||
ConfigFile(const Project& project, SystemStringView name, SystemStringView subdir = _SYS_STR("/.hecl/"));
|
||||
|
@ -311,7 +295,7 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Get the path of project's cooked directory for a specific DataSpec
|
||||
* @param DataSpec to retrieve path for
|
||||
* @param spec DataSpec to retrieve path for
|
||||
* @return project cooked path
|
||||
*
|
||||
* The cooked path matches the directory layout of the working directory
|
||||
|
@ -320,7 +304,7 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Add given file(s) to the database
|
||||
* @param path file or pattern within project
|
||||
* @param paths files or patterns within project
|
||||
* @return true on success
|
||||
*
|
||||
* This method blocks while object hashing takes place
|
||||
|
|
|
@ -18,28 +18,36 @@ class FourCC {
|
|||
protected:
|
||||
union {
|
||||
char fcc[4];
|
||||
uint32_t num;
|
||||
uint32_t num = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
constexpr FourCC() /* Sentinel FourCC */
|
||||
: num(0) {}
|
||||
constexpr FourCC(const FourCC& other) : num(other.num) {}
|
||||
constexpr FourCC(const char* name) : num(*(uint32_t*)name) {}
|
||||
constexpr FourCC(uint32_t n) : num(n) {}
|
||||
bool operator==(const FourCC& other) const { return num == other.num; }
|
||||
bool operator!=(const FourCC& other) const { return num != other.num; }
|
||||
bool operator==(const char* other) const { return num == *(uint32_t*)other; }
|
||||
bool operator!=(const char* other) const { return num != *(uint32_t*)other; }
|
||||
bool operator==(int32_t other) const { return num == uint32_t(other); }
|
||||
bool operator!=(int32_t other) const { return num != uint32_t(other); }
|
||||
bool operator==(uint32_t other) const { return num == other; }
|
||||
bool operator!=(uint32_t other) const { return num != other; }
|
||||
std::string toString() const { return std::string(fcc, 4); }
|
||||
uint32_t toUint32() const { return num; }
|
||||
const char* getChars() const { return fcc; }
|
||||
char* getChars() { return fcc; }
|
||||
bool IsValid() const { return num != 0; }
|
||||
// Sentinel FourCC
|
||||
constexpr FourCC() noexcept = default;
|
||||
constexpr FourCC(const FourCC& other) noexcept = default;
|
||||
constexpr FourCC(FourCC&& other) noexcept = default;
|
||||
constexpr FourCC(const char* name) noexcept : fcc{name[0], name[1], name[2], name[3]} {}
|
||||
constexpr FourCC(uint32_t n) noexcept : num(n) {}
|
||||
|
||||
constexpr FourCC& operator=(const FourCC&) noexcept = default;
|
||||
constexpr FourCC& operator=(FourCC&&) noexcept = default;
|
||||
|
||||
constexpr bool operator==(const FourCC& other) const { return num == other.num; }
|
||||
constexpr bool operator!=(const FourCC& other) const { return !operator==(other); }
|
||||
constexpr bool operator==(const char* other) const {
|
||||
return other[0] == fcc[0] && other[1] == fcc[1] && other[2] == fcc[2] && other[3] == fcc[3];
|
||||
}
|
||||
constexpr bool operator!=(const char* other) const { return !operator==(other); }
|
||||
constexpr bool operator==(int32_t other) const { return num == uint32_t(other); }
|
||||
constexpr bool operator!=(int32_t other) const { return !operator==(other); }
|
||||
constexpr bool operator==(uint32_t other) const { return num == other; }
|
||||
constexpr bool operator!=(uint32_t other) const { return !operator==(other); }
|
||||
|
||||
std::string toString() const { return std::string(std::begin(fcc), std::end(fcc)); }
|
||||
constexpr uint32_t toUint32() const { return num; }
|
||||
constexpr const char* getChars() const { return fcc; }
|
||||
constexpr char* getChars() { return fcc; }
|
||||
constexpr bool IsValid() const { return num != 0; }
|
||||
};
|
||||
#define FOURCC(chars) FourCC(SBIG(chars))
|
||||
|
||||
|
@ -55,25 +63,25 @@ public:
|
|||
AT_DECL_EXPLICIT_DNA_YAML
|
||||
};
|
||||
template <>
|
||||
inline void DNAFourCC::Enumerate<BigDNA::Read>(typename Read::StreamT& r) {
|
||||
r.readUBytesToBuf(fcc, 4);
|
||||
inline void DNAFourCC::Enumerate<BigDNA::Read>(Read::StreamT& r) {
|
||||
r.readUBytesToBuf(fcc, std::size(fcc));
|
||||
}
|
||||
template <>
|
||||
inline void DNAFourCC::Enumerate<BigDNA::Write>(typename Write::StreamT& w) {
|
||||
w.writeUBytes((atUint8*)fcc, 4);
|
||||
inline void DNAFourCC::Enumerate<BigDNA::Write>(Write::StreamT& w) {
|
||||
w.writeBytes(fcc, std::size(fcc));
|
||||
}
|
||||
template <>
|
||||
inline void DNAFourCC::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& r) {
|
||||
std::string rs = r.readString(nullptr);
|
||||
strncpy(fcc, rs.c_str(), 4);
|
||||
inline void DNAFourCC::Enumerate<BigDNA::ReadYaml>(ReadYaml::StreamT& r) {
|
||||
const std::string rs = r.readString(nullptr);
|
||||
rs.copy(fcc, std::size(fcc));
|
||||
}
|
||||
template <>
|
||||
inline void DNAFourCC::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& w) {
|
||||
w.writeString(nullptr, std::string(fcc, 4));
|
||||
inline void DNAFourCC::Enumerate<BigDNA::WriteYaml>(WriteYaml::StreamT& w) {
|
||||
w.writeString(nullptr, std::string_view{fcc, std::size(fcc)});
|
||||
}
|
||||
template <>
|
||||
inline void DNAFourCC::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
|
||||
s += 4;
|
||||
inline void DNAFourCC::Enumerate<BigDNA::BinarySize>(BinarySize::StreamT& s) {
|
||||
s += std::size(fcc);
|
||||
}
|
||||
|
||||
} // namespace hecl
|
||||
|
@ -85,7 +93,7 @@ struct hash<hecl::FourCC> {
|
|||
};
|
||||
} // namespace std
|
||||
|
||||
FMT_CUSTOM_FORMATTER(hecl::FourCC, "{:c}{:c}{:c}{:c}",
|
||||
obj.getChars()[0], obj.getChars()[1], obj.getChars()[2], obj.getChars()[3])
|
||||
FMT_CUSTOM_FORMATTER(hecl::DNAFourCC, "{:c}{:c}{:c}{:c}",
|
||||
obj.getChars()[0], obj.getChars()[1], obj.getChars()[2], obj.getChars()[3])
|
||||
FMT_CUSTOM_FORMATTER(hecl::FourCC, "{:c}{:c}{:c}{:c}", obj.getChars()[0], obj.getChars()[1], obj.getChars()[2],
|
||||
obj.getChars()[3])
|
||||
FMT_CUSTOM_FORMATTER(hecl::DNAFourCC, "{:c}{:c}{:c}{:c}", obj.getChars()[0], obj.getChars()[1], obj.getChars()[2],
|
||||
obj.getChars()[3])
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
#include "Compilers.hpp"
|
||||
extern "C" unsigned long long XXH64(const void* input, size_t length, unsigned long long seed);
|
||||
#include "../extern/boo/xxhash/xxhash.h"
|
||||
|
||||
#define HECL_RUNTIME 1
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ namespace hecl {
|
|||
|
||||
#if HECL_UCS2
|
||||
typedef wchar_t SystemChar;
|
||||
static inline size_t StrLen(const SystemChar* str) { return wcslen(str); }
|
||||
typedef std::wstring SystemString;
|
||||
typedef std::wstring_view SystemStringView;
|
||||
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towlower); }
|
||||
|
@ -37,15 +36,22 @@ static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.
|
|||
typedef struct _stat Sstat;
|
||||
#else
|
||||
typedef char SystemChar;
|
||||
static inline size_t StrLen(const SystemChar* str) { return strlen(str); }
|
||||
typedef std::string SystemString;
|
||||
typedef std::string_view SystemStringView;
|
||||
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), tolower); }
|
||||
static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), toupper); }
|
||||
static inline void ToLower(SystemString& str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(),
|
||||
[](SystemChar c) { return std::tolower(static_cast<unsigned char>(c)); });
|
||||
}
|
||||
static inline void ToUpper(SystemString& str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(),
|
||||
[](SystemChar c) { return std::toupper(static_cast<unsigned char>(c)); });
|
||||
}
|
||||
#ifndef _SYS_STR
|
||||
#define _SYS_STR(val) val
|
||||
#endif
|
||||
typedef struct stat Sstat;
|
||||
#endif
|
||||
|
||||
constexpr size_t StrLen(const SystemChar* str) { return std::char_traits<SystemChar>::length(str); }
|
||||
|
||||
} // namespace hecl
|
||||
|
|
|
@ -173,7 +173,7 @@ public:
|
|||
}, static_cast<const base&>(*this));
|
||||
}
|
||||
|
||||
constexpr operator bool() const noexcept {
|
||||
constexpr explicit operator bool() const noexcept {
|
||||
return !std::holds_alternative<typename std::variant_alternative_t<0, std::variant<_Types...>>>(*this);
|
||||
}
|
||||
};
|
||||
|
@ -204,7 +204,7 @@ template <> \
|
|||
template <> \
|
||||
inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::Read>(typename Read::StreamT & r) { \
|
||||
EnumType variant_type = {}; \
|
||||
Do<athena::io::DNA<athena::Big>::Read>({"variant_type"}, variant_type, r); \
|
||||
Do<athena::io::DNA<athena::Big>::Read>(athena::io::PropId("variant_type"), variant_type, r); \
|
||||
static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type); \
|
||||
visit([&](auto& var) { var.read(r); }); \
|
||||
} \
|
||||
|
@ -215,7 +215,7 @@ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<ath
|
|||
visit([&](auto& var) { \
|
||||
using T = std::decay_t<decltype(var)>; \
|
||||
EnumType variant_type = T::variant_type(); \
|
||||
Do<athena::io::DNA<athena::Big>::Write>({"variant_type"}, variant_type, w); \
|
||||
Do<athena::io::DNA<athena::Big>::Write>(athena::io::PropId("variant_type"), variant_type, w); \
|
||||
var.write(w); \
|
||||
}); \
|
||||
} \
|
||||
|
@ -226,7 +226,7 @@ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<ath
|
|||
visit([&](auto& var) { \
|
||||
using T = std::decay_t<decltype(var)>; \
|
||||
EnumType variant_type = T::variant_type(); \
|
||||
Do<athena::io::DNA<athena::Big>::BinarySize>({"variant_type"}, variant_type, sz); \
|
||||
Do<athena::io::DNA<athena::Big>::BinarySize>(athena::io::PropId("variant_type"), variant_type, sz); \
|
||||
var.binarySize(sz); \
|
||||
}); \
|
||||
} \
|
||||
|
@ -241,7 +241,7 @@ template <> \
|
|||
template <> \
|
||||
inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::ReadYaml>(typename ReadYaml::StreamT & r) { \
|
||||
EnumType variant_type = {}; \
|
||||
Do<athena::io::DNA<athena::Big>::ReadYaml>({"variant_type"}, variant_type, r); \
|
||||
Do<athena::io::DNA<athena::Big>::ReadYaml>(athena::io::PropId("variant_type"), variant_type, r); \
|
||||
static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type); \
|
||||
visit([&](auto& var) { var.read(r); }); \
|
||||
} \
|
||||
|
@ -252,7 +252,7 @@ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<ath
|
|||
visit([&](auto& var) { \
|
||||
using T = std::decay_t<decltype(var)>; \
|
||||
EnumType variant_type = T::variant_type(); \
|
||||
Do<athena::io::DNA<athena::Big>::WriteYaml>({"variant_type"}, variant_type, w); \
|
||||
Do<athena::io::DNA<athena::Big>::WriteYaml>(athena::io::PropId("variant_type"), variant_type, w); \
|
||||
var.write(w); \
|
||||
}); \
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ public:
|
|||
return {bucket.buffer, m_div.rem * m_pool->m_stride};
|
||||
}
|
||||
|
||||
operator bool() const { return m_pool != nullptr && m_index != -1; }
|
||||
explicit operator bool() const { return m_pool != nullptr && m_index != -1; }
|
||||
};
|
||||
|
||||
UniformBufferPool() = default;
|
||||
|
|
|
@ -158,7 +158,7 @@ public:
|
|||
return {bucket.buffer, m_div.rem};
|
||||
}
|
||||
|
||||
operator bool() const { return m_pool != nullptr && m_index != -1; }
|
||||
explicit operator bool() const { return m_pool != nullptr && m_index != -1; }
|
||||
};
|
||||
|
||||
VertexBufferPool() = default;
|
||||
|
|
|
@ -22,20 +22,22 @@ extern "C" int rep_closefrom(int lower);
|
|||
#endif
|
||||
#include <Windows.h>
|
||||
#include <cwchar>
|
||||
#include <cwctype>
|
||||
#include <Shlwapi.h>
|
||||
#include "winsupport.hpp"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <ctime>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include "logvisor/logvisor.hpp"
|
||||
#include "athena/Global.hpp"
|
||||
#include "../extern/boo/xxhash/xxhash.h"
|
||||
|
@ -109,46 +111,66 @@ class SystemUTF8Conv {
|
|||
|
||||
public:
|
||||
explicit SystemUTF8Conv(SystemStringView str) : m_utf8(WideToUTF8(str)) {}
|
||||
|
||||
std::string_view str() const { return m_utf8; }
|
||||
const char* c_str() const { return m_utf8.c_str(); }
|
||||
std::string operator+(std::string_view other) const { return m_utf8 + other.data(); }
|
||||
|
||||
friend std::string operator+(const SystemUTF8Conv& lhs, std::string_view rhs) { return lhs.m_utf8 + rhs.data(); }
|
||||
friend std::string operator+(std::string_view lhs, const SystemUTF8Conv& rhs) {
|
||||
return std::string(lhs).append(rhs.m_utf8);
|
||||
}
|
||||
};
|
||||
inline std::string operator+(std::string_view lhs, const SystemUTF8Conv& rhs) { return std::string(lhs) + rhs.c_str(); }
|
||||
|
||||
class SystemStringConv {
|
||||
std::wstring m_sys;
|
||||
|
||||
public:
|
||||
explicit SystemStringConv(std::string_view str) : m_sys(UTF8ToWide(str)) {}
|
||||
|
||||
SystemStringView sys_str() const { return m_sys; }
|
||||
const SystemChar* c_str() const { return m_sys.c_str(); }
|
||||
std::wstring operator+(const std::wstring_view other) const { return m_sys + other.data(); }
|
||||
|
||||
friend std::wstring operator+(const SystemStringConv& lhs, const std::wstring_view rhs) {
|
||||
return lhs.m_sys + rhs.data();
|
||||
}
|
||||
friend std::wstring operator+(std::wstring_view lhs, const SystemStringConv& rhs) {
|
||||
return std::wstring(lhs).append(rhs.m_sys);
|
||||
}
|
||||
};
|
||||
inline std::wstring operator+(std::wstring_view lhs, const SystemStringConv& rhs) {
|
||||
return std::wstring(lhs) + rhs.c_str();
|
||||
}
|
||||
#else
|
||||
class SystemUTF8Conv {
|
||||
std::string_view m_utf8;
|
||||
|
||||
public:
|
||||
explicit SystemUTF8Conv(SystemStringView str) : m_utf8(str) {}
|
||||
|
||||
std::string_view str() const { return m_utf8; }
|
||||
const char* c_str() const { return m_utf8.data(); }
|
||||
std::string operator+(std::string_view other) const { return std::string(m_utf8) + other.data(); }
|
||||
|
||||
friend std::string operator+(const SystemUTF8Conv& lhs, std::string_view rhs) {
|
||||
return std::string(lhs.m_utf8).append(rhs);
|
||||
}
|
||||
friend std::string operator+(std::string_view lhs, const SystemUTF8Conv& rhs) {
|
||||
return std::string(lhs).append(rhs.m_utf8);
|
||||
}
|
||||
};
|
||||
inline std::string operator+(std::string_view lhs, const SystemUTF8Conv& rhs) { return std::string(lhs) + rhs.c_str(); }
|
||||
|
||||
class SystemStringConv {
|
||||
std::string_view m_sys;
|
||||
|
||||
public:
|
||||
explicit SystemStringConv(std::string_view str) : m_sys(str) {}
|
||||
|
||||
SystemStringView sys_str() const { return m_sys; }
|
||||
const SystemChar* c_str() const { return m_sys.data(); }
|
||||
std::string operator+(std::string_view other) const { return std::string(m_sys) + other.data(); }
|
||||
|
||||
friend std::string operator+(const SystemStringConv& lhs, std::string_view rhs) {
|
||||
return std::string(lhs.m_sys).append(rhs);
|
||||
}
|
||||
friend std::string operator+(std::string_view lhs, const SystemStringConv& rhs) {
|
||||
return std::string(lhs).append(rhs.m_sys);
|
||||
}
|
||||
};
|
||||
inline std::string operator+(std::string_view lhs, const SystemStringConv& rhs) {
|
||||
return std::string(lhs) + rhs.c_str();
|
||||
}
|
||||
#endif
|
||||
|
||||
void SanitizePath(std::string& path);
|
||||
|
@ -167,7 +189,7 @@ inline void MakeDir(const char* dir) {
|
|||
HRESULT err;
|
||||
if (!CreateDirectoryA(dir, NULL))
|
||||
if ((err = GetLastError()) != ERROR_ALREADY_EXISTS)
|
||||
LogModule.report(logvisor::Fatal, fmt("MakeDir(%s)"), dir);
|
||||
LogModule.report(logvisor::Fatal, fmt("MakeDir({})"), dir);
|
||||
#else
|
||||
if (mkdir(dir, 0755))
|
||||
if (errno != EEXIST)
|
||||
|
@ -180,7 +202,7 @@ inline void MakeDir(const wchar_t* dir) {
|
|||
HRESULT err;
|
||||
if (!CreateDirectoryW(dir, NULL))
|
||||
if ((err = GetLastError()) != ERROR_ALREADY_EXISTS)
|
||||
LogModule.report(logvisor::Fatal, fmt(_SYS_STR("MakeDir(%s)")), dir);
|
||||
LogModule.report(logvisor::Fatal, fmt(_SYS_STR("MakeDir({})")), dir);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -253,6 +275,16 @@ inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType
|
|||
return fp;
|
||||
}
|
||||
|
||||
struct UniqueFileDeleter {
|
||||
void operator()(FILE* file) const noexcept { std::fclose(file); }
|
||||
};
|
||||
using UniqueFilePtr = std::unique_ptr<FILE, UniqueFileDeleter>;
|
||||
|
||||
inline UniqueFilePtr FopenUnique(const SystemChar* path, const SystemChar* mode,
|
||||
FileLockType lock = FileLockType::None) {
|
||||
return UniqueFilePtr{Fopen(path, mode, lock)};
|
||||
}
|
||||
|
||||
inline int FSeek(FILE* fp, int64_t offset, int whence) {
|
||||
#if _WIN32
|
||||
return _fseeki64(fp, offset, whence);
|
||||
|
@ -309,11 +341,8 @@ inline int StrCmp(const SystemChar* str1, const SystemChar* str2) {
|
|||
inline int StrNCmp(const SystemChar* str1, const SystemChar* str2, size_t count) {
|
||||
if (!str1 || !str2)
|
||||
return str1 != str2;
|
||||
#if HECL_UCS2
|
||||
return wcsncmp(str1, str2, count);
|
||||
#else
|
||||
return strncmp(str1, str2, count);
|
||||
#endif
|
||||
|
||||
return std::char_traits<SystemChar>::compare(str1, str2, count);
|
||||
}
|
||||
|
||||
inline int StrCaseCmp(const SystemChar* str1, const SystemChar* str2) {
|
||||
|
@ -341,11 +370,11 @@ inline bool CheckFreeSpace(const SystemChar* path, size_t reqSz) {
|
|||
wchar_t* end;
|
||||
DWORD ret = GetFullPathNameW(path, 1024, buf, &end);
|
||||
if (!ret || ret > 1024)
|
||||
LogModule.report(logvisor::Fatal, fmt(_SYS_STR("GetFullPathNameW %s")), path);
|
||||
LogModule.report(logvisor::Fatal, fmt(_SYS_STR("GetFullPathNameW {}")), path);
|
||||
if (end)
|
||||
end[0] = L'\0';
|
||||
if (!GetDiskFreeSpaceExW(buf, &freeBytes, nullptr, nullptr))
|
||||
LogModule.report(logvisor::Fatal, fmt(_SYS_STR("GetDiskFreeSpaceExW %s: %d")), path, GetLastError());
|
||||
LogModule.report(logvisor::Fatal, fmt(_SYS_STR("GetDiskFreeSpaceExW {}: {}")), path, GetLastError());
|
||||
return reqSz < freeBytes.QuadPart;
|
||||
#else
|
||||
struct statvfs svfs;
|
||||
|
@ -391,13 +420,12 @@ inline int ConsoleWidth(bool* ok = nullptr) {
|
|||
}
|
||||
|
||||
class MultiProgressPrinter;
|
||||
|
||||
typedef std::basic_regex<SystemChar> SystemRegex;
|
||||
typedef std::regex_token_iterator<SystemString::const_iterator> SystemRegexTokenIterator;
|
||||
typedef std::match_results<SystemString::const_iterator> SystemRegexMatch;
|
||||
|
||||
class ProjectRootPath;
|
||||
|
||||
using SystemRegex = std::basic_regex<SystemChar>;
|
||||
using SystemRegexMatch = std::match_results<SystemString::const_iterator>;
|
||||
using SystemRegexTokenIterator = std::regex_token_iterator<SystemString::const_iterator>;
|
||||
|
||||
/**
|
||||
* @brief Hash representation used for all storable and comparable objects
|
||||
*
|
||||
|
@ -409,35 +437,36 @@ protected:
|
|||
uint64_t hash = 0;
|
||||
|
||||
public:
|
||||
Hash() = default;
|
||||
operator bool() const { return hash != 0; }
|
||||
Hash(const void* buf, size_t len) : hash(XXH64((uint8_t*)buf, len, 0)) {}
|
||||
Hash(std::string_view str) : hash(XXH64((uint8_t*)str.data(), str.size(), 0)) {}
|
||||
Hash(std::wstring_view str) : hash(XXH64((uint8_t*)str.data(), str.size() * 2, 0)) {}
|
||||
Hash(uint64_t hashin) : hash(hashin) {}
|
||||
Hash(const Hash& other) { hash = other.hash; }
|
||||
uint32_t val32() const { return uint32_t(hash) ^ uint32_t(hash >> 32); }
|
||||
uint64_t val64() const { return uint64_t(hash); }
|
||||
size_t valSizeT() const { return size_t(hash); }
|
||||
constexpr Hash() noexcept = default;
|
||||
constexpr Hash(const Hash&) noexcept = default;
|
||||
constexpr Hash(Hash&&) noexcept = default;
|
||||
constexpr Hash(uint64_t hashin) noexcept : hash(hashin) {}
|
||||
explicit Hash(const void* buf, size_t len) noexcept : hash(XXH64(buf, len, 0)) {}
|
||||
explicit Hash(std::string_view str) noexcept : hash(XXH64(str.data(), str.size(), 0)) {}
|
||||
explicit Hash(std::wstring_view str) noexcept : hash(XXH64(str.data(), str.size() * 2, 0)) {}
|
||||
|
||||
constexpr uint32_t val32() const noexcept { return uint32_t(hash) ^ uint32_t(hash >> 32); }
|
||||
constexpr uint64_t val64() const noexcept { return uint64_t(hash); }
|
||||
constexpr size_t valSizeT() const noexcept { return size_t(hash); }
|
||||
template <typename T>
|
||||
T valT() const;
|
||||
Hash& operator=(const Hash& other) {
|
||||
hash = other.hash;
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const Hash& other) const { return hash == other.hash; }
|
||||
bool operator!=(const Hash& other) const { return hash != other.hash; }
|
||||
bool operator<(const Hash& other) const { return hash < other.hash; }
|
||||
bool operator>(const Hash& other) const { return hash > other.hash; }
|
||||
bool operator<=(const Hash& other) const { return hash <= other.hash; }
|
||||
bool operator>=(const Hash& other) const { return hash >= other.hash; }
|
||||
constexpr T valT() const noexcept;
|
||||
|
||||
constexpr Hash& operator=(const Hash& other) noexcept = default;
|
||||
constexpr Hash& operator=(Hash&& other) noexcept = default;
|
||||
constexpr bool operator==(const Hash& other) const noexcept { return hash == other.hash; }
|
||||
constexpr bool operator!=(const Hash& other) const noexcept { return !operator==(other); }
|
||||
constexpr bool operator<(const Hash& other) const noexcept { return hash < other.hash; }
|
||||
constexpr bool operator>(const Hash& other) const noexcept { return hash > other.hash; }
|
||||
constexpr bool operator<=(const Hash& other) const noexcept { return hash <= other.hash; }
|
||||
constexpr bool operator>=(const Hash& other) const noexcept { return hash >= other.hash; }
|
||||
constexpr explicit operator bool() const noexcept { return hash != 0; }
|
||||
};
|
||||
template <>
|
||||
inline uint32_t Hash::valT<uint32_t>() const {
|
||||
constexpr uint32_t Hash::valT<uint32_t>() const noexcept {
|
||||
return val32();
|
||||
}
|
||||
template <>
|
||||
inline uint64_t Hash::valT<uint64_t>() const {
|
||||
constexpr uint64_t Hash::valT<uint64_t>() const noexcept {
|
||||
return val64();
|
||||
}
|
||||
|
||||
|
@ -469,22 +498,16 @@ public:
|
|||
*/
|
||||
struct CaseInsensitiveCompare {
|
||||
bool operator()(std::string_view lhs, std::string_view rhs) const {
|
||||
#if _WIN32
|
||||
if (_stricmp(lhs.data(), rhs.data()) < 0)
|
||||
#else
|
||||
if (strcasecmp(lhs.data(), rhs.data()) < 0)
|
||||
#endif
|
||||
return true;
|
||||
return false;
|
||||
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](char lhs, char rhs) {
|
||||
return std::tolower(static_cast<unsigned char>(lhs)) < std::tolower(static_cast<unsigned char>(rhs));
|
||||
});
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
bool operator()(std::wstring_view lhs, std::wstring_view rhs) const {
|
||||
if (_wcsicmp(lhs.data(), rhs.data()) < 0)
|
||||
return true;
|
||||
return false;
|
||||
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](wchar_t lhs, wchar_t rhs) {
|
||||
return std::towlower(lhs) < std::towlower(rhs);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -499,8 +522,8 @@ public:
|
|||
size_t m_fileSz;
|
||||
bool m_isDir;
|
||||
|
||||
Entry(const hecl::SystemString& path, const hecl::SystemChar* name, size_t sz, bool isDir)
|
||||
: m_path(path), m_name(name), m_fileSz(sz), m_isDir(isDir) {}
|
||||
Entry(hecl::SystemString path, const hecl::SystemChar* name, size_t sz, bool isDir)
|
||||
: m_path(std::move(path)), m_name(name), m_fileSz(sz), m_isDir(isDir) {}
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -510,7 +533,7 @@ public:
|
|||
DirectoryEnumerator(SystemStringView path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
|
||||
bool reverse = false, bool noHidden = false);
|
||||
|
||||
operator bool() const { return m_entries.size() != 0; }
|
||||
explicit operator bool() const { return m_entries.size() != 0; }
|
||||
size_t size() const { return m_entries.size(); }
|
||||
std::vector<Entry>::const_iterator begin() const { return m_entries.cbegin(); }
|
||||
std::vector<Entry>::const_iterator end() const { return m_entries.cend(); }
|
||||
|
@ -542,7 +565,7 @@ public:
|
|||
/**
|
||||
* @brief Tests for non-empty project root path
|
||||
*/
|
||||
operator bool() const { return m_projRoot.size() != 0; }
|
||||
explicit operator bool() const { return m_projRoot.size() != 0; }
|
||||
|
||||
/**
|
||||
* @brief Construct a representation of a project root path
|
||||
|
@ -577,7 +600,8 @@ public:
|
|||
return SystemString(beginIt, absPathForward.cend());
|
||||
}
|
||||
}
|
||||
LogModule.report(logvisor::Fatal, fmt(_SYS_STR("unable to resolve '{}' as project relative '{}'")), absPath, m_projRoot);
|
||||
LogModule.report(logvisor::Fatal, fmt(_SYS_STR("unable to resolve '{}' as project relative '{}'")), absPath,
|
||||
m_projRoot);
|
||||
return SystemString();
|
||||
}
|
||||
|
||||
|
@ -593,9 +617,9 @@ public:
|
|||
* @brief HECL-specific xxhash
|
||||
* @return unique hash value
|
||||
*/
|
||||
Hash hash() const { return m_hash; }
|
||||
bool operator==(const ProjectRootPath& other) const { return m_hash == other.m_hash; }
|
||||
bool operator!=(const ProjectRootPath& other) const { return m_hash != other.m_hash; }
|
||||
Hash hash() const noexcept { return m_hash; }
|
||||
bool operator==(const ProjectRootPath& other) const noexcept { return m_hash == other.m_hash; }
|
||||
bool operator!=(const ProjectRootPath& other) const noexcept { return !operator==(other); }
|
||||
|
||||
/**
|
||||
* @brief Obtain c-string of final path component
|
||||
|
@ -661,7 +685,7 @@ public:
|
|||
/**
|
||||
* @brief Tests for non-empty project path
|
||||
*/
|
||||
operator bool() const { return m_absPath.size() != 0; }
|
||||
explicit operator bool() const { return m_absPath.size() != 0; }
|
||||
|
||||
/**
|
||||
* @brief Clears path
|
||||
|
@ -1026,9 +1050,9 @@ public:
|
|||
* @brief HECL-specific xxhash
|
||||
* @return unique hash value
|
||||
*/
|
||||
Hash hash() const { return m_hash; }
|
||||
bool operator==(const ProjectPath& other) const { return m_hash == other.m_hash; }
|
||||
bool operator!=(const ProjectPath& other) const { return m_hash != other.m_hash; }
|
||||
Hash hash() const noexcept { return m_hash; }
|
||||
bool operator==(const ProjectPath& other) const noexcept { return m_hash == other.m_hash; }
|
||||
bool operator!=(const ProjectPath& other) const noexcept { return !operator==(other); }
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1039,21 +1063,21 @@ public:
|
|||
static bool BeginsWith(SystemStringView str, SystemStringView test) {
|
||||
if (test.size() > str.size())
|
||||
return false;
|
||||
return !StrNCmp(str.data(), test.data(), test.size());
|
||||
return str.compare(0, test.size(), test) == 0;
|
||||
}
|
||||
|
||||
static bool EndsWith(SystemStringView str, SystemStringView test) {
|
||||
if (test.size() > str.size())
|
||||
return false;
|
||||
return !StrNCmp(&*(str.end() - test.size()), test.data(), test.size());
|
||||
return str.compare(str.size() - test.size(), SystemStringView::npos, test) == 0;
|
||||
}
|
||||
|
||||
static std::string TrimWhitespace(std::string_view str) {
|
||||
auto bit = str.begin();
|
||||
while (bit != str.cend() && isspace(*bit))
|
||||
while (bit != str.cend() && std::isspace(static_cast<unsigned char>(*bit)))
|
||||
++bit;
|
||||
auto eit = str.end();
|
||||
while (eit != str.cbegin() && isspace(*(eit - 1)))
|
||||
while (eit != str.cbegin() && std::isspace(static_cast<unsigned char>(*(eit - 1))))
|
||||
--eit;
|
||||
return {bit, eit};
|
||||
}
|
||||
|
@ -1062,21 +1086,21 @@ public:
|
|||
static bool BeginsWith(std::string_view str, std::string_view test) {
|
||||
if (test.size() > str.size())
|
||||
return false;
|
||||
return !strncmp(str.data(), test.data(), test.size());
|
||||
return str.compare(0, test.size(), test) == 0;
|
||||
}
|
||||
|
||||
static bool EndsWith(std::string_view str, std::string_view test) {
|
||||
if (test.size() > str.size())
|
||||
return false;
|
||||
return !strncmp(&*(str.end() - test.size()), test.data(), test.size());
|
||||
return str.compare(str.size() - test.size(), std::string_view::npos, test) == 0;
|
||||
}
|
||||
|
||||
static SystemString TrimWhitespace(SystemStringView str) {
|
||||
auto bit = str.begin();
|
||||
while (bit != str.cend() && iswspace(*bit))
|
||||
while (bit != str.cend() && std::iswspace(*bit))
|
||||
++bit;
|
||||
auto eit = str.end();
|
||||
while (eit != str.cbegin() && iswspace(*(eit - 1)))
|
||||
while (eit != str.cbegin() && std::iswspace(*(eit - 1)))
|
||||
--eit;
|
||||
return {bit, eit};
|
||||
}
|
||||
|
@ -1095,9 +1119,9 @@ class ResourceLock {
|
|||
bool good;
|
||||
|
||||
public:
|
||||
operator bool() const { return good; }
|
||||
explicit operator bool() const { return good; }
|
||||
static bool InProgress(const ProjectPath& path);
|
||||
ResourceLock(const ProjectPath& path) { good = SetThreadRes(path); }
|
||||
explicit ResourceLock(const ProjectPath& path) : good{SetThreadRes(path)} {}
|
||||
~ResourceLock() {
|
||||
if (good)
|
||||
ClearThreadRes();
|
||||
|
@ -1150,7 +1174,7 @@ bool IsPathYAML(const hecl::ProjectPath& path);
|
|||
|
||||
/* Type-sensitive byte swappers */
|
||||
template <typename T>
|
||||
constexpr T bswap16(T val) {
|
||||
constexpr T bswap16(T val) noexcept {
|
||||
#if __GNUC__
|
||||
return __builtin_bswap16(val);
|
||||
#elif _WIN32
|
||||
|
@ -1161,7 +1185,7 @@ constexpr T bswap16(T val) {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T bswap32(T val) {
|
||||
constexpr T bswap32(T val) noexcept {
|
||||
#if __GNUC__
|
||||
return __builtin_bswap32(val);
|
||||
#elif _WIN32
|
||||
|
@ -1174,7 +1198,7 @@ constexpr T bswap32(T val) {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T bswap64(T val) {
|
||||
constexpr T bswap64(T val) noexcept {
|
||||
#if __GNUC__
|
||||
return __builtin_bswap64(val);
|
||||
#elif _WIN32
|
||||
|
@ -1188,49 +1212,61 @@ constexpr T bswap64(T val) {
|
|||
}
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
constexpr int16_t SBig(int16_t val) { return bswap16(val); }
|
||||
constexpr uint16_t SBig(uint16_t val) { return bswap16(val); }
|
||||
constexpr int32_t SBig(int32_t val) { return bswap32(val); }
|
||||
constexpr uint32_t SBig(uint32_t val) { return bswap32(val); }
|
||||
constexpr int64_t SBig(int64_t val) { return bswap64(val); }
|
||||
constexpr uint64_t SBig(uint64_t val) { return bswap64(val); }
|
||||
constexpr float SBig(float val) {
|
||||
union { float f; atInt32 i; } uval1 = {val};
|
||||
union { atInt32 i; float f; } uval2 = {bswap32(uval1.i)};
|
||||
constexpr int16_t SBig(int16_t val) noexcept { return bswap16(val); }
|
||||
constexpr uint16_t SBig(uint16_t val) noexcept { return bswap16(val); }
|
||||
constexpr int32_t SBig(int32_t val) noexcept { return bswap32(val); }
|
||||
constexpr uint32_t SBig(uint32_t val) noexcept { return bswap32(val); }
|
||||
constexpr int64_t SBig(int64_t val) noexcept { return bswap64(val); }
|
||||
constexpr uint64_t SBig(uint64_t val) noexcept { return bswap64(val); }
|
||||
constexpr float SBig(float val) noexcept {
|
||||
union {
|
||||
float f;
|
||||
atInt32 i;
|
||||
} uval1 = {val};
|
||||
union {
|
||||
atInt32 i;
|
||||
float f;
|
||||
} uval2 = {bswap32(uval1.i)};
|
||||
return uval2.f;
|
||||
}
|
||||
constexpr double SBig(double val) {
|
||||
union { double f; atInt64 i; } uval1 = {val};
|
||||
union { atInt64 i; double f; } uval2 = {bswap64(uval1.i)};
|
||||
constexpr double SBig(double val) noexcept {
|
||||
union {
|
||||
double f;
|
||||
atInt64 i;
|
||||
} uval1 = {val};
|
||||
union {
|
||||
atInt64 i;
|
||||
double f;
|
||||
} uval2 = {bswap64(uval1.i)};
|
||||
return uval2.f;
|
||||
}
|
||||
#ifndef SBIG
|
||||
#define SBIG(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
|
||||
#endif
|
||||
|
||||
constexpr int16_t SLittle(int16_t val) { return val; }
|
||||
constexpr uint16_t SLittle(uint16_t val) { return val; }
|
||||
constexpr int32_t SLittle(int32_t val) { return val; }
|
||||
constexpr uint32_t SLittle(uint32_t val) { return val; }
|
||||
constexpr int64_t SLittle(int64_t val) { return val; }
|
||||
constexpr uint64_t SLittle(uint64_t val) { return val; }
|
||||
constexpr float SLittle(float val) { return val; }
|
||||
constexpr double SLittle(double val) { return val; }
|
||||
constexpr int16_t SLittle(int16_t val) noexcept { return val; }
|
||||
constexpr uint16_t SLittle(uint16_t val) noexcept { return val; }
|
||||
constexpr int32_t SLittle(int32_t val) noexcept { return val; }
|
||||
constexpr uint32_t SLittle(uint32_t val) noexcept { return val; }
|
||||
constexpr int64_t SLittle(int64_t val) noexcept { return val; }
|
||||
constexpr uint64_t SLittle(uint64_t val) noexcept { return val; }
|
||||
constexpr float SLittle(float val) noexcept { return val; }
|
||||
constexpr double SLittle(double val) noexcept { return val; }
|
||||
#ifndef SLITTLE
|
||||
#define SLITTLE(q) (q)
|
||||
#endif
|
||||
#else
|
||||
constexpr int16_t SLittle(int16_t val) { return bswap16(val); }
|
||||
constexpr uint16_t SLittle(uint16_t val) { return bswap16(val); }
|
||||
constexpr int32_t SLittle(int32_t val) { return bswap32(val); }
|
||||
constexpr uint32_t SLittle(uint32_t val) { return bswap32(val); }
|
||||
constexpr int64_t SLittle(int64_t val) { return bswap64(val); }
|
||||
constexpr uint64_t SLittle(uint64_t val) { return bswap64(val); }
|
||||
constexpr float SLittle(float val) {
|
||||
constexpr int16_t SLittle(int16_t val) noexcept { return bswap16(val); }
|
||||
constexpr uint16_t SLittle(uint16_t val) noexcept { return bswap16(val); }
|
||||
constexpr int32_t SLittle(int32_t val) noexcept { return bswap32(val); }
|
||||
constexpr uint32_t SLittle(uint32_t val) noexcept { return bswap32(val); }
|
||||
constexpr int64_t SLittle(int64_t val) noexcept { return bswap64(val); }
|
||||
constexpr uint64_t SLittle(uint64_t val) noexcept { return bswap64(val); }
|
||||
constexpr float SLittle(float val) noexcept {
|
||||
int32_t ival = bswap32(*((int32_t*)(&val)));
|
||||
return *((float*)(&ival));
|
||||
}
|
||||
constexpr double SLittle(double val) {
|
||||
constexpr double SLittle(double val) noexcept {
|
||||
int64_t ival = bswap64(*((int64_t*)(&val)));
|
||||
return *((double*)(&ival));
|
||||
}
|
||||
|
@ -1238,22 +1274,22 @@ constexpr double SLittle(double val) {
|
|||
#define SLITTLE(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
|
||||
#endif
|
||||
|
||||
constexpr int16_t SBig(int16_t val) { return val; }
|
||||
constexpr uint16_t SBig(uint16_t val) { return val; }
|
||||
constexpr int32_t SBig(int32_t val) { return val; }
|
||||
constexpr uint32_t SBig(uint32_t val) { return val; }
|
||||
constexpr int64_t SBig(int64_t val) { return val; }
|
||||
constexpr uint64_t SBig(uint64_t val) { return val; }
|
||||
constexpr float SBig(float val) { return val; }
|
||||
constexpr double SBig(double val) { return val; }
|
||||
constexpr int16_t SBig(int16_t val) noexcept { return val; }
|
||||
constexpr uint16_t SBig(uint16_t val) noexcept { return val; }
|
||||
constexpr int32_t SBig(int32_t val) noexcept { return val; }
|
||||
constexpr uint32_t SBig(uint32_t val) noexcept { return val; }
|
||||
constexpr int64_t SBig(int64_t val) noexcept { return val; }
|
||||
constexpr uint64_t SBig(uint64_t val) noexcept { return val; }
|
||||
constexpr float SBig(float val) noexcept { return val; }
|
||||
constexpr double SBig(double val) noexcept { return val; }
|
||||
#ifndef SBIG
|
||||
#define SBIG(q) (q)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template <typename SizeT>
|
||||
constexpr void hash_combine_impl(SizeT& seed, SizeT value) {
|
||||
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
constexpr void hash_combine_impl(SizeT& seed, SizeT value) noexcept {
|
||||
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
} // namespace hecl
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cfloat>
|
||||
#include <chrono>
|
||||
#include <cinttypes>
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
#include <signal.h>
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
|
||||
#include <hecl/hecl.hpp>
|
||||
#include <hecl/Database.hpp>
|
||||
#include "logvisor/logvisor.hpp"
|
||||
#include "hecl/Blender/Connection.hpp"
|
||||
#include "hecl/Blender/Token.hpp"
|
||||
#include "hecl/SteamFinder.hpp"
|
||||
#include "MeshOptimizer.hpp"
|
||||
|
||||
#include <athena/MemoryWriter.hpp>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
#if _WIN32
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -60,19 +65,23 @@ extern "C" uint8_t HECL_STARTUP[];
|
|||
extern "C" size_t HECL_STARTUP_SZ;
|
||||
|
||||
static void InstallBlendershell(const SystemChar* path) {
|
||||
FILE* fp = hecl::Fopen(path, _SYS_STR("w"));
|
||||
if (!fp)
|
||||
auto fp = hecl::FopenUnique(path, _SYS_STR("w"));
|
||||
|
||||
if (fp == nullptr) {
|
||||
BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("unable to open {} for writing")), path);
|
||||
fwrite(HECL_BLENDERSHELL, 1, HECL_BLENDERSHELL_SZ, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
std::fwrite(HECL_BLENDERSHELL, 1, HECL_BLENDERSHELL_SZ, fp.get());
|
||||
}
|
||||
|
||||
static void InstallAddon(const SystemChar* path) {
|
||||
FILE* fp = hecl::Fopen(path, _SYS_STR("wb"));
|
||||
if (!fp)
|
||||
auto fp = hecl::FopenUnique(path, _SYS_STR("wb"));
|
||||
|
||||
if (fp == nullptr) {
|
||||
BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("Unable to install blender addon at '{}'")), path);
|
||||
fwrite(HECL_ADDON, 1, HECL_ADDON_SZ, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
std::fwrite(HECL_ADDON, 1, HECL_ADDON_SZ, fp.get());
|
||||
}
|
||||
|
||||
static int Read(int fd, void* buf, size_t size) {
|
||||
|
@ -107,7 +116,7 @@ static int Write(int fd, const void* buf, size_t size) {
|
|||
|
||||
uint32_t Connection::_readStr(char* buf, uint32_t bufSz) {
|
||||
uint32_t readLen;
|
||||
int ret = Read(m_readpipe[0], &readLen, 4);
|
||||
int ret = Read(m_readpipe[0], &readLen, sizeof(readLen));
|
||||
if (ret < 4) {
|
||||
BlenderLog.report(logvisor::Error, fmt("Pipe error {} {}"), ret, strerror(errno));
|
||||
_blenderDied();
|
||||
|
@ -124,8 +133,11 @@ uint32_t Connection::_readStr(char* buf, uint32_t bufSz) {
|
|||
if (ret < 0) {
|
||||
BlenderLog.report(logvisor::Fatal, fmt("{}"), strerror(errno));
|
||||
return 0;
|
||||
} else if (readLen >= 9) {
|
||||
if (!memcmp(buf, "EXCEPTION", std::min(readLen, uint32_t(9)))) {
|
||||
}
|
||||
|
||||
constexpr std::string_view exception_str{"EXCEPTION"};
|
||||
if (readLen >= exception_str.size()) {
|
||||
if (exception_str.compare(0, exception_str.size(), buf) == 0) {
|
||||
_blenderDied();
|
||||
return 0;
|
||||
}
|
||||
|
@ -136,54 +148,75 @@ uint32_t Connection::_readStr(char* buf, uint32_t bufSz) {
|
|||
}
|
||||
|
||||
uint32_t Connection::_writeStr(const char* buf, uint32_t len, int wpipe) {
|
||||
int ret, nlerr;
|
||||
nlerr = Write(wpipe, &len, 4);
|
||||
if (nlerr < 4)
|
||||
goto err;
|
||||
ret = Write(wpipe, buf, len);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
return (uint32_t)ret;
|
||||
err:
|
||||
const auto error = [this] {
|
||||
_blenderDied();
|
||||
return 0;
|
||||
return 0U;
|
||||
};
|
||||
|
||||
const int nlerr = Write(wpipe, &len, 4);
|
||||
if (nlerr < 4) {
|
||||
return error();
|
||||
}
|
||||
|
||||
const int ret = Write(wpipe, buf, len);
|
||||
if (ret < 0) {
|
||||
return error();
|
||||
}
|
||||
|
||||
return static_cast<uint32_t>(ret);
|
||||
}
|
||||
|
||||
size_t Connection::_readBuf(void* buf, size_t len) {
|
||||
uint8_t* cBuf = reinterpret_cast<uint8_t*>(buf);
|
||||
size_t readLen = 0;
|
||||
do {
|
||||
int ret = Read(m_readpipe[0], cBuf, len);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
if (len >= 9)
|
||||
if (!memcmp((char*)cBuf, "EXCEPTION", std::min(len, size_t(9))))
|
||||
const auto error = [this] {
|
||||
_blenderDied();
|
||||
return 0U;
|
||||
};
|
||||
|
||||
auto* cBuf = static_cast<uint8_t*>(buf);
|
||||
size_t readLen = 0;
|
||||
|
||||
do {
|
||||
const int ret = Read(m_readpipe[0], cBuf, len);
|
||||
if (ret < 0) {
|
||||
return error();
|
||||
}
|
||||
|
||||
constexpr std::string_view exception_str{"EXCEPTION"};
|
||||
if (len >= exception_str.size()) {
|
||||
if (exception_str.compare(0, exception_str.size(), static_cast<char*>(buf)) == 0) {
|
||||
_blenderDied();
|
||||
}
|
||||
}
|
||||
|
||||
readLen += ret;
|
||||
cBuf += ret;
|
||||
len -= ret;
|
||||
} while (len);
|
||||
} while (len != 0);
|
||||
|
||||
return readLen;
|
||||
err:
|
||||
_blenderDied();
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t Connection::_writeBuf(const void* buf, size_t len) {
|
||||
const uint8_t* cBuf = reinterpret_cast<const uint8_t*>(buf);
|
||||
const auto error = [this] {
|
||||
_blenderDied();
|
||||
return 0U;
|
||||
};
|
||||
|
||||
const auto* cBuf = static_cast<const uint8_t*>(buf);
|
||||
size_t writeLen = 0;
|
||||
|
||||
do {
|
||||
int ret = Write(m_writepipe[1], cBuf, len);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
const int ret = Write(m_writepipe[1], cBuf, len);
|
||||
if (ret < 0) {
|
||||
return error();
|
||||
}
|
||||
|
||||
writeLen += ret;
|
||||
cBuf += ret;
|
||||
len -= ret;
|
||||
} while (len);
|
||||
} while (len != 0);
|
||||
|
||||
return writeLen;
|
||||
err:
|
||||
_blenderDied();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Connection::_closePipe() {
|
||||
|
@ -200,18 +233,20 @@ void Connection::_closePipe() {
|
|||
|
||||
void Connection::_blenderDied() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
FILE* errFp = hecl::Fopen(m_errPath.c_str(), _SYS_STR("r"));
|
||||
if (errFp) {
|
||||
fseek(errFp, 0, SEEK_END);
|
||||
int64_t len = hecl::FTell(errFp);
|
||||
if (len) {
|
||||
fseek(errFp, 0, SEEK_SET);
|
||||
std::unique_ptr<char[]> buf(new char[len + 1]);
|
||||
memset(buf.get(), 0, len + 1);
|
||||
fread(buf.get(), 1, len, errFp);
|
||||
auto errFp = hecl::FopenUnique(m_errPath.c_str(), _SYS_STR("r"));
|
||||
|
||||
if (errFp != nullptr) {
|
||||
std::fseek(errFp.get(), 0, SEEK_END);
|
||||
const int64_t len = hecl::FTell(errFp.get());
|
||||
|
||||
if (len != 0) {
|
||||
std::fseek(errFp.get(), 0, SEEK_SET);
|
||||
const auto buf = std::make_unique<char[]>(len + 1);
|
||||
std::fread(buf.get(), 1, len, errFp.get());
|
||||
BlenderLog.report(logvisor::Fatal, fmt("\n{:.{}s}"), buf.get(), len);
|
||||
}
|
||||
}
|
||||
|
||||
BlenderLog.report(logvisor::Fatal, fmt("Blender Exception"));
|
||||
}
|
||||
|
||||
|
@ -253,14 +288,14 @@ Connection::Connection(int verbosityLevel) {
|
|||
while (true) {
|
||||
/* Construct communication pipes */
|
||||
#if _WIN32
|
||||
_pipe(m_readpipe, 2048, _O_BINARY);
|
||||
_pipe(m_writepipe, 2048, _O_BINARY);
|
||||
_pipe(m_readpipe.data(), 2048, _O_BINARY);
|
||||
_pipe(m_writepipe.data(), 2048, _O_BINARY);
|
||||
HANDLE writehandle = HANDLE(_get_osfhandle(m_writepipe[0]));
|
||||
SetHandleInformation(writehandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||
HANDLE readhandle = HANDLE(_get_osfhandle(m_readpipe[1]));
|
||||
SetHandleInformation(readhandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||
|
||||
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
|
||||
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE};
|
||||
HANDLE consoleOutReadTmp, consoleOutWrite, consoleErrWrite, consoleOutRead;
|
||||
if (!CreatePipe(&consoleOutReadTmp, &consoleOutWrite, &sattrs, 1024))
|
||||
BlenderLog.report(logvisor::Fatal, fmt("Error with CreatePipe"));
|
||||
|
@ -278,8 +313,8 @@ Connection::Connection(int verbosityLevel) {
|
|||
if (!CloseHandle(consoleOutReadTmp))
|
||||
BlenderLog.report(logvisor::Fatal, fmt("Error with CloseHandle"));
|
||||
#else
|
||||
pipe(m_readpipe);
|
||||
pipe(m_writepipe);
|
||||
pipe(m_readpipe.data());
|
||||
pipe(m_writepipe.data());
|
||||
#endif
|
||||
|
||||
/* User-specified blender path */
|
||||
|
@ -315,12 +350,12 @@ Connection::Connection(int verbosityLevel) {
|
|||
}
|
||||
}
|
||||
|
||||
std::wstring cmdLine = fmt::format(fmt(L" --background -P \"{}\" -- {} {} {} \"{}\""),
|
||||
blenderShellPath, uintptr_t(writehandle), uintptr_t(readhandle), verbosityLevel, blenderAddonPath);
|
||||
std::wstring cmdLine = fmt::format(fmt(L" --background -P \"{}\" -- {} {} {} \"{}\""), blenderShellPath,
|
||||
uintptr_t(writehandle), uintptr_t(readhandle), verbosityLevel, blenderAddonPath);
|
||||
|
||||
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
|
||||
HANDLE nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sattrs, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
sinfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
sinfo.hStdInput = nulHandle;
|
||||
if (verbosityLevel == 0) {
|
||||
|
@ -331,11 +366,12 @@ Connection::Connection(int verbosityLevel) {
|
|||
sinfo.hStdOutput = consoleOutWrite;
|
||||
}
|
||||
|
||||
if (!CreateProcessW(blenderBin, const_cast<wchar_t*>(cmdLine.c_str()), NULL, NULL, TRUE,
|
||||
NORMAL_PRIORITY_CLASS, NULL, NULL, &sinfo, &m_pinfo)) {
|
||||
if (!CreateProcessW(blenderBin, cmdLine.data(), nullptr, nullptr, TRUE, NORMAL_PRIORITY_CLASS, nullptr, nullptr,
|
||||
&sinfo, &m_pinfo)) {
|
||||
LPWSTR messageBuffer = nullptr;
|
||||
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
|
||||
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
|
||||
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0,
|
||||
nullptr);
|
||||
BlenderLog.report(logvisor::Fatal, fmt(L"unable to launch blender from {}: {}"), blenderBin, messageBuffer);
|
||||
}
|
||||
|
||||
|
@ -353,7 +389,7 @@ Connection::Connection(int verbosityLevel) {
|
|||
DWORD nCharsWritten;
|
||||
|
||||
while (m_consoleThreadRunning) {
|
||||
if (!ReadFile(consoleOutRead, lpBuffer, sizeof(lpBuffer), &nBytesRead, NULL) || !nBytesRead) {
|
||||
if (!ReadFile(consoleOutRead, lpBuffer, sizeof(lpBuffer), &nBytesRead, nullptr) || !nBytesRead) {
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_BROKEN_PIPE)
|
||||
break; // pipe done - normal exit path.
|
||||
|
@ -363,7 +399,7 @@ Connection::Connection(int verbosityLevel) {
|
|||
|
||||
// Display the character read on the screen.
|
||||
auto lk = logvisor::LockLog();
|
||||
if (!WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), lpBuffer, nBytesRead, &nCharsWritten, NULL)) {
|
||||
if (!WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), lpBuffer, nBytesRead, &nCharsWritten, nullptr)) {
|
||||
// BlenderLog.report(logvisor::Error, fmt("Error with WriteConsole: %08X"), GetLastError());
|
||||
}
|
||||
}
|
||||
|
@ -396,8 +432,8 @@ Connection::Connection(int verbosityLevel) {
|
|||
|
||||
/* Try user-specified blender first */
|
||||
if (blenderBin) {
|
||||
execlp(blenderBin, blenderBin, "--background", "-P", blenderShellPath.c_str(), "--",
|
||||
readfds.c_str(), writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), NULL);
|
||||
execlp(blenderBin, blenderBin, "--background", "-P", blenderShellPath.c_str(), "--", readfds.c_str(),
|
||||
writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
|
||||
if (errno != ENOENT) {
|
||||
errbuf = fmt::format(fmt("NOLAUNCH {}"), strerror(errno));
|
||||
_writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]);
|
||||
|
@ -414,8 +450,8 @@ Connection::Connection(int verbosityLevel) {
|
|||
steamBlender += "/blender";
|
||||
#endif
|
||||
blenderBin = steamBlender.c_str();
|
||||
execlp(blenderBin, blenderBin, "--background", "-P", blenderShellPath.c_str(), "--",
|
||||
readfds.c_str(), writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), NULL);
|
||||
execlp(blenderBin, blenderBin, "--background", "-P", blenderShellPath.c_str(), "--", readfds.c_str(),
|
||||
writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
|
||||
if (errno != ENOENT) {
|
||||
errbuf = fmt::format(fmt("NOLAUNCH {}"), strerror(errno));
|
||||
_writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]);
|
||||
|
@ -425,7 +461,7 @@ Connection::Connection(int verbosityLevel) {
|
|||
|
||||
/* Otherwise default blender */
|
||||
execlp(DEFAULT_BLENDER_BIN, DEFAULT_BLENDER_BIN, "--background", "-P", blenderShellPath.c_str(), "--",
|
||||
readfds.c_str(), writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), NULL);
|
||||
readfds.c_str(), writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
|
||||
if (errno != ENOENT) {
|
||||
errbuf = fmt::format(fmt("NOLAUNCH {}"), strerror(errno));
|
||||
_writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]);
|
||||
|
@ -446,8 +482,8 @@ Connection::Connection(int verbosityLevel) {
|
|||
m_errPath = hecl::SystemString(TMPDIR) +
|
||||
fmt::format(fmt(_SYS_STR("/hecl_{:016X}.derp")), (unsigned long long)m_pinfo.dwProcessId);
|
||||
#else
|
||||
m_errPath =
|
||||
hecl::SystemString(TMPDIR) + fmt::format(fmt(_SYS_STR("/hecl_{:016X}.derp")), (unsigned long long)m_blenderProc);
|
||||
m_errPath = hecl::SystemString(TMPDIR) +
|
||||
fmt::format(fmt(_SYS_STR("/hecl_{:016X}.derp")), (unsigned long long)m_blenderProc);
|
||||
#endif
|
||||
hecl::Unlink(m_errPath.c_str());
|
||||
|
||||
|
@ -528,8 +564,9 @@ std::streambuf::int_type PyOutStream::StreamBuf::overflow(int_type ch) {
|
|||
return ch;
|
||||
}
|
||||
|
||||
static const char* BlendTypeStrs[] = {"NONE", "MESH", "CMESH", "ACTOR", "AREA", "WORLD",
|
||||
"MAPAREA", "MAPUNIVERSE", "FRAME", "PATH", nullptr};
|
||||
constexpr std::array<const char*, 11> BlendTypeStrs{
|
||||
"NONE", "MESH", "CMESH", "ACTOR", "AREA", "WORLD", "MAPAREA", "MAPUNIVERSE", "FRAME", "PATH", nullptr,
|
||||
};
|
||||
|
||||
bool Connection::createBlend(const ProjectPath& path, BlendType type) {
|
||||
if (m_lock) {
|
||||
|
@ -628,8 +665,7 @@ void PyOutStream::close() {
|
|||
}
|
||||
|
||||
void PyOutStream::linkBlend(const char* target, const char* objName, bool link) {
|
||||
format(fmt(
|
||||
"if '{}' not in bpy.data.scenes:\n"
|
||||
format(fmt("if '{}' not in bpy.data.scenes:\n"
|
||||
" with bpy.data.libraries.load('''{}''', link={}, relative=True) as (data_from, data_to):\n"
|
||||
" data_to.scenes = data_from.scenes\n"
|
||||
" obj_scene = None\n"
|
||||
|
@ -651,8 +687,7 @@ void PyOutStream::linkBlend(const char* target, const char* objName, bool link)
|
|||
|
||||
void PyOutStream::linkBackground(const char* target, const char* sceneName) {
|
||||
if (!sceneName) {
|
||||
format(fmt(
|
||||
"with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
|
||||
format(fmt("with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
|
||||
" data_to.scenes = data_from.scenes\n"
|
||||
"obj_scene = None\n"
|
||||
"for scene in data_to.scenes:\n"
|
||||
|
@ -664,8 +699,7 @@ void PyOutStream::linkBackground(const char* target, const char* sceneName) {
|
|||
"bpy.context.scene.background_set = obj_scene\n"),
|
||||
target, target);
|
||||
} else {
|
||||
format(fmt(
|
||||
"if '{}' not in bpy.data.scenes:\n"
|
||||
format(fmt("if '{}' not in bpy.data.scenes:\n"
|
||||
" with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
|
||||
" data_to.scenes = data_from.scenes\n"
|
||||
" obj_scene = None\n"
|
||||
|
@ -684,8 +718,7 @@ void PyOutStream::linkBackground(const char* target, const char* sceneName) {
|
|||
void PyOutStream::AABBToBMesh(const atVec3f& min, const atVec3f& max) {
|
||||
athena::simd_floats minf(min.simd);
|
||||
athena::simd_floats maxf(max.simd);
|
||||
format(fmt(
|
||||
"bm = bmesh.new()\n"
|
||||
format(fmt("bm = bmesh.new()\n"
|
||||
"bm.verts.new(({},{},{}))\n"
|
||||
"bm.verts.new(({},{},{}))\n"
|
||||
"bm.verts.new(({},{},{}))\n"
|
||||
|
@ -805,8 +838,7 @@ Mesh::Mesh(Connection& conn, HMDLTopology topologyIn, int skinSlotCount, bool us
|
|||
Index matSetCount(conn);
|
||||
materialSets.reserve(matSetCount.val);
|
||||
for (uint32_t i = 0; i < matSetCount.val; ++i) {
|
||||
materialSets.emplace_back();
|
||||
std::vector<Material>& materials = materialSets.back();
|
||||
std::vector<Material>& materials = materialSets.emplace_back();
|
||||
Index matCount(conn);
|
||||
materials.reserve(matCount.val);
|
||||
for (uint32_t j = 0; j < matCount.val; ++j)
|
||||
|
@ -969,26 +1001,12 @@ Material::Material(Connection& conn) {
|
|||
}
|
||||
|
||||
bool Mesh::Surface::Vert::operator==(const Vert& other) const {
|
||||
if (iPos != other.iPos)
|
||||
return false;
|
||||
if (iNorm != other.iNorm)
|
||||
return false;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
if (iColor[i] != other.iColor[i])
|
||||
return false;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
if (iUv[i] != other.iUv[i])
|
||||
return false;
|
||||
if (iSkin != other.iSkin)
|
||||
return false;
|
||||
return true;
|
||||
return std::tie(iPos, iNorm, iColor, iUv, iSkin) ==
|
||||
std::tie(other.iPos, other.iNorm, other.iColor, other.iUv, other.iSkin);
|
||||
}
|
||||
|
||||
static bool VertInBank(const std::vector<uint32_t>& bank, uint32_t sIdx) {
|
||||
for (uint32_t idx : bank)
|
||||
if (sIdx == idx)
|
||||
return true;
|
||||
return false;
|
||||
return std::any_of(bank.cbegin(), bank.cend(), [sIdx](auto index) { return index == sIdx; });
|
||||
}
|
||||
|
||||
void Mesh::SkinBanks::Bank::addSkins(const Mesh& parent, const std::vector<uint32_t>& skinIdxs) {
|
||||
|
@ -1153,8 +1171,7 @@ MapArea::Surface::Surface(Connection& conn) {
|
|||
conn._readBuf(&borderCount, 4);
|
||||
borders.reserve(borderCount);
|
||||
for (uint32_t i = 0; i < borderCount; ++i) {
|
||||
borders.emplace_back();
|
||||
std::pair<Index, Index>& idx = borders.back();
|
||||
std::pair<Index, Index>& idx = borders.emplace_back();
|
||||
conn._readBuf(&idx, 8);
|
||||
}
|
||||
}
|
||||
|
@ -1344,14 +1361,13 @@ Actor::Subtype::Subtype(Connection& conn) {
|
|||
name.assign(bufSz, ' ');
|
||||
conn._readBuf(&name[0], bufSz);
|
||||
|
||||
std::string meshPath;
|
||||
conn._readBuf(&bufSz, 4);
|
||||
if (bufSz) {
|
||||
meshPath.assign(bufSz, ' ');
|
||||
conn._readBuf(&meshPath[0], bufSz);
|
||||
SystemStringConv meshPathAbs(meshPath);
|
||||
if (bufSz != 0) {
|
||||
std::string meshPath(bufSz, ' ');
|
||||
conn._readBuf(meshPath.data(), meshPath.size());
|
||||
const SystemStringConv meshPathAbs(meshPath);
|
||||
|
||||
SystemString meshPathRel =
|
||||
const SystemString meshPathRel =
|
||||
conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str());
|
||||
mesh.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), meshPathRel);
|
||||
}
|
||||
|
@ -1367,14 +1383,13 @@ Actor::Subtype::Subtype(Connection& conn) {
|
|||
overlayName.assign(bufSz, ' ');
|
||||
conn._readBuf(&overlayName[0], bufSz);
|
||||
|
||||
std::string meshPath;
|
||||
conn._readBuf(&bufSz, 4);
|
||||
if (bufSz) {
|
||||
meshPath.assign(bufSz, ' ');
|
||||
conn._readBuf(&meshPath[0], bufSz);
|
||||
SystemStringConv meshPathAbs(meshPath);
|
||||
if (bufSz != 0) {
|
||||
std::string meshPath(bufSz, ' ');
|
||||
conn._readBuf(meshPath.data(), meshPath.size());
|
||||
const SystemStringConv meshPathAbs(meshPath);
|
||||
|
||||
SystemString meshPathRel =
|
||||
const SystemString meshPathRel =
|
||||
conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str());
|
||||
overlayMeshes.emplace_back(std::move(overlayName),
|
||||
ProjectPath(conn.getBlendPath().getProject().getProjectWorkingPath(), meshPathRel));
|
||||
|
@ -1431,12 +1446,11 @@ Action::Action(Connection& conn) {
|
|||
conn._readBuf(&aabbCount, 4);
|
||||
subtypeAABBs.reserve(aabbCount);
|
||||
for (uint32_t i = 0; i < aabbCount; ++i) {
|
||||
subtypeAABBs.emplace_back();
|
||||
subtypeAABBs.back().first.read(conn);
|
||||
subtypeAABBs.back().second.read(conn);
|
||||
//printf("AABB %s %d (%f %f %f) (%f %f %f)\n", name.c_str(), i,
|
||||
// float(subtypeAABBs.back().first.val.simd[0]), float(subtypeAABBs.back().first.val.simd[1]), float(subtypeAABBs.back().first.val.simd[2]),
|
||||
// float(subtypeAABBs.back().second.val.simd[0]), float(subtypeAABBs.back().second.val.simd[1]), float(subtypeAABBs.back().second.val.simd[2]));
|
||||
subtypeAABBs.emplace_back(conn, conn);
|
||||
// printf("AABB %s %d (%f %f %f) (%f %f %f)\n", name.c_str(), i,
|
||||
// float(subtypeAABBs.back().first.val.simd[0]), float(subtypeAABBs.back().first.val.simd[1]),
|
||||
// float(subtypeAABBs.back().first.val.simd[2]), float(subtypeAABBs.back().second.val.simd[0]),
|
||||
// float(subtypeAABBs.back().second.val.simd[1]), float(subtypeAABBs.back().second.val.simd[2]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1532,7 +1546,7 @@ std::pair<atVec3f, atVec3f> DataStream::getMeshAABB() {
|
|||
}
|
||||
|
||||
const char* DataStream::MeshOutputModeString(HMDLTopology topology) {
|
||||
static const char* STRS[] = {"TRIANGLES", "TRISTRIPS"};
|
||||
static constexpr std::array<const char*, 2> STRS{"TRIANGLES", "TRISTRIPS"};
|
||||
return STRS[int(topology)];
|
||||
}
|
||||
|
||||
|
@ -1787,12 +1801,11 @@ std::vector<std::string> DataStream::getArmatureNames() {
|
|||
m_parent->_readBuf(&armCount, 4);
|
||||
ret.reserve(armCount);
|
||||
for (uint32_t i = 0; i < armCount; ++i) {
|
||||
ret.emplace_back();
|
||||
std::string& name = ret.back();
|
||||
std::string& name = ret.emplace_back();
|
||||
uint32_t bufSz;
|
||||
m_parent->_readBuf(&bufSz, 4);
|
||||
name.assign(bufSz, ' ');
|
||||
m_parent->_readBuf(&name[0], bufSz);
|
||||
m_parent->_readBuf(name.data(), name.size());
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1816,12 +1829,11 @@ std::vector<std::string> DataStream::getSubtypeNames() {
|
|||
m_parent->_readBuf(&subCount, 4);
|
||||
ret.reserve(subCount);
|
||||
for (uint32_t i = 0; i < subCount; ++i) {
|
||||
ret.emplace_back();
|
||||
std::string& name = ret.back();
|
||||
std::string& name = ret.emplace_back();
|
||||
uint32_t bufSz;
|
||||
m_parent->_readBuf(&bufSz, 4);
|
||||
name.assign(bufSz, ' ');
|
||||
m_parent->_readBuf(&name[0], bufSz);
|
||||
m_parent->_readBuf(name.data(), name.size());
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1845,12 +1857,11 @@ std::vector<std::string> DataStream::getActionNames() {
|
|||
m_parent->_readBuf(&actCount, 4);
|
||||
ret.reserve(actCount);
|
||||
for (uint32_t i = 0; i < actCount; ++i) {
|
||||
ret.emplace_back();
|
||||
std::string& name = ret.back();
|
||||
std::string& name = ret.emplace_back();
|
||||
uint32_t bufSz;
|
||||
m_parent->_readBuf(&bufSz, 4);
|
||||
name.assign(bufSz, ' ');
|
||||
m_parent->_readBuf(&name[0], bufSz);
|
||||
m_parent->_readBuf(name.data(), name.size());
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1874,12 +1885,11 @@ std::vector<std::string> DataStream::getSubtypeOverlayNames(std::string_view nam
|
|||
m_parent->_readBuf(&subCount, 4);
|
||||
ret.reserve(subCount);
|
||||
for (uint32_t i = 0; i < subCount; ++i) {
|
||||
ret.emplace_back();
|
||||
std::string& name = ret.back();
|
||||
std::string& subtypeName = ret.emplace_back();
|
||||
uint32_t bufSz;
|
||||
m_parent->_readBuf(&bufSz, 4);
|
||||
name.assign(bufSz, ' ');
|
||||
m_parent->_readBuf(&name[0], bufSz);
|
||||
subtypeName.assign(bufSz, ' ');
|
||||
m_parent->_readBuf(subtypeName.data(), subtypeName.size());
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1903,12 +1913,11 @@ std::vector<std::string> DataStream::getAttachmentNames() {
|
|||
m_parent->_readBuf(&attCount, 4);
|
||||
ret.reserve(attCount);
|
||||
for (uint32_t i = 0; i < attCount; ++i) {
|
||||
ret.emplace_back();
|
||||
std::string& name = ret.back();
|
||||
std::string& name = ret.emplace_back();
|
||||
uint32_t bufSz;
|
||||
m_parent->_readBuf(&bufSz, 4);
|
||||
name.assign(bufSz, ' ');
|
||||
m_parent->_readBuf(&name[0], bufSz);
|
||||
m_parent->_readBuf(name.data(), name.size());
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1935,23 +1944,22 @@ std::unordered_map<std::string, Matrix3f> DataStream::getBoneMatrices(std::strin
|
|||
m_parent->_readBuf(&boneCount, 4);
|
||||
ret.reserve(boneCount);
|
||||
for (uint32_t i = 0; i < boneCount; ++i) {
|
||||
std::string name;
|
||||
uint32_t bufSz;
|
||||
m_parent->_readBuf(&bufSz, 4);
|
||||
name.assign(bufSz, ' ');
|
||||
m_parent->_readBuf(&name[0], bufSz);
|
||||
std::string mat_name(bufSz, ' ');
|
||||
m_parent->_readBuf(mat_name.data(), bufSz);
|
||||
|
||||
Matrix3f matOut;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int mat_i = 0; mat_i < 3; ++mat_i) {
|
||||
for (int mat_j = 0; mat_j < 3; ++mat_j) {
|
||||
float val;
|
||||
m_parent->_readBuf(&val, 4);
|
||||
matOut[i].simd[j] = val;
|
||||
matOut[mat_i].simd[mat_j] = val;
|
||||
}
|
||||
reinterpret_cast<atVec4f&>(matOut[i]).simd[3] = 0.f;
|
||||
reinterpret_cast<atVec4f&>(matOut[mat_i]).simd[3] = 0.f;
|
||||
}
|
||||
|
||||
ret.emplace(std::make_pair(std::move(name), std::move(matOut)));
|
||||
ret.emplace(std::move(mat_name), std::move(matOut));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#include "hecl/Blender/Connection.hpp"
|
||||
#include <cmath>
|
||||
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
|
||||
#include <athena/MemoryWriter.hpp>
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "MeshOptimizer.hpp"
|
||||
#include <numeric>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
|
||||
namespace hecl::blender {
|
||||
|
|
|
@ -191,23 +191,25 @@ int CVar::toInteger(bool* isValid) const {
|
|||
return strtol(m_value.c_str(), nullptr, 0);
|
||||
}
|
||||
|
||||
const std::string CVar::toLiteral(bool* isValid) const {
|
||||
std::string CVar::toLiteral(bool* isValid) const {
|
||||
if (m_type != EType::Literal && (com_developer && com_developer->toBoolean())) {
|
||||
if (isValid != nullptr)
|
||||
*isValid = false;
|
||||
} else if (isValid != nullptr)
|
||||
} else if (isValid != nullptr) {
|
||||
*isValid = true;
|
||||
}
|
||||
|
||||
// Even if it's not a literal, it's still safe to return
|
||||
return m_value;
|
||||
}
|
||||
|
||||
const std::wstring CVar::toWideLiteral(bool* isValid) const {
|
||||
std::wstring CVar::toWideLiteral(bool* isValid) const {
|
||||
if (m_type != EType::Literal && (com_developer && com_developer->toBoolean())) {
|
||||
if (isValid != nullptr)
|
||||
*isValid = false;
|
||||
} else if (isValid != nullptr)
|
||||
} else if (isValid != nullptr) {
|
||||
*isValid = true;
|
||||
}
|
||||
|
||||
// Even if it's not a literal, it's still safe to return
|
||||
return hecl::UTF8ToWide(m_value);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <athena/Utility.hpp>
|
||||
#include <hecl/Runtime.hpp>
|
||||
#include <hecl/hecl.hpp>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
|
||||
|
@ -24,11 +25,10 @@ CVarManager::CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary)
|
|||
com_configfile = newCVar("config", "File to store configuration", std::string("config"), CVar::EFlags::System);
|
||||
com_developer = newCVar("developer", "Enables developer mode", false,
|
||||
(CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable));
|
||||
com_enableCheats =
|
||||
newCVar("cheats", "Enable cheats", false,
|
||||
com_enableCheats = newCVar(
|
||||
"cheats", "Enable cheats", false,
|
||||
(CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::Hidden | CVar::EFlags::InternalArchivable));
|
||||
com_cubemaps =
|
||||
newCVar("cubemaps", "Enable cubemaps", false,
|
||||
com_cubemaps = newCVar("cubemaps", "Enable cubemaps", false,
|
||||
(CVar::EFlags::Game | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable));
|
||||
}
|
||||
|
||||
|
@ -37,11 +37,13 @@ CVarManager::~CVarManager() {}
|
|||
CVar* CVarManager::registerCVar(std::unique_ptr<CVar>&& cvar) {
|
||||
std::string tmp(cvar->name());
|
||||
athena::utility::tolower(tmp);
|
||||
if (m_cvars.find(tmp) != m_cvars.end())
|
||||
|
||||
if (m_cvars.find(tmp) != m_cvars.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CVar* ret = cvar.get();
|
||||
m_cvars[tmp] = std::move(cvar);
|
||||
m_cvars.insert_or_assign(std::move(tmp), std::move(cvar));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -80,8 +82,8 @@ void CVarManager::deserialize(CVar* cvar) {
|
|||
/* First let's check for a deferred value */
|
||||
std::string lowName = cvar->name().data();
|
||||
athena::utility::tolower(lowName);
|
||||
if (m_deferedCVars.find(lowName) != m_deferedCVars.end()) {
|
||||
std::string val = m_deferedCVars[lowName];
|
||||
if (const auto iter = m_deferedCVars.find(lowName); iter != m_deferedCVars.end()) {
|
||||
std::string val = std::move(iter->second);
|
||||
m_deferedCVars.erase(lowName);
|
||||
if (cvar->fromLiteralToType(val))
|
||||
return;
|
||||
|
@ -162,10 +164,13 @@ void CVarManager::serialize() {
|
|||
|
||||
if (m_useBinary) {
|
||||
CVarContainer container;
|
||||
for (const auto& pair : m_cvars)
|
||||
if (pair.second->isArchive() ||
|
||||
(pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue()))
|
||||
container.cvars.push_back(*pair.second);
|
||||
for (const auto& pair : m_cvars) {
|
||||
const auto& cvar = pair.second;
|
||||
|
||||
if (cvar->isArchive() || (cvar->isInternalArchivable() && cvar->wasDeserialized() && !cvar->hasDefaultValue())) {
|
||||
container.cvars.push_back(*cvar);
|
||||
}
|
||||
}
|
||||
container.cvarCount = atUint32(container.cvars.size());
|
||||
|
||||
filename += _SYS_STR(".bin");
|
||||
|
@ -180,10 +185,13 @@ void CVarManager::serialize() {
|
|||
r.close();
|
||||
|
||||
docWriter.setStyle(athena::io::YAMLNodeStyle::Block);
|
||||
for (const auto& pair : m_cvars)
|
||||
if (pair.second->isArchive() ||
|
||||
(pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue()))
|
||||
docWriter.writeString(pair.second->name().data(), pair.second->toLiteral());
|
||||
for (const auto& pair : m_cvars) {
|
||||
const auto& cvar = pair.second;
|
||||
|
||||
if (cvar->isArchive() || (cvar->isInternalArchivable() && cvar->wasDeserialized() && !cvar->hasDefaultValue())) {
|
||||
docWriter.writeString(cvar->name().data(), cvar->toLiteral());
|
||||
}
|
||||
}
|
||||
|
||||
athena::io::FileWriter w(filename);
|
||||
if (w.isOpen())
|
||||
|
@ -208,12 +216,13 @@ void CVarManager::setCVar(Console* con, const std::vector<std::string>& args) {
|
|||
|
||||
std::string cvName = args[0];
|
||||
athena::utility::tolower(cvName);
|
||||
if (m_cvars.find(cvName) == m_cvars.end()) {
|
||||
const auto iter = m_cvars.find(cvName);
|
||||
if (iter == m_cvars.end()) {
|
||||
con->report(Console::Level::Error, fmt("CVar '{}' does not exist"), args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& cv = m_cvars[cvName];
|
||||
const auto& cv = iter->second;
|
||||
std::string oldVal = cv->value();
|
||||
std::string value = args[1];
|
||||
auto it = args.begin() + 2;
|
||||
|
@ -238,12 +247,13 @@ void CVarManager::getCVar(Console* con, const std::vector<std::string>& args) {
|
|||
|
||||
std::string cvName = args[0];
|
||||
athena::utility::tolower(cvName);
|
||||
if (m_cvars.find(cvName) == m_cvars.end()) {
|
||||
const auto iter = m_cvars.find(cvName);
|
||||
if (iter == m_cvars.end()) {
|
||||
con->report(Console::Level::Error, fmt("CVar '{}' does not exist"), args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& cv = m_cvars[cvName];
|
||||
const auto& cv = iter->second;
|
||||
con->report(Console::Level::Info, fmt("'{}' = '{}'"), cv->name(), cv->value());
|
||||
}
|
||||
|
||||
|
@ -266,24 +276,26 @@ void CVarManager::setCheatsEnabled(bool v, bool setDeserialized) {
|
|||
}
|
||||
|
||||
bool CVarManager::restartRequired() const {
|
||||
for (const auto& cv : m_cvars) {
|
||||
if (cv.second->isModified() && cv.second->modificationRequiresRestart())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return std::any_of(m_cvars.cbegin(), m_cvars.cend(), [](const auto& entry) {
|
||||
return entry.second->isModified() && entry.second->modificationRequiresRestart();
|
||||
});
|
||||
}
|
||||
|
||||
void CVarManager::parseCommandLine(const std::vector<SystemString>& args) {
|
||||
bool oldDeveloper = suppressDeveloper();
|
||||
std::string developerName = com_developer->name().data();
|
||||
std::string developerName(com_developer->name());
|
||||
athena::utility::tolower(developerName);
|
||||
for (const SystemString& arg : args) {
|
||||
if (arg[0] == _SYS_STR('+')) {
|
||||
std::string tmp = SystemUTF8Conv(arg).c_str();
|
||||
if (arg[0] != _SYS_STR('+')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string tmp(SystemUTF8Conv(arg).str());
|
||||
std::smatch matches;
|
||||
if (std::regex_match(tmp, matches, cmdLineRegex)) {
|
||||
if (!std::regex_match(tmp, matches, cmdLineRegex)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string cvarName = matches[1].str();
|
||||
std::string cvarValue = matches[2].str();
|
||||
if (CVar* cv = findCVar(cvarName)) {
|
||||
|
@ -295,9 +307,7 @@ void CVarManager::parseCommandLine(const std::vector<SystemString>& args) {
|
|||
} else {
|
||||
/* Unable to find an existing CVar, let's defer for the time being 8 */
|
||||
athena::utility::tolower(cvarName);
|
||||
m_deferedCVars[cvarName] = cvarValue;
|
||||
}
|
||||
}
|
||||
m_deferedCVars.insert_or_assign(std::move(cvarName), std::move(cvarValue));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ void ClientProcess::BufferTransaction::run(blender::Token& btok) {
|
|||
void ClientProcess::CookTransaction::run(blender::Token& btok) {
|
||||
m_dataSpec->setThreadProject();
|
||||
m_returnResult = m_parent.syncCook(m_path, m_dataSpec, btok, m_force, m_fast);
|
||||
std::unique_lock<std::mutex> lk(m_parent.m_mutex);
|
||||
std::unique_lock lk{m_parent.m_mutex};
|
||||
++m_parent.m_completedCooks;
|
||||
m_parent.m_progPrinter->setMainFactor(m_parent.m_completedCooks / float(m_parent.m_addedCooks));
|
||||
m_complete = true;
|
||||
|
@ -92,7 +92,7 @@ void ClientProcess::Worker::proc() {
|
|||
std::string thrName = fmt::format(fmt("HECL Worker {}"), m_idx);
|
||||
logvisor::RegisterThreadName(thrName.c_str());
|
||||
|
||||
std::unique_lock<std::mutex> lk(m_proc.m_mutex);
|
||||
std::unique_lock lk{m_proc.m_mutex};
|
||||
while (m_proc.m_running) {
|
||||
if (!m_didInit) {
|
||||
m_proc.m_initCv.notify_one();
|
||||
|
@ -125,7 +125,7 @@ ClientProcess::ClientProcess(const MultiProgressPrinter* progPrinter) : m_progPr
|
|||
#endif
|
||||
m_workers.reserve(cpuCount);
|
||||
for (int i = 0; i < cpuCount; ++i) {
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
std::unique_lock lk{m_mutex};
|
||||
m_workers.emplace_back(*this, m_workers.size());
|
||||
m_initCv.wait(lk);
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ ClientProcess::ClientProcess(const MultiProgressPrinter* progPrinter) : m_progPr
|
|||
std::shared_ptr<const ClientProcess::BufferTransaction> ClientProcess::addBufferTransaction(const ProjectPath& path,
|
||||
void* target, size_t maxLen,
|
||||
size_t offset) {
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
std::unique_lock lk{m_mutex};
|
||||
auto ret = std::make_shared<BufferTransaction>(*this, path, target, maxLen, offset);
|
||||
m_pendingQueue.emplace_back(ret);
|
||||
m_cv.notify_one();
|
||||
|
@ -144,7 +144,7 @@ std::shared_ptr<const ClientProcess::BufferTransaction> ClientProcess::addBuffer
|
|||
std::shared_ptr<const ClientProcess::CookTransaction> ClientProcess::addCookTransaction(const hecl::ProjectPath& path,
|
||||
bool force, bool fast,
|
||||
Database::IDataSpec* spec) {
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
std::unique_lock lk{m_mutex};
|
||||
auto ret = std::make_shared<CookTransaction>(*this, path, force, fast, spec);
|
||||
m_pendingQueue.emplace_back(ret);
|
||||
m_cv.notify_one();
|
||||
|
@ -155,7 +155,7 @@ std::shared_ptr<const ClientProcess::CookTransaction> ClientProcess::addCookTran
|
|||
|
||||
std::shared_ptr<const ClientProcess::LambdaTransaction>
|
||||
ClientProcess::addLambdaTransaction(std::function<void(blender::Token&)>&& func) {
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
std::unique_lock lk{m_mutex};
|
||||
auto ret = std::make_shared<LambdaTransaction>(*this, std::move(func));
|
||||
m_pendingQueue.emplace_back(ret);
|
||||
m_cv.notify_one();
|
||||
|
@ -204,12 +204,12 @@ bool ClientProcess::syncCook(const hecl::ProjectPath& path, Database::IDataSpec*
|
|||
}
|
||||
|
||||
void ClientProcess::swapCompletedQueue(std::list<std::shared_ptr<Transaction>>& queue) {
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
std::unique_lock lk{m_mutex};
|
||||
queue.swap(m_completedQueue);
|
||||
}
|
||||
|
||||
void ClientProcess::waitUntilComplete() {
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
std::unique_lock lk{m_mutex};
|
||||
while (isBusy())
|
||||
m_waitCv.wait(lk);
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ void ClientProcess::waitUntilComplete() {
|
|||
void ClientProcess::shutdown() {
|
||||
if (!m_running)
|
||||
return;
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
std::unique_lock lk{m_mutex};
|
||||
m_pendingQueue.clear();
|
||||
m_running = false;
|
||||
m_cv.notify_all();
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
#include "hecl/Compilers.hpp"
|
||||
#include "boo/graphicsdev/GLSLMacros.hpp"
|
||||
#include "logvisor/logvisor.hpp"
|
||||
#include <boo/graphicsdev/GLSLMacros.hpp>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
#include <glslang/Public/ShaderLang.h>
|
||||
#include <StandAlone/ResourceLimits.h>
|
||||
#include <SPIRV/GlslangToSpv.h>
|
||||
#include <SPIRV/disassemble.h>
|
||||
|
||||
#if _WIN32
|
||||
#include <d3dcompiler.h>
|
||||
extern pD3DCompile D3DCompilePROC;
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
#include <unistd.h>
|
||||
#include <memory>
|
||||
|
@ -17,23 +20,6 @@ extern pD3DCompile D3DCompilePROC;
|
|||
namespace hecl {
|
||||
logvisor::Module Log("hecl::Compilers");
|
||||
|
||||
namespace PlatformType {
|
||||
const char* OpenGL::Name = "OpenGL";
|
||||
const char* Vulkan::Name = "Vulkan";
|
||||
const char* D3D11::Name = "D3D11";
|
||||
const char* Metal::Name = "Metal";
|
||||
const char* NX::Name = "NX";
|
||||
} // namespace PlatformType
|
||||
|
||||
namespace PipelineStage {
|
||||
const char* Null::Name = "Null";
|
||||
const char* Vertex::Name = "Vertex";
|
||||
const char* Fragment::Name = "Fragment";
|
||||
const char* Geometry::Name = "Geometry";
|
||||
const char* Control::Name = "Control";
|
||||
const char* Evaluation::Name = "Evaluation";
|
||||
} // namespace PipelineStage
|
||||
|
||||
template <typename P>
|
||||
struct ShaderCompiler {};
|
||||
|
||||
|
@ -99,7 +85,7 @@ struct ShaderCompiler<PlatformType::D3D11> {
|
|||
ComPtr<ID3DBlob> blobOut;
|
||||
if (FAILED(D3DCompilePROC(text.data(), text.size(), "Boo HLSL Source", nullptr, nullptr, "main",
|
||||
D3DShaderTypes[int(S::Enum)], BOO_D3DCOMPILE_FLAG, 0, &blobOut, &errBlob))) {
|
||||
printf("%s\n", text.data());
|
||||
fmt::print(fmt("{}\n"), text);
|
||||
Log.report(logvisor::Fatal, fmt("error compiling shader: {}"), (char*)errBlob->GetBufferPointer());
|
||||
return {};
|
||||
}
|
||||
|
@ -124,7 +110,7 @@ struct ShaderCompiler<PlatformType::Metal> {
|
|||
|
||||
pid_t pid = fork();
|
||||
if (!pid) {
|
||||
execlp("xcrun", "xcrun", "-sdk", "macosx", "metal", "--version", NULL);
|
||||
execlp("xcrun", "xcrun", "-sdk", "macosx", "metal", "--version", nullptr);
|
||||
/* xcrun returns 72 if metal command not found;
|
||||
* emulate that if xcrun not found */
|
||||
exit(72);
|
||||
|
@ -180,8 +166,8 @@ struct ShaderCompiler<PlatformType::Metal> {
|
|||
#ifndef NDEBUG
|
||||
"-gline-tables-only", "-MO",
|
||||
#endif
|
||||
"-", NULL);
|
||||
fprintf(stderr, "execlp fail %s\n", strerror(errno));
|
||||
"-", nullptr);
|
||||
fmt::print(stderr, fmt("execlp fail {}\n"), strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
close(compilerIn[0]);
|
||||
|
@ -196,8 +182,8 @@ struct ShaderCompiler<PlatformType::Metal> {
|
|||
close(compilerIn[1]);
|
||||
|
||||
/* metallib doesn't like outputting to a pipe, so temp file will have to do */
|
||||
execlp("xcrun", "xcrun", "-sdk", "macosx", "metallib", "-", "-o", libFile.c_str(), NULL);
|
||||
fprintf(stderr, "execlp fail %s\n", strerror(errno));
|
||||
execlp("xcrun", "xcrun", "-sdk", "macosx", "metallib", "-", "-o", libFile.c_str(), nullptr);
|
||||
fmt::print(stderr, fmt("execlp fail {}\n"), strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
close(compilerOut[0]);
|
||||
|
@ -208,7 +194,7 @@ struct ShaderCompiler<PlatformType::Metal> {
|
|||
while (inRem) {
|
||||
ssize_t writeRes = write(compilerIn[1], inPtr, inRem);
|
||||
if (writeRes < 0) {
|
||||
fprintf(stderr, "write fail %s\n", strerror(errno));
|
||||
fmt::print(stderr, fmt("write fail {}\n"), strerror(errno));
|
||||
break;
|
||||
}
|
||||
inPtr += writeRes;
|
||||
|
@ -221,7 +207,7 @@ struct ShaderCompiler<PlatformType::Metal> {
|
|||
while (waitpid(compilerPid, &compilerStat, 0) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
Log.report(logvisor::Fatal, fmt("waitpid fail %s"), strerror(errno));
|
||||
Log.report(logvisor::Fatal, fmt("waitpid fail {}"), strerror(errno));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -233,7 +219,7 @@ struct ShaderCompiler<PlatformType::Metal> {
|
|||
while (waitpid(linkerPid, &linkerStat, 0) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
Log.report(logvisor::Fatal, fmt("waitpid fail %s"), strerror(errno));
|
||||
Log.report(logvisor::Fatal, fmt("waitpid fail {}"), strerror(errno));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -368,8 +368,8 @@ void Console::LogVisorAdapter::report(const char* modName, logvisor::Level sever
|
|||
auto tmp = fmt::internal::vformat(format, args);
|
||||
std::vector<std::string> lines = athena::utility::split(tmp, '\n');
|
||||
for (const std::string& line : lines) {
|
||||
auto v = fmt::format(fmt("[%s] %s"), modName, line.c_str());
|
||||
m_con->m_log.emplace_back(v, Console::Level(severity));
|
||||
auto v = fmt::format(fmt("[{}] {}"), modName, line);
|
||||
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,16 +378,16 @@ void Console::LogVisorAdapter::report(const char* modName, logvisor::Level sever
|
|||
auto tmp = fmt::internal::vformat(format, args);
|
||||
std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n');
|
||||
for (const std::string& line : lines) {
|
||||
auto v = fmt::format(fmt("[%s] %s"), modName, line.c_str());
|
||||
m_con->m_log.emplace_back(v, Console::Level(severity));
|
||||
auto v = fmt::format(fmt("[{}] {}"), modName, line);
|
||||
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
|
||||
}
|
||||
}
|
||||
|
||||
void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file,
|
||||
unsigned linenum, fmt::string_view format, fmt::format_args args) {
|
||||
auto tmp = fmt::internal::vformat(format, args);
|
||||
auto v = fmt::format(fmt("[%s] %s %s:%i"), modName, tmp, file, linenum);
|
||||
m_con->m_log.emplace_back(v, Console::Level(severity));
|
||||
auto v = fmt::format(fmt("[{}] {} {}:{}"), modName, tmp, file, linenum);
|
||||
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
|
||||
}
|
||||
|
||||
void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file,
|
||||
|
@ -395,8 +395,8 @@ void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level
|
|||
auto tmp = fmt::internal::vformat(format, args);
|
||||
std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n');
|
||||
for (const std::string& line : lines) {
|
||||
auto v = fmt::format(fmt("[%s] %s %s:%i"), modName, line.c_str(), file, linenum);
|
||||
m_con->m_log.emplace_back(v, Console::Level(severity));
|
||||
auto v = fmt::format(fmt("[{}] {} {}:{}"), modName, line, file, linenum);
|
||||
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -242,9 +242,12 @@ void MultiProgressPrinter::DoPrint() {
|
|||
void MultiProgressPrinter::LogProc() {
|
||||
while (m_running) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
if (!m_dirty && !m_mainIndeterminate)
|
||||
|
||||
if (!m_dirty && !m_mainIndeterminate) {
|
||||
continue;
|
||||
std::lock_guard<std::mutex> lk(m_logLock);
|
||||
}
|
||||
|
||||
std::lock_guard lk{m_logLock};
|
||||
DoPrint();
|
||||
}
|
||||
}
|
||||
|
@ -280,22 +283,30 @@ MultiProgressPrinter::~MultiProgressPrinter() {
|
|||
|
||||
void MultiProgressPrinter::print(const hecl::SystemChar* message, const hecl::SystemChar* submessage, float factor,
|
||||
int threadIdx) const {
|
||||
if (!m_running)
|
||||
if (!m_running) {
|
||||
return;
|
||||
std::lock_guard<std::mutex> lk(m_logLock);
|
||||
if (threadIdx < 0)
|
||||
}
|
||||
|
||||
std::lock_guard lk{m_logLock};
|
||||
if (threadIdx < 0) {
|
||||
threadIdx = 0;
|
||||
if (threadIdx >= m_threadStats.size())
|
||||
}
|
||||
if (threadIdx >= m_threadStats.size()) {
|
||||
m_threadStats.resize(threadIdx + 1);
|
||||
}
|
||||
|
||||
ThreadStat& stat = m_threadStats[threadIdx];
|
||||
if (message)
|
||||
if (message) {
|
||||
stat.m_message = message;
|
||||
else
|
||||
} else {
|
||||
stat.m_message.clear();
|
||||
if (submessage)
|
||||
}
|
||||
if (submessage) {
|
||||
stat.m_submessage = submessage;
|
||||
else
|
||||
} else {
|
||||
stat.m_submessage.clear();
|
||||
}
|
||||
|
||||
stat.m_factor = factor;
|
||||
stat.m_active = true;
|
||||
m_latestThread = threadIdx;
|
||||
|
@ -303,18 +314,23 @@ void MultiProgressPrinter::print(const hecl::SystemChar* message, const hecl::Sy
|
|||
}
|
||||
|
||||
void MultiProgressPrinter::setMainFactor(float factor) const {
|
||||
if (!m_running)
|
||||
if (!m_running) {
|
||||
return;
|
||||
std::lock_guard<std::mutex> lk(m_logLock);
|
||||
if (!m_mainIndeterminate)
|
||||
}
|
||||
|
||||
std::lock_guard lk{m_logLock};
|
||||
if (!m_mainIndeterminate) {
|
||||
m_dirty = true;
|
||||
}
|
||||
m_mainFactor = factor;
|
||||
}
|
||||
|
||||
void MultiProgressPrinter::setMainIndeterminate(bool indeterminate) const {
|
||||
if (!m_running)
|
||||
if (!m_running) {
|
||||
return;
|
||||
std::lock_guard<std::mutex> lk(m_logLock);
|
||||
}
|
||||
|
||||
std::lock_guard lk{m_logLock};
|
||||
if (m_mainIndeterminate != indeterminate) {
|
||||
m_mainIndeterminate = indeterminate;
|
||||
m_dirty = true;
|
||||
|
@ -322,9 +338,11 @@ void MultiProgressPrinter::setMainIndeterminate(bool indeterminate) const {
|
|||
}
|
||||
|
||||
void MultiProgressPrinter::startNewLine() const {
|
||||
if (!m_running)
|
||||
if (!m_running) {
|
||||
return;
|
||||
std::lock_guard<std::mutex> lk(m_logLock);
|
||||
}
|
||||
|
||||
std::lock_guard lk{m_logLock};
|
||||
const_cast<MultiProgressPrinter&>(*this).DoPrint();
|
||||
m_threadStats.clear();
|
||||
m_latestThread = -1;
|
||||
|
@ -335,7 +353,7 @@ void MultiProgressPrinter::startNewLine() const {
|
|||
}
|
||||
|
||||
void MultiProgressPrinter::flush() const {
|
||||
std::lock_guard<std::mutex> lk(m_logLock);
|
||||
std::lock_guard lk{m_logLock};
|
||||
const_cast<MultiProgressPrinter&>(*this).DoPrint();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@ public:
|
|||
m_zstrm.avail_in = 0;
|
||||
inflateInit(&m_zstrm);
|
||||
}
|
||||
~ShaderCacheZipStream() { inflateEnd(&m_zstrm); }
|
||||
operator bool() const { return m_compBuf.operator bool(); }
|
||||
atUint64 readUBytesToBuf(void* buf, atUint64 len) {
|
||||
~ShaderCacheZipStream() override { inflateEnd(&m_zstrm); }
|
||||
explicit operator bool() const { return m_compBuf.operator bool(); }
|
||||
atUint64 readUBytesToBuf(void* buf, atUint64 len) override {
|
||||
m_zstrm.next_out = (Bytef*)buf;
|
||||
m_zstrm.avail_out = len;
|
||||
m_zstrm.total_out = 0;
|
||||
|
@ -42,9 +42,9 @@ public:
|
|||
}
|
||||
return m_zstrm.total_out;
|
||||
}
|
||||
void seek(atInt64, athena::SeekOrigin) {}
|
||||
atUint64 position() const { return 0; }
|
||||
atUint64 length() const { return 0; }
|
||||
void seek(atInt64, athena::SeekOrigin) override {}
|
||||
atUint64 position() const override { return 0; }
|
||||
atUint64 length() const override { return 0; }
|
||||
};
|
||||
|
||||
template <typename P, typename S>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
namespace hecl::Database {
|
||||
|
||||
logvisor::Module LogModule("hecl::Database");
|
||||
static const hecl::FourCC HECLfcc("HECL");
|
||||
constexpr hecl::FourCC HECLfcc("HECL");
|
||||
|
||||
/**********************************************
|
||||
* Project::ConfigFile
|
||||
|
@ -43,17 +43,19 @@ Project::ConfigFile::ConfigFile(const Project& project, SystemStringView name, S
|
|||
}
|
||||
|
||||
std::vector<std::string>& Project::ConfigFile::lockAndRead() {
|
||||
if (m_lockedFile)
|
||||
if (m_lockedFile != nullptr) {
|
||||
return m_lines;
|
||||
}
|
||||
|
||||
m_lockedFile = hecl::Fopen(m_filepath.c_str(), _SYS_STR("a+"), FileLockType::Write);
|
||||
hecl::FSeek(m_lockedFile, 0, SEEK_SET);
|
||||
m_lockedFile = hecl::FopenUnique(m_filepath.c_str(), _SYS_STR("a+"), FileLockType::Write);
|
||||
hecl::FSeek(m_lockedFile.get(), 0, SEEK_SET);
|
||||
|
||||
std::string mainString;
|
||||
char readBuf[1024];
|
||||
size_t readSz;
|
||||
while ((readSz = fread(readBuf, 1, 1024, m_lockedFile)))
|
||||
while ((readSz = std::fread(readBuf, 1, sizeof(readBuf), m_lockedFile.get()))) {
|
||||
mainString += std::string(readBuf, readSz);
|
||||
}
|
||||
|
||||
std::string::const_iterator begin = mainString.begin();
|
||||
std::string::const_iterator end = mainString.begin();
|
||||
|
@ -110,14 +112,13 @@ bool Project::ConfigFile::checkForLine(std::string_view refLine) {
|
|||
}
|
||||
|
||||
void Project::ConfigFile::unlockAndDiscard() {
|
||||
if (!m_lockedFile) {
|
||||
if (m_lockedFile == nullptr) {
|
||||
LogModule.reportSource(logvisor::Fatal, __FILE__, __LINE__, fmt("Project::ConfigFile::lockAndRead not yet called"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_lines.clear();
|
||||
fclose(m_lockedFile);
|
||||
m_lockedFile = NULL;
|
||||
m_lockedFile.reset();
|
||||
}
|
||||
|
||||
bool Project::ConfigFile::unlockAndCommit() {
|
||||
|
@ -126,23 +127,22 @@ bool Project::ConfigFile::unlockAndCommit() {
|
|||
return false;
|
||||
}
|
||||
|
||||
SystemString newPath = m_filepath + _SYS_STR(".part");
|
||||
FILE* newFile = hecl::Fopen(newPath.c_str(), _SYS_STR("w"), FileLockType::Write);
|
||||
const SystemString newPath = m_filepath + _SYS_STR(".part");
|
||||
auto newFile = hecl::FopenUnique(newPath.c_str(), _SYS_STR("w"), FileLockType::Write);
|
||||
bool fail = false;
|
||||
for (const std::string& line : m_lines) {
|
||||
if (fwrite(line.c_str(), 1, line.size(), newFile) != line.size()) {
|
||||
if (std::fwrite(line.c_str(), 1, line.size(), newFile.get()) != line.size()) {
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
if (fwrite("\n", 1, 1, newFile) != 1) {
|
||||
if (std::fputc('\n', newFile.get()) == EOF) {
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_lines.clear();
|
||||
fclose(newFile);
|
||||
fclose(m_lockedFile);
|
||||
m_lockedFile = NULL;
|
||||
newFile.reset();
|
||||
m_lockedFile.reset();
|
||||
if (fail) {
|
||||
#if HECL_UCS2
|
||||
_wunlink(newPath.c_str());
|
||||
|
@ -191,20 +191,21 @@ Project::Project(const ProjectRootPath& rootPath)
|
|||
m_cookedRoot.makeDir();
|
||||
|
||||
/* Ensure beacon is valid or created */
|
||||
ProjectPath beaconPath(m_dotPath, _SYS_STR("beacon"));
|
||||
FILE* bf = hecl::Fopen(beaconPath.getAbsolutePath().data(), _SYS_STR("a+b"));
|
||||
const ProjectPath beaconPath(m_dotPath, _SYS_STR("beacon"));
|
||||
auto bf = hecl::FopenUnique(beaconPath.getAbsolutePath().data(), _SYS_STR("a+b"));
|
||||
struct BeaconStruct {
|
||||
hecl::FourCC magic;
|
||||
uint32_t version;
|
||||
} beacon;
|
||||
#define DATA_VERSION 1
|
||||
if (fread(&beacon, 1, sizeof(beacon), bf) != sizeof(beacon)) {
|
||||
fseek(bf, 0, SEEK_SET);
|
||||
constexpr uint32_t DATA_VERSION = 1;
|
||||
if (std::fread(&beacon, 1, sizeof(beacon), bf.get()) != sizeof(beacon)) {
|
||||
std::fseek(bf.get(), 0, SEEK_SET);
|
||||
beacon.magic = HECLfcc;
|
||||
beacon.version = SBig(DATA_VERSION);
|
||||
fwrite(&beacon, 1, sizeof(beacon), bf);
|
||||
std::fwrite(&beacon, 1, sizeof(beacon), bf.get());
|
||||
}
|
||||
fclose(bf);
|
||||
bf.reset();
|
||||
|
||||
if (beacon.magic != HECLfcc || SBig(beacon.version) != DATA_VERSION) {
|
||||
LogModule.report(logvisor::Fatal, fmt("incompatible project version"));
|
||||
return;
|
||||
|
@ -413,9 +414,11 @@ bool Project::cookPath(const ProjectPath& path, const hecl::MultiProgressPrinter
|
|||
}
|
||||
} else if (m_cookSpecs.empty()) {
|
||||
m_cookSpecs.reserve(m_compiledSpecs.size());
|
||||
for (const ProjectDataSpec& spec : m_compiledSpecs)
|
||||
if (spec.active && spec.spec.m_factory)
|
||||
m_cookSpecs.push_back(spec.spec.m_factory(*this, DataSpecTool::Cook));
|
||||
for (const ProjectDataSpec& projectSpec : m_compiledSpecs) {
|
||||
if (projectSpec.active && projectSpec.spec.m_factory) {
|
||||
m_cookSpecs.push_back(projectSpec.spec.m_factory(*this, DataSpecTool::Cook));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate complete directory/file/glob list */
|
||||
|
@ -443,17 +446,18 @@ bool Project::packagePath(const ProjectPath& path, const hecl::MultiProgressPrin
|
|||
/* Construct DataSpec instance for packaging */
|
||||
const DataSpecEntry* specEntry = nullptr;
|
||||
if (spec) {
|
||||
if (spec->m_factory)
|
||||
if (spec->m_factory) {
|
||||
specEntry = spec;
|
||||
}
|
||||
} else {
|
||||
bool foundPC = false;
|
||||
for (const ProjectDataSpec& spec : m_compiledSpecs) {
|
||||
if (spec.active && spec.spec.m_factory) {
|
||||
if (hecl::StringUtils::EndsWith(spec.spec.m_name, _SYS_STR("-PC"))) {
|
||||
for (const ProjectDataSpec& projectSpec : m_compiledSpecs) {
|
||||
if (projectSpec.active && projectSpec.spec.m_factory) {
|
||||
if (hecl::StringUtils::EndsWith(projectSpec.spec.m_name, _SYS_STR("-PC"))) {
|
||||
foundPC = true;
|
||||
specEntry = &spec.spec;
|
||||
specEntry = &projectSpec.spec;
|
||||
} else if (!foundPC) {
|
||||
specEntry = &spec.spec;
|
||||
specEntry = &projectSpec.spec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -256,17 +256,22 @@ ProjectRootPath SearchForProject(SystemStringView path) {
|
|||
Sstat theStat;
|
||||
if (!hecl::Stat(testIndexPath.c_str(), &theStat)) {
|
||||
if (S_ISREG(theStat.st_mode)) {
|
||||
FILE* fp = hecl::Fopen(testIndexPath.c_str(), _SYS_STR("rb"));
|
||||
if (!fp)
|
||||
const auto fp = hecl::FopenUnique(testIndexPath.c_str(), _SYS_STR("rb"));
|
||||
if (fp == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char magic[4];
|
||||
size_t readSize = fread(magic, 1, 4, fp);
|
||||
fclose(fp);
|
||||
if (readSize != 4)
|
||||
const size_t readSize = std::fread(magic, 1, sizeof(magic), fp.get());
|
||||
if (readSize != sizeof(magic)) {
|
||||
continue;
|
||||
static const hecl::FourCC hecl("HECL");
|
||||
if (hecl::FourCC(magic) != hecl)
|
||||
}
|
||||
|
||||
static constexpr hecl::FourCC hecl("HECL");
|
||||
if (hecl::FourCC(magic) != hecl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return ProjectRootPath(testPath);
|
||||
}
|
||||
}
|
||||
|
@ -280,41 +285,52 @@ ProjectRootPath SearchForProject(SystemStringView path) {
|
|||
}
|
||||
|
||||
ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut) {
|
||||
ProjectRootPath testRoot(path);
|
||||
const ProjectRootPath testRoot(path);
|
||||
auto begin = testRoot.getAbsolutePath().begin();
|
||||
auto end = testRoot.getAbsolutePath().end();
|
||||
|
||||
while (begin != end) {
|
||||
SystemString testPath(begin, end);
|
||||
SystemString testIndexPath = testPath + _SYS_STR("/.hecl/beacon");
|
||||
Sstat theStat;
|
||||
|
||||
if (!hecl::Stat(testIndexPath.c_str(), &theStat)) {
|
||||
if (S_ISREG(theStat.st_mode)) {
|
||||
FILE* fp = hecl::Fopen(testIndexPath.c_str(), _SYS_STR("rb"));
|
||||
if (!fp)
|
||||
const auto fp = hecl::FopenUnique(testIndexPath.c_str(), _SYS_STR("rb"));
|
||||
if (fp == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char magic[4];
|
||||
size_t readSize = fread(magic, 1, 4, fp);
|
||||
fclose(fp);
|
||||
if (readSize != 4)
|
||||
const size_t readSize = std::fread(magic, 1, sizeof(magic), fp.get());
|
||||
if (readSize != sizeof(magic)) {
|
||||
continue;
|
||||
if (hecl::FourCC(magic) != FOURCC('HECL'))
|
||||
}
|
||||
if (hecl::FourCC(magic) != FOURCC('HECL')) {
|
||||
continue;
|
||||
ProjectRootPath newRootPath = ProjectRootPath(testPath);
|
||||
auto origEnd = testRoot.getAbsolutePath().end();
|
||||
while (end != origEnd && *end != _SYS_STR('/') && *end != _SYS_STR('\\'))
|
||||
}
|
||||
|
||||
const ProjectRootPath newRootPath = ProjectRootPath(testPath);
|
||||
const auto origEnd = testRoot.getAbsolutePath().end();
|
||||
while (end != origEnd && *end != _SYS_STR('/') && *end != _SYS_STR('\\')) {
|
||||
++end;
|
||||
if (end != origEnd && (*end == _SYS_STR('/') || *end == _SYS_STR('\\')))
|
||||
}
|
||||
if (end != origEnd && (*end == _SYS_STR('/') || *end == _SYS_STR('\\'))) {
|
||||
++end;
|
||||
}
|
||||
|
||||
subpathOut.assign(end, origEnd);
|
||||
return newRootPath;
|
||||
}
|
||||
}
|
||||
|
||||
while (begin != end && *(end - 1) != _SYS_STR('/') && *(end - 1) != _SYS_STR('\\'))
|
||||
while (begin != end && *(end - 1) != _SYS_STR('/') && *(end - 1) != _SYS_STR('\\')) {
|
||||
--end;
|
||||
if (begin != end)
|
||||
}
|
||||
if (begin != end) {
|
||||
--end;
|
||||
}
|
||||
}
|
||||
return ProjectRootPath();
|
||||
}
|
||||
|
||||
|
|
|
@ -57,44 +57,45 @@ hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name) {
|
|||
|
||||
#endif
|
||||
|
||||
hecl::SystemString appPath = hecl::SystemString(_SYS_STR("common")) + PATH_SEP + name;
|
||||
const hecl::SystemString appPath = hecl::SystemString(_SYS_STR("common")) + PATH_SEP + name;
|
||||
|
||||
/* Try main steam install directory first */
|
||||
hecl::SystemString steamAppsMain = steamInstallDir + PATH_SEP + _SYS_STR("steamapps");
|
||||
hecl::SystemString mainAppPath = steamAppsMain + PATH_SEP + appPath;
|
||||
if (!hecl::Stat(mainAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode))
|
||||
const hecl::SystemString steamAppsMain = steamInstallDir + PATH_SEP + _SYS_STR("steamapps");
|
||||
const hecl::SystemString mainAppPath = steamAppsMain + PATH_SEP + appPath;
|
||||
if (!hecl::Stat(mainAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) {
|
||||
return mainAppPath;
|
||||
}
|
||||
|
||||
/* Iterate alternate steam install dirs */
|
||||
hecl::SystemString libraryFoldersVdfPath = steamAppsMain + PATH_SEP + _SYS_STR("libraryfolders.vdf");
|
||||
FILE* fp = hecl::Fopen(libraryFoldersVdfPath.c_str(), _SYS_STR("r"));
|
||||
if (!fp)
|
||||
const hecl::SystemString libraryFoldersVdfPath = steamAppsMain + PATH_SEP + _SYS_STR("libraryfolders.vdf");
|
||||
auto fp = hecl::FopenUnique(libraryFoldersVdfPath.c_str(), _SYS_STR("r"));
|
||||
if (fp == nullptr) {
|
||||
return {};
|
||||
hecl::FSeek(fp, 0, SEEK_END);
|
||||
int64_t fileLen = hecl::FTell(fp);
|
||||
}
|
||||
hecl::FSeek(fp.get(), 0, SEEK_END);
|
||||
const int64_t fileLen = hecl::FTell(fp.get());
|
||||
if (fileLen <= 0) {
|
||||
fclose(fp);
|
||||
return {};
|
||||
}
|
||||
hecl::FSeek(fp, 0, SEEK_SET);
|
||||
std::string fileBuf;
|
||||
fileBuf.resize(fileLen);
|
||||
if (fread(&fileBuf[0], 1, fileLen, fp) != fileLen) {
|
||||
fclose(fp);
|
||||
hecl::FSeek(fp.get(), 0, SEEK_SET);
|
||||
std::string fileBuf(fileLen, '\0');
|
||||
if (std::fread(fileBuf.data(), 1, fileLen, fp.get()) != fileLen) {
|
||||
return {};
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
std::smatch dirMatch;
|
||||
auto begin = fileBuf.cbegin();
|
||||
auto end = fileBuf.cend();
|
||||
const auto end = fileBuf.cend();
|
||||
while (std::regex_search(begin, end, dirMatch, regSteamPath)) {
|
||||
std::string match = dirMatch[1].str();
|
||||
hecl::SystemStringConv otherInstallDir(match);
|
||||
hecl::SystemString otherAppPath =
|
||||
const std::string match = dirMatch[1].str();
|
||||
const hecl::SystemStringConv otherInstallDir(match);
|
||||
const auto otherAppPath =
|
||||
hecl::SystemString(otherInstallDir.sys_str()) + PATH_SEP + _SYS_STR("steamapps") + PATH_SEP + appPath;
|
||||
if (!hecl::Stat(otherAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode))
|
||||
|
||||
if (!hecl::Stat(otherAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) {
|
||||
return otherAppPath;
|
||||
}
|
||||
|
||||
begin = dirMatch.suffix().first;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
#include "hecl/hecl.hpp"
|
||||
#include <thread>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
#ifdef WIN32
|
||||
|
@ -20,11 +28,13 @@
|
|||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
namespace hecl {
|
||||
unsigned VerbosityLevel = 0;
|
||||
bool GuiMode = false;
|
||||
logvisor::Module LogModule("hecl");
|
||||
static const std::string Illegals{"<>?\""};
|
||||
constexpr std::string_view Illegals{"<>?\""};
|
||||
|
||||
void SanitizePath(std::string& path) {
|
||||
if (path.empty())
|
||||
|
@ -54,7 +64,7 @@ void SanitizePath(std::string& path) {
|
|||
path.pop_back();
|
||||
}
|
||||
|
||||
static const std::wstring WIllegals{L"<>?\""};
|
||||
constexpr std::wstring_view WIllegals{L"<>?\""};
|
||||
|
||||
void SanitizePath(std::wstring& path) {
|
||||
if (path.empty())
|
||||
|
@ -90,8 +100,9 @@ SystemString GetcwdStr() {
|
|||
// const int MaxChunks=10240; // 2550 KiBs of current path are more than enough
|
||||
|
||||
SystemChar stackBuffer[255]; // Stack buffer for the "normal" case
|
||||
if (Getcwd(stackBuffer, 255) != nullptr)
|
||||
if (Getcwd(stackBuffer, int(std::size(stackBuffer))) != nullptr) {
|
||||
return SystemString(stackBuffer);
|
||||
}
|
||||
if (errno != ERANGE) {
|
||||
// It's not ERANGE, so we don't know how to handle it
|
||||
LogModule.report(logvisor::Fatal, fmt("Cannot determine the current path."));
|
||||
|
@ -101,9 +112,11 @@ SystemString GetcwdStr() {
|
|||
for (int chunks = 2; chunks < 10240; chunks++) {
|
||||
// With boost use scoped_ptr; in C++0x, use unique_ptr
|
||||
// If you want to be less C++ but more efficient you may want to use realloc
|
||||
std::unique_ptr<SystemChar[]> cwd(new SystemChar[255 * chunks]);
|
||||
if (Getcwd(cwd.get(), 255 * chunks) != nullptr)
|
||||
const int bufSize = 255 * chunks;
|
||||
std::unique_ptr<SystemChar[]> cwd(new SystemChar[bufSize]);
|
||||
if (Getcwd(cwd.get(), bufSize) != nullptr) {
|
||||
return SystemString(cwd.get());
|
||||
}
|
||||
if (errno != ERANGE) {
|
||||
// It's not ERANGE, so we don't know how to handle it
|
||||
LogModule.report(logvisor::Fatal, fmt("Cannot determine the current path."));
|
||||
|
@ -118,64 +131,65 @@ static std::mutex PathsMutex;
|
|||
static std::unordered_map<std::thread::id, ProjectPath> PathsInProgress;
|
||||
|
||||
bool ResourceLock::InProgress(const ProjectPath& path) {
|
||||
std::unique_lock<std::mutex> lk(PathsMutex);
|
||||
for (const auto& p : PathsInProgress)
|
||||
if (p.second == path)
|
||||
return true;
|
||||
return false;
|
||||
std::unique_lock lk{PathsMutex};
|
||||
return std::any_of(PathsInProgress.cbegin(), PathsInProgress.cend(),
|
||||
[&path](const auto& entry) { return entry.second == path; });
|
||||
}
|
||||
|
||||
bool ResourceLock::SetThreadRes(const ProjectPath& path) {
|
||||
std::unique_lock<std::mutex> lk(PathsMutex);
|
||||
if (PathsInProgress.find(std::this_thread::get_id()) != PathsInProgress.cend())
|
||||
std::unique_lock lk{PathsMutex};
|
||||
if (PathsInProgress.find(std::this_thread::get_id()) != PathsInProgress.cend()) {
|
||||
LogModule.report(logvisor::Fatal, fmt("multiple resource locks on thread"));
|
||||
}
|
||||
|
||||
for (const auto& p : PathsInProgress)
|
||||
if (p.second == path)
|
||||
const bool isInProgress = std::any_of(PathsInProgress.cbegin(), PathsInProgress.cend(),
|
||||
[&path](const auto& entry) { return entry.second == path; });
|
||||
if (isInProgress) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PathsInProgress[std::this_thread::get_id()] = path;
|
||||
PathsInProgress.insert_or_assign(std::this_thread::get_id(), path);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResourceLock::ClearThreadRes() {
|
||||
std::unique_lock<std::mutex> lk(PathsMutex);
|
||||
std::unique_lock lk{PathsMutex};
|
||||
PathsInProgress.erase(std::this_thread::get_id());
|
||||
}
|
||||
|
||||
bool IsPathPNG(const hecl::ProjectPath& path) {
|
||||
FILE* fp = hecl::Fopen(path.getAbsolutePath().data(), _SYS_STR("rb"));
|
||||
if (!fp)
|
||||
return false;
|
||||
uint32_t buf = 0;
|
||||
if (fread(&buf, 1, 4, fp) != 4) {
|
||||
fclose(fp);
|
||||
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), _SYS_STR("rb"));
|
||||
if (fp == nullptr) {
|
||||
return false;
|
||||
}
|
||||
fclose(fp);
|
||||
buf = hecl::SBig(buf);
|
||||
if (buf == 0x89504e47)
|
||||
return true;
|
||||
|
||||
uint32_t buf = 0;
|
||||
if (std::fread(&buf, 1, sizeof(buf), fp.get()) != sizeof(buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
buf = hecl::SBig(buf);
|
||||
return buf == 0x89504e47;
|
||||
}
|
||||
|
||||
bool IsPathBlend(const hecl::ProjectPath& path) {
|
||||
auto lastCompExt = path.getLastComponentExt();
|
||||
if (lastCompExt.empty() || hecl::StrCmp(lastCompExt.data(), _SYS_STR("blend")))
|
||||
return false;
|
||||
FILE* fp = hecl::Fopen(path.getAbsolutePath().data(), _SYS_STR("rb"));
|
||||
if (!fp)
|
||||
return false;
|
||||
uint32_t buf = 0;
|
||||
if (fread(&buf, 1, 4, fp) != 4) {
|
||||
fclose(fp);
|
||||
const auto lastCompExt = path.getLastComponentExt();
|
||||
if (lastCompExt.empty() || hecl::StrCmp(lastCompExt.data(), _SYS_STR("blend"))) {
|
||||
return false;
|
||||
}
|
||||
fclose(fp);
|
||||
buf = hecl::SLittle(buf);
|
||||
if (buf == 0x4e454c42 || buf == 0x88b1f)
|
||||
return true;
|
||||
|
||||
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), _SYS_STR("rb"));
|
||||
if (fp == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t buf = 0;
|
||||
if (std::fread(&buf, 1, sizeof(buf), fp.get()) != sizeof(buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
buf = hecl::SLittle(buf);
|
||||
return buf == 0x4e454c42 || buf == 0x88b1f;
|
||||
}
|
||||
|
||||
bool IsPathYAML(const hecl::ProjectPath& path) {
|
||||
|
@ -431,8 +445,6 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
|
|||
#endif
|
||||
}
|
||||
|
||||
#define FILE_MAXDIR 768
|
||||
|
||||
static std::pair<hecl::SystemString, std::string> NameFromPath(hecl::SystemStringView path) {
|
||||
hecl::SystemUTF8Conv utf8(path);
|
||||
if (utf8.str().size() == 1 && utf8.str()[0] == '/')
|
||||
|
@ -450,46 +462,44 @@ std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations() {
|
|||
#if !WINDOWS_STORE
|
||||
/* Add the drive names to the listing (as queried by blender) */
|
||||
{
|
||||
constexpr uint32_t FILE_MAXDIR = 768;
|
||||
wchar_t wline[FILE_MAXDIR];
|
||||
wchar_t* name;
|
||||
__int64 tmp;
|
||||
int i;
|
||||
const uint32_t tmp = GetLogicalDrives();
|
||||
|
||||
tmp = GetLogicalDrives();
|
||||
|
||||
for (i = 0; i < 26; i++) {
|
||||
for (uint32_t i = 0; i < 26; i++) {
|
||||
if ((tmp >> i) & 1) {
|
||||
wline[0] = L'A' + i;
|
||||
wline[1] = L':';
|
||||
wline[2] = L'/';
|
||||
wline[3] = L'\0';
|
||||
name = nullptr;
|
||||
wchar_t* name = nullptr;
|
||||
|
||||
/* Flee from horrible win querying hover floppy drives! */
|
||||
if (i > 1) {
|
||||
/* Try to get volume label as well... */
|
||||
if (GetVolumeInformationW(wline, wline + 4, FILE_MAXDIR - 4, nullptr, nullptr, nullptr, nullptr, 0)) {
|
||||
size_t labelLen = wcslen(wline + 4);
|
||||
const size_t labelLen = std::wcslen(wline + 4);
|
||||
_snwprintf(wline + 4 + labelLen, FILE_MAXDIR - 4 - labelLen, L" (%.2s)", wline);
|
||||
name = wline + 4;
|
||||
}
|
||||
}
|
||||
|
||||
wline[2] = L'\0';
|
||||
if (name)
|
||||
ret.emplace_back(wline, hecl::WideToUTF8(name));
|
||||
else
|
||||
if (name == nullptr) {
|
||||
ret.push_back(NameFromPath(wline));
|
||||
} else {
|
||||
ret.emplace_back(wline, hecl::WideToUTF8(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Adding Desktop and My Documents */
|
||||
SystemString wpath;
|
||||
SHGetSpecialFolderPathW(0, wline, CSIDL_PERSONAL, 0);
|
||||
SHGetSpecialFolderPathW(nullptr, wline, CSIDL_PERSONAL, 0);
|
||||
wpath.assign(wline);
|
||||
SanitizePath(wpath);
|
||||
ret.push_back(NameFromPath(wpath));
|
||||
SHGetSpecialFolderPathW(0, wline, CSIDL_DESKTOPDIRECTORY, 0);
|
||||
SHGetSpecialFolderPathW(nullptr, wline, CSIDL_DESKTOPDIRECTORY, 0);
|
||||
wpath.assign(wline);
|
||||
SanitizePath(wpath);
|
||||
ret.push_back(NameFromPath(wpath));
|
||||
|
@ -513,18 +523,20 @@ std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations() {
|
|||
/*https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html*/
|
||||
/* we get all volumes sorted including network and do not relay on user-defined finder visibility, less confusing */
|
||||
|
||||
CFURLRef cfURL = NULL;
|
||||
CFURLRef cfURL = nullptr;
|
||||
CFURLEnumeratorResult result = kCFURLEnumeratorSuccess;
|
||||
CFURLEnumeratorRef volEnum = CFURLEnumeratorCreateForMountedVolumes(NULL, kCFURLEnumeratorSkipInvisibles, NULL);
|
||||
CFURLEnumeratorRef volEnum =
|
||||
CFURLEnumeratorCreateForMountedVolumes(nullptr, kCFURLEnumeratorSkipInvisibles, nullptr);
|
||||
|
||||
while (result != kCFURLEnumeratorEnd) {
|
||||
char defPath[1024];
|
||||
|
||||
result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, NULL);
|
||||
if (result != kCFURLEnumeratorSuccess)
|
||||
result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, nullptr);
|
||||
if (result != kCFURLEnumeratorSuccess) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CFURLGetFileSystemRepresentation(cfURL, false, (UInt8*)defPath, 1024);
|
||||
CFURLGetFileSystemRepresentation(cfURL, false, reinterpret_cast<UInt8*>(defPath), std::size(defPath));
|
||||
ret.push_back(NameFromPath(defPath));
|
||||
}
|
||||
|
||||
|
@ -582,14 +594,11 @@ std::wstring Char16ToWide(std::u16string_view src) { return std::wstring(src.beg
|
|||
#if _WIN32
|
||||
int RecursiveMakeDir(const SystemChar* dir) {
|
||||
SystemChar tmp[1024];
|
||||
SystemChar* p = nullptr;
|
||||
Sstat sb;
|
||||
size_t len;
|
||||
|
||||
/* copy path */
|
||||
wcsncpy(tmp, dir, 1024);
|
||||
len = wcslen(tmp);
|
||||
if (len >= 1024) {
|
||||
std::wcsncpy(tmp, dir, std::size(tmp));
|
||||
const size_t len = std::wcslen(tmp);
|
||||
if (len >= std::size(tmp)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -599,6 +608,8 @@ int RecursiveMakeDir(const SystemChar* dir) {
|
|||
}
|
||||
|
||||
/* recursive mkdir */
|
||||
SystemChar* p = nullptr;
|
||||
Sstat sb;
|
||||
for (p = tmp + 1; *p; p++) {
|
||||
if (*p == '/' || *p == '\\') {
|
||||
*p = 0;
|
||||
|
@ -630,14 +641,11 @@ int RecursiveMakeDir(const SystemChar* dir) {
|
|||
#else
|
||||
int RecursiveMakeDir(const SystemChar* dir) {
|
||||
SystemChar tmp[1024];
|
||||
SystemChar* p = nullptr;
|
||||
Sstat sb;
|
||||
size_t len;
|
||||
|
||||
/* copy path */
|
||||
strncpy(tmp, dir, 1024);
|
||||
len = strlen(tmp);
|
||||
if (len >= 1024) {
|
||||
std::strncpy(tmp, dir, std::size(tmp));
|
||||
const size_t len = std::strlen(tmp);
|
||||
if (len >= std::size(tmp)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -647,6 +655,8 @@ int RecursiveMakeDir(const SystemChar* dir) {
|
|||
}
|
||||
|
||||
/* recursive mkdir */
|
||||
SystemChar* p = nullptr;
|
||||
Sstat sb;
|
||||
for (p = tmp + 1; *p; p++) {
|
||||
if (*p == '/') {
|
||||
*p = 0;
|
||||
|
@ -680,16 +690,16 @@ int RecursiveMakeDir(const SystemChar* dir) {
|
|||
const SystemChar* GetTmpDir() {
|
||||
#ifdef _WIN32
|
||||
#if WINDOWS_STORE
|
||||
wchar_t* TMPDIR = nullptr;
|
||||
const wchar_t* TMPDIR = nullptr;
|
||||
#else
|
||||
wchar_t* TMPDIR = _wgetenv(L"TEMP");
|
||||
const wchar_t* TMPDIR = _wgetenv(L"TEMP");
|
||||
if (!TMPDIR)
|
||||
TMPDIR = (wchar_t*)L"\\Temp";
|
||||
TMPDIR = L"\\Temp";
|
||||
#endif
|
||||
#else
|
||||
char* TMPDIR = getenv("TMPDIR");
|
||||
const char* TMPDIR = getenv("TMPDIR");
|
||||
if (!TMPDIR)
|
||||
TMPDIR = (char*)"/tmp";
|
||||
TMPDIR = "/tmp";
|
||||
#endif
|
||||
return TMPDIR;
|
||||
}
|
||||
|
@ -697,13 +707,15 @@ const SystemChar* GetTmpDir() {
|
|||
#if !WINDOWS_STORE
|
||||
int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
|
||||
#ifdef _WIN32
|
||||
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
|
||||
HANDLE consoleOutReadTmp, consoleOutWrite, consoleErrWrite, consoleOutRead;
|
||||
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE};
|
||||
HANDLE consoleOutReadTmp = INVALID_HANDLE_VALUE;
|
||||
HANDLE consoleOutWrite = INVALID_HANDLE_VALUE;
|
||||
if (!CreatePipe(&consoleOutReadTmp, &consoleOutWrite, &sattrs, 0)) {
|
||||
LogModule.report(logvisor::Fatal, fmt("Error with CreatePipe"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
HANDLE consoleErrWrite = INVALID_HANDLE_VALUE;
|
||||
if (!DuplicateHandle(GetCurrentProcess(), consoleOutWrite, GetCurrentProcess(), &consoleErrWrite, 0, TRUE,
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
LogModule.report(logvisor::Fatal, fmt("Error with DuplicateHandle"));
|
||||
|
@ -712,11 +724,12 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
HANDLE consoleOutRead = INVALID_HANDLE_VALUE;
|
||||
if (!DuplicateHandle(GetCurrentProcess(), consoleOutReadTmp, GetCurrentProcess(),
|
||||
&consoleOutRead, // Address of new handle.
|
||||
0, FALSE, // Make it uninheritable.
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
LogModule.report(logvisor::Fatal, fmt("Error with DupliateHandle"));
|
||||
LogModule.report(logvisor::Fatal, fmt("Error with DuplicateHandle"));
|
||||
CloseHandle(consoleOutReadTmp);
|
||||
CloseHandle(consoleOutWrite);
|
||||
CloseHandle(consoleErrWrite);
|
||||
|
@ -735,18 +748,18 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
|
|||
|
||||
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
|
||||
HANDLE nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sattrs, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
sinfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
sinfo.hStdInput = nulHandle;
|
||||
sinfo.hStdError = consoleErrWrite;
|
||||
sinfo.hStdOutput = consoleOutWrite;
|
||||
|
||||
PROCESS_INFORMATION pinfo = {};
|
||||
if (!CreateProcessW(path, (LPWSTR)cmdLine.c_str(), NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &sinfo,
|
||||
if (!CreateProcessW(path, cmdLine.data(), nullptr, nullptr, TRUE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &sinfo,
|
||||
&pinfo)) {
|
||||
LPWSTR messageBuffer = nullptr;
|
||||
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
|
||||
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
|
||||
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
|
||||
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
|
||||
LogModule.report(logvisor::Error, fmt(L"unable to launch process from {}: {}"), path, messageBuffer);
|
||||
LocalFree(messageBuffer);
|
||||
|
||||
|
@ -768,7 +781,7 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
|
|||
DWORD nCharsWritten;
|
||||
|
||||
while (consoleThreadRunning) {
|
||||
if (!ReadFile(consoleOutRead, lpBuffer, sizeof(lpBuffer), &nBytesRead, NULL) || !nBytesRead) {
|
||||
if (!ReadFile(consoleOutRead, lpBuffer, sizeof(lpBuffer), &nBytesRead, nullptr) || !nBytesRead) {
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_BROKEN_PIPE)
|
||||
break; // pipe done - normal exit path.
|
||||
|
@ -778,8 +791,8 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
|
|||
|
||||
// Display the character read on the screen.
|
||||
auto lk = logvisor::LockLog();
|
||||
if (!WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), lpBuffer, nBytesRead, &nCharsWritten, NULL)) {
|
||||
// LogModule.report(logvisor::Error, fmt("Error with WriteConsole: %08X"), GetLastError());
|
||||
if (!WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), lpBuffer, nBytesRead, &nCharsWritten, nullptr)) {
|
||||
// LogModule.report(logvisor::Error, fmt("Error with WriteConsole: {:08X}"), GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue