2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-07-04 15:15:52 +00:00

Merge branch 'master' of ssh://git.axiodl.com:6431/AxioDL/hecl

This commit is contained in:
Jack Andersen 2019-08-31 10:38:33 -10:00
commit c180cbd529
38 changed files with 1119 additions and 969 deletions

View File

@ -88,7 +88,7 @@ protected:
} }
public: public:
ToolBase(const ToolPassInfo& info) : m_info(info) { explicit ToolBase(const ToolPassInfo& info) : m_info(info) {
hecl::VerbosityLevel = info.verbosityLevel; hecl::VerbosityLevel = info.verbosityLevel;
hecl::GuiMode = info.gui; hecl::GuiMode = info.gui;
} }
@ -96,15 +96,15 @@ public:
virtual hecl::SystemString toolName() const = 0; virtual hecl::SystemString toolName() const = 0;
virtual int run() = 0; virtual int run() = 0;
virtual void cancel() {} virtual void cancel() {}
inline operator bool() const { return m_good; } explicit operator bool() const { return m_good; }
}; };
class HelpOutput { class HelpOutput {
public: public:
typedef void (*HelpFunc)(HelpOutput&); using HelpFunc = void (*)(HelpOutput&);
private: private:
FILE* m_sout; FILE* m_sout = nullptr;
HelpFunc m_helpFunc; HelpFunc m_helpFunc;
int m_lineWidth; int m_lineWidth;
hecl::SystemString m_wrapBuffer; hecl::SystemString m_wrapBuffer;
@ -156,8 +156,8 @@ private:
} }
public: public:
HelpOutput(HelpFunc helpFunc) explicit HelpOutput(HelpFunc helpFunc)
: m_sout(NULL), m_helpFunc(helpFunc), m_lineWidth(hecl::GuiMode ? 120 : hecl::ConsoleWidth()) {} : m_helpFunc(helpFunc), m_lineWidth(hecl::GuiMode ? 120 : hecl::ConsoleWidth()) {}
void go() { void go() {
#if _WIN32 #if _WIN32

View File

@ -13,7 +13,7 @@ class ToolCook final : public ToolBase {
bool m_fast = false; bool m_fast = false;
public: 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 */ /* Check for recursive flag */
for (hecl::SystemChar arg : info.flags) for (hecl::SystemChar arg : info.flags)
if (arg == _SYS_STR('r')) 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::MultiProgressPrinter printer(true);
hecl::ClientProcess cp(&printer); hecl::ClientProcess cp(&printer);
for (const hecl::ProjectPath& path : m_selectedItems) for (const hecl::ProjectPath& path : m_selectedItems)
@ -156,5 +156,5 @@ public:
return 0; return 0;
} }
void cancel() { m_useProj->interruptCook(); } void cancel() override { m_useProj->interruptCook(); }
}; };

View File

