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

View File

@ -13,7 +13,7 @@ class ToolCook final : public ToolBase {
bool m_fast = false;
public:
ToolCook(const ToolPassInfo& info) : ToolBase(info), m_useProj(info.project) {
explicit ToolCook(const ToolPassInfo& info) : ToolBase(info), m_useProj(info.project) {
/* Check for recursive flag */
for (hecl::SystemChar arg : info.flags)
if (arg == _SYS_STR('r'))
@ -145,9 +145,9 @@ public:
}
}
hecl::SystemString toolName() const { return _SYS_STR("cook"); }
hecl::SystemString toolName() const override { return _SYS_STR("cook"); }
int run() {
int run() override {
hecl::MultiProgressPrinter printer(true);
hecl::ClientProcess cp(&printer);
for (const hecl::ProjectPath& path : m_selectedItems)
@ -156,5 +156,5 @@ public:
return 0;
}
void cancel() { m_useProj->interruptCook(); }
void cancel() override { m_useProj->interruptCook(); }
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ class ToolSpec final : public ToolBase {
enum Mode { MLIST = 0, MENABLE, MDISABLE } mode = MLIST;
public:
ToolSpec(const ToolPassInfo& info) : ToolBase(info) {
explicit ToolSpec(const ToolPassInfo& info) : ToolBase(info) {
if (info.args.empty())
return;
@ -71,9 +71,9 @@ public:
help.endWrap();
}
hecl::SystemString toolName() const { return _SYS_STR("spec"); }
hecl::SystemString toolName() const override { return _SYS_STR("spec"); }
int run() {
int run() override {
if (!m_info.project) {
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
if (XTERM_COLOR)

View File

@ -77,14 +77,196 @@ static void SIGINTHandler(int sig) {
}
static logvisor::Module AthenaLog("Athena");
static void AthenaExc(athena::error::Level level, const char* file, const char*, int line,
fmt::string_view fmt, fmt::format_args args) {
static void AthenaExc(athena::error::Level level, const char* file, const char*, int line, fmt::string_view fmt,
fmt::format_args args) {
AthenaLog.vreport(logvisor::Level(level), fmt, args);
}
static hecl::SystemChar cwdbuf[1024];
hecl::SystemString ExeDir;
#if _WIN32
static ToolPassInfo CreateInfo(int argc, const wchar_t** argv) {
#else
static ToolPassInfo CreateInfo(int argc, const char** argv) {
#endif
hecl::SystemChar cwdbuf[1024];
ToolPassInfo info;
info.pname = argv[0];
if (hecl::Getcwd(cwdbuf, static_cast<int>(std::size(cwdbuf)))) {
info.cwd = cwdbuf;
if (info.cwd.size() && info.cwd.back() != _SYS_STR('/') && info.cwd.back() != _SYS_STR('\\')) {
#if _WIN32
info.cwd += _SYS_STR('\\');
#else
info.cwd += _SYS_STR('/');
#endif
}
if (hecl::PathRelative(argv[0])) {
ExeDir = hecl::SystemString(cwdbuf) + _SYS_STR('/');
}
hecl::SystemString Argv0(argv[0]);
hecl::SystemString::size_type lastIdx = Argv0.find_last_of(_SYS_STR("/\\"));
if (lastIdx != hecl::SystemString::npos) {
ExeDir.insert(ExeDir.end(), Argv0.begin(), Argv0.begin() + lastIdx);
}
}
/* Concatenate args */
std::vector<hecl::SystemString> args;
args.reserve(argc - 2);
for (int i = 2; i < argc; ++i) {
args.emplace_back(argv[i]);
}
if (!args.empty()) {
/* Extract output argument */
for (auto it = args.cbegin(); it != args.cend();) {
const hecl::SystemString& arg = *it;
hecl::SystemRegexMatch oMatch;
if (std::regex_search(arg, oMatch, regOPEN)) {
const hecl::SystemString& token = oMatch[1].str();
if (token.size()) {
if (info.output.empty()) {
info.output = oMatch[1].str();
}
it = args.erase(it);
} else {
it = args.erase(it);
if (it == args.end()) {
break;
}
if (info.output.empty()) {
info.output = *it;
}
it = args.erase(it);
}
continue;
}
++it;
}
/* Iterate flags */
bool threadArg = false;
for (auto it = args.cbegin(); it != args.cend();) {
const hecl::SystemString& arg = *it;
if (threadArg) {
threadArg = false;
hecl::CpuCountOverride = int(hecl::StrToUl(arg.c_str(), nullptr, 0));
it = args.erase(it);
continue;
}
if (arg.size() < 2 || arg[0] != _SYS_STR('-') || arg[1] == _SYS_STR('-')) {
++it;
continue;
}
for (auto chit = arg.cbegin() + 1; chit != arg.cend(); ++chit) {
if (*chit == _SYS_STR('v'))
++info.verbosityLevel;
else if (*chit == _SYS_STR('f'))
info.force = true;
else if (*chit == _SYS_STR('y'))
info.yes = true;
else if (*chit == _SYS_STR('g'))
info.gui = true;
else if (*chit == _SYS_STR('j')) {
++chit;
if (*chit)
hecl::CpuCountOverride = int(hecl::StrToUl(&*chit, nullptr, 0));
else
threadArg = true;
break;
} else
info.flags.push_back(*chit);
}
it = args.erase(it);
}
/* Gather remaining args */
info.args.reserve(args.size());
for (const hecl::SystemString& arg : args)
info.args.push_back(arg);
}
return info;
}
static std::unique_ptr<hecl::Database::Project> FindProject(hecl::SystemStringView cwd) {
const hecl::ProjectRootPath rootPath = hecl::SearchForProject(cwd);
if (!rootPath) {
return nullptr;
}
const size_t ErrorRef = logvisor::ErrorCount;
auto newProj = std::make_unique<hecl::Database::Project>(rootPath);
if (logvisor::ErrorCount > ErrorRef) {
#if WIN_PAUSE
system("PAUSE");
#endif
return nullptr;
}
return newProj;
}
static std::unique_ptr<ToolBase> MakeSelectedTool(hecl::SystemString toolName, ToolPassInfo& info) {
hecl::SystemString toolNameLower = toolName;
hecl::ToLower(toolNameLower);
if (toolNameLower == _SYS_STR("init")) {
return std::make_unique<ToolInit>(info);
}
if (toolNameLower == _SYS_STR("spec")) {
return std::make_unique<ToolSpec>(info);
}
if (toolNameLower == _SYS_STR("extract")) {
return std::make_unique<ToolExtract>(info);
}
if (toolNameLower == _SYS_STR("cook")) {
return std::make_unique<ToolCook>(info);
}
if (toolNameLower == _SYS_STR("package") || toolNameLower == _SYS_STR("pack")) {
return std::make_unique<ToolPackage>(info);
}
#if HECL_HAS_NOD
if (toolNameLower == _SYS_STR("image")) {
return std::make_unique<ToolImage>(info);
}
#endif
if (toolNameLower == _SYS_STR("help")) {
return std::make_unique<ToolHelp>(info);
}
auto fp = hecl::FopenUnique(toolName.c_str(), _SYS_STR("rb"));
if (fp == nullptr) {
LogModule.report(logvisor::Error, fmt(_SYS_STR("unrecognized tool '{}'")), toolNameLower);
return nullptr;
}
fp.reset();
/* Shortcut-case: implicit extract */
info.args.insert(info.args.begin(), std::move(toolName));
return std::make_unique<ToolExtract>(info);
}
#if _WIN32
int wmain(int argc, const wchar_t** argv)
#else
@ -140,167 +322,34 @@ int main(int argc, const char** argv)
HECLRegisterDataSpecs();
/* Assemble common tool pass info */
ToolPassInfo info;
info.pname = argv[0];
if (hecl::Getcwd(cwdbuf, 1024)) {
info.cwd = cwdbuf;
if (info.cwd.size() && info.cwd.back() != _SYS_STR('/') && info.cwd.back() != _SYS_STR('\\'))
#if _WIN32
info.cwd += _SYS_STR('\\');
#else
info.cwd += _SYS_STR('/');
#endif
if (hecl::PathRelative(argv[0]))
ExeDir = hecl::SystemString(cwdbuf) + _SYS_STR('/');
hecl::SystemString Argv0(argv[0]);
hecl::SystemString::size_type lastIdx = Argv0.find_last_of(_SYS_STR("/\\"));
if (lastIdx != hecl::SystemString::npos)
ExeDir.insert(ExeDir.end(), Argv0.begin(), Argv0.begin() + lastIdx);
}
/* Concatenate args */
std::vector<hecl::SystemString> args;
args.reserve(argc - 2);
for (int i = 2; i < argc; ++i)
args.push_back(hecl::SystemString(argv[i]));
if (!args.empty()) {
/* Extract output argument */
for (auto it = args.cbegin(); it != args.cend();) {
const hecl::SystemString& arg = *it;
hecl::SystemRegexMatch oMatch;
if (std::regex_search(arg, oMatch, regOPEN)) {
const hecl::SystemString& token = oMatch[1].str();
if (token.size()) {
if (info.output.empty())
info.output = oMatch[1].str();
it = args.erase(it);
} else {
it = args.erase(it);
if (it == args.end())
break;
if (info.output.empty())
info.output = *it;
it = args.erase(it);
}
continue;
}
++it;
}
/* Iterate flags */
bool threadArg = false;
for (auto it = args.cbegin(); it != args.cend();) {
const hecl::SystemString& arg = *it;
if (threadArg) {
threadArg = false;
hecl::CpuCountOverride = int(hecl::StrToUl(arg.c_str(), nullptr, 0));
it = args.erase(it);
continue;
}
if (arg.size() < 2 || arg[0] != _SYS_STR('-') || arg[1] == _SYS_STR('-')) {
++it;
continue;
}
for (auto chit = arg.cbegin() + 1; chit != arg.cend(); ++chit) {
if (*chit == _SYS_STR('v'))
++info.verbosityLevel;
else if (*chit == _SYS_STR('f'))
info.force = true;
else if (*chit == _SYS_STR('y'))
info.yes = true;
else if (*chit == _SYS_STR('g'))
info.gui = true;
else if (*chit == _SYS_STR('j')) {
++chit;
if (*chit)
hecl::CpuCountOverride = int(hecl::StrToUl(&*chit, nullptr, 0));
else
threadArg = true;
break;
}
else
info.flags.push_back(*chit);
}
it = args.erase(it);
}
/* Gather remaining args */
info.args.reserve(args.size());
for (const hecl::SystemString& arg : args)
info.args.push_back(arg);
}
ToolPassInfo info = CreateInfo(argc, argv);
/* Attempt to find hecl project */
hecl::ProjectRootPath rootPath = hecl::SearchForProject(info.cwd);
std::unique_ptr<hecl::Database::Project> project;
if (rootPath) {
size_t ErrorRef = logvisor::ErrorCount;
hecl::Database::Project* newProj = new hecl::Database::Project(rootPath);
if (logvisor::ErrorCount > ErrorRef) {
#if WIN_PAUSE
system("PAUSE");
#endif
delete newProj;
return 1;
}
project.reset(newProj);
info.project = newProj;
auto project = FindProject(info.cwd);
if (project != nullptr) {
info.project = project.get();
}
/* Construct selected tool */
hecl::SystemString toolName(argv[1]);
hecl::ToLower(toolName);
std::unique_ptr<ToolBase> tool;
size_t ErrorRef = logvisor::ErrorCount;
if (toolName == _SYS_STR("init"))
tool.reset(new ToolInit(info));
else if (toolName == _SYS_STR("spec"))
tool.reset(new ToolSpec(info));
else if (toolName == _SYS_STR("extract"))
tool.reset(new ToolExtract(info));
else if (toolName == _SYS_STR("cook"))
tool.reset(new ToolCook(info));
else if (toolName == _SYS_STR("package") || toolName == _SYS_STR("pack"))
tool.reset(new ToolPackage(info));
#if HECL_HAS_NOD
else if (toolName == _SYS_STR("image"))
tool.reset(new ToolImage(info));
#endif
else if (toolName == _SYS_STR("help"))
tool.reset(new ToolHelp(info));
else {
FILE* fp = hecl::Fopen(argv[1], _SYS_STR("rb"));
if (!fp)
LogModule.report(logvisor::Error, fmt(_SYS_STR("unrecognized tool '{}'")), toolName);
else {
/* Shortcut-case: implicit extract */
fclose(fp);
info.args.insert(info.args.begin(), argv[1]);
tool.reset(new ToolExtract(info));
}
}
if (logvisor::ErrorCount > ErrorRef) {
const size_t MakeToolErrorRef = logvisor::ErrorCount;
auto tool = MakeSelectedTool(argv[1], info);
if (logvisor::ErrorCount > MakeToolErrorRef) {
#if WIN_PAUSE
system("PAUSE");
#endif
return 1;
}
if (info.verbosityLevel)
LogModule.report(logvisor::Info, fmt(_SYS_STR("Constructed tool '{}' {}\n")), tool->toolName(), info.verbosityLevel);
if (info.verbosityLevel) {
LogModule.report(logvisor::Info, fmt(_SYS_STR("Constructed tool '{}' {}\n")), tool->toolName(),
info.verbosityLevel);
}
/* Run tool */
ErrorRef = logvisor::ErrorCount;
const size_t RunToolErrorRef = logvisor::ErrorCount;
ToolPtr = tool.get();
int retval = tool->run();
const int retval = tool->run();
ToolPtr = nullptr;
if (logvisor::ErrorCount > ErrorRef) {
if (logvisor::ErrorCount > RunToolErrorRef) {
hecl::blender::Connection::Shutdown();
#if WIN_PAUSE
system("PAUSE");

View File

@ -67,7 +67,7 @@ public:
return *this;
}
operator bool() const { return ((*WordRef) & (BitWord(1) << BitPos)) != 0; }
explicit operator bool() const { return ((*WordRef) & (BitWord(1) << BitPos)) != 0; }
};
/// BitVector default ctor - Creates an empty bitvector.

View File

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

View File

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

View File

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

View File

@ -36,7 +36,7 @@ public:
void* m_targetBuf;
size_t m_maxLen;
size_t m_offset;
void run(blender::Token& btok);
void run(blender::Token& btok) override;
BufferTransaction(ClientProcess& parent, const ProjectPath& path, void* target, size_t maxLen, size_t offset)
: Transaction(parent, Type::Buffer), m_path(path), m_targetBuf(target), m_maxLen(maxLen), m_offset(offset) {}
};
@ -46,13 +46,13 @@ public:
bool m_returnResult = false;
bool m_force;
bool m_fast;
void run(blender::Token& btok);
void run(blender::Token& btok) override;
CookTransaction(ClientProcess& parent, const ProjectPath& path, bool force, bool fast, Database::IDataSpec* spec)
: Transaction(parent, Type::Cook), m_path(path), m_dataSpec(spec), m_force(force), m_fast(fast) {}
};
struct LambdaTransaction final : Transaction {
std::function<void(blender::Token&)> m_func;
void run(blender::Token& btok);
void run(blender::Token& btok) override;
LambdaTransaction(ClientProcess& parent, std::function<void(blender::Token&)>&& func)
: Transaction(parent, Type::Lambda), m_func(std::move(func)) {}
};

View File

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

View File

@ -26,13 +26,14 @@ class Console {
Console* m_con;
LogVisorAdapter(Console* con) : m_con(con) {}
~LogVisorAdapter() = default;
void report(const char* modName, logvisor::Level severity, fmt::string_view format, fmt::format_args args);
void report(const char* modName, logvisor::Level severity, fmt::wstring_view format, fmt::wformat_args args);
~LogVisorAdapter() override = default;
void report(const char* modName, logvisor::Level severity, fmt::string_view format, fmt::format_args args) override;
void report(const char* modName, logvisor::Level severity, fmt::wstring_view format,
fmt::wformat_args args) override;
void reportSource(const char* modName, logvisor::Level severity, const char* file, unsigned linenum,
fmt::string_view format, fmt::format_args args);
fmt::string_view format, fmt::format_args args) override;
void reportSource(const char* modName, logvisor::Level severity, const char* file, unsigned linenum,
fmt::wstring_view format, fmt::wformat_args args);
fmt::wstring_view format, fmt::wformat_args args) override;
};
public:

View File

@ -1,21 +1,17 @@
#pragma once
#include <iterator>
#include <string>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <functional>
#include <vector>
#include <map>
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <memory>
#include <atomic>
#include <fstream>
#include <stdint.h>
#include <cassert>
#include <vector>
#include "athena/IStreamReader.hpp"
#include "logvisor/logvisor.hpp"
#include <logvisor/logvisor.hpp>
#include "hecl.hpp"
@ -62,7 +58,7 @@ class IDataSpec {
public:
IDataSpec(const DataSpecEntry* specEntry) : m_specEntry(specEntry) {}
virtual ~IDataSpec() {}
virtual ~IDataSpec() = default;
using FCookProgress = std::function<void(const SystemChar*)>;
/**
@ -91,43 +87,33 @@ public:
virtual void setThreadProject() {}
virtual bool canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps) {
(void)info;
(void)reps;
virtual bool canExtract([[maybe_unused]] const ExtractPassInfo& info,
[[maybe_unused]] std::vector<ExtractReport>& reps) {
LogModule.report(logvisor::Error, fmt("not implemented"));
return false;
}
virtual void doExtract(const ExtractPassInfo& info, const MultiProgressPrinter& progress) {
(void)info;
(void)progress;
}
virtual void doExtract([[maybe_unused]] const ExtractPassInfo& info,
[[maybe_unused]] const MultiProgressPrinter& progress) {}
virtual bool canCook(const ProjectPath& path, blender::Token& btok) {
(void)path;
virtual bool canCook([[maybe_unused]] const ProjectPath& path, [[maybe_unused]] blender::Token& btok) {
LogModule.report(logvisor::Error, fmt("not implemented"));
return false;
}
virtual const DataSpecEntry* overrideDataSpec(const ProjectPath& path,
const Database::DataSpecEntry* oldEntry) const {
(void)path;
virtual const DataSpecEntry* overrideDataSpec([[maybe_unused]] const ProjectPath& path,
const DataSpecEntry* oldEntry) const {
return oldEntry;
}
virtual void doCook(const ProjectPath& path, const ProjectPath& cookedPath, bool fast, blender::Token& btok,
FCookProgress progress) {
(void)path;
(void)cookedPath;
(void)fast;
(void)progress;
}
virtual void doCook([[maybe_unused]] const ProjectPath& path, [[maybe_unused]] const ProjectPath& cookedPath,
[[maybe_unused]] bool fast, [[maybe_unused]] blender::Token& btok,
[[maybe_unused]] FCookProgress progress) {}
virtual bool canPackage(const ProjectPath& path) {
(void)path;
virtual bool canPackage([[maybe_unused]] const ProjectPath& path) {
return false;
}
virtual void doPackage(const ProjectPath& path, const Database::DataSpecEntry* entry, bool fast, blender::Token& btok,
const MultiProgressPrinter& progress, ClientProcess* cp = nullptr) {
(void)path;
}
virtual void doPackage([[maybe_unused]] const ProjectPath& path, [[maybe_unused]] const DataSpecEntry* entry,
[[maybe_unused]] bool fast, [[maybe_unused]] blender::Token& btok,
[[maybe_unused]] const MultiProgressPrinter& progress,
[[maybe_unused]] ClientProcess* cp = nullptr) {}
virtual void interruptCook() {}
@ -190,7 +176,7 @@ protected:
Cafe /**< Swizzled textures and R700 shader objects */
};
typedef std::function<void(const void* data, size_t len)> FDataAppender;
using FDataAppender = std::function<void(const void* data, size_t len)>;
/**
* @brief Optional private method implemented by subclasses to cook objects
@ -203,14 +189,12 @@ protected:
* Part of the cooking process may include embedding database-refs to dependencies.
* This method should store the 64-bit value provided by IDataObject::id() when doing this.
*/
virtual bool cookObject(FDataAppender dataAppender, DataEndianness endianness, DataPlatform platform) {
(void)dataAppender;
(void)endianness;
(void)platform;
virtual bool cookObject([[maybe_unused]] FDataAppender dataAppender, [[maybe_unused]] DataEndianness endianness,
[[maybe_unused]] DataPlatform platform) {
return true;
}
typedef std::function<void(ObjectBase*)> FDepAdder;
using FDepAdder = std::function<void(ObjectBase*)>;
/**
* @brief Optional private method implemented by CProjectObject subclasses to resolve dependencies
@ -220,7 +204,7 @@ protected:
* Dependencies registered via this method will eventually have this method called on themselves
* as well. This is a non-recursive operation, no need for subclasses to implement recursion-control.
*/
virtual void gatherDeps(FDepAdder depAdder) { (void)depAdder; }
virtual void gatherDeps([[maybe_unused]] FDepAdder depAdder) {}
/**
* @brief Get a packagable FourCC representation of the object's type
@ -262,7 +246,7 @@ private:
public:
Project(const ProjectRootPath& rootPath);
operator bool() const { return m_valid; }
explicit operator bool() const { return m_valid; }
/**
* @brief Configuration file handle
@ -273,7 +257,7 @@ public:
class ConfigFile {
SystemString m_filepath;
std::vector<std::string> m_lines;
FILE* m_lockedFile = NULL;
UniqueFilePtr m_lockedFile;
public:
ConfigFile(const Project& project, SystemStringView name, SystemStringView subdir = _SYS_STR("/.hecl/"));
@ -311,7 +295,7 @@ public:
/**
* @brief Get the path of project's cooked directory for a specific DataSpec
* @param DataSpec to retrieve path for
* @param spec DataSpec to retrieve path for
* @return project cooked path
*
* The cooked path matches the directory layout of the working directory
@ -320,7 +304,7 @@ public:
/**
* @brief Add given file(s) to the database
* @param path file or pattern within project
* @param paths files or patterns within project
* @return true on success
*
* This method blocks while object hashing takes place

View File

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

View File

@ -1,6 +1,6 @@
#pragma once
#include "Compilers.hpp"
extern "C" unsigned long long XXH64(const void* input, size_t length, unsigned long long seed);
#include "../extern/boo/xxhash/xxhash.h"
#define HECL_RUNTIME 1

View File

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

View File

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

View File

@ -153,7 +153,7 @@ public:
return {bucket.buffer, m_div.rem * m_pool->m_stride};
}
operator bool() const { return m_pool != nullptr && m_index != -1; }
explicit operator bool() const { return m_pool != nullptr && m_index != -1; }
};
UniformBufferPool() = default;

View File

@ -158,7 +158,7 @@ public:
return {bucket.buffer, m_div.rem};
}
operator bool() const { return m_pool != nullptr && m_index != -1; }
explicit operator bool() const { return m_pool != nullptr && m_index != -1; }
};
VertexBufferPool() = default;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,6 +4,7 @@
#include <athena/Utility.hpp>
#include <hecl/Runtime.hpp>
#include <hecl/hecl.hpp>
#include <algorithm>
#include <memory>
#include <regex>
@ -24,12 +25,11 @@ CVarManager::CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary)
com_configfile = newCVar("config", "File to store configuration", std::string("config"), CVar::EFlags::System);
com_developer = newCVar("developer", "Enables developer mode", false,
(CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable));
com_enableCheats =
newCVar("cheats", "Enable cheats", false,
(CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::Hidden | CVar::EFlags::InternalArchivable));
com_cubemaps =
newCVar("cubemaps", "Enable cubemaps", false,
(CVar::EFlags::Game | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable));
com_enableCheats = newCVar(
"cheats", "Enable cheats", false,
(CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::Hidden | CVar::EFlags::InternalArchivable));
com_cubemaps = newCVar("cubemaps", "Enable cubemaps", false,
(CVar::EFlags::Game | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable));
}
CVarManager::~CVarManager() {}
@ -37,11 +37,13 @@ CVarManager::~CVarManager() {}
CVar* CVarManager::registerCVar(std::unique_ptr<CVar>&& cvar) {
std::string tmp(cvar->name());
athena::utility::tolower(tmp);
if (m_cvars.find(tmp) != m_cvars.end())
if (m_cvars.find(tmp) != m_cvars.end()) {
return nullptr;
}
CVar* ret = cvar.get();
m_cvars[tmp] = std::move(cvar);
m_cvars.insert_or_assign(std::move(tmp), std::move(cvar));
return ret;
}
@ -80,8 +82,8 @@ void CVarManager::deserialize(CVar* cvar) {
/* First let's check for a deferred value */
std::string lowName = cvar->name().data();
athena::utility::tolower(lowName);
if (m_deferedCVars.find(lowName) != m_deferedCVars.end()) {
std::string val = m_deferedCVars[lowName];
if (const auto iter = m_deferedCVars.find(lowName); iter != m_deferedCVars.end()) {
std::string val = std::move(iter->second);
m_deferedCVars.erase(lowName);
if (cvar->fromLiteralToType(val))
return;
@ -162,10 +164,13 @@ void CVarManager::serialize() {
if (m_useBinary) {
CVarContainer container;
for (const auto& pair : m_cvars)
if (pair.second->isArchive() ||
(pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue()))
container.cvars.push_back(*pair.second);
for (const auto& pair : m_cvars) {
const auto& cvar = pair.second;
if (cvar->isArchive() || (cvar->isInternalArchivable() && cvar->wasDeserialized() && !cvar->hasDefaultValue())) {
container.cvars.push_back(*cvar);
}
}
container.cvarCount = atUint32(container.cvars.size());
filename += _SYS_STR(".bin");
@ -180,10 +185,13 @@ void CVarManager::serialize() {
r.close();
docWriter.setStyle(athena::io::YAMLNodeStyle::Block);
for (const auto& pair : m_cvars)
if (pair.second->isArchive() ||
(pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue()))
docWriter.writeString(pair.second->name().data(), pair.second->toLiteral());
for (const auto& pair : m_cvars) {
const auto& cvar = pair.second;
if (cvar->isArchive() || (cvar->isInternalArchivable() && cvar->wasDeserialized() && !cvar->hasDefaultValue())) {
docWriter.writeString(cvar->name().data(), cvar->toLiteral());
}
}
athena::io::FileWriter w(filename);
if (w.isOpen())
@ -208,12 +216,13 @@ void CVarManager::setCVar(Console* con, const std::vector<std::string>& args) {
std::string cvName = args[0];
athena::utility::tolower(cvName);
if (m_cvars.find(cvName) == m_cvars.end()) {
const auto iter = m_cvars.find(cvName);
if (iter == m_cvars.end()) {
con->report(Console::Level::Error, fmt("CVar '{}' does not exist"), args[0]);
return;
}
const auto& cv = m_cvars[cvName];
const auto& cv = iter->second;
std::string oldVal = cv->value();
std::string value = args[1];
auto it = args.begin() + 2;
@ -238,12 +247,13 @@ void CVarManager::getCVar(Console* con, const std::vector<std::string>& args) {
std::string cvName = args[0];
athena::utility::tolower(cvName);
if (m_cvars.find(cvName) == m_cvars.end()) {
const auto iter = m_cvars.find(cvName);
if (iter == m_cvars.end()) {
con->report(Console::Level::Error, fmt("CVar '{}' does not exist"), args[0]);
return;
}
const auto& cv = m_cvars[cvName];
const auto& cv = iter->second;
con->report(Console::Level::Info, fmt("'{}' = '{}'"), cv->name(), cv->value());
}
@ -266,38 +276,38 @@ void CVarManager::setCheatsEnabled(bool v, bool setDeserialized) {
}
bool CVarManager::restartRequired() const {
for (const auto& cv : m_cvars) {
if (cv.second->isModified() && cv.second->modificationRequiresRestart())
return true;
}
return false;
return std::any_of(m_cvars.cbegin(), m_cvars.cend(), [](const auto& entry) {
return entry.second->isModified() && entry.second->modificationRequiresRestart();
});
}
void CVarManager::parseCommandLine(const std::vector<SystemString>& args) {
bool oldDeveloper = suppressDeveloper();
std::string developerName = com_developer->name().data();
std::string developerName(com_developer->name());
athena::utility::tolower(developerName);
for (const SystemString& arg : args) {
if (arg[0] == _SYS_STR('+')) {
std::string tmp = SystemUTF8Conv(arg).c_str();
if (arg[0] != _SYS_STR('+')) {
continue;
}
std::smatch matches;
if (std::regex_match(tmp, matches, cmdLineRegex)) {
std::string cvarName = matches[1].str();
std::string cvarValue = matches[2].str();
if (CVar* cv = findCVar(cvarName)) {
cv->fromLiteralToType(cvarValue);
athena::utility::tolower(cvarName);
if (developerName == cvarName)
/* Make sure we're not overriding developer mode when we restore */
oldDeveloper = com_developer->toBoolean();
} else {
/* Unable to find an existing CVar, let's defer for the time being 8 */
athena::utility::tolower(cvarName);
m_deferedCVars[cvarName] = cvarValue;
}
}
const std::string tmp(SystemUTF8Conv(arg).str());
std::smatch matches;
if (!std::regex_match(tmp, matches, cmdLineRegex)) {
continue;
}
std::string cvarName = matches[1].str();
std::string cvarValue = matches[2].str();
if (CVar* cv = findCVar(cvarName)) {
cv->fromLiteralToType(cvarValue);
athena::utility::tolower(cvarName);
if (developerName == cvarName)
/* Make sure we're not overriding developer mode when we restore */
oldDeveloper = com_developer->toBoolean();
} else {
/* Unable to find an existing CVar, let's defer for the time being 8 */
athena::utility::tolower(cvarName);
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) {
m_dataSpec->setThreadProject();
m_returnResult = m_parent.syncCook(m_path, m_dataSpec, btok, m_force, m_fast);
std::unique_lock<std::mutex> lk(m_parent.m_mutex);
std::unique_lock lk{m_parent.m_mutex};
++m_parent.m_completedCooks;
m_parent.m_progPrinter->setMainFactor(m_parent.m_completedCooks / float(m_parent.m_addedCooks));
m_complete = true;
@ -92,7 +92,7 @@ void ClientProcess::Worker::proc() {
std::string thrName = fmt::format(fmt("HECL Worker {}"), m_idx);
logvisor::RegisterThreadName(thrName.c_str());
std::unique_lock<std::mutex> lk(m_proc.m_mutex);
std::unique_lock lk{m_proc.m_mutex};
while (m_proc.m_running) {
if (!m_didInit) {
m_proc.m_initCv.notify_one();
@ -125,7 +125,7 @@ ClientProcess::ClientProcess(const MultiProgressPrinter* progPrinter) : m_progPr
#endif
m_workers.reserve(cpuCount);
for (int i = 0; i < cpuCount; ++i) {
std::unique_lock<std::mutex> lk(m_mutex);
std::unique_lock lk{m_mutex};
m_workers.emplace_back(*this, m_workers.size());
m_initCv.wait(lk);
}
@ -134,7 +134,7 @@ ClientProcess::ClientProcess(const MultiProgressPrinter* progPrinter) : m_progPr
std::shared_ptr<const ClientProcess::BufferTransaction> ClientProcess::addBufferTransaction(const ProjectPath& path,
void* target, size_t maxLen,
size_t offset) {
std::unique_lock<std::mutex> lk(m_mutex);
std::unique_lock lk{m_mutex};
auto ret = std::make_shared<BufferTransaction>(*this, path, target, maxLen, offset);
m_pendingQueue.emplace_back(ret);
m_cv.notify_one();
@ -144,7 +144,7 @@ std::shared_ptr<const ClientProcess::BufferTransaction> ClientProcess::addBuffer
std::shared_ptr<const ClientProcess::CookTransaction> ClientProcess::addCookTransaction(const hecl::ProjectPath& path,
bool force, bool fast,
Database::IDataSpec* spec) {
std::unique_lock<std::mutex> lk(m_mutex);
std::unique_lock lk{m_mutex};
auto ret = std::make_shared<CookTransaction>(*this, path, force, fast, spec);
m_pendingQueue.emplace_back(ret);
m_cv.notify_one();
@ -155,7 +155,7 @@ std::shared_ptr<const ClientProcess::CookTransaction> ClientProcess::addCookTran
std::shared_ptr<const ClientProcess::LambdaTransaction>
ClientProcess::addLambdaTransaction(std::function<void(blender::Token&)>&& func) {
std::unique_lock<std::mutex> lk(m_mutex);
std::unique_lock lk{m_mutex};
auto ret = std::make_shared<LambdaTransaction>(*this, std::move(func));
m_pendingQueue.emplace_back(ret);
m_cv.notify_one();
@ -204,12 +204,12 @@ bool ClientProcess::syncCook(const hecl::ProjectPath& path, Database::IDataSpec*
}
void ClientProcess::swapCompletedQueue(std::list<std::shared_ptr<Transaction>>& queue) {
std::unique_lock<std::mutex> lk(m_mutex);
std::unique_lock lk{m_mutex};
queue.swap(m_completedQueue);
}
void ClientProcess::waitUntilComplete() {
std::unique_lock<std::mutex> lk(m_mutex);
std::unique_lock lk{m_mutex};
while (isBusy())
m_waitCv.wait(lk);
}
@ -217,7 +217,7 @@ void ClientProcess::waitUntilComplete() {
void ClientProcess::shutdown() {
if (!m_running)
return;
std::unique_lock<std::mutex> lk(m_mutex);
std::unique_lock lk{m_mutex};
m_pendingQueue.clear();
m_running = false;
m_cv.notify_all();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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