@ -27,7 +27,7 @@ class ToolExtract final : public ToolBase {
hecl::Database::Project* m_useProj = nullptr; hecl::Database::Project* m_useProj = nullptr;
public: public:
ToolExtract(const ToolPassInfo& info) : ToolBase(info) { explicit ToolExtract(const ToolPassInfo& info) : ToolBase(info) {
if (!m_info.args.size()) if (!m_info.args.size())
LogModule.report(logvisor::Fatal, fmt("hecl extract needs a source path as its first argument")); LogModule.report(logvisor::Fatal, fmt("hecl extract needs a source path as its first argument"));
@ -112,7 +112,7 @@ public:
help.endWrap(); 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) { static void _recursivePrint(int level, hecl::Database::IDataSpec::ExtractReport& rep) {
for (int l = 0; l < level; ++l) for (int l = 0; l < level; ++l)
@ -129,7 +129,7 @@ public:
_recursivePrint(level + 1, child); _recursivePrint(level + 1, child);
} }
int run() { int run() override {
if (m_specPasses.empty()) { if (m_specPasses.empty()) {
if (XTERM_COLOR) if (XTERM_COLOR)
fmt::print(fmt(_SYS_STR("" RED BOLD "NOTHING TO EXTRACT" NORMAL "\n"))); fmt::print(fmt(_SYS_STR("" RED BOLD "NOTHING TO EXTRACT" NORMAL "\n")));

View File

@ -7,7 +7,7 @@
class ToolHelp final : public ToolBase { class ToolHelp final : public ToolBase {
public: public:
ToolHelp(const ToolPassInfo& info) : ToolBase(info) { explicit ToolHelp(const ToolPassInfo& info) : ToolBase(info) {
if (m_info.args.empty()) { if (m_info.args.empty()) {
LogModule.report(logvisor::Error, fmt("help requires a tool name argument")); LogModule.report(logvisor::Error, fmt("help requires a tool name argument"));
return; return;
@ -15,7 +15,7 @@ public:
m_good = true; m_good = true;
} }
~ToolHelp() {} ~ToolHelp() override = default;
static void Help(HelpOutput& help) { static void Help(HelpOutput& help) {
help.printBold( help.printBold(
@ -50,7 +50,7 @@ public:
static void ShowHelp(const hecl::SystemString& toolName) { static void ShowHelp(const hecl::SystemString& toolName) {
/* Select tool's help-text streamer */ /* Select tool's help-text streamer */
HelpOutput::HelpFunc helpFunc = NULL; HelpOutput::HelpFunc helpFunc = nullptr;
if (toolName == _SYS_STR("init")) if (toolName == _SYS_STR("init"))
helpFunc = ToolInit::Help; helpFunc = ToolInit::Help;
else if (toolName == _SYS_STR("spec")) else if (toolName == _SYS_STR("spec"))
@ -72,9 +72,9 @@ public:
ho.go(); 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()); ShowHelp(m_info.args.front());
return 0; return 0;
} }

View File

@ -15,7 +15,7 @@ class ToolImage final : public ToolBase {
hecl::Database::Project* m_useProj; hecl::Database::Project* m_useProj;
public: 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) if (!info.project)
LogModule.report(logvisor::Fatal, fmt("hecl image must be ran within a project directory")); 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")); "provided a path within a project"));
} }
~ToolImage() {} ~ToolImage() override = default;
static void Help(HelpOutput& help) { static void Help(HelpOutput& help) {
help.secHead(_SYS_STR("NAME")); help.secHead(_SYS_STR("NAME"));
@ -71,9 +71,9 @@ public:
help.endWrap(); 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) if (XTERM_COLOR)
fmt::print(fmt(_SYS_STR("" GREEN BOLD "ABOUT TO IMAGE:" NORMAL "\n"))); fmt::print(fmt(_SYS_STR("" GREEN BOLD "ABOUT TO IMAGE:" NORMAL "\n")));
else else

View File

@ -4,10 +4,10 @@
#include <cstdio> #include <cstdio>
class ToolInit final : public ToolBase { class ToolInit final : public ToolBase {
const hecl::SystemString* m_dir = NULL; const hecl::SystemString* m_dir = nullptr;
public: public:
ToolInit(const ToolPassInfo& info) : ToolBase(info) { explicit ToolInit(const ToolPassInfo& info) : ToolBase(info) {
hecl::Sstat theStat; hecl::Sstat theStat;
const hecl::SystemString* dir; const hecl::SystemString* dir;
if (info.args.size()) if (info.args.size())
@ -36,7 +36,7 @@ public:
m_dir = dir; m_dir = dir;
} }
int run() { int run() override {
if (!m_dir) if (!m_dir)
return 1; return 1;
size_t ErrorRef = logvisor::ErrorCount; size_t ErrorRef = logvisor::ErrorCount;
@ -73,5 +73,5 @@ public:
help.endWrap(); help.endWrap();
} }
hecl::SystemString toolName() const { return _SYS_STR("init"); } hecl::SystemString toolName() const override { return _SYS_STR("init"); }
}; };

View File

@ -59,7 +59,7 @@ class ToolPackage final : public ToolBase {
} }
public: 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) if (!info.project)
LogModule.report(logvisor::Fatal, fmt("hecl package must be ran within a project directory")); LogModule.report(logvisor::Fatal, fmt("hecl package must be ran within a project directory"));
@ -156,9 +156,9 @@ public:
help.endWrap(); 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) if (XTERM_COLOR)
fmt::print(fmt(_SYS_STR("" GREEN BOLD "ABOUT TO PACKAGE:" NORMAL "\n"))); fmt::print(fmt(_SYS_STR("" GREEN BOLD "ABOUT TO PACKAGE:" NORMAL "\n")));
else else
@ -181,5 +181,5 @@ public:
return 0; return 0;
} }
void cancel() { m_useProj->interruptCook(); } void cancel() override { m_useProj->interruptCook(); }
}; };

View File

@ -8,7 +8,7 @@ class ToolSpec final : public ToolBase {
enum Mode { MLIST = 0, MENABLE, MDISABLE } mode = MLIST; enum Mode { MLIST = 0, MENABLE, MDISABLE } mode = MLIST;
public: public:
ToolSpec(const ToolPassInfo& info) : ToolBase(info) { explicit ToolSpec(const ToolPassInfo& info) : ToolBase(info) {
if (info.args.empty()) if (info.args.empty())
return; return;
@ -71,9 +71,9 @@ public:
help.endWrap(); 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) { if (!m_info.project) {
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) { for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
if (XTERM_COLOR) if (XTERM_COLOR)

View File

@ -77,14 +77,196 @@ static void SIGINTHandler(int sig) {
} }
static logvisor::Module AthenaLog("Athena"); static logvisor::Module AthenaLog("Athena");
static void AthenaExc(athena::error::Level level, const char* file, const char*, int line, static void AthenaExc(athena::error::Level level, const char* file, const char*, int line, fmt::string_view fmt,
fmt::string_view fmt, fmt::format_args args) { fmt::format_args args) {
AthenaLog.vreport(logvisor::Level(level), fmt, args); AthenaLog.vreport(logvisor::Level(level), fmt, args);
} }
static hecl::SystemChar cwdbuf[1024];
hecl::SystemString ExeDir; 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 #if _WIN32
int wmain(int argc, const wchar_t** argv) int wmain(int argc, const wchar_t** argv)
#else #else
@ -140,167 +322,34 @@ int main(int argc, const char** argv)
HECLRegisterDataSpecs(); HECLRegisterDataSpecs();
/* Assemble common tool pass info */ /* Assemble common tool pass info */
ToolPassInfo info; ToolPassInfo info = CreateInfo(argc, argv);
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);
}
/* Attempt to find hecl project */ /* Attempt to find hecl project */
hecl::ProjectRootPath rootPath = hecl::SearchForProject(info.cwd); auto project = FindProject(info.cwd);
std::unique_ptr<hecl::Database::Project> project; if (project != nullptr) {
if (rootPath) { info.project = project.get();
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;
} }
/* Construct selected tool */ /* Construct selected tool */
hecl::SystemString toolName(argv[1]); const size_t MakeToolErrorRef = logvisor::ErrorCount;
hecl::ToLower(toolName); auto tool = MakeSelectedTool(argv[1], info);
std::unique_ptr<ToolBase> tool; if (logvisor::ErrorCount > MakeToolErrorRef) {
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) {
#if WIN_PAUSE #if WIN_PAUSE
system("PAUSE"); system("PAUSE");
#endif #endif
return 1; return 1;
} }
if (info.verbosityLevel) {
if (info.verbosityLevel) LogModule.report(logvisor::Info, fmt(_SYS_STR("Constructed tool '{}' {}\n")), tool->toolName(),
LogModule.report(logvisor::Info, fmt(_SYS_STR("Constructed tool '{}' {}\n")), tool->toolName(), info.verbosityLevel); info.verbosityLevel);
}
/* Run tool */ /* Run tool */
ErrorRef = logvisor::ErrorCount; const size_t RunToolErrorRef = logvisor::ErrorCount;
ToolPtr = tool.get(); ToolPtr = tool.get();
int retval = tool->run(); const int retval = tool->run();
ToolPtr = nullptr; ToolPtr = nullptr;
if (logvisor::ErrorCount > ErrorRef) { if (logvisor::ErrorCount > RunToolErrorRef) {
hecl::blender::Connection::Shutdown(); hecl::blender::Connection::Shutdown();
#if WIN_PAUSE #if WIN_PAUSE
system("PAUSE"); system("PAUSE");

View File

@ -67,7 +67,7 @@ public:
return *this; 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. /// BitVector default ctor - Creates an empty bitvector.

View File

@ -12,32 +12,37 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <array>
#include <atomic>
#include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
#include <cfloat>
#include <string>
#include <functional> #include <functional>
#include <iostream> #include <memory>
#include <optional>
#include <ostream>
#include <string>
#include <unordered_map> #include <unordered_map>
#include <atomic> #include <utility>
#include <variant> #include <variant>
#include <vector>
#include "hecl/hecl.hpp" #include "hecl/hecl.hpp"
#include "hecl/Backend.hpp"
#include "hecl/HMDLMeta.hpp" #include "hecl/HMDLMeta.hpp"
#include "hecl/TypedVariant.hpp" #include "hecl/TypedVariant.hpp"
#include "hecl/Backend.hpp"
#include "athena/Types.hpp" #include <athena/Types.hpp>
#include "athena/MemoryWriter.hpp"
#include <optional>
#include "Token.hpp"
#include <fmt/ostream.h> #include <fmt/ostream.h>
#include <logvisor/logvisor.hpp>
namespace hecl::blender { namespace hecl::blender {
using namespace std::literals; using namespace std::literals;
extern logvisor::Module BlenderLog;
class HMDLBuffers;
class Connection; class Connection;
class HMDLBuffers;
extern logvisor::Module BlenderLog;
struct PoolSkinIndex { struct PoolSkinIndex {
size_t m_poolSz = 0; 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(PyOutStream& parent, bool deleteOnError) : m_parent(parent), m_deleteOnError(deleteOnError) {}
StreamBuf(const StreamBuf& other) = delete; StreamBuf(const StreamBuf& other) = delete;
StreamBuf(StreamBuf&& other) = default; StreamBuf(StreamBuf&& other) = default;
int_type overflow(int_type ch); int_type overflow(int_type ch) override;
} m_sbuf; } m_sbuf;
PyOutStream(Connection* parent, bool deleteOnError); 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)) { PyOutStream(PyOutStream&& other) : std::ostream(&m_sbuf), m_parent(other.m_parent), m_sbuf(std::move(other.m_sbuf)) {
other.m_parent = nullptr; other.m_parent = nullptr;
} }
~PyOutStream() { close(); } ~PyOutStream() override { close(); }
void close(); void close();
template <typename S, typename... Args, typename Char = fmt::char_t<S>> template <typename S, typename... Args, typename Char = fmt::char_t<S>>
void format(const S& format, Args&&... args); void format(const S& format, Args&&... args);
@ -136,15 +141,15 @@ struct Vector4f {
} }
}; };
struct Matrix3f { struct Matrix3f {
atVec3f m[3]; std::array<atVec3f, 3> m;
inline atVec3f& operator[](size_t idx) { return m[idx]; } atVec3f& operator[](size_t idx) { return m[idx]; }
inline const atVec3f& operator[](size_t idx) const { return m[idx]; } const atVec3f& operator[](size_t idx) const { return m[idx]; }
}; };
struct Matrix4f { struct Matrix4f {
atVec4f val[4]; std::array<atVec4f, 4> val;
Matrix4f() = default; Matrix4f() = default;
void read(Connection& conn);
Matrix4f(Connection& conn) { read(conn); } Matrix4f(Connection& conn) { read(conn); }
void read(Connection& conn);
const atVec4f& operator[](size_t idx) const { return val[idx]; } const atVec4f& operator[](size_t idx) const { return val[idx]; }
}; };
struct Index { struct Index {
@ -343,8 +348,8 @@ struct Mesh {
struct Vert { struct Vert {
uint32_t iPos = 0xffffffff; uint32_t iPos = 0xffffffff;
uint32_t iNorm = 0xffffffff; uint32_t iNorm = 0xffffffff;
uint32_t iColor[4] = {0xffffffff}; std::array<uint32_t, 4> iColor = {0xffffffff};
uint32_t iUv[8] = {0xffffffff}; std::array<uint32_t, 8> iUv = {0xffffffff};
uint32_t iSkin = 0xffffffff; uint32_t iSkin = 0xffffffff;
uint32_t iBankSkin = 0xffffffff; uint32_t iBankSkin = 0xffffffff;
@ -433,14 +438,14 @@ struct ColMesh {
std::vector<Vector3f> verts; std::vector<Vector3f> verts;
struct Edge { struct Edge {
uint32_t verts[2]; std::array<uint32_t, 2> verts;
bool seam; bool seam;
Edge(Connection& conn); Edge(Connection& conn);
}; };
std::vector<Edge> edges; std::vector<Edge> edges;
struct Triangle { struct Triangle {
uint32_t edges[3]; std::array<uint32_t, 3> edges;
uint32_t matIdx; uint32_t matIdx;
bool flip; bool flip;
Triangle(Connection& conn); Triangle(Connection& conn);
@ -454,10 +459,10 @@ struct ColMesh {
struct World { struct World {
struct Area { struct Area {
ProjectPath path; ProjectPath path;
Vector3f aabb[2]; std::array<Vector3f, 2> aabb;
Matrix4f transform; Matrix4f transform;
struct Dock { struct Dock {
Vector3f verts[4]; std::array<Vector3f, 4> verts;
Index targetArea; Index targetArea;
Index targetDock; Index targetDock;
Dock(Connection& conn); Dock(Connection& conn);
@ -666,30 +671,30 @@ public:
}; };
class Connection { class Connection {
friend class ANIMOutStream;
friend class DataStream; friend class DataStream;
friend class PyOutStream; friend class PyOutStream;
friend class ANIMOutStream; friend struct Action;
friend struct PyOutStream::StreamBuf; friend struct Actor;
friend struct Mesh; friend struct Armature;
friend struct Material; friend struct Bone;
friend struct Boolean;
friend struct ColMesh; friend struct ColMesh;
friend struct World; friend struct Float;
friend struct Index;
friend struct Light; friend struct Light;
friend struct MapArea; friend struct MapArea;
friend struct MapUniverse; friend struct MapUniverse;
friend struct Actor; friend struct Material;
friend struct Armature; friend struct Matrix3f;
friend struct Action; friend struct Matrix4f;
friend struct Bone; friend struct Mesh;
friend struct PathMesh; friend struct PathMesh;
friend struct PyOutStream::StreamBuf;
friend struct Vector2f; friend struct Vector2f;
friend struct Vector3f; friend struct Vector3f;
friend struct Vector4f; friend struct Vector4f;
friend struct Matrix3f; friend struct World;
friend struct Matrix4f;
friend struct Index;
friend struct Float;
friend struct Boolean;
std::atomic_bool m_lock = {false}; std::atomic_bool m_lock = {false};
bool m_pyStreamActive = false; bool m_pyStreamActive = false;
@ -701,8 +706,8 @@ class Connection {
#else #else
pid_t m_blenderProc = 0; pid_t m_blenderProc = 0;
#endif #endif
int m_readpipe[2]; std::array<int, 2> m_readpipe{};
int m_writepipe[2]; std::array<int, 2> m_writepipe{};
BlendType m_loadedType = BlendType::None; BlendType m_loadedType = BlendType::None;
bool m_loadedRigged = false; bool m_loadedRigged = false;
ProjectPath m_loadedBlend; ProjectPath m_loadedBlend;
@ -710,8 +715,7 @@ class Connection {
uint32_t _readStr(char* buf, uint32_t bufSz); 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, int wpipe);
uint32_t _writeStr(const char* str, uint32_t len) { return _writeStr(str, len, m_writepipe[1]); } 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(std::string_view view) { return _writeStr(view.data(), view.size()); }
uint32_t _writeStr(const std::string& str) { return _writeStr(str.c_str(), str.size()); }
size_t _readBuf(void* buf, size_t len); size_t _readBuf(void* buf, size_t len);
size_t _writeBuf(const void* buf, size_t len); size_t _writeBuf(const void* buf, size_t len);
void _closePipe(); void _closePipe();

View File

@ -57,7 +57,7 @@ class SDNARead {
public: public:
explicit SDNARead(SystemStringView path); 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; } const SDNABlock& sdnaBlock() const { return m_sdnaBlock; }
void enumerate(const std::function<bool(const FileBlock& block, athena::io::MemoryReader& r)>& func) const; void enumerate(const std::function<bool(const FileBlock& block, athena::io::MemoryReader& r)>& func) const;
}; };

View File

@ -70,8 +70,8 @@ public:
float toFloat(bool* isValid = nullptr) const; float toFloat(bool* isValid = nullptr) const;
bool toBoolean(bool* isValid = nullptr) const; bool toBoolean(bool* isValid = nullptr) const;
int toInteger(bool* isValid = nullptr) const; int toInteger(bool* isValid = nullptr) const;
const std::wstring toWideLiteral(bool* isValid = nullptr) const; std::wstring toWideLiteral(bool* isValid = nullptr) const;
const std::string toLiteral(bool* isValid = nullptr) const; std::string toLiteral(bool* isValid = nullptr) const;
bool fromVec4f(const atVec4f& val); bool fromVec4f(const atVec4f& val);
bool fromFloat(float val); bool fromFloat(float val);
@ -117,7 +117,7 @@ public:
*/ */
void lock(); void lock();
void addListener(ListenerFunc func) { m_listeners.push_back(func); } void addListener(ListenerFunc func) { m_listeners.push_back(std::move(func)); }
private: private:
void dispatch(); void dispatch();

View File

@ -36,7 +36,7 @@ public:
void* m_targetBuf; void* m_targetBuf;
size_t m_maxLen; size_t m_maxLen;
size_t m_offset; 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) 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) {} : 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_returnResult = false;
bool m_force; bool m_force;
bool m_fast; 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) 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) {} : Transaction(parent, Type::Cook), m_path(path), m_dataSpec(spec), m_force(force), m_fast(fast) {}
}; };
struct LambdaTransaction final : Transaction { struct LambdaTransaction final : Transaction {
std::function<void(blender::Token&)> m_func; 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) LambdaTransaction(ClientProcess& parent, std::function<void(blender::Token&)>&& func)
: Transaction(parent, Type::Lambda), m_func(std::move(func)) {} : Transaction(parent, Type::Lambda), m_func(std::move(func)) {}
}; };

View File

@ -12,35 +12,35 @@ using PlatformEnum = boo::IGraphicsDataFactory::Platform;
struct Null {}; struct Null {};
struct OpenGL { struct OpenGL {
static constexpr PlatformEnum Enum = PlatformEnum::OpenGL; static constexpr PlatformEnum Enum = PlatformEnum::OpenGL;
static const char* Name; static constexpr char Name[] = "OpenGL";
#if BOO_HAS_GL #if BOO_HAS_GL
using Context = boo::GLDataFactory::Context; using Context = boo::GLDataFactory::Context;
#endif #endif
}; };
struct D3D11 { struct D3D11 {
static constexpr PlatformEnum Enum = PlatformEnum::D3D11; static constexpr PlatformEnum Enum = PlatformEnum::D3D11;
static const char* Name; static constexpr char Name[] = "D3D11";
#if _WIN32 #if _WIN32
using Context = boo::D3D11DataFactory::Context; using Context = boo::D3D11DataFactory::Context;
#endif #endif
}; };
struct Metal { struct Metal {
static constexpr PlatformEnum Enum = PlatformEnum::Metal; static constexpr PlatformEnum Enum = PlatformEnum::Metal;
static const char* Name; static constexpr char Name[] = "Metal";
#if BOO_HAS_METAL #if BOO_HAS_METAL
using Context = boo::MetalDataFactory::Context; using Context = boo::MetalDataFactory::Context;
#endif #endif
}; };
struct Vulkan { struct Vulkan {
static constexpr PlatformEnum Enum = PlatformEnum::Vulkan; static constexpr PlatformEnum Enum = PlatformEnum::Vulkan;
static const char* Name; static constexpr char Name[] = "Vulkan";
#if BOO_HAS_VULKAN #if BOO_HAS_VULKAN
using Context = boo::VulkanDataFactory::Context; using Context = boo::VulkanDataFactory::Context;
#endif #endif
}; };
struct NX { struct NX {
static constexpr PlatformEnum Enum = PlatformEnum::NX; static constexpr PlatformEnum Enum = PlatformEnum::NX;
static const char* Name; static constexpr char Name[] = "NX";
#if BOO_HAS_NX #if BOO_HAS_NX
using Context = boo::NXDataFactory::Context; using Context = boo::NXDataFactory::Context;
#endif #endif
@ -51,27 +51,27 @@ namespace PipelineStage {
using StageEnum = boo::PipelineStage; using StageEnum = boo::PipelineStage;
struct Null { struct Null {
static constexpr StageEnum Enum = StageEnum::Null; static constexpr StageEnum Enum = StageEnum::Null;
static const char* Name; static constexpr char Name[] = "Null";
}; };
struct Vertex { struct Vertex {
static constexpr StageEnum Enum = StageEnum::Vertex; static constexpr StageEnum Enum = StageEnum::Vertex;
static const char* Name; static constexpr char Name[] = "Vertex";
}; };
struct Fragment { struct Fragment {
static constexpr StageEnum Enum = StageEnum::Fragment; static constexpr StageEnum Enum = StageEnum::Fragment;
static const char* Name; static constexpr char Name[] = "Fragment";
}; };
struct Geometry { struct Geometry {
static constexpr StageEnum Enum = StageEnum::Geometry; static constexpr StageEnum Enum = StageEnum::Geometry;
static const char* Name; static constexpr char Name[] = "Geometry";
}; };
struct Control { struct Control {
static constexpr StageEnum Enum = StageEnum::Control; static constexpr StageEnum Enum = StageEnum::Control;
static const char* Name; static constexpr char Name[] = "Control";
}; };
struct Evaluation { struct Evaluation {
static constexpr StageEnum Enum = StageEnum::Evaluation; static constexpr StageEnum Enum = StageEnum::Evaluation;
static const char* Name; static constexpr char Name[] = "Evaluation";
}; };
} // namespace PipelineStage } // namespace PipelineStage

View File

@ -26,13 +26,14 @@ class Console {
Console* m_con; Console* m_con;
LogVisorAdapter(Console* con) : m_con(con) {} LogVisorAdapter(Console* con) : m_con(con) {}
~LogVisorAdapter() = default; ~LogVisorAdapter() override = 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::string_view format, fmt::format_args args) override;
void report(const char* modName, logvisor::Level severity, fmt::wstring_view format, fmt::wformat_args args); 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, 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, 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: public:

View File

@ -1,21 +1,17 @@
#pragma once #pragma once
#include <iterator> #include <cassert>
#include <string> #include <cstddef>
#include <cstdint>
#include <cstdio>
#include <functional> #include <functional>
#include <vector> #include <memory>
#include <map> #include <string>
#include <list>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <memory> #include <vector>
#include <atomic>
#include <fstream>
#include <stdint.h>
#include <cassert>
#include "athena/IStreamReader.hpp" #include <logvisor/logvisor.hpp>
#include "logvisor/logvisor.hpp"
#include "hecl.hpp" #include "hecl.hpp"
@ -62,7 +58,7 @@ class IDataSpec {
public: public:
IDataSpec(const DataSpecEntry* specEntry) : m_specEntry(specEntry) {} IDataSpec(const DataSpecEntry* specEntry) : m_specEntry(specEntry) {}
virtual ~IDataSpec() {} virtual ~IDataSpec() = default;
using FCookProgress = std::function<void(const SystemChar*)>; using FCookProgress = std::function<void(const SystemChar*)>;
/** /**
@ -91,43 +87,33 @@ public:
virtual void setThreadProject() {} virtual void setThreadProject() {}
virtual bool canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps) { virtual bool canExtract([[maybe_unused]] const ExtractPassInfo& info,
(void)info; [[maybe_unused]] std::vector<ExtractReport>& reps) {
(void)reps;
LogModule.report(logvisor::Error, fmt("not implemented")); LogModule.report(logvisor::Error, fmt("not implemented"));
return false; return false;
} }
virtual void doExtract(const ExtractPassInfo& info, const MultiProgressPrinter& progress) { virtual void doExtract([[maybe_unused]] const ExtractPassInfo& info,
(void)info; [[maybe_unused]] const MultiProgressPrinter& progress) {}
(void)progress;
}
virtual bool canCook(const ProjectPath& path, blender::Token& btok) { virtual bool canCook([[maybe_unused]] const ProjectPath& path, [[maybe_unused]] blender::Token& btok) {
(void)path;
LogModule.report(logvisor::Error, fmt("not implemented")); LogModule.report(logvisor::Error, fmt("not implemented"));
return false; return false;
} }
virtual const DataSpecEntry* overrideDataSpec(const ProjectPath& path, virtual const DataSpecEntry* overrideDataSpec([[maybe_unused]] const ProjectPath& path,
const Database::DataSpecEntry* oldEntry) const { const DataSpecEntry* oldEntry) const {
(void)path;
return oldEntry; return oldEntry;
} }
virtual void doCook(const ProjectPath& path, const ProjectPath& cookedPath, bool fast, blender::Token& btok, virtual void doCook([[maybe_unused]] const ProjectPath& path, [[maybe_unused]] const ProjectPath& cookedPath,
FCookProgress progress) { [[maybe_unused]] bool fast, [[maybe_unused]] blender::Token& btok,
(void)path; [[maybe_unused]] FCookProgress progress) {}
(void)cookedPath;
(void)fast;
(void)progress;
}
virtual bool canPackage(const ProjectPath& path) { virtual bool canPackage([[maybe_unused]] const ProjectPath& path) {
(void)path;
return false; return false;
} }
virtual void doPackage(const ProjectPath& path, const Database::DataSpecEntry* entry, bool fast, blender::Token& btok, virtual void doPackage([[maybe_unused]] const ProjectPath& path, [[maybe_unused]] const DataSpecEntry* entry,
const MultiProgressPrinter& progress, ClientProcess* cp = nullptr) { [[maybe_unused]] bool fast, [[maybe_unused]] blender::Token& btok,
(void)path; [[maybe_unused]] const MultiProgressPrinter& progress,
} [[maybe_unused]] ClientProcess* cp = nullptr) {}
virtual void interruptCook() {} virtual void interruptCook() {}
@ -190,7 +176,7 @@ protected:
Cafe /**< Swizzled textures and R700 shader objects */ 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 * @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. * 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. * This method should store the 64-bit value provided by IDataObject::id() when doing this.
*/ */
virtual bool cookObject(FDataAppender dataAppender, DataEndianness endianness, DataPlatform platform) { virtual bool cookObject([[maybe_unused]] FDataAppender dataAppender, [[maybe_unused]] DataEndianness endianness,
(void)dataAppender; [[maybe_unused]] DataPlatform platform) {
(void)endianness;
(void)platform;
return true; 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 * @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 * 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. * 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 * @brief Get a packagable FourCC representation of the object's type
@ -262,7 +246,7 @@ private:
public: public:
Project(const ProjectRootPath& rootPath); Project(const ProjectRootPath& rootPath);
operator bool() const { return m_valid; } explicit operator bool() const { return m_valid; }
/** /**
* @brief Configuration file handle * @brief Configuration file handle
@ -273,7 +257,7 @@ public:
class ConfigFile { class ConfigFile {
SystemString m_filepath; SystemString m_filepath;
std::vector<std::string> m_lines; std::vector<std::string> m_lines;
FILE* m_lockedFile = NULL; UniqueFilePtr m_lockedFile;
public: public:
ConfigFile(const Project& project, SystemStringView name, SystemStringView subdir = _SYS_STR("/.hecl/")); 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 * @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 * @return project cooked path
* *
* The cooked path matches the directory layout of the working directory * The cooked path matches the directory layout of the working directory
@ -320,7 +304,7 @@ public:
/** /**
* @brief Add given file(s) to the database * @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 * @return true on success
* *
* This method blocks while object hashing takes place * This method blocks while object hashing takes place

View File

@ -18,28 +18,36 @@ class FourCC {
protected: protected:
union { union {
char fcc[4]; char fcc[4];
uint32_t num; uint32_t num = 0;
}; };
public: public:
constexpr FourCC() /* Sentinel FourCC */ // Sentinel FourCC
: num(0) {} constexpr FourCC() noexcept = default;
constexpr FourCC(const FourCC& other) : num(other.num) {} constexpr FourCC(const FourCC& other) noexcept = default;
constexpr FourCC(const char* name) : num(*(uint32_t*)name) {} constexpr FourCC(FourCC&& other) noexcept = default;
constexpr FourCC(uint32_t n) : num(n) {} constexpr FourCC(const char* name) noexcept : fcc{name[0], name[1], name[2], name[3]} {}
bool operator==(const FourCC& other) const { return num == other.num; } constexpr FourCC(uint32_t n) noexcept : num(n) {}
bool operator!=(const FourCC& other) const { return num != other.num; }
bool operator==(const char* other) const { return num == *(uint32_t*)other; } constexpr FourCC& operator=(const FourCC&) noexcept = default;
bool operator!=(const char* other) const { return num != *(uint32_t*)other; } constexpr FourCC& operator=(FourCC&&) noexcept = default;
bool operator==(int32_t other) const { return num == uint32_t(other); }
bool operator!=(int32_t other) const { return num != uint32_t(other); } constexpr bool operator==(const FourCC& other) const { return num == other.num; }
bool operator==(uint32_t other) const { return num == other; } constexpr bool operator!=(const FourCC& other) const { return !operator==(other); }
bool operator!=(uint32_t other) const { return num != other; } constexpr bool operator==(const char* other) const {
std::string toString() const { return std::string(fcc, 4); } return other[0] == fcc[0] && other[1] == fcc[1] && other[2] == fcc[2] && other[3] == fcc[3];
uint32_t toUint32() const { return num; } }
const char* getChars() const { return fcc; } constexpr bool operator!=(const char* other) const { return !operator==(other); }
char* getChars() { return fcc; } constexpr bool operator==(int32_t other) const { return num == uint32_t(other); }
bool IsValid() const { return num != 0; } 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)) #define FOURCC(chars) FourCC(SBIG(chars))
@ -55,25 +63,25 @@ public:
AT_DECL_EXPLICIT_DNA_YAML AT_DECL_EXPLICIT_DNA_YAML
}; };
template <> template <>
inline void DNAFourCC::Enumerate<BigDNA::Read>(typename Read::StreamT& r) { inline void DNAFourCC::Enumerate<BigDNA::Read>(Read::StreamT& r) {
r.readUBytesToBuf(fcc, 4); r.readUBytesToBuf(fcc, std::size(fcc));
} }
template <> template <>
inline void DNAFourCC::Enumerate<BigDNA::Write>(typename Write::StreamT& w) { inline void DNAFourCC::Enumerate<BigDNA::Write>(Write::StreamT& w) {
w.writeUBytes((atUint8*)fcc, 4); w.writeBytes(fcc, std::size(fcc));
} }
template <> template <>
inline void DNAFourCC::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& r) { inline void DNAFourCC::Enumerate<BigDNA::ReadYaml>(ReadYaml::StreamT& r) {
std::string rs = r.readString(nullptr); const std::string rs = r.readString(nullptr);
strncpy(fcc, rs.c_str(), 4); rs.copy(fcc, std::size(fcc));
} }
template <> template <>
inline void DNAFourCC::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& w) { inline void DNAFourCC::Enumerate<BigDNA::WriteYaml>(WriteYaml::StreamT& w) {
w.writeString(nullptr, std::string(fcc, 4)); w.writeString(nullptr, std::string_view{fcc, std::size(fcc)});
} }
template <> template <>
inline void DNAFourCC::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) { inline void DNAFourCC::Enumerate<BigDNA::BinarySize>(BinarySize::StreamT& s) {
s += 4; s += std::size(fcc);
} }
} // namespace hecl } // namespace hecl
@ -85,7 +93,7 @@ struct hash<hecl::FourCC> {
}; };
} // namespace std } // namespace std
FMT_CUSTOM_FORMATTER(hecl::FourCC, "{:c}{:c}{:c}{:c}", FMT_CUSTOM_FORMATTER(hecl::FourCC, "{:c}{:c}{:c}{:c}", obj.getChars()[0], obj.getChars()[1], obj.getChars()[2],
obj.getChars()[0], obj.getChars()[1], obj.getChars()[2], obj.getChars()[3]) obj.getChars()[3])
FMT_CUSTOM_FORMATTER(hecl::DNAFourCC, "{:c}{:c}{:c}{:c}", FMT_CUSTOM_FORMATTER(hecl::DNAFourCC, "{:c}{:c}{:c}{:c}", obj.getChars()[0], obj.getChars()[1], obj.getChars()[2],
obj.getChars()[0], obj.getChars()[1], obj.getChars()[2], obj.getChars()[3]) obj.getChars()[3])

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "Compilers.hpp" #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 #define HECL_RUNTIME 1

View File

@ -26,7 +26,6 @@ namespace hecl {
#if HECL_UCS2 #if HECL_UCS2
typedef wchar_t SystemChar; typedef wchar_t SystemChar;
static inline size_t StrLen(const SystemChar* str) { return wcslen(str); }
typedef std::wstring SystemString; typedef std::wstring SystemString;
typedef std::wstring_view SystemStringView; typedef std::wstring_view SystemStringView;
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towlower); } 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; typedef struct _stat Sstat;
#else #else
typedef char SystemChar; typedef char SystemChar;
static inline size_t StrLen(const SystemChar* str) { return strlen(str); }
typedef std::string SystemString; typedef std::string SystemString;
typedef std::string_view SystemStringView; typedef std::string_view SystemStringView;
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), tolower); } static inline void ToLower(SystemString& str) {
static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), toupper); } 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 #ifndef _SYS_STR
#define _SYS_STR(val) val #define _SYS_STR(val) val
#endif #endif
typedef struct stat Sstat; typedef struct stat Sstat;
#endif #endif
constexpr size_t StrLen(const SystemChar* str) { return std::char_traits<SystemChar>::length(str); }
} // namespace hecl } // namespace hecl

View File

@ -173,7 +173,7 @@ public:
}, static_cast<const base&>(*this)); }, 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); return !std::holds_alternative<typename std::variant_alternative_t<0, std::variant<_Types...>>>(*this);
} }
}; };
@ -204,7 +204,7 @@ template <> \
template <> \ template <> \
inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::Read>(typename Read::StreamT & r) { \ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::Read>(typename Read::StreamT & r) { \
EnumType variant_type = {}; \ 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); \ static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type); \
visit([&](auto& var) { var.read(r); }); \ visit([&](auto& var) { var.read(r); }); \
} \ } \
@ -215,7 +215,7 @@ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<ath
visit([&](auto& var) { \ visit([&](auto& var) { \
using T = std::decay_t<decltype(var)>; \ using T = std::decay_t<decltype(var)>; \
EnumType variant_type = T::variant_type(); \ 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); \ var.write(w); \
}); \ }); \
} \ } \
@ -226,7 +226,7 @@ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<ath
visit([&](auto& var) { \ visit([&](auto& var) { \
using T = std::decay_t<decltype(var)>; \ using T = std::decay_t<decltype(var)>; \
EnumType variant_type = T::variant_type(); \ 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); \ var.binarySize(sz); \
}); \ }); \
} \ } \
@ -241,7 +241,7 @@ template <> \
template <> \ template <> \
inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::ReadYaml>(typename ReadYaml::StreamT & r) { \ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::ReadYaml>(typename ReadYaml::StreamT & r) { \
EnumType variant_type = {}; \ 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); \ static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type); \
visit([&](auto& var) { var.read(r); }); \ visit([&](auto& var) { var.read(r); }); \
} \ } \
@ -252,7 +252,7 @@ inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<ath
visit([&](auto& var) { \ visit([&](auto& var) { \
using T = std::decay_t<decltype(var)>; \ using T = std::decay_t<decltype(var)>; \
EnumType variant_type = T::variant_type(); \ 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); \ var.write(w); \
}); \ }); \
} }

View File

@ -153,7 +153,7 @@ public:
return {bucket.buffer, m_div.rem * m_pool->m_stride}; 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; UniformBufferPool() = default;

View File

@ -158,7 +158,7 @@ public:
return {bucket.buffer, m_div.rem}; 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; VertexBufferPool() = default;

View File

@ -22,20 +22,22 @@ extern "C" int rep_closefrom(int lower);
#endif #endif
#include <Windows.h> #include <Windows.h>
#include <cwchar> #include <cwchar>
#include <cwctype>
#include <Shlwapi.h> #include <Shlwapi.h>
#include "winsupport.hpp" #include "winsupport.hpp"
#endif #endif
#include <algorithm>
#include <cinttypes> #include <cinttypes>
#include <ctime>
#include <cstdarg> #include <cstdarg>
#include <cstdio> #include <cstdio>
#include <ctime>
#include <functional> #include <functional>
#include <string>
#include <algorithm>
#include <regex>
#include <list> #include <list>
#include <map> #include <map>
#include <regex>
#include <string>
#include "logvisor/logvisor.hpp" #include "logvisor/logvisor.hpp"
#include "athena/Global.hpp" #include "athena/Global.hpp"
#include "../extern/boo/xxhash/xxhash.h" #include "../extern/boo/xxhash/xxhash.h"
@ -109,46 +111,66 @@ class SystemUTF8Conv {
public: public:
explicit SystemUTF8Conv(SystemStringView str) : m_utf8(WideToUTF8(str)) {} explicit SystemUTF8Conv(SystemStringView str) : m_utf8(WideToUTF8(str)) {}
std::string_view str() const { return m_utf8; } std::string_view str() const { return m_utf8; }
const char* c_str() const { return m_utf8.c_str(); } 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 { class SystemStringConv {
std::wstring m_sys; std::wstring m_sys;
public: public:
explicit SystemStringConv(std::string_view str) : m_sys(UTF8ToWide(str)) {} explicit SystemStringConv(std::string_view str) : m_sys(UTF8ToWide(str)) {}
SystemStringView sys_str() const { return m_sys; } SystemStringView sys_str() const { return m_sys; }
const SystemChar* c_str() const { return m_sys.c_str(); } 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) {
inline std::wstring operator+(std::wstring_view lhs, const SystemStringConv& rhs) { return lhs.m_sys + rhs.data();
return std::wstring(lhs) + rhs.c_str();
} }
friend std::wstring operator+(std::wstring_view lhs, const SystemStringConv& rhs) {
return std::wstring(lhs).append(rhs.m_sys);
}
};
#else #else
class SystemUTF8Conv { class SystemUTF8Conv {
std::string_view m_utf8; std::string_view m_utf8;
public: public:
explicit SystemUTF8Conv(SystemStringView str) : m_utf8(str) {} explicit SystemUTF8Conv(SystemStringView str) : m_utf8(str) {}
std::string_view str() const { return m_utf8; } std::string_view str() const { return m_utf8; }
const char* c_str() const { return m_utf8.data(); } 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 { class SystemStringConv {
std::string_view m_sys; std::string_view m_sys;
public: public:
explicit SystemStringConv(std::string_view str) : m_sys(str) {} explicit SystemStringConv(std::string_view str) : m_sys(str) {}
SystemStringView sys_str() const { return m_sys; } SystemStringView sys_str() const { return m_sys; }
const SystemChar* c_str() const { return m_sys.data(); } 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) {
inline std::string operator+(std::string_view lhs, const SystemStringConv& rhs) { return std::string(lhs.m_sys).append(rhs);
return std::string(lhs) + rhs.c_str();
} }
friend std::string operator+(std::string_view lhs, const SystemStringConv& rhs) {
return std::string(lhs).append(rhs.m_sys);
}
};
#endif #endif
void SanitizePath(std::string& path); void SanitizePath(std::string& path);
@ -167,7 +189,7 @@ inline void MakeDir(const char* dir) {
HRESULT err; HRESULT err;
if (!CreateDirectoryA(dir, NULL)) if (!CreateDirectoryA(dir, NULL))
if ((err = GetLastError()) != ERROR_ALREADY_EXISTS) if ((err = GetLastError()) != ERROR_ALREADY_EXISTS)
LogModule.report(logvisor::Fatal, fmt("MakeDir(%s)"), dir); LogModule.report(logvisor::Fatal, fmt("MakeDir({})"), dir);
#else #else
if (mkdir(dir, 0755)) if (mkdir(dir, 0755))
if (errno != EEXIST) if (errno != EEXIST)
@ -180,7 +202,7 @@ inline void MakeDir(const wchar_t* dir) {
HRESULT err; HRESULT err;
if (!CreateDirectoryW(dir, NULL)) if (!CreateDirectoryW(dir, NULL))
if ((err = GetLastError()) != ERROR_ALREADY_EXISTS) 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 #endif
@ -253,6 +275,16 @@ inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType
return fp; 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) { inline int FSeek(FILE* fp, int64_t offset, int whence) {
#if _WIN32 #if _WIN32
return _fseeki64(fp, offset, whence); 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) { inline int StrNCmp(const SystemChar* str1, const SystemChar* str2, size_t count) {
if (!str1 || !str2) if (!str1 || !str2)
return str1 != str2; return str1 != str2;
#if HECL_UCS2
return wcsncmp(str1, str2, count); return std::char_traits<SystemChar>::compare(str1, str2, count);
#else
return strncmp(str1, str2, count);
#endif
} }
inline int StrCaseCmp(const SystemChar* str1, const SystemChar* str2) { 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; wchar_t* end;
DWORD ret = GetFullPathNameW(path, 1024, buf, &end); DWORD ret = GetFullPathNameW(path, 1024, buf, &end);
if (!ret || ret > 1024) 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) if (end)
end[0] = L'\0'; end[0] = L'\0';
if (!GetDiskFreeSpaceExW(buf, &freeBytes, nullptr, nullptr)) 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; return reqSz < freeBytes.QuadPart;
#else #else
struct statvfs svfs; struct statvfs svfs;
@ -391,13 +420,12 @@ inline int ConsoleWidth(bool* ok = nullptr) {
} }
class MultiProgressPrinter; 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; 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 * @brief Hash representation used for all storable and comparable objects
* *
@ -409,35 +437,36 @@ protected:
uint64_t hash = 0; uint64_t hash = 0;
public: public:
Hash() = default; constexpr Hash() noexcept = default;
operator bool() const { return hash != 0; } constexpr Hash(const Hash&) noexcept = default;
Hash(const void* buf, size_t len) : hash(XXH64((uint8_t*)buf, len, 0)) {} constexpr Hash(Hash&&) noexcept = default;
Hash(std::string_view str) : hash(XXH64((uint8_t*)str.data(), str.size(), 0)) {} constexpr Hash(uint64_t hashin) noexcept : hash(hashin) {}
Hash(std::wstring_view str) : hash(XXH64((uint8_t*)str.data(), str.size() * 2, 0)) {} explicit Hash(const void* buf, size_t len) noexcept : hash(XXH64(buf, len, 0)) {}
Hash(uint64_t hashin) : hash(hashin) {} explicit Hash(std::string_view str) noexcept : hash(XXH64(str.data(), str.size(), 0)) {}
Hash(const Hash& other) { hash = other.hash; } explicit Hash(std::wstring_view str) noexcept : hash(XXH64(str.data(), str.size() * 2, 0)) {}
uint32_t val32() const { return uint32_t(hash) ^ uint32_t(hash >> 32); }
uint64_t val64() const { return uint64_t(hash); } constexpr uint32_t val32() const noexcept { return uint32_t(hash) ^ uint32_t(hash >> 32); }
size_t valSizeT() const { return size_t(hash); } constexpr uint64_t val64() const noexcept { return uint64_t(hash); }
constexpr size_t valSizeT() const noexcept { return size_t(hash); }
template <typename T> template <typename T>
T valT() const; constexpr T valT() const noexcept;
Hash& operator=(const Hash& other) {
hash = other.hash; constexpr Hash& operator=(const Hash& other) noexcept = default;
return *this; constexpr Hash& operator=(Hash&& other) noexcept = default;
} constexpr bool operator==(const Hash& other) const noexcept { return hash == other.hash; }
bool operator==(const Hash& other) const { return hash == other.hash; } constexpr bool operator!=(const Hash& other) const noexcept { return !operator==(other); }
bool operator!=(const Hash& other) const { return hash != other.hash; } constexpr bool operator<(const Hash& other) const noexcept { return hash < other.hash; }
bool operator<(const Hash& other) const { return hash < other.hash; } constexpr bool operator>(const Hash& other) const noexcept { return hash > other.hash; }
bool operator>(const Hash& other) const { return hash > other.hash; } constexpr bool operator<=(const Hash& other) const noexcept { return hash <= other.hash; }
bool operator<=(const Hash& other) const { return hash <= other.hash; } constexpr bool operator>=(const Hash& other) const noexcept { return hash >= other.hash; }
bool operator>=(const Hash& other) const { return hash >= other.hash; } constexpr explicit operator bool() const noexcept { return hash != 0; }
}; };
template <> template <>
inline uint32_t Hash::valT<uint32_t>() const { constexpr uint32_t Hash::valT<uint32_t>() const noexcept {
return val32(); return val32();
} }
template <> template <>
inline uint64_t Hash::valT<uint64_t>() const { constexpr uint64_t Hash::valT<uint64_t>() const noexcept {
return val64(); return val64();
} }
@ -469,22 +498,16 @@ public:
*/ */
struct CaseInsensitiveCompare { struct CaseInsensitiveCompare {
bool operator()(std::string_view lhs, std::string_view rhs) const { bool operator()(std::string_view lhs, std::string_view rhs) const {
#if _WIN32 return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](char lhs, char rhs) {
if (_stricmp(lhs.data(), rhs.data()) < 0) return std::tolower(static_cast<unsigned char>(lhs)) < std::tolower(static_cast<unsigned char>(rhs));
#else });
if (strcasecmp(lhs.data(), rhs.data()) < 0)
#endif
return true;
return false;
} }
#if _WIN32
bool operator()(std::wstring_view lhs, std::wstring_view rhs) const { bool operator()(std::wstring_view lhs, std::wstring_view rhs) const {
if (_wcsicmp(lhs.data(), rhs.data()) < 0) return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](wchar_t lhs, wchar_t rhs) {
return true; return std::towlower(lhs) < std::towlower(rhs);
return false; });
} }
#endif
}; };
/** /**
@ -499,8 +522,8 @@ public:
size_t m_fileSz; size_t m_fileSz;
bool m_isDir; bool m_isDir;
Entry(const hecl::SystemString& path, const hecl::SystemChar* name, size_t sz, bool isDir) Entry(hecl::SystemString path, const hecl::SystemChar* name, size_t sz, bool isDir)
: m_path(path), m_name(name), m_fileSz(sz), m_isDir(isDir) {} : m_path(std::move(path)), m_name(name), m_fileSz(sz), m_isDir(isDir) {}
}; };
private: private:
@ -510,7 +533,7 @@ public:
DirectoryEnumerator(SystemStringView path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false, DirectoryEnumerator(SystemStringView path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
bool reverse = false, bool noHidden = 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(); } size_t size() const { return m_entries.size(); }
std::vector<Entry>::const_iterator begin() const { return m_entries.cbegin(); } std::vector<Entry>::const_iterator begin() const { return m_entries.cbegin(); }
std::vector<Entry>::const_iterator end() const { return m_entries.cend(); } std::vector<Entry>::const_iterator end() const { return m_entries.cend(); }
@ -542,7 +565,7 @@ public:
/** /**
* @brief Tests for non-empty project root path * @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 * @brief Construct a representation of a project root path
@ -577,7 +600,8 @@ public:
return SystemString(beginIt, absPathForward.cend()); 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(); return SystemString();
} }
@ -593,9 +617,9 @@ public:
* @brief HECL-specific xxhash * @brief HECL-specific xxhash
* @return unique hash value * @return unique hash value
*/ */
Hash hash() const { return m_hash; } Hash hash() const noexcept { return m_hash; }
bool operator==(const ProjectRootPath& other) const { return m_hash == other.m_hash; } bool operator==(const ProjectRootPath& other) const noexcept { return m_hash == other.m_hash; }
bool operator!=(const ProjectRootPath& other) const { return m_hash != other.m_hash; } bool operator!=(const ProjectRootPath& other) const noexcept { return !operator==(other); }
/** /**
* @brief Obtain c-string of final path component * @brief Obtain c-string of final path component
@ -661,7 +685,7 @@ public:
/** /**
* @brief Tests for non-empty project path * @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 * @brief Clears path
@ -1026,9 +1050,9 @@ public:
* @brief HECL-specific xxhash * @brief HECL-specific xxhash
* @return unique hash value * @return unique hash value
*/ */
Hash hash() const { return m_hash; } Hash hash() const noexcept { return m_hash; }
bool operator==(const ProjectPath& other) const { return m_hash == other.m_hash; } bool operator==(const ProjectPath& other) const noexcept { return m_hash == other.m_hash; }
bool operator!=(const ProjectPath& other) const { 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) { static bool BeginsWith(SystemStringView str, SystemStringView test) {
if (test.size() > str.size()) if (test.size() > str.size())
return false; 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) { static bool EndsWith(SystemStringView str, SystemStringView test) {
if (test.size() > str.size()) if (test.size() > str.size())
return false; 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) { static std::string TrimWhitespace(std::string_view str) {
auto bit = str.begin(); auto bit = str.begin();
while (bit != str.cend() && isspace(*bit)) while (bit != str.cend() && std::isspace(static_cast<unsigned char>(*bit)))
++bit; ++bit;
auto eit = str.end(); auto eit = str.end();
while (eit != str.cbegin() && isspace(*(eit - 1))) while (eit != str.cbegin() && std::isspace(static_cast<unsigned char>(*(eit - 1))))
--eit; --eit;
return {bit, eit}; return {bit, eit};
} }
@ -1062,21 +1086,21 @@ public:
static bool BeginsWith(std::string_view str, std::string_view test) { static bool BeginsWith(std::string_view str, std::string_view test) {
if (test.size() > str.size()) if (test.size() > str.size())
return false; 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) { static bool EndsWith(std::string_view str, std::string_view test) {
if (test.size() > str.size()) if (test.size() > str.size())
return false; 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) { static SystemString TrimWhitespace(SystemStringView str) {
auto bit = str.begin(); auto bit = str.begin();
while (bit != str.cend() && iswspace(*bit)) while (bit != str.cend() && std::iswspace(*bit))
++bit; ++bit;
auto eit = str.end(); auto eit = str.end();
while (eit != str.cbegin() && iswspace(*(eit - 1))) while (eit != str.cbegin() && std::iswspace(*(eit - 1)))
--eit; --eit;
return {bit, eit}; return {bit, eit};
} }
@ -1095,9 +1119,9 @@ class ResourceLock {
bool good; bool good;
public: public:
operator bool() const { return good; } explicit operator bool() const { return good; }
static bool InProgress(const ProjectPath& path); static bool InProgress(const ProjectPath& path);
ResourceLock(const ProjectPath& path) { good = SetThreadRes(path); } explicit ResourceLock(const ProjectPath& path) : good{SetThreadRes(path)} {}
~ResourceLock() { ~ResourceLock() {
if (good) if (good)
ClearThreadRes(); ClearThreadRes();
@ -1150,7 +1174,7 @@ bool IsPathYAML(const hecl::ProjectPath& path);
/* Type-sensitive byte swappers */ /* Type-sensitive byte swappers */
template <typename T> template <typename T>
constexpr T bswap16(T val) { constexpr T bswap16(T val) noexcept {
#if __GNUC__ #if __GNUC__
return __builtin_bswap16(val); return __builtin_bswap16(val);
#elif _WIN32 #elif _WIN32
@ -1161,7 +1185,7 @@ constexpr T bswap16(T val) {
} }
template <typename T> template <typename T>
constexpr T bswap32(T val) { constexpr T bswap32(T val) noexcept {
#if __GNUC__ #if __GNUC__
return __builtin_bswap32(val); return __builtin_bswap32(val);
#elif _WIN32 #elif _WIN32
@ -1174,7 +1198,7 @@ constexpr T bswap32(T val) {
} }
template <typename T> template <typename T>
constexpr T bswap64(T val) { constexpr T bswap64(T val) noexcept {
#if __GNUC__ #if __GNUC__
return __builtin_bswap64(val); return __builtin_bswap64(val);
#elif _WIN32 #elif _WIN32
@ -1188,49 +1212,61 @@ constexpr T bswap64(T val) {
} }
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
constexpr int16_t SBig(int16_t val) { return bswap16(val); } constexpr int16_t SBig(int16_t val) noexcept { return bswap16(val); }
constexpr uint16_t SBig(uint16_t val) { return bswap16(val); } constexpr uint16_t SBig(uint16_t val) noexcept { return bswap16(val); }
constexpr int32_t SBig(int32_t val) { return bswap32(val); } constexpr int32_t SBig(int32_t val) noexcept { return bswap32(val); }
constexpr uint32_t SBig(uint32_t val) { return bswap32(val); } constexpr uint32_t SBig(uint32_t val) noexcept { return bswap32(val); }
constexpr int64_t SBig(int64_t val) { return bswap64(val); } constexpr int64_t SBig(int64_t val) noexcept { return bswap64(val); }
constexpr uint64_t SBig(uint64_t val) { return bswap64(val); } constexpr uint64_t SBig(uint64_t val) noexcept { return bswap64(val); }
constexpr float SBig(float val) { constexpr float SBig(float val) noexcept {
union { float f; atInt32 i; } uval1 = {val}; union {
union { atInt32 i; float f; } uval2 = {bswap32(uval1.i)}; float f;
atInt32 i;
} uval1 = {val};
union {
atInt32 i;
float f;
} uval2 = {bswap32(uval1.i)};
return uval2.f; return uval2.f;
} }
constexpr double SBig(double val) { constexpr double SBig(double val) noexcept {
union { double f; atInt64 i; } uval1 = {val}; union {
union { atInt64 i; double f; } uval2 = {bswap64(uval1.i)}; double f;
atInt64 i;
} uval1 = {val};
union {
atInt64 i;
double f;
} uval2 = {bswap64(uval1.i)};
return uval2.f; return uval2.f;
} }
#ifndef SBIG #ifndef SBIG
#define SBIG(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24) #define SBIG(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
#endif #endif
constexpr int16_t SLittle(int16_t val) { return val; } constexpr int16_t SLittle(int16_t val) noexcept { return val; }
constexpr uint16_t SLittle(uint16_t val) { return val; } constexpr uint16_t SLittle(uint16_t val) noexcept { return val; }
constexpr int32_t SLittle(int32_t val) { return val; } constexpr int32_t SLittle(int32_t val) noexcept { return val; }
constexpr uint32_t SLittle(uint32_t val) { return val; } constexpr uint32_t SLittle(uint32_t val) noexcept { return val; }
constexpr int64_t SLittle(int64_t val) { return val; } constexpr int64_t SLittle(int64_t val) noexcept { return val; }
constexpr uint64_t SLittle(uint64_t val) { return val; } constexpr uint64_t SLittle(uint64_t val) noexcept { return val; }
constexpr float SLittle(float val) { return val; } constexpr float SLittle(float val) noexcept { return val; }
constexpr double SLittle(double val) { return val; } constexpr double SLittle(double val) noexcept { return val; }
#ifndef SLITTLE #ifndef SLITTLE
#define SLITTLE(q) (q) #define SLITTLE(q) (q)
#endif #endif
#else #else
constexpr int16_t SLittle(int16_t val) { return bswap16(val); } constexpr int16_t SLittle(int16_t val) noexcept { return bswap16(val); }
constexpr uint16_t SLittle(uint16_t val) { return bswap16(val); } constexpr uint16_t SLittle(uint16_t val) noexcept { return bswap16(val); }
constexpr int32_t SLittle(int32_t val) { return bswap32(val); } constexpr int32_t SLittle(int32_t val) noexcept { return bswap32(val); }
constexpr uint32_t SLittle(uint32_t val) { return bswap32(val); } constexpr uint32_t SLittle(uint32_t val) noexcept { return bswap32(val); }
constexpr int64_t SLittle(int64_t val) { return bswap64(val); } constexpr int64_t SLittle(int64_t val) noexcept { return bswap64(val); }
constexpr uint64_t SLittle(uint64_t val) { return bswap64(val); } constexpr uint64_t SLittle(uint64_t val) noexcept { return bswap64(val); }
constexpr float SLittle(float val) { constexpr float SLittle(float val) noexcept {
int32_t ival = bswap32(*((int32_t*)(&val))); int32_t ival = bswap32(*((int32_t*)(&val)));
return *((float*)(&ival)); return *((float*)(&ival));
} }
constexpr double SLittle(double val) { constexpr double SLittle(double val) noexcept {
int64_t ival = bswap64(*((int64_t*)(&val))); int64_t ival = bswap64(*((int64_t*)(&val)));
return *((double*)(&ival)); return *((double*)(&ival));
} }
@ -1238,21 +1274,21 @@ constexpr double SLittle(double val) {
#define SLITTLE(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24) #define SLITTLE(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
#endif #endif
constexpr int16_t SBig(int16_t val) { return val; } constexpr int16_t SBig(int16_t val) noexcept { return val; }
constexpr uint16_t SBig(uint16_t val) { return val; } constexpr uint16_t SBig(uint16_t val) noexcept { return val; }
constexpr int32_t SBig(int32_t val) { return val; } constexpr int32_t SBig(int32_t val) noexcept { return val; }
constexpr uint32_t SBig(uint32_t val) { return val; } constexpr uint32_t SBig(uint32_t val) noexcept { return val; }
constexpr int64_t SBig(int64_t val) { return val; } constexpr int64_t SBig(int64_t val) noexcept { return val; }
constexpr uint64_t SBig(uint64_t val) { return val; } constexpr uint64_t SBig(uint64_t val) noexcept { return val; }
constexpr float SBig(float val) { return val; } constexpr float SBig(float val) noexcept { return val; }
constexpr double SBig(double val) { return val; } constexpr double SBig(double val) noexcept { return val; }
#ifndef SBIG #ifndef SBIG
#define SBIG(q) (q) #define SBIG(q) (q)
#endif #endif
#endif #endif
template <typename SizeT> template <typename SizeT>
constexpr void hash_combine_impl(SizeT& seed, SizeT value) { constexpr void hash_combine_impl(SizeT& seed, SizeT value) noexcept {
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2); seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
} }

View File

@ -1,23 +1,28 @@
#include <algorithm>
#include <cerrno> #include <cerrno>
#include <cfloat>
#include <chrono>
#include <cinttypes>
#include <csignal>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <cinttypes>
#include <signal.h>
#include <system_error>
#include <string>
#include <algorithm>
#include <chrono>
#include <thread>
#include <mutex> #include <mutex>
#include <string>
#include <system_error>
#include <thread>
#include <tuple>
#include <hecl/hecl.hpp> #include <hecl/hecl.hpp>
#include <hecl/Database.hpp> #include <hecl/Database.hpp>
#include "logvisor/logvisor.hpp"
#include "hecl/Blender/Connection.hpp" #include "hecl/Blender/Connection.hpp"
#include "hecl/Blender/Token.hpp"
#include "hecl/SteamFinder.hpp" #include "hecl/SteamFinder.hpp"
#include "MeshOptimizer.hpp" #include "MeshOptimizer.hpp"
#include <athena/MemoryWriter.hpp>
#include <logvisor/logvisor.hpp>
#if _WIN32 #if _WIN32
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
@ -60,19 +65,23 @@ extern "C" uint8_t HECL_STARTUP[];
extern "C" size_t HECL_STARTUP_SZ; extern "C" size_t HECL_STARTUP_SZ;
static void InstallBlendershell(const SystemChar* path) { static void InstallBlendershell(const SystemChar* path) {
FILE* fp = hecl::Fopen(path, _SYS_STR("w")); auto fp = hecl::FopenUnique(path, _SYS_STR("w"));
if (!fp)
if (fp == nullptr) {
BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("unable to open {} for writing")), path); 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) { static void InstallAddon(const SystemChar* path) {
FILE* fp = hecl::Fopen(path, _SYS_STR("wb")); auto fp = hecl::FopenUnique(path, _SYS_STR("wb"));
if (!fp)
if (fp == nullptr) {
BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("Unable to install blender addon at '{}'")), path); 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) { 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 Connection::_readStr(char* buf, uint32_t bufSz) {
uint32_t readLen; uint32_t readLen;
int ret = Read(m_readpipe[0], &readLen, 4); int ret = Read(m_readpipe[0], &readLen, sizeof(readLen));
if (ret < 4) { if (ret < 4) {
BlenderLog.report(logvisor::Error, fmt("Pipe error {} {}"), ret, strerror(errno)); BlenderLog.report(logvisor::Error, fmt("Pipe error {} {}"), ret, strerror(errno));
_blenderDied(); _blenderDied();
@ -124,8 +133,11 @@ uint32_t Connection::_readStr(char* buf, uint32_t bufSz) {
if (ret < 0) { if (ret < 0) {
BlenderLog.report(logvisor::Fatal, fmt("{}"), strerror(errno)); BlenderLog.report(logvisor::Fatal, fmt("{}"), strerror(errno));
return 0; 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(); _blenderDied();
return 0; 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) { uint32_t Connection::_writeStr(const char* buf, uint32_t len, int wpipe) {
int ret, nlerr; const auto error = [this] {
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:
_blenderDied(); _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) { size_t Connection::_readBuf(void* buf, size_t len) {
uint8_t* cBuf = reinterpret_cast<uint8_t*>(buf); const auto error = [this] {
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))))
_blenderDied(); _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; readLen += ret;
cBuf += ret; cBuf += ret;
len -= ret; len -= ret;
} while (len); } while (len != 0);
return readLen; return readLen;
err:
_blenderDied();
return 0;
} }
size_t Connection::_writeBuf(const void* buf, size_t len) { 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; size_t writeLen = 0;
do { do {
int ret = Write(m_writepipe[1], cBuf, len); const int ret = Write(m_writepipe[1], cBuf, len);
if (ret < 0) if (ret < 0) {
goto err; return error();
}
writeLen += ret; writeLen += ret;
cBuf += ret; cBuf += ret;
len -= ret; len -= ret;
} while (len); } while (len != 0);
return writeLen; return writeLen;
err:
_blenderDied();
return 0;
} }
void Connection::_closePipe() { void Connection::_closePipe() {
@ -200,18 +233,20 @@ void Connection::_closePipe() {
void Connection::_blenderDied() { void Connection::_blenderDied() {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
FILE* errFp = hecl::Fopen(m_errPath.c_str(), _SYS_STR("r")); auto errFp = hecl::FopenUnique(m_errPath.c_str(), _SYS_STR("r"));
if (errFp) {
fseek(errFp, 0, SEEK_END); if (errFp != nullptr) {
int64_t len = hecl::FTell(errFp); std::fseek(errFp.get(), 0, SEEK_END);
if (len) { const int64_t len = hecl::FTell(errFp.get());
fseek(errFp, 0, SEEK_SET);
std::unique_ptr<char[]> buf(new char[len + 1]); if (len != 0) {
memset(buf.get(), 0, len + 1); std::fseek(errFp.get(), 0, SEEK_SET);
fread(buf.get(), 1, len, errFp); 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("\n{:.{}s}"), buf.get(), len);
} }
} }
BlenderLog.report(logvisor::Fatal, fmt("Blender Exception")); BlenderLog.report(logvisor::Fatal, fmt("Blender Exception"));
} }
@ -253,14 +288,14 @@ Connection::Connection(int verbosityLevel) {
while (true) { while (true) {
/* Construct communication pipes */ /* Construct communication pipes */
#if _WIN32 #if _WIN32
_pipe(m_readpipe, 2048, _O_BINARY); _pipe(m_readpipe.data(), 2048, _O_BINARY);
_pipe(m_writepipe, 2048, _O_BINARY); _pipe(m_writepipe.data(), 2048, _O_BINARY);
HANDLE writehandle = HANDLE(_get_osfhandle(m_writepipe[0])); HANDLE writehandle = HANDLE(_get_osfhandle(m_writepipe[0]));
SetHandleInformation(writehandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); SetHandleInformation(writehandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
HANDLE readhandle = HANDLE(_get_osfhandle(m_readpipe[1])); HANDLE readhandle = HANDLE(_get_osfhandle(m_readpipe[1]));
SetHandleInformation(readhandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); 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; HANDLE consoleOutReadTmp, consoleOutWrite, consoleErrWrite, consoleOutRead;
if (!CreatePipe(&consoleOutReadTmp, &consoleOutWrite, &sattrs, 1024)) if (!CreatePipe(&consoleOutReadTmp, &consoleOutWrite, &sattrs, 1024))
BlenderLog.report(logvisor::Fatal, fmt("Error with CreatePipe")); BlenderLog.report(logvisor::Fatal, fmt("Error with CreatePipe"));
@ -278,8 +313,8 @@ Connection::Connection(int verbosityLevel) {
if (!CloseHandle(consoleOutReadTmp)) if (!CloseHandle(consoleOutReadTmp))
BlenderLog.report(logvisor::Fatal, fmt("Error with CloseHandle")); BlenderLog.report(logvisor::Fatal, fmt("Error with CloseHandle"));
#else #else
pipe(m_readpipe); pipe(m_readpipe.data());
pipe(m_writepipe); pipe(m_writepipe.data());
#endif #endif
/* User-specified blender path */ /* User-specified blender path */
@ -315,12 +350,12 @@ Connection::Connection(int verbosityLevel) {
} }
} }
std::wstring cmdLine = fmt::format(fmt(L" --background -P \"{}\" -- {} {} {} \"{}\""), std::wstring cmdLine = fmt::format(fmt(L" --background -P \"{}\" -- {} {} {} \"{}\""), blenderShellPath,
blenderShellPath, uintptr_t(writehandle), uintptr_t(readhandle), verbosityLevel, blenderAddonPath); uintptr_t(writehandle), uintptr_t(readhandle), verbosityLevel, blenderAddonPath);
STARTUPINFO sinfo = {sizeof(STARTUPINFO)}; STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
HANDLE nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sattrs, OPEN_EXISTING, 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.dwFlags = STARTF_USESTDHANDLES;
sinfo.hStdInput = nulHandle; sinfo.hStdInput = nulHandle;
if (verbosityLevel == 0) { if (verbosityLevel == 0) {
@ -331,11 +366,12 @@ Connection::Connection(int verbosityLevel) {
sinfo.hStdOutput = consoleOutWrite; sinfo.hStdOutput = consoleOutWrite;
} }
if (!CreateProcessW(blenderBin, const_cast<wchar_t*>(cmdLine.c_str()), NULL, NULL, TRUE, if (!CreateProcessW(blenderBin, cmdLine.data(), nullptr, nullptr, TRUE, NORMAL_PRIORITY_CLASS, nullptr, nullptr,
NORMAL_PRIORITY_CLASS, NULL, NULL, &sinfo, &m_pinfo)) { &sinfo, &m_pinfo)) {
LPWSTR messageBuffer = nullptr; LPWSTR messageBuffer = nullptr;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL); nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0,
nullptr);
BlenderLog.report(logvisor::Fatal, fmt(L"unable to launch blender from {}: {}"), blenderBin, messageBuffer); BlenderLog.report(logvisor::Fatal, fmt(L"unable to launch blender from {}: {}"), blenderBin, messageBuffer);
} }
@ -353,7 +389,7 @@ Connection::Connection(int verbosityLevel) {
DWORD nCharsWritten; DWORD nCharsWritten;
while (m_consoleThreadRunning) { while (m_consoleThreadRunning) {
if (!ReadFile(consoleOutRead, lpBuffer, sizeof(lpBuffer), &nBytesRead, NULL) || !nBytesRead) { if (!ReadFile(consoleOutRead, lpBuffer, sizeof(lpBuffer), &nBytesRead, nullptr) || !nBytesRead) {
DWORD err = GetLastError(); DWORD err = GetLastError();
if (err == ERROR_BROKEN_PIPE) if (err == ERROR_BROKEN_PIPE)
break; // pipe done - normal exit path. break; // pipe done - normal exit path.
@ -363,7 +399,7 @@ Connection::Connection(int verbosityLevel) {
// Display the character read on the screen. // Display the character read on the screen.
auto lk = logvisor::LockLog(); 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()); // BlenderLog.report(logvisor::Error, fmt("Error with WriteConsole: %08X"), GetLastError());
} }
} }
@ -396,8 +432,8 @@ Connection::Connection(int verbosityLevel) {
/* Try user-specified blender first */ /* Try user-specified blender first */
if (blenderBin) { if (blenderBin) {
execlp(blenderBin, blenderBin, "--background", "-P", blenderShellPath.c_str(), "--", execlp(blenderBin, blenderBin, "--background", "-P", blenderShellPath.c_str(), "--", readfds.c_str(),
readfds.c_str(), writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), NULL); writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
if (errno != ENOENT) { if (errno != ENOENT) {
errbuf = fmt::format(fmt("NOLAUNCH {}"), strerror(errno)); errbuf = fmt::format(fmt("NOLAUNCH {}"), strerror(errno));
_writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]); _writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]);
@ -414,8 +450,8 @@ Connection::Connection(int verbosityLevel) {
steamBlender += "/blender"; steamBlender += "/blender";
#endif #endif
blenderBin = steamBlender.c_str(); blenderBin = steamBlender.c_str();
execlp(blenderBin, blenderBin, "--background", "-P", blenderShellPath.c_str(), "--", execlp(blenderBin, blenderBin, "--background", "-P", blenderShellPath.c_str(), "--", readfds.c_str(),
readfds.c_str(), writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), NULL); writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
if (errno != ENOENT) { if (errno != ENOENT) {
errbuf = fmt::format(fmt("NOLAUNCH {}"), strerror(errno)); errbuf = fmt::format(fmt("NOLAUNCH {}"), strerror(errno));
_writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]); _writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]);
@ -425,7 +461,7 @@ Connection::Connection(int verbosityLevel) {
/* Otherwise default blender */ /* Otherwise default blender */
execlp(DEFAULT_BLENDER_BIN, DEFAULT_BLENDER_BIN, "--background", "-P", blenderShellPath.c_str(), "--", 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) { if (errno != ENOENT) {
errbuf = fmt::format(fmt("NOLAUNCH {}"), strerror(errno)); errbuf = fmt::format(fmt("NOLAUNCH {}"), strerror(errno));
_writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]); _writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]);
@ -446,8 +482,8 @@ Connection::Connection(int verbosityLevel) {
m_errPath = hecl::SystemString(TMPDIR) + m_errPath = hecl::SystemString(TMPDIR) +
fmt::format(fmt(_SYS_STR("/hecl_{:016X}.derp")), (unsigned long long)m_pinfo.dwProcessId); fmt::format(fmt(_SYS_STR("/hecl_{:016X}.derp")), (unsigned long long)m_pinfo.dwProcessId);
#else #else
m_errPath = m_errPath = hecl::SystemString(TMPDIR) +
hecl::SystemString(TMPDIR) + fmt::format(fmt(_SYS_STR("/hecl_{:016X}.derp")), (unsigned long long)m_blenderProc); fmt::format(fmt(_SYS_STR("/hecl_{:016X}.derp")), (unsigned long long)m_blenderProc);
#endif #endif
hecl::Unlink(m_errPath.c_str()); hecl::Unlink(m_errPath.c_str());
@ -528,8 +564,9 @@ std::streambuf::int_type PyOutStream::StreamBuf::overflow(int_type ch) {
return ch; return ch;
} }
static const char* BlendTypeStrs[] = {"NONE", "MESH", "CMESH", "ACTOR", "AREA", "WORLD", constexpr std::array<const char*, 11> BlendTypeStrs{
"MAPAREA", "MAPUNIVERSE", "FRAME", "PATH", nullptr}; "NONE", "MESH", "CMESH", "ACTOR", "AREA", "WORLD", "MAPAREA", "MAPUNIVERSE", "FRAME", "PATH", nullptr,
};
bool Connection::createBlend(const ProjectPath& path, BlendType type) { bool Connection::createBlend(const ProjectPath& path, BlendType type) {
if (m_lock) { if (m_lock) {
@ -628,8 +665,7 @@ void PyOutStream::close() {
} }
void PyOutStream::linkBlend(const char* target, const char* objName, bool link) { void PyOutStream::linkBlend(const char* target, const char* objName, bool link) {
format(fmt( format(fmt("if '{}' not in bpy.data.scenes:\n"
"if '{}' not in bpy.data.scenes:\n"
" with bpy.data.libraries.load('''{}''', link={}, relative=True) as (data_from, data_to):\n" " with bpy.data.libraries.load('''{}''', link={}, relative=True) as (data_from, data_to):\n"
" data_to.scenes = data_from.scenes\n" " data_to.scenes = data_from.scenes\n"
" obj_scene = None\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) { void PyOutStream::linkBackground(const char* target, const char* sceneName) {
if (!sceneName) { if (!sceneName) {
format(fmt( format(fmt("with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
"with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
" data_to.scenes = data_from.scenes\n" " data_to.scenes = data_from.scenes\n"
"obj_scene = None\n" "obj_scene = None\n"
"for scene in data_to.scenes:\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"), "bpy.context.scene.background_set = obj_scene\n"),
target, target); target, target);
} else { } else {
format(fmt( format(fmt("if '{}' not in bpy.data.scenes:\n"
"if '{}' not in bpy.data.scenes:\n"
" with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n" " with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
" data_to.scenes = data_from.scenes\n" " data_to.scenes = data_from.scenes\n"
" obj_scene = None\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) { void PyOutStream::AABBToBMesh(const atVec3f& min, const atVec3f& max) {
athena::simd_floats minf(min.simd); athena::simd_floats minf(min.simd);
athena::simd_floats maxf(max.simd); athena::simd_floats maxf(max.simd);
format(fmt( format(fmt("bm = bmesh.new()\n"
"bm = bmesh.new()\n"
"bm.verts.new(({},{},{}))\n" "bm.verts.new(({},{},{}))\n"
"bm.verts.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); Index matSetCount(conn);
materialSets.reserve(matSetCount.val); materialSets.reserve(matSetCount.val);
for (uint32_t i = 0; i < matSetCount.val; ++i) { for (uint32_t i = 0; i < matSetCount.val; ++i) {
materialSets.emplace_back(); std::vector<Material>& materials = materialSets.emplace_back();
std::vector<Material>& materials = materialSets.back();
Index matCount(conn); Index matCount(conn);
materials.reserve(matCount.val); materials.reserve(matCount.val);
for (uint32_t j = 0; j < matCount.val; ++j) 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 { bool Mesh::Surface::Vert::operator==(const Vert& other) const {
if (iPos != other.iPos) return std::tie(iPos, iNorm, iColor, iUv, iSkin) ==
return false; std::tie(other.iPos, other.iNorm, other.iColor, other.iUv, other.iSkin);
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;
} }
static bool VertInBank(const std::vector<uint32_t>& bank, uint32_t sIdx) { static bool VertInBank(const std::vector<uint32_t>& bank, uint32_t sIdx) {
for (uint32_t idx : bank) return std::any_of(bank.cbegin(), bank.cend(), [sIdx](auto index) { return index == sIdx; });
if (sIdx == idx)
return true;
return false;
} }
void Mesh::SkinBanks::Bank::addSkins(const Mesh& parent, const std::vector<uint32_t>& skinIdxs) { 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); conn._readBuf(&borderCount, 4);
borders.reserve(borderCount); borders.reserve(borderCount);
for (uint32_t i = 0; i < borderCount; ++i) { for (uint32_t i = 0; i < borderCount; ++i) {
borders.emplace_back(); std::pair<Index, Index>& idx = borders.emplace_back();
std::pair<Index, Index>& idx = borders.back();
conn._readBuf(&idx, 8); conn._readBuf(&idx, 8);
} }
} }
@ -1344,14 +1361,13 @@ Actor::Subtype::Subtype(Connection& conn) {
name.assign(bufSz, ' '); name.assign(bufSz, ' ');
conn._readBuf(&name[0], bufSz); conn._readBuf(&name[0], bufSz);
std::string meshPath;
conn._readBuf(&bufSz, 4); conn._readBuf(&bufSz, 4);
if (bufSz) { if (bufSz != 0) {
meshPath.assign(bufSz, ' '); std::string meshPath(bufSz, ' ');
conn._readBuf(&meshPath[0], bufSz); conn._readBuf(meshPath.data(), meshPath.size());
SystemStringConv meshPathAbs(meshPath); const SystemStringConv meshPathAbs(meshPath);
SystemString meshPathRel = const SystemString meshPathRel =
conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str()); conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str());
mesh.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), meshPathRel); mesh.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), meshPathRel);
} }
@ -1367,14 +1383,13 @@ Actor::Subtype::Subtype(Connection& conn) {
overlayName.assign(bufSz, ' '); overlayName.assign(bufSz, ' ');
conn._readBuf(&overlayName[0], bufSz); conn._readBuf(&overlayName[0], bufSz);
std::string meshPath;
conn._readBuf(&bufSz, 4); conn._readBuf(&bufSz, 4);
if (bufSz) { if (bufSz != 0) {
meshPath.assign(bufSz, ' '); std::string meshPath(bufSz, ' ');
conn._readBuf(&meshPath[0], bufSz); conn._readBuf(meshPath.data(), meshPath.size());
SystemStringConv meshPathAbs(meshPath); const SystemStringConv meshPathAbs(meshPath);
SystemString meshPathRel = const SystemString meshPathRel =
conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str()); conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str());
overlayMeshes.emplace_back(std::move(overlayName), overlayMeshes.emplace_back(std::move(overlayName),
ProjectPath(conn.getBlendPath().getProject().getProjectWorkingPath(), meshPathRel)); ProjectPath(conn.getBlendPath().getProject().getProjectWorkingPath(), meshPathRel));
@ -1431,12 +1446,11 @@ Action::Action(Connection& conn) {
conn._readBuf(&aabbCount, 4); conn._readBuf(&aabbCount, 4);
subtypeAABBs.reserve(aabbCount); subtypeAABBs.reserve(aabbCount);
for (uint32_t i = 0; i < aabbCount; ++i) { for (uint32_t i = 0; i < aabbCount; ++i) {
subtypeAABBs.emplace_back(); subtypeAABBs.emplace_back(conn, conn);
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, // 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().first.val.simd[0]), float(subtypeAABBs.back().first.val.simd[1]),
// float(subtypeAABBs.back().second.val.simd[0]), float(subtypeAABBs.back().second.val.simd[1]), float(subtypeAABBs.back().second.val.simd[2])); // 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) { 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)]; return STRS[int(topology)];
} }
@ -1787,12 +1801,11 @@ std::vector<std::string> DataStream::getArmatureNames() {
m_parent->_readBuf(&armCount, 4); m_parent->_readBuf(&armCount, 4);
ret.reserve(armCount); ret.reserve(armCount);
for (uint32_t i = 0; i < armCount; ++i) { for (uint32_t i = 0; i < armCount; ++i) {
ret.emplace_back(); std::string& name = ret.emplace_back();
std::string& name = ret.back();
uint32_t bufSz; uint32_t bufSz;
m_parent->_readBuf(&bufSz, 4); m_parent->_readBuf(&bufSz, 4);
name.assign(bufSz, ' '); name.assign(bufSz, ' ');
m_parent->_readBuf(&name[0], bufSz); m_parent->_readBuf(name.data(), name.size());
} }
return ret; return ret;
@ -1816,12 +1829,11 @@ std::vector<std::string> DataStream::getSubtypeNames() {
m_parent->_readBuf(&subCount, 4); m_parent->_readBuf(&subCount, 4);
ret.reserve(subCount); ret.reserve(subCount);
for (uint32_t i = 0; i < subCount; ++i) { for (uint32_t i = 0; i < subCount; ++i) {
ret.emplace_back(); std::string& name = ret.emplace_back();
std::string& name = ret.back();
uint32_t bufSz; uint32_t bufSz;
m_parent->_readBuf(&bufSz, 4); m_parent->_readBuf(&bufSz, 4);
name.assign(bufSz, ' '); name.assign(bufSz, ' ');
m_parent->_readBuf(&name[0], bufSz); m_parent->_readBuf(name.data(), name.size());
} }
return ret; return ret;
@ -1845,12 +1857,11 @@ std::vector<std::string> DataStream::getActionNames() {
m_parent->_readBuf(&actCount, 4); m_parent->_readBuf(&actCount, 4);
ret.reserve(actCount); ret.reserve(actCount);
for (uint32_t i = 0; i < actCount; ++i) { for (uint32_t i = 0; i < actCount; ++i) {
ret.emplace_back(); std::string& name = ret.emplace_back();
std::string& name = ret.back();
uint32_t bufSz; uint32_t bufSz;
m_parent->_readBuf(&bufSz, 4); m_parent->_readBuf(&bufSz, 4);
name.assign(bufSz, ' '); name.assign(bufSz, ' ');
m_parent->_readBuf(&name[0], bufSz); m_parent->_readBuf(name.data(), name.size());
} }
return ret; return ret;
@ -1874,12 +1885,11 @@ std::vector<std::string> DataStream::getSubtypeOverlayNames(std::string_view nam
m_parent->_readBuf(&subCount, 4); m_parent->_readBuf(&subCount, 4);
ret.reserve(subCount); ret.reserve(subCount);
for (uint32_t i = 0; i < subCount; ++i) { for (uint32_t i = 0; i < subCount; ++i) {
ret.emplace_back(); std::string& subtypeName = ret.emplace_back();
std::string& name = ret.back();
uint32_t bufSz; uint32_t bufSz;
m_parent->_readBuf(&bufSz, 4); m_parent->_readBuf(&bufSz, 4);
name.assign(bufSz, ' '); subtypeName.assign(bufSz, ' ');
m_parent->_readBuf(&name[0], bufSz); m_parent->_readBuf(subtypeName.data(), subtypeName.size());
} }
return ret; return ret;
@ -1903,12 +1913,11 @@ std::vector<std::string> DataStream::getAttachmentNames() {
m_parent->_readBuf(&attCount, 4); m_parent->_readBuf(&attCount, 4);
ret.reserve(attCount); ret.reserve(attCount);
for (uint32_t i = 0; i < attCount; ++i) { for (uint32_t i = 0; i < attCount; ++i) {
ret.emplace_back(); std::string& name = ret.emplace_back();
std::string& name = ret.back();
uint32_t bufSz; uint32_t bufSz;
m_parent->_readBuf(&bufSz, 4); m_parent->_readBuf(&bufSz, 4);
name.assign(bufSz, ' '); name.assign(bufSz, ' ');
m_parent->_readBuf(&name[0], bufSz); m_parent->_readBuf(name.data(), name.size());
} }
return ret; return ret;
@ -1935,23 +1944,22 @@ std::unordered_map<std::string, Matrix3f> DataStream::getBoneMatrices(std::strin
m_parent->_readBuf(&boneCount, 4); m_parent->_readBuf(&boneCount, 4);
ret.reserve(boneCount); ret.reserve(boneCount);
for (uint32_t i = 0; i < boneCount; ++i) { for (uint32_t i = 0; i < boneCount; ++i) {
std::string name;
uint32_t bufSz; uint32_t bufSz;
m_parent->_readBuf(&bufSz, 4); m_parent->_readBuf(&bufSz, 4);
name.assign(bufSz, ' '); std::string mat_name(bufSz, ' ');
m_parent->_readBuf(&name[0], bufSz); m_parent->_readBuf(mat_name.data(), bufSz);
Matrix3f matOut; Matrix3f matOut;
for (int i = 0; i < 3; ++i) { for (int mat_i = 0; mat_i < 3; ++mat_i) {
for (int j = 0; j < 3; ++j) { for (int mat_j = 0; mat_j < 3; ++mat_j) {
float val; float val;
m_parent->_readBuf(&val, 4); 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; return ret;

View File

@ -1,6 +1,9 @@
#include "hecl/Blender/Connection.hpp" #include "hecl/Blender/Connection.hpp"
#include <cmath>
#include <cfloat> #include <cfloat>
#include <cmath>
#include <athena/MemoryWriter.hpp>
#undef min #undef min
#undef max #undef max

View File

@ -1,5 +1,6 @@
#include "MeshOptimizer.hpp" #include "MeshOptimizer.hpp"
#include <numeric> #include <numeric>
#include <cfloat>
#include <cmath> #include <cmath>
namespace hecl::blender { namespace hecl::blender {

View File

@ -191,23 +191,25 @@ int CVar::toInteger(bool* isValid) const {
return strtol(m_value.c_str(), nullptr, 0); 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 (m_type != EType::Literal && (com_developer && com_developer->toBoolean())) {
if (isValid != nullptr) if (isValid != nullptr)
*isValid = false; *isValid = false;
} else if (isValid != nullptr) } else if (isValid != nullptr) {
*isValid = true; *isValid = true;
}
// Even if it's not a literal, it's still safe to return // Even if it's not a literal, it's still safe to return
return m_value; 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 (m_type != EType::Literal && (com_developer && com_developer->toBoolean())) {
if (isValid != nullptr) if (isValid != nullptr)
*isValid = false; *isValid = false;
} else if (isValid != nullptr) } else if (isValid != nullptr) {
*isValid = true; *isValid = true;
}
// Even if it's not a literal, it's still safe to return // Even if it's not a literal, it's still safe to return
return hecl::UTF8ToWide(m_value); return hecl::UTF8ToWide(m_value);

View File

@ -4,6 +4,7 @@
#include <athena/Utility.hpp> #include <athena/Utility.hpp>
#include <hecl/Runtime.hpp> #include <hecl/Runtime.hpp>
#include <hecl/hecl.hpp> #include <hecl/hecl.hpp>
#include <algorithm>
#include <memory> #include <memory>
#include <regex> #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_configfile = newCVar("config", "File to store configuration", std::string("config"), CVar::EFlags::System);
com_developer = newCVar("developer", "Enables developer mode", false, com_developer = newCVar("developer", "Enables developer mode", false,
(CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable)); (CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable));
com_enableCheats = com_enableCheats = newCVar(
newCVar("cheats", "Enable cheats", false, "cheats", "Enable cheats", false,
(CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::Hidden | CVar::EFlags::InternalArchivable)); (CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::Hidden | CVar::EFlags::InternalArchivable));
com_cubemaps = com_cubemaps = newCVar("cubemaps", "Enable cubemaps", false,
newCVar("cubemaps", "Enable cubemaps", false,
(CVar::EFlags::Game | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable)); (CVar::EFlags::Game | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable));
} }
@ -37,11 +37,13 @@ CVarManager::~CVarManager() {}
CVar* CVarManager::registerCVar(std::unique_ptr<CVar>&& cvar) { CVar* CVarManager::registerCVar(std::unique_ptr<CVar>&& cvar) {
std::string tmp(cvar->name()); std::string tmp(cvar->name());
athena::utility::tolower(tmp); athena::utility::tolower(tmp);
if (m_cvars.find(tmp) != m_cvars.end())
if (m_cvars.find(tmp) != m_cvars.end()) {
return nullptr; return nullptr;
}
CVar* ret = cvar.get(); CVar* ret = cvar.get();
m_cvars[tmp] = std::move(cvar); m_cvars.insert_or_assign(std::move(tmp), std::move(cvar));
return ret; return ret;
} }
@ -80,8 +82,8 @@ void CVarManager::deserialize(CVar* cvar) {
/* First let's check for a deferred value */ /* First let's check for a deferred value */
std::string lowName = cvar->name().data(); std::string lowName = cvar->name().data();
athena::utility::tolower(lowName); athena::utility::tolower(lowName);
if (m_deferedCVars.find(lowName) != m_deferedCVars.end()) { if (const auto iter = m_deferedCVars.find(lowName); iter != m_deferedCVars.end()) {
std::string val = m_deferedCVars[lowName]; std::string val = std::move(iter->second);
m_deferedCVars.erase(lowName); m_deferedCVars.erase(lowName);
if (cvar->fromLiteralToType(val)) if (cvar->fromLiteralToType(val))
return; return;
@ -162,10 +164,13 @@ void CVarManager::serialize() {
if (m_useBinary) { if (m_useBinary) {
CVarContainer container; CVarContainer container;
for (const auto& pair : m_cvars) for (const auto& pair : m_cvars) {
if (pair.second->isArchive() || const auto& cvar = pair.second;
(pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue()))
container.cvars.push_back(*pair.second); if (cvar->isArchive() || (cvar->isInternalArchivable() && cvar->wasDeserialized() && !cvar->hasDefaultValue())) {
container.cvars.push_back(*cvar);
}
}
container.cvarCount = atUint32(container.cvars.size()); container.cvarCount = atUint32(container.cvars.size());
filename += _SYS_STR(".bin"); filename += _SYS_STR(".bin");
@ -180,10 +185,13 @@ void CVarManager::serialize() {
r.close(); r.close();
docWriter.setStyle(athena::io::YAMLNodeStyle::Block); docWriter.setStyle(athena::io::YAMLNodeStyle::Block);
for (const auto& pair : m_cvars) for (const auto& pair : m_cvars) {
if (pair.second->isArchive() || const auto& cvar = pair.second;
(pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue()))
docWriter.writeString(pair.second->name().data(), pair.second->toLiteral()); if (cvar->isArchive() || (cvar->isInternalArchivable() && cvar->wasDeserialized() && !cvar->hasDefaultValue())) {
docWriter.writeString(cvar->name().data(), cvar->toLiteral());
}
}
athena::io::FileWriter w(filename); athena::io::FileWriter w(filename);
if (w.isOpen()) if (w.isOpen())
@ -208,12 +216,13 @@ void CVarManager::setCVar(Console* con, const std::vector<std::string>& args) {
std::string cvName = args[0]; std::string cvName = args[0];
athena::utility::tolower(cvName); 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]); con->report(Console::Level::Error, fmt("CVar '{}' does not exist"), args[0]);
return; return;
} }
const auto& cv = m_cvars[cvName]; const auto& cv = iter->second;
std::string oldVal = cv->value(); std::string oldVal = cv->value();
std::string value = args[1]; std::string value = args[1];
auto it = args.begin() + 2; 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]; std::string cvName = args[0];
athena::utility::tolower(cvName); 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]); con->report(Console::Level::Error, fmt("CVar '{}' does not exist"), args[0]);
return; return;
} }
const auto& cv = m_cvars[cvName]; const auto& cv = iter->second;
con->report(Console::Level::Info, fmt("'{}' = '{}'"), cv->name(), cv->value()); 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 { bool CVarManager::restartRequired() const {
for (const auto& cv : m_cvars) { return std::any_of(m_cvars.cbegin(), m_cvars.cend(), [](const auto& entry) {
if (cv.second->isModified() && cv.second->modificationRequiresRestart()) return entry.second->isModified() && entry.second->modificationRequiresRestart();
return true; });
}
return false;
} }
void CVarManager::parseCommandLine(const std::vector<SystemString>& args) { void CVarManager::parseCommandLine(const std::vector<SystemString>& args) {
bool oldDeveloper = suppressDeveloper(); bool oldDeveloper = suppressDeveloper();
std::string developerName = com_developer->name().data(); std::string developerName(com_developer->name());
athena::utility::tolower(developerName); athena::utility::tolower(developerName);
for (const SystemString& arg : args) { for (const SystemString& arg : args) {
if (arg[0] == _SYS_STR('+')) { if (arg[0] != _SYS_STR('+')) {
std::string tmp = SystemUTF8Conv(arg).c_str(); continue;
}
const std::string tmp(SystemUTF8Conv(arg).str());
std::smatch matches; 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 cvarName = matches[1].str();
std::string cvarValue = matches[2].str(); std::string cvarValue = matches[2].str();
if (CVar* cv = findCVar(cvarName)) { if (CVar* cv = findCVar(cvarName)) {
@ -295,9 +307,7 @@ void CVarManager::parseCommandLine(const std::vector<SystemString>& args) {
} else { } else {
/* Unable to find an existing CVar, let's defer for the time being 8 */ /* Unable to find an existing CVar, let's defer for the time being 8 */
athena::utility::tolower(cvarName); athena::utility::tolower(cvarName);
m_deferedCVars[cvarName] = cvarValue; m_deferedCVars.insert_or_assign(std::move(cvarName), std::move(cvarValue));
}
}
} }
} }

View File

@ -71,7 +71,7 @@ void ClientProcess::BufferTransaction::run(blender::Token& btok) {
void ClientProcess::CookTransaction::run(blender::Token& btok) { void ClientProcess::CookTransaction::run(blender::Token& btok) {
m_dataSpec->setThreadProject(); m_dataSpec->setThreadProject();
m_returnResult = m_parent.syncCook(m_path, m_dataSpec, btok, m_force, m_fast); 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_completedCooks;
m_parent.m_progPrinter->setMainFactor(m_parent.m_completedCooks / float(m_parent.m_addedCooks)); m_parent.m_progPrinter->setMainFactor(m_parent.m_completedCooks / float(m_parent.m_addedCooks));
m_complete = true; m_complete = true;
@ -92,7 +92,7 @@ void ClientProcess::Worker::proc() {
std::string thrName = fmt::format(fmt("HECL Worker {}"), m_idx); std::string thrName = fmt::format(fmt("HECL Worker {}"), m_idx);
logvisor::RegisterThreadName(thrName.c_str()); 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) { while (m_proc.m_running) {
if (!m_didInit) { if (!m_didInit) {
m_proc.m_initCv.notify_one(); m_proc.m_initCv.notify_one();
@ -125,7 +125,7 @@ ClientProcess::ClientProcess(const MultiProgressPrinter* progPrinter) : m_progPr
#endif #endif
m_workers.reserve(cpuCount); m_workers.reserve(cpuCount);
for (int i = 0; i < cpuCount; ++i) { 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_workers.emplace_back(*this, m_workers.size());
m_initCv.wait(lk); 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, std::shared_ptr<const ClientProcess::BufferTransaction> ClientProcess::addBufferTransaction(const ProjectPath& path,
void* target, size_t maxLen, void* target, size_t maxLen,
size_t offset) { 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); auto ret = std::make_shared<BufferTransaction>(*this, path, target, maxLen, offset);
m_pendingQueue.emplace_back(ret); m_pendingQueue.emplace_back(ret);
m_cv.notify_one(); 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, std::shared_ptr<const ClientProcess::CookTransaction> ClientProcess::addCookTransaction(const hecl::ProjectPath& path,
bool force, bool fast, bool force, bool fast,
Database::IDataSpec* spec) { 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); auto ret = std::make_shared<CookTransaction>(*this, path, force, fast, spec);
m_pendingQueue.emplace_back(ret); m_pendingQueue.emplace_back(ret);
m_cv.notify_one(); m_cv.notify_one();
@ -155,7 +155,7 @@ std::shared_ptr<const ClientProcess::CookTransaction> ClientProcess::addCookTran
std::shared_ptr<const ClientProcess::LambdaTransaction> std::shared_ptr<const ClientProcess::LambdaTransaction>
ClientProcess::addLambdaTransaction(std::function<void(blender::Token&)>&& func) { 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)); auto ret = std::make_shared<LambdaTransaction>(*this, std::move(func));
m_pendingQueue.emplace_back(ret); m_pendingQueue.emplace_back(ret);
m_cv.notify_one(); 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) { 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); queue.swap(m_completedQueue);
} }
void ClientProcess::waitUntilComplete() { void ClientProcess::waitUntilComplete() {
std::unique_lock<std::mutex> lk(m_mutex); std::unique_lock lk{m_mutex};
while (isBusy()) while (isBusy())
m_waitCv.wait(lk); m_waitCv.wait(lk);
} }
@ -217,7 +217,7 @@ void ClientProcess::waitUntilComplete() {
void ClientProcess::shutdown() { void ClientProcess::shutdown() {
if (!m_running) if (!m_running)
return; return;
std::unique_lock<std::mutex> lk(m_mutex); std::unique_lock lk{m_mutex};
m_pendingQueue.clear(); m_pendingQueue.clear();
m_running = false; m_running = false;
m_cv.notify_all(); m_cv.notify_all();

View File

@ -1,14 +1,17 @@
#include "hecl/Compilers.hpp" #include "hecl/Compilers.hpp"
#include "boo/graphicsdev/GLSLMacros.hpp" #include <boo/graphicsdev/GLSLMacros.hpp>
#include "logvisor/logvisor.hpp" #include <logvisor/logvisor.hpp>
#include <glslang/Public/ShaderLang.h> #include <glslang/Public/ShaderLang.h>
#include <StandAlone/ResourceLimits.h> #include <StandAlone/ResourceLimits.h>
#include <SPIRV/GlslangToSpv.h> #include <SPIRV/GlslangToSpv.h>
#include <SPIRV/disassemble.h> #include <SPIRV/disassemble.h>
#if _WIN32 #if _WIN32
#include <d3dcompiler.h> #include <d3dcompiler.h>
extern pD3DCompile D3DCompilePROC; extern pD3DCompile D3DCompilePROC;
#endif #endif
#if __APPLE__ #if __APPLE__
#include <unistd.h> #include <unistd.h>
#include <memory> #include <memory>
@ -17,23 +20,6 @@ extern pD3DCompile D3DCompilePROC;
namespace hecl { namespace hecl {
logvisor::Module Log("hecl::Compilers"); 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> template <typename P>
struct ShaderCompiler {}; struct ShaderCompiler {};
@ -99,7 +85,7 @@ struct ShaderCompiler<PlatformType::D3D11> {
ComPtr<ID3DBlob> blobOut; ComPtr<ID3DBlob> blobOut;
if (FAILED(D3DCompilePROC(text.data(), text.size(), "Boo HLSL Source", nullptr, nullptr, "main", if (FAILED(D3DCompilePROC(text.data(), text.size(), "Boo HLSL Source", nullptr, nullptr, "main",
D3DShaderTypes[int(S::Enum)], BOO_D3DCOMPILE_FLAG, 0, &blobOut, &errBlob))) { 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()); Log.report(logvisor::Fatal, fmt("error compiling shader: {}"), (char*)errBlob->GetBufferPointer());
return {}; return {};
} }
@ -124,7 +110,7 @@ struct ShaderCompiler<PlatformType::Metal> {
pid_t pid = fork(); pid_t pid = fork();
if (!pid) { 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; /* xcrun returns 72 if metal command not found;
* emulate that if xcrun not found */ * emulate that if xcrun not found */
exit(72); exit(72);
@ -180,8 +166,8 @@ struct ShaderCompiler<PlatformType::Metal> {
#ifndef NDEBUG #ifndef NDEBUG
"-gline-tables-only", "-MO", "-gline-tables-only", "-MO",
#endif #endif
"-", NULL); "-", nullptr);
fprintf(stderr, "execlp fail %s\n", strerror(errno)); fmt::print(stderr, fmt("execlp fail {}\n"), strerror(errno));
exit(1); exit(1);
} }
close(compilerIn[0]); close(compilerIn[0]);
@ -196,8 +182,8 @@ struct ShaderCompiler<PlatformType::Metal> {
close(compilerIn[1]); close(compilerIn[1]);
/* metallib doesn't like outputting to a pipe, so temp file will have to do */ /* 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); execlp("xcrun", "xcrun", "-sdk", "macosx", "metallib", "-", "-o", libFile.c_str(), nullptr);
fprintf(stderr, "execlp fail %s\n", strerror(errno)); fmt::print(stderr, fmt("execlp fail {}\n"), strerror(errno));
exit(1); exit(1);
} }
close(compilerOut[0]); close(compilerOut[0]);
@ -208,7 +194,7 @@ struct ShaderCompiler<PlatformType::Metal> {
while (inRem) { while (inRem) {
ssize_t writeRes = write(compilerIn[1], inPtr, inRem); ssize_t writeRes = write(compilerIn[1], inPtr, inRem);
if (writeRes < 0) { if (writeRes < 0) {
fprintf(stderr, "write fail %s\n", strerror(errno)); fmt::print(stderr, fmt("write fail {}\n"), strerror(errno));
break; break;
} }
inPtr += writeRes; inPtr += writeRes;
@ -221,7 +207,7 @@ struct ShaderCompiler<PlatformType::Metal> {
while (waitpid(compilerPid, &compilerStat, 0) < 0) { while (waitpid(compilerPid, &compilerStat, 0) < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
Log.report(logvisor::Fatal, fmt("waitpid fail %s"), strerror(errno)); Log.report(logvisor::Fatal, fmt("waitpid fail {}"), strerror(errno));
return {}; return {};
} }
@ -233,7 +219,7 @@ struct ShaderCompiler<PlatformType::Metal> {
while (waitpid(linkerPid, &linkerStat, 0) < 0) { while (waitpid(linkerPid, &linkerStat, 0) < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
Log.report(logvisor::Fatal, fmt("waitpid fail %s"), strerror(errno)); Log.report(logvisor::Fatal, fmt("waitpid fail {}"), strerror(errno));
return {}; return {};
} }

View File

@ -368,8 +368,8 @@ void Console::LogVisorAdapter::report(const char* modName, logvisor::Level sever
auto tmp = fmt::internal::vformat(format, args); auto tmp = fmt::internal::vformat(format, args);
std::vector<std::string> lines = athena::utility::split(tmp, '\n'); std::vector<std::string> lines = athena::utility::split(tmp, '\n');
for (const std::string& line : lines) { for (const std::string& line : lines) {
auto v = fmt::format(fmt("[%s] %s"), modName, line.c_str()); auto v = fmt::format(fmt("[{}] {}"), modName, line);
m_con->m_log.emplace_back(v, Console::Level(severity)); 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); auto tmp = fmt::internal::vformat(format, args);
std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n'); std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n');
for (const std::string& line : lines) { for (const std::string& line : lines) {
auto v = fmt::format(fmt("[%s] %s"), modName, line.c_str()); auto v = fmt::format(fmt("[{}] {}"), modName, line);
m_con->m_log.emplace_back(v, Console::Level(severity)); 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, void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file,
unsigned linenum, fmt::string_view format, fmt::format_args args) { unsigned linenum, fmt::string_view format, fmt::format_args args) {
auto tmp = fmt::internal::vformat(format, args); auto tmp = fmt::internal::vformat(format, args);
auto v = fmt::format(fmt("[%s] %s %s:%i"), modName, tmp, file, linenum); auto v = fmt::format(fmt("[{}] {} {}:{}"), modName, tmp, file, linenum);
m_con->m_log.emplace_back(v, Console::Level(severity)); 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, 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); auto tmp = fmt::internal::vformat(format, args);
std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n'); std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n');
for (const std::string& line : lines) { for (const std::string& line : lines) {
auto v = fmt::format(fmt("[%s] %s %s:%i"), modName, line.c_str(), file, linenum); auto v = fmt::format(fmt("[{}] {} {}:{}"), modName, line, file, linenum);
m_con->m_log.emplace_back(v, Console::Level(severity)); m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
} }
} }

View File

@ -242,9 +242,12 @@ void MultiProgressPrinter::DoPrint() {
void MultiProgressPrinter::LogProc() { void MultiProgressPrinter::LogProc() {
while (m_running) { while (m_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (!m_dirty && !m_mainIndeterminate)
if (!m_dirty && !m_mainIndeterminate) {
continue; continue;
std::lock_guard<std::mutex> lk(m_logLock); }
std::lock_guard lk{m_logLock};
DoPrint(); DoPrint();
} }
} }
@ -280,22 +283,30 @@ MultiProgressPrinter::~MultiProgressPrinter() {
void MultiProgressPrinter::print(const hecl::SystemChar* message, const hecl::SystemChar* submessage, float factor, void MultiProgressPrinter::print(const hecl::SystemChar* message, const hecl::SystemChar* submessage, float factor,
int threadIdx) const { int threadIdx) const {
if (!m_running) if (!m_running) {
return; return;
std::lock_guard<std::mutex> lk(m_logLock); }
if (threadIdx < 0)
std::lock_guard lk{m_logLock};
if (threadIdx < 0) {
threadIdx = 0; threadIdx = 0;
if (threadIdx >= m_threadStats.size()) }
if (threadIdx >= m_threadStats.size()) {
m_threadStats.resize(threadIdx + 1); m_threadStats.resize(threadIdx + 1);
}
ThreadStat& stat = m_threadStats[threadIdx]; ThreadStat& stat = m_threadStats[threadIdx];
if (message) if (message) {
stat.m_message = message; stat.m_message = message;
else } else {
stat.m_message.clear(); stat.m_message.clear();
if (submessage) }
if (submessage) {
stat.m_submessage = submessage; stat.m_submessage = submessage;
else } else {
stat.m_submessage.clear(); stat.m_submessage.clear();
}
stat.m_factor = factor; stat.m_factor = factor;
stat.m_active = true; stat.m_active = true;
m_latestThread = threadIdx; m_latestThread = threadIdx;
@ -303,18 +314,23 @@ void MultiProgressPrinter::print(const hecl::SystemChar* message, const hecl::Sy
} }
void MultiProgressPrinter::setMainFactor(float factor) const { void MultiProgressPrinter::setMainFactor(float factor) const {
if (!m_running) if (!m_running) {
return; 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_dirty = true;
}
m_mainFactor = factor; m_mainFactor = factor;
} }
void MultiProgressPrinter::setMainIndeterminate(bool indeterminate) const { void MultiProgressPrinter::setMainIndeterminate(bool indeterminate) const {
if (!m_running) if (!m_running) {
return; return;
std::lock_guard<std::mutex> lk(m_logLock); }
std::lock_guard lk{m_logLock};
if (m_mainIndeterminate != indeterminate) { if (m_mainIndeterminate != indeterminate) {
m_mainIndeterminate = indeterminate; m_mainIndeterminate = indeterminate;
m_dirty = true; m_dirty = true;
@ -322,9 +338,11 @@ void MultiProgressPrinter::setMainIndeterminate(bool indeterminate) const {
} }
void MultiProgressPrinter::startNewLine() const { void MultiProgressPrinter::startNewLine() const {
if (!m_running) if (!m_running) {
return; return;
std::lock_guard<std::mutex> lk(m_logLock); }
std::lock_guard lk{m_logLock};
const_cast<MultiProgressPrinter&>(*this).DoPrint(); const_cast<MultiProgressPrinter&>(*this).DoPrint();
m_threadStats.clear(); m_threadStats.clear();
m_latestThread = -1; m_latestThread = -1;
@ -335,7 +353,7 @@ void MultiProgressPrinter::startNewLine() const {
} }
void MultiProgressPrinter::flush() const { void MultiProgressPrinter::flush() const {
std::lock_guard<std::mutex> lk(m_logLock); std::lock_guard lk{m_logLock};
const_cast<MultiProgressPrinter&>(*this).DoPrint(); const_cast<MultiProgressPrinter&>(*this).DoPrint();
} }

View File

@ -24,9 +24,9 @@ public:
m_zstrm.avail_in = 0; m_zstrm.avail_in = 0;
inflateInit(&m_zstrm); inflateInit(&m_zstrm);
} }
~ShaderCacheZipStream() { inflateEnd(&m_zstrm); } ~ShaderCacheZipStream() override { inflateEnd(&m_zstrm); }
operator bool() const { return m_compBuf.operator bool(); } explicit operator bool() const { return m_compBuf.operator bool(); }
atUint64 readUBytesToBuf(void* buf, atUint64 len) { atUint64 readUBytesToBuf(void* buf, atUint64 len) override {
m_zstrm.next_out = (Bytef*)buf; m_zstrm.next_out = (Bytef*)buf;
m_zstrm.avail_out = len; m_zstrm.avail_out = len;
m_zstrm.total_out = 0; m_zstrm.total_out = 0;
@ -42,9 +42,9 @@ public:
} }
return m_zstrm.total_out; return m_zstrm.total_out;
} }
void seek(atInt64, athena::SeekOrigin) {} void seek(atInt64, athena::SeekOrigin) override {}
atUint64 position() const { return 0; } atUint64 position() const override { return 0; }
atUint64 length() const { return 0; } atUint64 length() const override { return 0; }
}; };
template <typename P, typename S> template <typename P, typename S>

View File

@ -17,7 +17,7 @@
namespace hecl::Database { namespace hecl::Database {
logvisor::Module LogModule("hecl::Database"); logvisor::Module LogModule("hecl::Database");
static const hecl::FourCC HECLfcc("HECL"); constexpr hecl::FourCC HECLfcc("HECL");
/********************************************** /**********************************************
* Project::ConfigFile * Project::ConfigFile
@ -43,17 +43,19 @@ Project::ConfigFile::ConfigFile(const Project& project, SystemStringView name, S
} }
std::vector<std::string>& Project::ConfigFile::lockAndRead() { std::vector<std::string>& Project::ConfigFile::lockAndRead() {
if (m_lockedFile) if (m_lockedFile != nullptr) {
return m_lines; return m_lines;
}
m_lockedFile = hecl::Fopen(m_filepath.c_str(), _SYS_STR("a+"), FileLockType::Write); m_lockedFile = hecl::FopenUnique(m_filepath.c_str(), _SYS_STR("a+"), FileLockType::Write);
hecl::FSeek(m_lockedFile, 0, SEEK_SET); hecl::FSeek(m_lockedFile.get(), 0, SEEK_SET);
std::string mainString; std::string mainString;
char readBuf[1024]; char readBuf[1024];
size_t readSz; 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); mainString += std::string(readBuf, readSz);
}
std::string::const_iterator begin = mainString.begin(); std::string::const_iterator begin = mainString.begin();
std::string::const_iterator end = 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() { void Project::ConfigFile::unlockAndDiscard() {
if (!m_lockedFile) { if (m_lockedFile == nullptr) {
LogModule.reportSource(logvisor::Fatal, __FILE__, __LINE__, fmt("Project::ConfigFile::lockAndRead not yet called")); LogModule.reportSource(logvisor::Fatal, __FILE__, __LINE__, fmt("Project::ConfigFile::lockAndRead not yet called"));
return; return;
} }
m_lines.clear(); m_lines.clear();
fclose(m_lockedFile); m_lockedFile.reset();
m_lockedFile = NULL;
} }
bool Project::ConfigFile::unlockAndCommit() { bool Project::ConfigFile::unlockAndCommit() {
@ -126,23 +127,22 @@ bool Project::ConfigFile::unlockAndCommit() {
return false; return false;
} }
SystemString newPath = m_filepath + _SYS_STR(".part"); const SystemString newPath = m_filepath + _SYS_STR(".part");
FILE* newFile = hecl::Fopen(newPath.c_str(), _SYS_STR("w"), FileLockType::Write); auto newFile = hecl::FopenUnique(newPath.c_str(), _SYS_STR("w"), FileLockType::Write);
bool fail = false; bool fail = false;
for (const std::string& line : m_lines) { 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; fail = true;
break; break;
} }
if (fwrite("\n", 1, 1, newFile) != 1) { if (std::fputc('\n', newFile.get()) == EOF) {
fail = true; fail = true;
break; break;
} }
} }
m_lines.clear(); m_lines.clear();
fclose(newFile); newFile.reset();
fclose(m_lockedFile); m_lockedFile.reset();
m_lockedFile = NULL;
if (fail) { if (fail) {
#if HECL_UCS2 #if HECL_UCS2
_wunlink(newPath.c_str()); _wunlink(newPath.c_str());
@ -191,20 +191,21 @@ Project::Project(const ProjectRootPath& rootPath)
m_cookedRoot.makeDir(); m_cookedRoot.makeDir();
/* Ensure beacon is valid or created */ /* Ensure beacon is valid or created */
ProjectPath beaconPath(m_dotPath, _SYS_STR("beacon")); const ProjectPath beaconPath(m_dotPath, _SYS_STR("beacon"));
FILE* bf = hecl::Fopen(beaconPath.getAbsolutePath().data(), _SYS_STR("a+b")); auto bf = hecl::FopenUnique(beaconPath.getAbsolutePath().data(), _SYS_STR("a+b"));
struct BeaconStruct { struct BeaconStruct {
hecl::FourCC magic; hecl::FourCC magic;
uint32_t version; uint32_t version;
} beacon; } beacon;
#define DATA_VERSION 1 constexpr uint32_t DATA_VERSION = 1;
if (fread(&beacon, 1, sizeof(beacon), bf) != sizeof(beacon)) { if (std::fread(&beacon, 1, sizeof(beacon), bf.get()) != sizeof(beacon)) {
fseek(bf, 0, SEEK_SET); std::fseek(bf.get(), 0, SEEK_SET);
beacon.magic = HECLfcc; beacon.magic = HECLfcc;
beacon.version = SBig(DATA_VERSION); 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) { if (beacon.magic != HECLfcc || SBig(beacon.version) != DATA_VERSION) {
LogModule.report(logvisor::Fatal, fmt("incompatible project version")); LogModule.report(logvisor::Fatal, fmt("incompatible project version"));
return; return;
@ -413,9 +414,11 @@ bool Project::cookPath(const ProjectPath& path, const hecl::MultiProgressPrinter
} }
} else if (m_cookSpecs.empty()) { } else if (m_cookSpecs.empty()) {
m_cookSpecs.reserve(m_compiledSpecs.size()); m_cookSpecs.reserve(m_compiledSpecs.size());
for (const ProjectDataSpec& spec : m_compiledSpecs) for (const ProjectDataSpec& projectSpec : m_compiledSpecs) {
if (spec.active && spec.spec.m_factory) if (projectSpec.active && projectSpec.spec.m_factory) {
m_cookSpecs.push_back(spec.spec.m_factory(*this, DataSpecTool::Cook)); m_cookSpecs.push_back(projectSpec.spec.m_factory(*this, DataSpecTool::Cook));
}
}
} }
/* Iterate complete directory/file/glob list */ /* Iterate complete directory/file/glob list */
@ -443,17 +446,18 @@ bool Project::packagePath(const ProjectPath& path, const hecl::MultiProgressPrin
/* Construct DataSpec instance for packaging */ /* Construct DataSpec instance for packaging */
const DataSpecEntry* specEntry = nullptr; const DataSpecEntry* specEntry = nullptr;
if (spec) { if (spec) {
if (spec->m_factory) if (spec->m_factory) {
specEntry = spec; specEntry = spec;
}
} else { } else {
bool foundPC = false; bool foundPC = false;
for (const ProjectDataSpec& spec : m_compiledSpecs) { for (const ProjectDataSpec& projectSpec : m_compiledSpecs) {
if (spec.active && spec.spec.m_factory) { if (projectSpec.active && projectSpec.spec.m_factory) {
if (hecl::StringUtils::EndsWith(spec.spec.m_name, _SYS_STR("-PC"))) { if (hecl::StringUtils::EndsWith(projectSpec.spec.m_name, _SYS_STR("-PC"))) {
foundPC = true; foundPC = true;
specEntry = &spec.spec; specEntry = &projectSpec.spec;
} else if (!foundPC) { } else if (!foundPC) {
specEntry = &spec.spec; specEntry = &projectSpec.spec;
} }
} }
} }

View File

@ -256,17 +256,22 @@ ProjectRootPath SearchForProject(SystemStringView path) {
Sstat theStat; Sstat theStat;
if (!hecl::Stat(testIndexPath.c_str(), &theStat)) { if (!hecl::Stat(testIndexPath.c_str(), &theStat)) {
if (S_ISREG(theStat.st_mode)) { if (S_ISREG(theStat.st_mode)) {
FILE* fp = hecl::Fopen(testIndexPath.c_str(), _SYS_STR("rb")); const auto fp = hecl::FopenUnique(testIndexPath.c_str(), _SYS_STR("rb"));
if (!fp) if (fp == nullptr) {
continue; continue;
}
char magic[4]; char magic[4];
size_t readSize = fread(magic, 1, 4, fp); const size_t readSize = std::fread(magic, 1, sizeof(magic), fp.get());
fclose(fp); if (readSize != sizeof(magic)) {
if (readSize != 4)
continue; continue;
static const hecl::FourCC hecl("HECL"); }
if (hecl::FourCC(magic) != hecl)
static constexpr hecl::FourCC hecl("HECL");
if (hecl::FourCC(magic) != hecl) {
continue; continue;
}
return ProjectRootPath(testPath); return ProjectRootPath(testPath);
} }
} }
@ -280,41 +285,52 @@ ProjectRootPath SearchForProject(SystemStringView path) {
} }
ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut) { ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut) {
ProjectRootPath testRoot(path); const ProjectRootPath testRoot(path);
auto begin = testRoot.getAbsolutePath().begin(); auto begin = testRoot.getAbsolutePath().begin();
auto end = testRoot.getAbsolutePath().end(); auto end = testRoot.getAbsolutePath().end();
while (begin != end) { while (begin != end) {
SystemString testPath(begin, end); SystemString testPath(begin, end);
SystemString testIndexPath = testPath + _SYS_STR("/.hecl/beacon"); SystemString testIndexPath = testPath + _SYS_STR("/.hecl/beacon");
Sstat theStat; Sstat theStat;
if (!hecl::Stat(testIndexPath.c_str(), &theStat)) { if (!hecl::Stat(testIndexPath.c_str(), &theStat)) {
if (S_ISREG(theStat.st_mode)) { if (S_ISREG(theStat.st_mode)) {
FILE* fp = hecl::Fopen(testIndexPath.c_str(), _SYS_STR("rb")); const auto fp = hecl::FopenUnique(testIndexPath.c_str(), _SYS_STR("rb"));
if (!fp) if (fp == nullptr) {
continue; continue;
}
char magic[4]; char magic[4];
size_t readSize = fread(magic, 1, 4, fp); const size_t readSize = std::fread(magic, 1, sizeof(magic), fp.get());
fclose(fp); if (readSize != sizeof(magic)) {
if (readSize != 4)
continue; continue;
if (hecl::FourCC(magic) != FOURCC('HECL')) }
if (hecl::FourCC(magic) != FOURCC('HECL')) {
continue; 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; ++end;
if (end != origEnd && (*end == _SYS_STR('/') || *end == _SYS_STR('\\'))) }
if (end != origEnd && (*end == _SYS_STR('/') || *end == _SYS_STR('\\'))) {
++end; ++end;
}
subpathOut.assign(end, origEnd); subpathOut.assign(end, origEnd);
return newRootPath; 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; --end;
if (begin != end) }
if (begin != end) {
--end; --end;
} }
}
return ProjectRootPath(); return ProjectRootPath();
} }

View File

@ -57,44 +57,45 @@ hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name) {
#endif #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 */ /* Try main steam install directory first */
hecl::SystemString steamAppsMain = steamInstallDir + PATH_SEP + _SYS_STR("steamapps"); const hecl::SystemString steamAppsMain = steamInstallDir + PATH_SEP + _SYS_STR("steamapps");
hecl::SystemString mainAppPath = steamAppsMain + PATH_SEP + appPath; const hecl::SystemString mainAppPath = steamAppsMain + PATH_SEP + appPath;
if (!hecl::Stat(mainAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) if (!hecl::Stat(mainAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) {
return mainAppPath; return mainAppPath;
}
/* Iterate alternate steam install dirs */ /* Iterate alternate steam install dirs */
hecl::SystemString libraryFoldersVdfPath = steamAppsMain + PATH_SEP + _SYS_STR("libraryfolders.vdf"); const hecl::SystemString libraryFoldersVdfPath = steamAppsMain + PATH_SEP + _SYS_STR("libraryfolders.vdf");
FILE* fp = hecl::Fopen(libraryFoldersVdfPath.c_str(), _SYS_STR("r")); auto fp = hecl::FopenUnique(libraryFoldersVdfPath.c_str(), _SYS_STR("r"));
if (!fp) if (fp == nullptr) {
return {}; 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) { if (fileLen <= 0) {
fclose(fp);
return {}; return {};
} }
hecl::FSeek(fp, 0, SEEK_SET); hecl::FSeek(fp.get(), 0, SEEK_SET);
std::string fileBuf; std::string fileBuf(fileLen, '\0');
fileBuf.resize(fileLen); if (std::fread(fileBuf.data(), 1, fileLen, fp.get()) != fileLen) {
if (fread(&fileBuf[0], 1, fileLen, fp) != fileLen) {
fclose(fp);
return {}; return {};
} }
fclose(fp);
std::smatch dirMatch; std::smatch dirMatch;
auto begin = fileBuf.cbegin(); auto begin = fileBuf.cbegin();
auto end = fileBuf.cend(); const auto end = fileBuf.cend();
while (std::regex_search(begin, end, dirMatch, regSteamPath)) { while (std::regex_search(begin, end, dirMatch, regSteamPath)) {
std::string match = dirMatch[1].str(); const std::string match = dirMatch[1].str();
hecl::SystemStringConv otherInstallDir(match); const hecl::SystemStringConv otherInstallDir(match);
hecl::SystemString otherAppPath = const auto otherAppPath =
hecl::SystemString(otherInstallDir.sys_str()) + PATH_SEP + _SYS_STR("steamapps") + PATH_SEP + appPath; 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; return otherAppPath;
}
begin = dirMatch.suffix().first; begin = dirMatch.suffix().first;
} }

View File

@ -1,6 +1,14 @@
#include "hecl/hecl.hpp" #include "hecl/hecl.hpp"
#include <thread>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <memory>
#include <mutex> #include <mutex>
#include <string>
#include <string_view>
#include <thread>
#include <unordered_map> #include <unordered_map>
#ifdef WIN32 #ifdef WIN32
@ -20,11 +28,13 @@
#include <sys/wait.h> #include <sys/wait.h>
#endif #endif
#include <logvisor/logvisor.hpp>
namespace hecl { namespace hecl {
unsigned VerbosityLevel = 0; unsigned VerbosityLevel = 0;
bool GuiMode = false; bool GuiMode = false;
logvisor::Module LogModule("hecl"); logvisor::Module LogModule("hecl");
static const std::string Illegals{"<>?\""}; constexpr std::string_view Illegals{"<>?\""};
void SanitizePath(std::string& path) { void SanitizePath(std::string& path) {
if (path.empty()) if (path.empty())
@ -54,7 +64,7 @@ void SanitizePath(std::string& path) {
path.pop_back(); path.pop_back();
} }
static const std::wstring WIllegals{L"<>?\""}; constexpr std::wstring_view WIllegals{L"<>?\""};
void SanitizePath(std::wstring& path) { void SanitizePath(std::wstring& path) {
if (path.empty()) if (path.empty())
@ -90,8 +100,9 @@ SystemString GetcwdStr() {
// const int MaxChunks=10240; // 2550 KiBs of current path are more than enough // const int MaxChunks=10240; // 2550 KiBs of current path are more than enough
SystemChar stackBuffer[255]; // Stack buffer for the "normal" case 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); return SystemString(stackBuffer);
}
if (errno != ERANGE) { if (errno != ERANGE) {
// It's not ERANGE, so we don't know how to handle it // It's not ERANGE, so we don't know how to handle it
LogModule.report(logvisor::Fatal, fmt("Cannot determine the current path.")); LogModule.report(logvisor::Fatal, fmt("Cannot determine the current path."));
@ -101,9 +112,11 @@ SystemString GetcwdStr() {
for (int chunks = 2; chunks < 10240; chunks++) { for (int chunks = 2; chunks < 10240; chunks++) {
// With boost use scoped_ptr; in C++0x, use unique_ptr // 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 // 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]); const int bufSize = 255 * chunks;
if (Getcwd(cwd.get(), 255 * chunks) != nullptr) std::unique_ptr<SystemChar[]> cwd(new SystemChar[bufSize]);
if (Getcwd(cwd.get(), bufSize) != nullptr) {
return SystemString(cwd.get()); return SystemString(cwd.get());
}
if (errno != ERANGE) { if (errno != ERANGE) {
// It's not ERANGE, so we don't know how to handle it // It's not ERANGE, so we don't know how to handle it
LogModule.report(logvisor::Fatal, fmt("Cannot determine the current path.")); LogModule.report(logvisor::Fatal, fmt("Cannot determine the current path."));
@ -118,66 +131,67 @@ static std::mutex PathsMutex;
static std::unordered_map<std::thread::id, ProjectPath> PathsInProgress; static std::unordered_map<std::thread::id, ProjectPath> PathsInProgress;
bool ResourceLock::InProgress(const ProjectPath& path) { bool ResourceLock::InProgress(const ProjectPath& path) {
std::unique_lock<std::mutex> lk(PathsMutex); std::unique_lock lk{PathsMutex};
for (const auto& p : PathsInProgress) return std::any_of(PathsInProgress.cbegin(), PathsInProgress.cend(),
if (p.second == path) [&path](const auto& entry) { return entry.second == path; });
return true;
return false;
} }
bool ResourceLock::SetThreadRes(const ProjectPath& path) { bool ResourceLock::SetThreadRes(const ProjectPath& path) {
std::unique_lock<std::mutex> lk(PathsMutex); std::unique_lock lk{PathsMutex};
if (PathsInProgress.find(std::this_thread::get_id()) != PathsInProgress.cend()) if (PathsInProgress.find(std::this_thread::get_id()) != PathsInProgress.cend()) {
LogModule.report(logvisor::Fatal, fmt("multiple resource locks on thread")); LogModule.report(logvisor::Fatal, fmt("multiple resource locks on thread"));
}
for (const auto& p : PathsInProgress) const bool isInProgress = std::any_of(PathsInProgress.cbegin(), PathsInProgress.cend(),
if (p.second == path) [&path](const auto& entry) { return entry.second == path; });
if (isInProgress) {
return false; return false;
}
PathsInProgress[std::this_thread::get_id()] = path; PathsInProgress.insert_or_assign(std::this_thread::get_id(), path);
return true; return true;
} }
void ResourceLock::ClearThreadRes() { void ResourceLock::ClearThreadRes() {
std::unique_lock<std::mutex> lk(PathsMutex); std::unique_lock lk{PathsMutex};
PathsInProgress.erase(std::this_thread::get_id()); PathsInProgress.erase(std::this_thread::get_id());
} }
bool IsPathPNG(const hecl::ProjectPath& path) { bool IsPathPNG(const hecl::ProjectPath& path) {
FILE* fp = hecl::Fopen(path.getAbsolutePath().data(), _SYS_STR("rb")); const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), _SYS_STR("rb"));
if (!fp) if (fp == nullptr) {
return false;
uint32_t buf = 0;
if (fread(&buf, 1, 4, fp) != 4) {
fclose(fp);
return false;
}
fclose(fp);
buf = hecl::SBig(buf);
if (buf == 0x89504e47)
return true;
return false; return false;
} }
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; uint32_t buf = 0;
if (fread(&buf, 1, 4, fp) != 4) { if (std::fread(&buf, 1, sizeof(buf), fp.get()) != sizeof(buf)) {
fclose(fp);
return false; return false;
} }
fclose(fp);
buf = hecl::SLittle(buf); buf = hecl::SBig(buf);
if (buf == 0x4e454c42 || buf == 0x88b1f) return buf == 0x89504e47;
return true; }
bool IsPathBlend(const hecl::ProjectPath& path) {
const auto lastCompExt = path.getLastComponentExt();
if (lastCompExt.empty() || hecl::StrCmp(lastCompExt.data(), _SYS_STR("blend"))) {
return false; return false;
} }
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) { bool IsPathYAML(const hecl::ProjectPath& path) {
if (!hecl::StrCmp(path.getLastComponent().data(), _SYS_STR("!catalog.yaml"))) if (!hecl::StrCmp(path.getLastComponent().data(), _SYS_STR("!catalog.yaml")))
return false; /* !catalog.yaml is exempt from general use */ return false; /* !catalog.yaml is exempt from general use */
@ -431,8 +445,6 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
#endif #endif
} }
#define FILE_MAXDIR 768
static std::pair<hecl::SystemString, std::string> NameFromPath(hecl::SystemStringView path) { static std::pair<hecl::SystemString, std::string> NameFromPath(hecl::SystemStringView path) {
hecl::SystemUTF8Conv utf8(path); hecl::SystemUTF8Conv utf8(path);
if (utf8.str().size() == 1 && utf8.str()[0] == '/') if (utf8.str().size() == 1 && utf8.str()[0] == '/')
@ -450,46 +462,44 @@ std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations() {
#if !WINDOWS_STORE #if !WINDOWS_STORE
/* Add the drive names to the listing (as queried by blender) */ /* Add the drive names to the listing (as queried by blender) */
{ {
constexpr uint32_t FILE_MAXDIR = 768;
wchar_t wline[FILE_MAXDIR]; wchar_t wline[FILE_MAXDIR];
wchar_t* name; const uint32_t tmp = GetLogicalDrives();
__int64 tmp;
int i;
tmp = GetLogicalDrives(); for (uint32_t i = 0; i < 26; i++) {
for (i = 0; i < 26; i++) {
if ((tmp >> i) & 1) { if ((tmp >> i) & 1) {
wline[0] = L'A' + i; wline[0] = L'A' + i;
wline[1] = L':'; wline[1] = L':';
wline[2] = L'/'; wline[2] = L'/';
wline[3] = L'\0'; wline[3] = L'\0';
name = nullptr; wchar_t* name = nullptr;
/* Flee from horrible win querying hover floppy drives! */ /* Flee from horrible win querying hover floppy drives! */
if (i > 1) { if (i > 1) {
/* Try to get volume label as well... */ /* Try to get volume label as well... */
if (GetVolumeInformationW(wline, wline + 4, FILE_MAXDIR - 4, nullptr, nullptr, nullptr, nullptr, 0)) { 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); _snwprintf(wline + 4 + labelLen, FILE_MAXDIR - 4 - labelLen, L" (%.2s)", wline);
name = wline + 4; name = wline + 4;
} }
} }
wline[2] = L'\0'; wline[2] = L'\0';
if (name) if (name == nullptr) {
ret.emplace_back(wline, hecl::WideToUTF8(name));
else
ret.push_back(NameFromPath(wline)); ret.push_back(NameFromPath(wline));
} else {
ret.emplace_back(wline, hecl::WideToUTF8(name));
}
} }
} }
/* Adding Desktop and My Documents */ /* Adding Desktop and My Documents */
SystemString wpath; SystemString wpath;
SHGetSpecialFolderPathW(0, wline, CSIDL_PERSONAL, 0); SHGetSpecialFolderPathW(nullptr, wline, CSIDL_PERSONAL, 0);
wpath.assign(wline); wpath.assign(wline);
SanitizePath(wpath); SanitizePath(wpath);
ret.push_back(NameFromPath(wpath)); ret.push_back(NameFromPath(wpath));
SHGetSpecialFolderPathW(0, wline, CSIDL_DESKTOPDIRECTORY, 0); SHGetSpecialFolderPathW(nullptr, wline, CSIDL_DESKTOPDIRECTORY, 0);
wpath.assign(wline); wpath.assign(wline);
SanitizePath(wpath); SanitizePath(wpath);
ret.push_back(NameFromPath(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*/ /*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 */ /* 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; CFURLEnumeratorResult result = kCFURLEnumeratorSuccess;
CFURLEnumeratorRef volEnum = CFURLEnumeratorCreateForMountedVolumes(NULL, kCFURLEnumeratorSkipInvisibles, NULL); CFURLEnumeratorRef volEnum =
CFURLEnumeratorCreateForMountedVolumes(nullptr, kCFURLEnumeratorSkipInvisibles, nullptr);
while (result != kCFURLEnumeratorEnd) { while (result != kCFURLEnumeratorEnd) {
char defPath[1024]; char defPath[1024];
result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, NULL); result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, nullptr);
if (result != kCFURLEnumeratorSuccess) if (result != kCFURLEnumeratorSuccess) {
continue; continue;
}
CFURLGetFileSystemRepresentation(cfURL, false, (UInt8*)defPath, 1024); CFURLGetFileSystemRepresentation(cfURL, false, reinterpret_cast<UInt8*>(defPath), std::size(defPath));
ret.push_back(NameFromPath(defPath)); ret.push_back(NameFromPath(defPath));
} }
@ -582,14 +594,11 @@ std::wstring Char16ToWide(std::u16string_view src) { return std::wstring(src.beg
#if _WIN32 #if _WIN32
int RecursiveMakeDir(const SystemChar* dir) { int RecursiveMakeDir(const SystemChar* dir) {
SystemChar tmp[1024]; SystemChar tmp[1024];
SystemChar* p = nullptr;
Sstat sb;
size_t len;
/* copy path */ /* copy path */
wcsncpy(tmp, dir, 1024); std::wcsncpy(tmp, dir, std::size(tmp));
len = wcslen(tmp); const size_t len = std::wcslen(tmp);
if (len >= 1024) { if (len >= std::size(tmp)) {
return -1; return -1;
} }
@ -599,6 +608,8 @@ int RecursiveMakeDir(const SystemChar* dir) {
} }
/* recursive mkdir */ /* recursive mkdir */
SystemChar* p = nullptr;
Sstat sb;
for (p = tmp + 1; *p; p++) { for (p = tmp + 1; *p; p++) {
if (*p == '/' || *p == '\\') { if (*p == '/' || *p == '\\') {
*p = 0; *p = 0;
@ -630,14 +641,11 @@ int RecursiveMakeDir(const SystemChar* dir) {
#else #else
int RecursiveMakeDir(const SystemChar* dir) { int RecursiveMakeDir(const SystemChar* dir) {
SystemChar tmp[1024]; SystemChar tmp[1024];
SystemChar* p = nullptr;
Sstat sb;
size_t len;
/* copy path */ /* copy path */
strncpy(tmp, dir, 1024); std::strncpy(tmp, dir, std::size(tmp));
len = strlen(tmp); const size_t len = std::strlen(tmp);
if (len >= 1024) { if (len >= std::size(tmp)) {
return -1; return -1;
} }
@ -647,6 +655,8 @@ int RecursiveMakeDir(const SystemChar* dir) {
} }
/* recursive mkdir */ /* recursive mkdir */
SystemChar* p = nullptr;
Sstat sb;
for (p = tmp + 1; *p; p++) { for (p = tmp + 1; *p; p++) {
if (*p == '/') { if (*p == '/') {
*p = 0; *p = 0;
@ -680,16 +690,16 @@ int RecursiveMakeDir(const SystemChar* dir) {
const SystemChar* GetTmpDir() { const SystemChar* GetTmpDir() {
#ifdef _WIN32 #ifdef _WIN32
#if WINDOWS_STORE #if WINDOWS_STORE
wchar_t* TMPDIR = nullptr; const wchar_t* TMPDIR = nullptr;
#else #else
wchar_t* TMPDIR = _wgetenv(L"TEMP"); const wchar_t* TMPDIR = _wgetenv(L"TEMP");
if (!TMPDIR) if (!TMPDIR)
TMPDIR = (wchar_t*)L"\\Temp"; TMPDIR = L"\\Temp";
#endif #endif
#else #else
char* TMPDIR = getenv("TMPDIR"); const char* TMPDIR = getenv("TMPDIR");
if (!TMPDIR) if (!TMPDIR)
TMPDIR = (char*)"/tmp"; TMPDIR = "/tmp";
#endif #endif
return TMPDIR; return TMPDIR;
} }
@ -697,13 +707,15 @@ const SystemChar* GetTmpDir() {
#if !WINDOWS_STORE #if !WINDOWS_STORE
int RunProcess(const SystemChar* path, const SystemChar* const args[]) { int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
#ifdef _WIN32 #ifdef _WIN32
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE};
HANDLE consoleOutReadTmp, consoleOutWrite, consoleErrWrite, consoleOutRead; HANDLE consoleOutReadTmp = INVALID_HANDLE_VALUE;
HANDLE consoleOutWrite = INVALID_HANDLE_VALUE;
if (!CreatePipe(&consoleOutReadTmp, &consoleOutWrite, &sattrs, 0)) { if (!CreatePipe(&consoleOutReadTmp, &consoleOutWrite, &sattrs, 0)) {
LogModule.report(logvisor::Fatal, fmt("Error with CreatePipe")); LogModule.report(logvisor::Fatal, fmt("Error with CreatePipe"));
return -1; return -1;
} }
HANDLE consoleErrWrite = INVALID_HANDLE_VALUE;
if (!DuplicateHandle(GetCurrentProcess(), consoleOutWrite, GetCurrentProcess(), &consoleErrWrite, 0, TRUE, if (!DuplicateHandle(GetCurrentProcess(), consoleOutWrite, GetCurrentProcess(), &consoleErrWrite, 0, TRUE,
DUPLICATE_SAME_ACCESS)) { DUPLICATE_SAME_ACCESS)) {
LogModule.report(logvisor::Fatal, fmt("Error with DuplicateHandle")); LogModule.report(logvisor::Fatal, fmt("Error with DuplicateHandle"));
@ -712,11 +724,12 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
return -1; return -1;
} }
HANDLE consoleOutRead = INVALID_HANDLE_VALUE;
if (!DuplicateHandle(GetCurrentProcess(), consoleOutReadTmp, GetCurrentProcess(), if (!DuplicateHandle(GetCurrentProcess(), consoleOutReadTmp, GetCurrentProcess(),
&consoleOutRead, // Address of new handle. &consoleOutRead, // Address of new handle.
0, FALSE, // Make it uninheritable. 0, FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS)) { DUPLICATE_SAME_ACCESS)) {
LogModule.report(logvisor::Fatal, fmt("Error with DupliateHandle")); LogModule.report(logvisor::Fatal, fmt("Error with DuplicateHandle"));
CloseHandle(consoleOutReadTmp); CloseHandle(consoleOutReadTmp);
CloseHandle(consoleOutWrite); CloseHandle(consoleOutWrite);
CloseHandle(consoleErrWrite); CloseHandle(consoleErrWrite);
@ -735,18 +748,18 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
STARTUPINFO sinfo = {sizeof(STARTUPINFO)}; STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
HANDLE nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sattrs, OPEN_EXISTING, 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.dwFlags = STARTF_USESTDHANDLES;
sinfo.hStdInput = nulHandle; sinfo.hStdInput = nulHandle;
sinfo.hStdError = consoleErrWrite; sinfo.hStdError = consoleErrWrite;
sinfo.hStdOutput = consoleOutWrite; sinfo.hStdOutput = consoleOutWrite;
PROCESS_INFORMATION pinfo = {}; 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)) { &pinfo)) {
LPWSTR messageBuffer = nullptr; LPWSTR messageBuffer = nullptr;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL); GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
LogModule.report(logvisor::Error, fmt(L"unable to launch process from {}: {}"), path, messageBuffer); LogModule.report(logvisor::Error, fmt(L"unable to launch process from {}: {}"), path, messageBuffer);
LocalFree(messageBuffer); LocalFree(messageBuffer);
@ -768,7 +781,7 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
DWORD nCharsWritten; DWORD nCharsWritten;
while (consoleThreadRunning) { while (consoleThreadRunning) {
if (!ReadFile(consoleOutRead, lpBuffer, sizeof(lpBuffer), &nBytesRead, NULL) || !nBytesRead) { if (!ReadFile(consoleOutRead, lpBuffer, sizeof(lpBuffer), &nBytesRead, nullptr) || !nBytesRead) {
DWORD err = GetLastError(); DWORD err = GetLastError();
if (err == ERROR_BROKEN_PIPE) if (err == ERROR_BROKEN_PIPE)
break; // pipe done - normal exit path. 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. // Display the character read on the screen.
auto lk = logvisor::LockLog(); auto lk = logvisor::LockLog();
if (!WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), lpBuffer, nBytesRead, &nCharsWritten, NULL)) { if (!WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), lpBuffer, nBytesRead, &nCharsWritten, nullptr)) {
// LogModule.report(logvisor::Error, fmt("Error with WriteConsole: %08X"), GetLastError()); // LogModule.report(logvisor::Error, fmt("Error with WriteConsole: {:08X}"), GetLastError());
} }
} }