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

New code style refactor

This commit is contained in:
Jack Andersen 2018-12-07 19:18:42 -10:00
parent 54c466276b
commit 72193079ae
74 changed files with 14647 additions and 17058 deletions

View File

@ -18,8 +18,7 @@
extern logvisor::Module LogModule; extern logvisor::Module LogModule;
struct ToolPassInfo struct ToolPassInfo {
{
hecl::SystemString pname; hecl::SystemString pname;
hecl::SystemString cwd; hecl::SystemString cwd;
std::vector<hecl::SystemString> args; std::vector<hecl::SystemString> args;
@ -48,16 +47,13 @@ struct ToolPassInfo
extern bool XTERM_COLOR; extern bool XTERM_COLOR;
class ToolBase class ToolBase {
{
protected: protected:
const ToolPassInfo& m_info; const ToolPassInfo& m_info;
bool m_good = false; bool m_good = false;
bool continuePrompt() bool continuePrompt() {
{ if (!m_info.yes) {
if (!m_info.yes)
{
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::Printf(_SYS_STR("\n" BLUE BOLD "Continue?" NORMAL " (Y/n) ")); hecl::Printf(_SYS_STR("\n" BLUE BOLD "Continue?" NORMAL " (Y/n) "));
else else
@ -76,8 +72,7 @@ protected:
while ((ch = getch())) while ((ch = getch()))
#endif #endif
{ {
if (ch == 'n' || ch == 'N') if (ch == 'n' || ch == 'N') {
{
hecl::Printf(_SYS_STR("\n")); hecl::Printf(_SYS_STR("\n"));
return false; return false;
} }
@ -93,51 +88,44 @@ protected:
} }
public: public:
ToolBase(const ToolPassInfo& info) ToolBase(const ToolPassInfo& info) : m_info(info) {
: m_info(info)
{
hecl::VerbosityLevel = info.verbosityLevel; hecl::VerbosityLevel = info.verbosityLevel;
hecl::GuiMode = info.gui; hecl::GuiMode = info.gui;
} }
virtual ~ToolBase() = default; virtual ~ToolBase() = default;
virtual hecl::SystemString toolName() const=0; virtual hecl::SystemString toolName() const = 0;
virtual int run()=0; virtual int run() = 0;
virtual void cancel() {} virtual void cancel() {}
inline operator bool() const {return m_good;} inline operator bool() const { return m_good; }
}; };
class HelpOutput class HelpOutput {
{
public: public:
typedef void(*HelpFunc)(HelpOutput&); typedef void (*HelpFunc)(HelpOutput&);
private: private:
FILE* m_sout; FILE* m_sout;
HelpFunc m_helpFunc; HelpFunc m_helpFunc;
int m_lineWidth; int m_lineWidth;
hecl::SystemString m_wrapBuffer; hecl::SystemString m_wrapBuffer;
void _wrapBuf(hecl::SystemString& string) void _wrapBuf(hecl::SystemString& string) {
{
int counter; int counter;
hecl::SystemString::iterator it = string.begin(); hecl::SystemString::iterator it = string.begin();
while (it != string.end()) while (it != string.end()) {
{
std::ptrdiff_t v = it - string.begin(); std::ptrdiff_t v = it - string.begin();
/* copy string until the end of the line is reached */ /* copy string until the end of the line is reached */
for (counter=WRAP_INDENT ; counter < m_lineWidth ; ++counter) for (counter = WRAP_INDENT; counter < m_lineWidth; ++counter) {
{
if (it >= string.end()) if (it >= string.end())
return; return;
if (*it == _SYS_STR('\n')) if (*it == _SYS_STR('\n')) {
{
counter = WRAP_INDENT; counter = WRAP_INDENT;
++it; ++it;
} }
if (counter == WRAP_INDENT) if (counter == WRAP_INDENT) {
{ for (int i = 0; i < WRAP_INDENT; ++i)
for (int i=0 ; i<WRAP_INDENT ; ++i)
it = string.insert(it, _SYS_STR(' ')) + 1; it = string.insert(it, _SYS_STR(' ')) + 1;
} }
if (it >= string.end()) if (it >= string.end())
@ -146,19 +134,14 @@ private:
++it; ++it;
} }
/* check for whitespace */ /* check for whitespace */
if (isspace(*it)) if (isspace(*it)) {
{
*it = _SYS_STR('\n'); *it = _SYS_STR('\n');
counter = WRAP_INDENT; counter = WRAP_INDENT;
++it; ++it;
} } else {
else
{
/* check for nearest whitespace back in string */ /* check for nearest whitespace back in string */
for (hecl::SystemString::iterator k=it ; k!=string.begin() ; --k) for (hecl::SystemString::iterator k = it; k != string.begin(); --k) {
{ if (isspace(*k)) {
if (isspace(*k))
{
counter = WRAP_INDENT; counter = WRAP_INDENT;
if (k - string.begin() < v) if (k - string.begin() < v)
k = string.insert(it, _SYS_STR('\n')); k = string.insert(it, _SYS_STR('\n'));
@ -173,72 +156,53 @@ private:
} }
public: public:
HelpOutput(HelpFunc helpFunc) HelpOutput(HelpFunc helpFunc)
: m_sout(NULL), m_helpFunc(helpFunc), m_lineWidth(hecl::GuiMode ? 120 : hecl::ConsoleWidth()) : m_sout(NULL), m_helpFunc(helpFunc), m_lineWidth(hecl::GuiMode ? 120 : hecl::ConsoleWidth()) {}
{}
void go() void go() {
{
#if _WIN32 #if _WIN32
m_sout = stdout; m_sout = stdout;
m_helpFunc(*this); m_helpFunc(*this);
#else #else
m_sout = popen("less -R", "w"); m_sout = popen("less -R", "w");
if (m_sout) if (m_sout) {
{
m_helpFunc(*this); m_helpFunc(*this);
pclose(m_sout); pclose(m_sout);
} } else {
else
{
m_sout = stdout; m_sout = stdout;
m_helpFunc(*this); m_helpFunc(*this);
} }
#endif #endif
} }
void print(const hecl::SystemChar* str) void print(const hecl::SystemChar* str) { hecl::FPrintf(m_sout, _SYS_STR("%s"), str); }
{
hecl::FPrintf(m_sout, _SYS_STR("%s"), str);
}
void printBold(const hecl::SystemChar* str) void printBold(const hecl::SystemChar* str) {
{
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::FPrintf(m_sout, _SYS_STR("" BOLD "%s" NORMAL ""), str); hecl::FPrintf(m_sout, _SYS_STR("" BOLD "%s" NORMAL ""), str);
else else
hecl::FPrintf(m_sout, _SYS_STR("%s"), str); hecl::FPrintf(m_sout, _SYS_STR("%s"), str);
} }
void secHead(const hecl::SystemChar* headName) void secHead(const hecl::SystemChar* headName) {
{
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::FPrintf(m_sout, _SYS_STR("" BOLD "%s" NORMAL "\n"), headName); hecl::FPrintf(m_sout, _SYS_STR("" BOLD "%s" NORMAL "\n"), headName);
else else
hecl::FPrintf(m_sout, _SYS_STR("%s\n"), headName); hecl::FPrintf(m_sout, _SYS_STR("%s\n"), headName);
} }
void optionHead(const hecl::SystemChar* flag, const hecl::SystemChar* synopsis) void optionHead(const hecl::SystemChar* flag, const hecl::SystemChar* synopsis) {
{
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::FPrintf(m_sout, _SYS_STR("" BOLD "%s" NORMAL " (%s)\n"), flag, synopsis); hecl::FPrintf(m_sout, _SYS_STR("" BOLD "%s" NORMAL " (%s)\n"), flag, synopsis);
else else
hecl::FPrintf(m_sout, _SYS_STR("%s (%s)\n"), flag, synopsis); hecl::FPrintf(m_sout, _SYS_STR("%s (%s)\n"), flag, synopsis);
} }
void beginWrap() void beginWrap() { m_wrapBuffer.clear(); }
{
m_wrapBuffer.clear();
}
void wrap(const hecl::SystemChar* str) void wrap(const hecl::SystemChar* str) { m_wrapBuffer += str; }
{
m_wrapBuffer += str;
}
void wrapBold(const hecl::SystemChar* str) void wrapBold(const hecl::SystemChar* str) {
{
if (XTERM_COLOR) if (XTERM_COLOR)
m_wrapBuffer += _SYS_STR("" BOLD ""); m_wrapBuffer += _SYS_STR("" BOLD "");
m_wrapBuffer += str; m_wrapBuffer += str;
@ -246,8 +210,7 @@ public:
m_wrapBuffer += _SYS_STR("" NORMAL ""); m_wrapBuffer += _SYS_STR("" NORMAL "");
} }
void endWrap() void endWrap() {
{
_wrapBuf(m_wrapBuffer); _wrapBuf(m_wrapBuffer);
m_wrapBuffer += _SYS_STR('\n'); m_wrapBuffer += _SYS_STR('\n');
hecl::FPrintf(m_sout, _SYS_STR("%s"), m_wrapBuffer.c_str()); hecl::FPrintf(m_sout, _SYS_STR("%s"), m_wrapBuffer.c_str());
@ -255,9 +218,7 @@ public:
} }
}; };
static hecl::SystemString MakePathArgAbsolute(const hecl::SystemString& arg, static hecl::SystemString MakePathArgAbsolute(const hecl::SystemString& arg, const hecl::SystemString& cwd) {
const hecl::SystemString& cwd)
{
#if _WIN32 #if _WIN32
if (arg.size() >= 2 && iswalpha(arg[0]) && arg[1] == _SYS_STR(':')) if (arg.size() >= 2 && iswalpha(arg[0]) && arg[1] == _SYS_STR(':'))
return arg; return arg;
@ -272,4 +233,3 @@ static hecl::SystemString MakePathArgAbsolute(const hecl::SystemString& arg,
return cwd + _SYS_STR('/') + arg; return cwd + _SYS_STR('/') + arg;
#endif #endif
} }

View File

@ -4,44 +4,35 @@
#include <cstdio> #include <cstdio>
#include "hecl/ClientProcess.hpp" #include "hecl/ClientProcess.hpp"
class ToolCook final : public ToolBase class ToolCook final : public ToolBase {
{
std::vector<hecl::ProjectPath> m_selectedItems; std::vector<hecl::ProjectPath> m_selectedItems;
std::unique_ptr<hecl::Database::Project> m_fallbackProj; std::unique_ptr<hecl::Database::Project> m_fallbackProj;
hecl::Database::Project* m_useProj; hecl::Database::Project* m_useProj;
const hecl::Database::DataSpecEntry* m_spec = nullptr; const hecl::Database::DataSpecEntry* m_spec = nullptr;
bool m_recursive = false; bool m_recursive = false;
bool m_fast = false; bool m_fast = false;
public: public:
ToolCook(const ToolPassInfo& info) ToolCook(const ToolPassInfo& info) : ToolBase(info), m_useProj(info.project) {
: ToolBase(info), m_useProj(info.project)
{
/* Check for recursive flag */ /* Check for recursive flag */
for (hecl::SystemChar arg : info.flags) for (hecl::SystemChar arg : info.flags)
if (arg == _SYS_STR('r')) if (arg == _SYS_STR('r'))
m_recursive = true; m_recursive = true;
/* Scan args */ /* Scan args */
if (info.args.size()) if (info.args.size()) {
{
/* See if project path is supplied via args and use that over the getcwd one */ /* See if project path is supplied via args and use that over the getcwd one */
m_selectedItems.reserve(info.args.size()); m_selectedItems.reserve(info.args.size());
for (const hecl::SystemString& arg : info.args) for (const hecl::SystemString& arg : info.args) {
{
if (arg.empty()) if (arg.empty())
continue; continue;
else if (!arg.compare(_SYS_STR("--fast"))) else if (!arg.compare(_SYS_STR("--fast"))) {
{
m_fast = true; m_fast = true;
continue; continue;
} } else if (arg.size() >= 8 && !arg.compare(0, 7, _SYS_STR("--spec="))) {
else if (arg.size() >= 8 && !arg.compare(0, 7, _SYS_STR("--spec=")))
{
hecl::SystemString specName(arg.begin() + 7, arg.end()); hecl::SystemString specName(arg.begin() + 7, arg.end());
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
{ if (!hecl::StrCaseCmp(spec->m_name.data(), specName.c_str())) {
if (!hecl::StrCaseCmp(spec->m_name.data(), specName.c_str()))
{
m_spec = spec; m_spec = spec;
break; break;
} }
@ -49,20 +40,16 @@ public:
if (!m_spec) if (!m_spec)
LogModule.report(logvisor::Fatal, "unable to find data spec '%s'", specName.c_str()); LogModule.report(logvisor::Fatal, "unable to find data spec '%s'", specName.c_str());
continue; continue;
} } else if (arg.size() >= 2 && arg[0] == _SYS_STR('-') && arg[1] == _SYS_STR('-'))
else if (arg.size() >= 2 && arg[0] == _SYS_STR('-') && arg[1] == _SYS_STR('-'))
continue; continue;
hecl::SystemString subPath; hecl::SystemString subPath;
hecl::ProjectRootPath root = hecl::SearchForProject(MakePathArgAbsolute(arg, info.cwd), subPath); hecl::ProjectRootPath root = hecl::SearchForProject(MakePathArgAbsolute(arg, info.cwd), subPath);
if (root) if (root) {
{ if (!m_fallbackProj) {
if (!m_fallbackProj)
{
m_fallbackProj.reset(new hecl::Database::Project(root)); m_fallbackProj.reset(new hecl::Database::Project(root));
m_useProj = m_fallbackProj.get(); m_useProj = m_fallbackProj.get();
} } else if (m_fallbackProj->getProjectRootPath() != root)
else if (m_fallbackProj->getProjectRootPath() != root)
LogModule.report(logvisor::Fatal, LogModule.report(logvisor::Fatal,
_SYS_STR("hecl cook can only process multiple items in the same project; ") _SYS_STR("hecl cook can only process multiple items in the same project; ")
_SYS_STR("'%s' and '%s' are different projects"), _SYS_STR("'%s' and '%s' are different projects"),
@ -78,16 +65,14 @@ public:
"provided a path within a project"); "provided a path within a project");
/* Default case: recursive at root */ /* Default case: recursive at root */
if (m_selectedItems.empty()) if (m_selectedItems.empty()) {
{
m_selectedItems.reserve(1); m_selectedItems.reserve(1);
m_selectedItems.push_back({hecl::ProjectPath(*m_useProj, _SYS_STR(""))}); m_selectedItems.push_back({hecl::ProjectPath(*m_useProj, _SYS_STR(""))});
m_recursive = true; m_recursive = true;
} }
} }
static void Help(HelpOutput& help) static void Help(HelpOutput& help) {
{
help.secHead(_SYS_STR("NAME")); help.secHead(_SYS_STR("NAME"));
help.beginWrap(); help.beginWrap();
help.wrap(_SYS_STR("hecl-cook - Cook objects within the project database\n")); help.wrap(_SYS_STR("hecl-cook - Cook objects within the project database\n"));
@ -114,8 +99,8 @@ public:
help.wrap(_SYS_STR(" images). If the dependent files are unable to be found, the cook process aborts.\n\n")); help.wrap(_SYS_STR(" images). If the dependent files are unable to be found, the cook process aborts.\n\n"));
help.wrapBold(_SYS_STR("- Modtime Comparison: ")); help.wrapBold(_SYS_STR("- Modtime Comparison: "));
help.wrap(_SYS_STR("Files that have previously finished a cook pass are inspected for their time of ") help.wrap(_SYS_STR("Files that have previously finished a cook pass are inspected for their time of ")
_SYS_STR("last modification. If the file hasn't changed since its previous cook-pass, the ") _SYS_STR("last modification. If the file hasn't changed since its previous cook-pass, the ") _SYS_STR(
_SYS_STR("process is skipped. If the file has been moved or deleted, the object is automatically ") "process is skipped. If the file has been moved or deleted, the object is automatically ")
_SYS_STR("removed from the project database.\n\n")); _SYS_STR("removed from the project database.\n\n"));
help.wrapBold(_SYS_STR("- Cook: ")); help.wrapBold(_SYS_STR("- Cook: "));
help.wrap(_SYS_STR("A type-specific procedure compiles the file's contents into an efficient format ") help.wrap(_SYS_STR("A type-specific procedure compiles the file's contents into an efficient format ")
@ -151,8 +136,7 @@ public:
help.beginWrap(); help.beginWrap();
help.wrap(_SYS_STR("Specifies a DataSpec to use when cooking. ") help.wrap(_SYS_STR("Specifies a DataSpec to use when cooking. ")
_SYS_STR("This build of hecl supports the following values of <spec>:\n")); _SYS_STR("This build of hecl supports the following values of <spec>:\n"));
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
{
if (!spec->m_factory) if (!spec->m_factory)
continue; continue;
help.wrap(_SYS_STR(" ")); help.wrap(_SYS_STR(" "));
@ -161,10 +145,9 @@ public:
} }
} }
hecl::SystemString toolName() const {return _SYS_STR("cook");} hecl::SystemString toolName() const { return _SYS_STR("cook"); }
int run() int run() {
{
hecl::MultiProgressPrinter printer(true); hecl::MultiProgressPrinter printer(true);
hecl::ClientProcess cp(&printer); hecl::ClientProcess cp(&printer);
for (const hecl::ProjectPath& path : m_selectedItems) for (const hecl::ProjectPath& path : m_selectedItems)
@ -173,9 +156,5 @@ public:
return 0; return 0;
} }
void cancel() void cancel() { m_useProj->interruptCook(); }
{
m_useProj->interruptCook();
}
}; };

View File

@ -11,15 +11,12 @@
#include "hecl/MultiProgressPrinter.hpp" #include "hecl/MultiProgressPrinter.hpp"
class ToolExtract final : public ToolBase class ToolExtract final : public ToolBase {
{
hecl::Database::IDataSpec::ExtractPassInfo m_einfo; hecl::Database::IDataSpec::ExtractPassInfo m_einfo;
struct SpecExtractPass struct SpecExtractPass {
{
const hecl::Database::DataSpecEntry* m_entry; const hecl::Database::DataSpecEntry* m_entry;
std::unique_ptr<hecl::Database::IDataSpec> m_instance; std::unique_ptr<hecl::Database::IDataSpec> m_instance;
SpecExtractPass(const hecl::Database::DataSpecEntry* entry, SpecExtractPass(const hecl::Database::DataSpecEntry* entry, std::unique_ptr<hecl::Database::IDataSpec>&& instance)
std::unique_ptr<hecl::Database::IDataSpec>&& instance)
: m_entry(entry), m_instance(std::move(instance)) {} : m_entry(entry), m_instance(std::move(instance)) {}
SpecExtractPass(const SpecExtractPass& other) = delete; SpecExtractPass(const SpecExtractPass& other) = delete;
SpecExtractPass(SpecExtractPass&& other) = default; SpecExtractPass(SpecExtractPass&& other) = default;
@ -28,19 +25,16 @@ class ToolExtract final : public ToolBase
std::vector<hecl::Database::IDataSpec::ExtractReport> m_reps; std::vector<hecl::Database::IDataSpec::ExtractReport> m_reps;
std::unique_ptr<hecl::Database::Project> m_fallbackProj; std::unique_ptr<hecl::Database::Project> m_fallbackProj;
hecl::Database::Project* m_useProj = nullptr; hecl::Database::Project* m_useProj = nullptr;
public: public:
ToolExtract(const ToolPassInfo& info) ToolExtract(const ToolPassInfo& info) : ToolBase(info) {
: ToolBase(info)
{
if (!m_info.args.size()) if (!m_info.args.size())
LogModule.report(logvisor::Fatal, "hecl extract needs a source path as its first argument"); LogModule.report(logvisor::Fatal, "hecl extract needs a source path as its first argument");
if (!info.project) if (!info.project) {
{
hecl::SystemString rootDir; hecl::SystemString rootDir;
if (info.output.empty()) if (info.output.empty()) {
{
/* Get name from input file and init project there */ /* Get name from input file and init project there */
hecl::SystemString baseFile = info.args.front(); hecl::SystemString baseFile = info.args.front();
size_t slashPos = baseFile.rfind(_SYS_STR('/')); size_t slashPos = baseFile.rfind(_SYS_STR('/'));
@ -56,9 +50,7 @@ public:
LogModule.report(logvisor::Fatal, "hecl extract must be ran within a project directory"); LogModule.report(logvisor::Fatal, "hecl extract must be ran within a project directory");
rootDir = info.cwd + baseFile; rootDir = info.cwd + baseFile;
} } else {
else
{
if (hecl::PathRelative(info.output.c_str())) if (hecl::PathRelative(info.output.c_str()))
rootDir = info.cwd + info.output; rootDir = info.cwd + info.output;
else else
@ -73,23 +65,20 @@ public:
LogModule.report(logvisor::Fatal, "unable to init project at '%s'", rootDir.c_str()); LogModule.report(logvisor::Fatal, "unable to init project at '%s'", rootDir.c_str());
LogModule.report(logvisor::Info, _SYS_STR("initialized project at '%s/.hecl'"), rootDir.c_str()); LogModule.report(logvisor::Info, _SYS_STR("initialized project at '%s/.hecl'"), rootDir.c_str());
m_useProj = m_fallbackProj.get(); m_useProj = m_fallbackProj.get();
} } else
else
m_useProj = info.project; m_useProj = info.project;
m_einfo.srcpath = m_info.args.front(); m_einfo.srcpath = m_info.args.front();
m_einfo.force = info.force; m_einfo.force = info.force;
m_einfo.extractArgs.reserve(info.args.size()); m_einfo.extractArgs.reserve(info.args.size());
auto it=info.args.cbegin(); auto it = info.args.cbegin();
++it; ++it;
for (; it != info.args.cend(); ++it) for (; it != info.args.cend(); ++it)
m_einfo.extractArgs.push_back(*it); m_einfo.extractArgs.push_back(*it);
m_specPasses.reserve(hecl::Database::DATA_SPEC_REGISTRY.size()); m_specPasses.reserve(hecl::Database::DATA_SPEC_REGISTRY.size());
for (const hecl::Database::DataSpecEntry* entry : hecl::Database::DATA_SPEC_REGISTRY) for (const hecl::Database::DataSpecEntry* entry : hecl::Database::DATA_SPEC_REGISTRY) {
{ if (entry->m_factory) {
if (entry->m_factory)
{
auto ds = entry->m_factory(*m_useProj, hecl::Database::DataSpecTool::Extract); auto ds = entry->m_factory(*m_useProj, hecl::Database::DataSpecTool::Extract);
if (ds && ds->canExtract(m_einfo, m_reps)) if (ds && ds->canExtract(m_einfo, m_reps))
m_specPasses.emplace_back(entry, std::move(ds)); m_specPasses.emplace_back(entry, std::move(ds));
@ -97,8 +86,7 @@ public:
} }
} }
static void Help(HelpOutput& help) static void Help(HelpOutput& help) {
{
help.secHead(_SYS_STR("NAME")); help.secHead(_SYS_STR("NAME"));
help.beginWrap(); help.beginWrap();
help.wrap(_SYS_STR("hecl-extract - Extract objects from supported package/image formats\n")); help.wrap(_SYS_STR("hecl-extract - Extract objects from supported package/image formats\n"));
@ -124,11 +112,10 @@ public:
help.endWrap(); help.endWrap();
} }
hecl::SystemString toolName() const {return _SYS_STR("extract");} hecl::SystemString toolName() const { return _SYS_STR("extract"); }
static void _recursivePrint(int level, hecl::Database::IDataSpec::ExtractReport& rep) static void _recursivePrint(int level, hecl::Database::IDataSpec::ExtractReport& rep) {
{ for (int l = 0; l < level; ++l)
for (int l=0 ; l<level ; ++l)
hecl::Printf(_SYS_STR(" ")); hecl::Printf(_SYS_STR(" "));
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::Printf(_SYS_STR("" BOLD "%s" NORMAL ""), rep.name.c_str()); hecl::Printf(_SYS_STR("" BOLD "%s" NORMAL ""), rep.name.c_str());
@ -142,10 +129,8 @@ public:
_recursivePrint(level + 1, child); _recursivePrint(level + 1, child);
} }
int run() int run() {
{ if (m_specPasses.empty()) {
if (m_specPasses.empty())
{
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::Printf(_SYS_STR("" RED BOLD "NOTHING TO EXTRACT" NORMAL "\n")); hecl::Printf(_SYS_STR("" RED BOLD "NOTHING TO EXTRACT" NORMAL "\n"));
else else
@ -158,17 +143,14 @@ public:
else else
hecl::Printf(_SYS_STR("ABOUT TO EXTRACT:\n")); hecl::Printf(_SYS_STR("ABOUT TO EXTRACT:\n"));
for (hecl::Database::IDataSpec::ExtractReport& rep : m_reps) for (hecl::Database::IDataSpec::ExtractReport& rep : m_reps) {
{
_recursivePrint(0, rep); _recursivePrint(0, rep);
hecl::Printf(_SYS_STR("\n")); hecl::Printf(_SYS_STR("\n"));
} }
fflush(stdout); fflush(stdout);
if (continuePrompt()) if (continuePrompt()) {
{ for (SpecExtractPass& ds : m_specPasses) {
for (SpecExtractPass& ds : m_specPasses)
{
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::Printf(_SYS_STR("" MAGENTA BOLD "Using DataSpec %s:" NORMAL "\n"), ds.m_entry->m_name.data()); hecl::Printf(_SYS_STR("" MAGENTA BOLD "Using DataSpec %s:" NORMAL "\n"), ds.m_entry->m_name.data());
else else
@ -182,4 +164,3 @@ public:
return 0; return 0;
} }
}; };

View File

@ -4,59 +4,51 @@
#include <cstdio> #include <cstdio>
#include <functional> #include <functional>
class ToolHelp final : public ToolBase class ToolHelp final : public ToolBase {
{
public: public:
ToolHelp(const ToolPassInfo& info) ToolHelp(const ToolPassInfo& info) : ToolBase(info) {
: ToolBase(info) if (m_info.args.empty()) {
{
if (m_info.args.empty())
{
LogModule.report(logvisor::Error, "help requires a tool name argument"); LogModule.report(logvisor::Error, "help requires a tool name argument");
return; return;
} }
m_good = true; m_good = true;
} }
~ToolHelp() ~ToolHelp() {}
{
}
static void Help(HelpOutput& help) {
static void Help(HelpOutput& help)
{
help.printBold( help.printBold(
_SYS_STR(" ___________ \n") _SYS_STR(" ___________ \n") _SYS_STR(
_SYS_STR(" ,.-'\"...........``~., \n") " ,.-'\"...........``~., \n") _SYS_STR(" "
_SYS_STR(" ,.-\".......................\"-., \n") ",.-\".......................\"-., \n")
_SYS_STR(" ,/..................................\":, \n") _SYS_STR(" ,/..................................\":, \n") _SYS_STR(
_SYS_STR(" .,?........................................, \n") " .,?........................................, \n")
_SYS_STR(" /...........................................,}\n") _SYS_STR(" /...........................................,}\n") _SYS_STR(
_SYS_STR(" ./........................................,:`^`..}\n") " ./........................................,:`^`..}\n")
_SYS_STR(" ./.......................................,:\"...../\n") _SYS_STR(" ./.......................................,:\"...../\n") _SYS_STR(
_SYS_STR(" ?.....__..................................:`...../\n") " ?.....__..................................:`...../\n")
_SYS_STR(" /__.(...\"~-,_...........................,:`....../\n") _SYS_STR(" /__.(...\"~-,_...........................,:`....../\n") _SYS_STR(
_SYS_STR(" /(_....\"~,_....\"~,_.....................,:`...._/ \n") " /(_....\"~,_....\"~,_.....................,:`...._/ \n")
_SYS_STR(" {.._$;_....\"=,_.....\"-,_......,.-~-,},.~\";/....} \n") _SYS_STR(" {.._$;_....\"=,_.....\"-,_......,.-~-,},.~\";/....} \n") _SYS_STR(
_SYS_STR(" ((...*~_......\"=-._...\";,,./`........../\"..../ \n") " ((...*~_......\"=-._...\";,,./`........../\"..../ \n")
_SYS_STR(" ,,,___.`~,......\"~.,....................`......}....../ \n") _SYS_STR(" ,,,___.`~,......\"~.,....................`......}....../ \n") _SYS_STR(
_SYS_STR("............(....`=-,,...`.........................(...;_,,-\" \n") "............(....`=-,,...`.........................(...;_,,-\" \n")
_SYS_STR("............/.`~,......`-.................................../ \n") _SYS_STR("............/.`~,......`-.................................../ \n")
_SYS_STR(".............`~.*-,.....................................|,./...,__ \n") _SYS_STR(".............`~.*-,.....................................|,./...,__ "
_SYS_STR(",,_..........}.>-._...................................|.......`=~-, \n") "\n") _SYS_STR(",,_..........}.>-._..................................."
_SYS_STR(".....`=~-,__......`,................................. \n") "|.......`=~-, \n") _SYS_STR(
".....`=~-,__......`,................................. \n")
_SYS_STR("...................`=~-,,.,........................... \n") _SYS_STR("...................`=~-,,.,........................... \n")
_SYS_STR(".........................`:,,..........................`\n") _SYS_STR(".........................`:,,..........................`\n")
_SYS_STR("...........................`=-,...............,%%`>--==`` \n") _SYS_STR(
_SYS_STR(".................................._.........._,-%%...` \n") "...........................`=-,...............,%%`>--==`` \n")
_SYS_STR(
".................................._.........._,-%%...` \n")
_SYS_STR("...................................,\n")); _SYS_STR("...................................,\n"));
} }
static void ShowHelp(const hecl::SystemString& toolName) static void ShowHelp(const hecl::SystemString& toolName) {
{
/* Select tool's help-text streamer */ /* Select tool's help-text streamer */
HelpOutput::HelpFunc helpFunc = NULL; HelpOutput::HelpFunc helpFunc = NULL;
if (toolName == _SYS_STR("init")) if (toolName == _SYS_STR("init"))
@ -71,8 +63,7 @@ public:
helpFunc = ToolPackage::Help; helpFunc = ToolPackage::Help;
else if (toolName == _SYS_STR("help")) else if (toolName == _SYS_STR("help"))
helpFunc = ToolHelp::Help; helpFunc = ToolHelp::Help;
else else {
{
LogModule.report(logvisor::Error, _SYS_STR("unrecognized tool '%s' - can't help"), toolName.c_str()); LogModule.report(logvisor::Error, _SYS_STR("unrecognized tool '%s' - can't help"), toolName.c_str());
return; return;
} }
@ -81,12 +72,10 @@ public:
ho.go(); ho.go();
} }
hecl::SystemString toolName() const {return _SYS_STR("help");} hecl::SystemString toolName() const { return _SYS_STR("help"); }
int run() int run() {
{
ShowHelp(m_info.args.front()); ShowHelp(m_info.args.front());
return 0; return 0;
} }
}; };

View File

@ -10,34 +10,27 @@
#include "nod/DiscWii.hpp" #include "nod/DiscWii.hpp"
#include "athena/FileReader.hpp" #include "athena/FileReader.hpp"
class ToolImage final : public ToolBase class ToolImage final : public ToolBase {
{
std::unique_ptr<hecl::Database::Project> m_fallbackProj; std::unique_ptr<hecl::Database::Project> m_fallbackProj;
hecl::Database::Project* m_useProj; hecl::Database::Project* m_useProj;
public: public:
ToolImage(const ToolPassInfo& info) ToolImage(const ToolPassInfo& info) : ToolBase(info), m_useProj(info.project) {
: ToolBase(info), m_useProj(info.project)
{
if (!info.project) if (!info.project)
LogModule.report(logvisor::Fatal, "hecl image must be ran within a project directory"); LogModule.report(logvisor::Fatal, "hecl image must be ran within a project directory");
/* Scan args */ /* Scan args */
if (info.args.size()) if (info.args.size()) {
{
/* See if project path is supplied via args and use that over the getcwd one */ /* See if project path is supplied via args and use that over the getcwd one */
for (const hecl::SystemString& arg : info.args) for (const hecl::SystemString& arg : info.args) {
{
if (arg.empty()) if (arg.empty())
continue; continue;
hecl::SystemString subPath; hecl::SystemString subPath;
hecl::ProjectRootPath root = hecl::SearchForProject(MakePathArgAbsolute(arg, info.cwd), subPath); hecl::ProjectRootPath root = hecl::SearchForProject(MakePathArgAbsolute(arg, info.cwd), subPath);
if (root) if (root) {
{ if (!m_fallbackProj) {
if (!m_fallbackProj)
{
m_fallbackProj.reset(new hecl::Database::Project(root)); m_fallbackProj.reset(new hecl::Database::Project(root));
m_useProj = m_fallbackProj.get(); m_useProj = m_fallbackProj.get();
break; break;
@ -51,12 +44,9 @@ public:
"provided a path within a project"); "provided a path within a project");
} }
~ToolImage() ~ToolImage() {}
{
}
static void Help(HelpOutput& help) static void Help(HelpOutput& help) {
{
help.secHead(_SYS_STR("NAME")); help.secHead(_SYS_STR("NAME"));
help.beginWrap(); help.beginWrap();
help.wrap(_SYS_STR("hecl-image - Generate GameCube/Wii disc image from packaged files\n")); help.wrap(_SYS_STR("hecl-image - Generate GameCube/Wii disc image from packaged files\n"));
@ -81,10 +71,9 @@ public:
help.endWrap(); help.endWrap();
} }
hecl::SystemString toolName() const {return _SYS_STR("image");} hecl::SystemString toolName() const { return _SYS_STR("image"); }
int run() int run() {
{
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::Printf(_SYS_STR("" GREEN BOLD "ABOUT TO IMAGE:" NORMAL "\n")); hecl::Printf(_SYS_STR("" GREEN BOLD "ABOUT TO IMAGE:" NORMAL "\n"));
else else
@ -93,25 +82,21 @@ public:
hecl::Printf(_SYS_STR(" %s\n"), m_useProj->getProjectRootPath().getAbsolutePath().data()); hecl::Printf(_SYS_STR(" %s\n"), m_useProj->getProjectRootPath().getAbsolutePath().data());
fflush(stdout); fflush(stdout);
if (continuePrompt()) if (continuePrompt()) {
{
hecl::ProjectPath outPath(m_useProj->getProjectWorkingPath(), _SYS_STR("out")); hecl::ProjectPath outPath(m_useProj->getProjectWorkingPath(), _SYS_STR("out"));
if (!outPath.isDirectory()) if (!outPath.isDirectory()) {
{
LogModule.report(logvisor::Error, _SYS_STR("%s is not a directory"), outPath.getAbsolutePath().data()); LogModule.report(logvisor::Error, _SYS_STR("%s is not a directory"), outPath.getAbsolutePath().data());
return 1; return 1;
} }
hecl::ProjectPath bootBinPath(outPath, _SYS_STR("sys/boot.bin")); hecl::ProjectPath bootBinPath(outPath, _SYS_STR("sys/boot.bin"));
if (!bootBinPath.isFile()) if (!bootBinPath.isFile()) {
{
LogModule.report(logvisor::Error, _SYS_STR("%s is not a file"), bootBinPath.getAbsolutePath().data()); LogModule.report(logvisor::Error, _SYS_STR("%s is not a file"), bootBinPath.getAbsolutePath().data());
return 1; return 1;
} }
athena::io::FileReader r(bootBinPath.getAbsolutePath()); athena::io::FileReader r(bootBinPath.getAbsolutePath());
if (r.hasError()) if (r.hasError()) {
{
LogModule.report(logvisor::Error, _SYS_STR("unable to open %s"), bootBinPath.getAbsolutePath().data()); LogModule.report(logvisor::Error, _SYS_STR("unable to open %s"), bootBinPath.getAbsolutePath().data());
return 1; return 1;
} }
@ -121,12 +106,10 @@ public:
hecl::SystemStringConv idView(id); hecl::SystemStringConv idView(id);
hecl::SystemString fileOut = hecl::SystemString(outPath.getAbsolutePath()) + _SYS_STR('/') + idView.c_str(); hecl::SystemString fileOut = hecl::SystemString(outPath.getAbsolutePath()) + _SYS_STR('/') + idView.c_str();
hecl::MultiProgressPrinter printer(true); hecl::MultiProgressPrinter printer(true);
auto progFunc = [&printer](float totalProg, nod::SystemStringView fileName, size_t fileBytesXfered) auto progFunc = [&printer](float totalProg, nod::SystemStringView fileName, size_t fileBytesXfered) {
{
printer.print(fileName.data(), nullptr, totalProg); printer.print(fileName.data(), nullptr, totalProg);
}; };
if (id[0] == 'G') if (id[0] == 'G') {
{
fileOut += _SYS_STR(".gcm"); fileOut += _SYS_STR(".gcm");
if (nod::DiscBuilderGCN::CalculateTotalSizeRequired(outPath.getAbsolutePath()) == -1) if (nod::DiscBuilderGCN::CalculateTotalSizeRequired(outPath.getAbsolutePath()) == -1)
return 1; return 1;
@ -134,9 +117,7 @@ public:
nod::DiscBuilderGCN db(fileOut, progFunc); nod::DiscBuilderGCN db(fileOut, progFunc);
if (db.buildFromDirectory(outPath.getAbsolutePath()) != nod::EBuildResult::Success) if (db.buildFromDirectory(outPath.getAbsolutePath()) != nod::EBuildResult::Success)
return 1; return 1;
} } else {
else
{
fileOut += _SYS_STR(".iso"); fileOut += _SYS_STR(".iso");
bool dualLayer; bool dualLayer;
if (nod::DiscBuilderWii::CalculateTotalSizeRequired(outPath.getAbsolutePath(), dualLayer) == -1) if (nod::DiscBuilderWii::CalculateTotalSizeRequired(outPath.getAbsolutePath(), dualLayer) == -1)
@ -154,4 +135,3 @@ public:
}; };
#endif #endif

View File

@ -3,13 +3,11 @@
#include "ToolBase.hpp" #include "ToolBase.hpp"
#include <cstdio> #include <cstdio>
class ToolInit final : public ToolBase class ToolInit final : public ToolBase {
{
const hecl::SystemString* m_dir = NULL; const hecl::SystemString* m_dir = NULL;
public: public:
ToolInit(const ToolPassInfo& info) ToolInit(const ToolPassInfo& info) : ToolBase(info) {
: ToolBase(info)
{
hecl::Sstat theStat; hecl::Sstat theStat;
const hecl::SystemString* dir; const hecl::SystemString* dir;
if (info.args.size()) if (info.args.size())
@ -17,24 +15,20 @@ public:
else else
dir = &info.cwd; dir = &info.cwd;
if (hecl::Stat(dir->c_str(), &theStat)) if (hecl::Stat(dir->c_str(), &theStat)) {
{
hecl::MakeDir(dir->c_str()); hecl::MakeDir(dir->c_str());
if (hecl::Stat(dir->c_str(), &theStat)) if (hecl::Stat(dir->c_str(), &theStat)) {
{
LogModule.report(logvisor::Fatal, _SYS_STR("unable to stat '%s'"), dir->c_str()); LogModule.report(logvisor::Fatal, _SYS_STR("unable to stat '%s'"), dir->c_str());
return; return;
} }
} }
if (!S_ISDIR(theStat.st_mode)) if (!S_ISDIR(theStat.st_mode)) {
{
LogModule.report(logvisor::Fatal, _SYS_STR("'%s' is not a directory"), dir->c_str()); LogModule.report(logvisor::Fatal, _SYS_STR("'%s' is not a directory"), dir->c_str());
return; return;
} }
hecl::SystemString testPath = *dir + _SYS_STR("/.hecl/beacon"); hecl::SystemString testPath = *dir + _SYS_STR("/.hecl/beacon");
if (!hecl::Stat(testPath.c_str(), &theStat)) if (!hecl::Stat(testPath.c_str(), &theStat)) {
{
LogModule.report(logvisor::Fatal, _SYS_STR("project already exists at '%s'"), dir->c_str()); LogModule.report(logvisor::Fatal, _SYS_STR("project already exists at '%s'"), dir->c_str());
return; return;
} }
@ -42,8 +36,7 @@ public:
m_dir = dir; m_dir = dir;
} }
int run() int run() {
{
if (!m_dir) if (!m_dir)
return 1; return 1;
size_t ErrorRef = logvisor::ErrorCount; size_t ErrorRef = logvisor::ErrorCount;
@ -54,8 +47,7 @@ public:
return 0; return 0;
} }
static void Help(HelpOutput& help) static void Help(HelpOutput& help) {
{
help.secHead(_SYS_STR("NAME")); help.secHead(_SYS_STR("NAME"));
help.beginWrap(); help.beginWrap();
help.wrap(_SYS_STR("hecl-init - Initialize a brand-new project database\n")); help.wrap(_SYS_STR("hecl-init - Initialize a brand-new project database\n"));
@ -81,6 +73,5 @@ public:
help.endWrap(); help.endWrap();
} }
hecl::SystemString toolName() const {return _SYS_STR("init");} hecl::SystemString toolName() const { return _SYS_STR("init"); }
}; };

View File

@ -5,29 +5,25 @@
#include "ToolBase.hpp" #include "ToolBase.hpp"
#include <cstdio> #include <cstdio>
class ToolPackage final : public ToolBase class ToolPackage final : public ToolBase {
{
std::vector<hecl::ProjectPath> m_selectedItems; std::vector<hecl::ProjectPath> m_selectedItems;
std::unique_ptr<hecl::Database::Project> m_fallbackProj; std::unique_ptr<hecl::Database::Project> m_fallbackProj;
hecl::Database::Project* m_useProj; hecl::Database::Project* m_useProj;
const hecl::Database::DataSpecEntry* m_spec = nullptr; const hecl::Database::DataSpecEntry* m_spec = nullptr;
bool m_fast = false; bool m_fast = false;
void AddSelectedItem(const hecl::ProjectPath& path) void AddSelectedItem(const hecl::ProjectPath& path) {
{
for (const hecl::ProjectPath& item : m_selectedItems) for (const hecl::ProjectPath& item : m_selectedItems)
if (item == path) if (item == path)
return; return;
m_selectedItems.push_back(path); m_selectedItems.push_back(path);
} }
void CheckFile(const hecl::ProjectPath& path) void CheckFile(const hecl::ProjectPath& path) {
{
if (!hecl::StrCmp(path.getLastComponent().data(), _SYS_STR("!world.blend"))) if (!hecl::StrCmp(path.getLastComponent().data(), _SYS_STR("!world.blend")))
AddSelectedItem(path); AddSelectedItem(path);
#if RUNTIME_ORIGINAL_IDS #if RUNTIME_ORIGINAL_IDS
else if (!hecl::StrCmp(path.getLastComponent().data(), _SYS_STR("!original_ids.yaml"))) else if (!hecl::StrCmp(path.getLastComponent().data(), _SYS_STR("!original_ids.yaml"))) {
{
auto pathComps = path.getPathComponents(); auto pathComps = path.getPathComponents();
if (pathComps.size() == 2 && pathComps[0] != _SYS_STR("out")) if (pathComps.size() == 2 && pathComps[0] != _SYS_STR("out"))
AddSelectedItem(path); AddSelectedItem(path);
@ -35,19 +31,16 @@ class ToolPackage final : public ToolBase
#endif #endif
} }
void FindSelectedItems(const hecl::ProjectPath& path, bool checkGeneral) void FindSelectedItems(const hecl::ProjectPath& path, bool checkGeneral) {
{ if (path.isFile()) {
if (path.isFile())
{
CheckFile(path); CheckFile(path);
return; return;
} }
size_t origSize = m_selectedItems.size(); size_t origSize = m_selectedItems.size();
hecl::DirectoryEnumerator dEnum(path.getAbsolutePath(), hecl::DirectoryEnumerator dEnum(path.getAbsolutePath(), hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted, false,
hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true); false, true);
for (const auto& ent : dEnum) for (const auto& ent : dEnum) {
{
hecl::ProjectPath childPath(path, ent.m_name); hecl::ProjectPath childPath(path, ent.m_name);
if (ent.m_isDir) if (ent.m_isDir)
FindSelectedItems(childPath, checkGeneral && childPath.getPathComponents().size() <= 2); FindSelectedItems(childPath, checkGeneral && childPath.getPathComponents().size() <= 2);
@ -57,43 +50,33 @@ class ToolPackage final : public ToolBase
/* Directory with 2 components not "Shared" or macOS app bundle /* Directory with 2 components not "Shared" or macOS app bundle
* and no nested !world.blend files == General PAK */ * and no nested !world.blend files == General PAK */
if (checkGeneral && origSize == m_selectedItems.size()) if (checkGeneral && origSize == m_selectedItems.size()) {
{
auto pathComps = path.getPathComponents(); auto pathComps = path.getPathComponents();
if (pathComps.size() == 2 && pathComps[0] != _SYS_STR("out") && if (pathComps.size() == 2 && pathComps[0] != _SYS_STR("out") && pathComps[1] != _SYS_STR("Shared") &&
pathComps[1] != _SYS_STR("Shared") && pathComps[0].find(_SYS_STR(".app")) == hecl::SystemString::npos) pathComps[0].find(_SYS_STR(".app")) == hecl::SystemString::npos)
AddSelectedItem(path); AddSelectedItem(path);
} }
} }
public: public:
ToolPackage(const ToolPassInfo& info) ToolPackage(const ToolPassInfo& info) : ToolBase(info), m_useProj(info.project) {
: ToolBase(info), m_useProj(info.project)
{
if (!info.project) if (!info.project)
LogModule.report(logvisor::Fatal, "hecl package must be ran within a project directory"); LogModule.report(logvisor::Fatal, "hecl package must be ran within a project directory");
/* Scan args */ /* Scan args */
if (info.args.size()) if (info.args.size()) {
{
/* See if project path is supplied via args and use that over the getcwd one */ /* See if project path is supplied via args and use that over the getcwd one */
m_selectedItems.reserve(info.args.size()); m_selectedItems.reserve(info.args.size());
for (const hecl::SystemString& arg : info.args) for (const hecl::SystemString& arg : info.args) {
{
if (arg.empty()) if (arg.empty())
continue; continue;
else if (!arg.compare(_SYS_STR("--fast"))) else if (!arg.compare(_SYS_STR("--fast"))) {
{
m_fast = true; m_fast = true;
continue; continue;
} } else if (arg.size() >= 8 && !arg.compare(0, 7, _SYS_STR("--spec="))) {
else if (arg.size() >= 8 && !arg.compare(0, 7, _SYS_STR("--spec=")))
{
hecl::SystemString specName(arg.begin() + 7, arg.end()); hecl::SystemString specName(arg.begin() + 7, arg.end());
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
{ if (!hecl::StrCaseCmp(spec->m_name.data(), specName.c_str())) {
if (!hecl::StrCaseCmp(spec->m_name.data(), specName.c_str()))
{
m_spec = spec; m_spec = spec;
break; break;
} }
@ -101,21 +84,17 @@ public:
if (!m_spec) if (!m_spec)
LogModule.report(logvisor::Fatal, "unable to find data spec '%s'", specName.c_str()); LogModule.report(logvisor::Fatal, "unable to find data spec '%s'", specName.c_str());
continue; continue;
} } else if (arg.size() >= 2 && arg[0] == _SYS_STR('-') && arg[1] == _SYS_STR('-'))
else if (arg.size() >= 2 && arg[0] == _SYS_STR('-') && arg[1] == _SYS_STR('-'))
continue; continue;
hecl::SystemString subPath; hecl::SystemString subPath;
hecl::ProjectRootPath root = hecl::SearchForProject(MakePathArgAbsolute(arg, info.cwd), subPath); hecl::ProjectRootPath root = hecl::SearchForProject(MakePathArgAbsolute(arg, info.cwd), subPath);
if (root) if (root) {
{ if (!m_fallbackProj) {
if (!m_fallbackProj)
{
m_fallbackProj.reset(new hecl::Database::Project(root)); m_fallbackProj.reset(new hecl::Database::Project(root));
m_useProj = m_fallbackProj.get(); m_useProj = m_fallbackProj.get();
} } else if (m_fallbackProj->getProjectRootPath() != root)
else if (m_fallbackProj->getProjectRootPath() != root)
LogModule.report(logvisor::Fatal, LogModule.report(logvisor::Fatal,
_SYS_STR("hecl package can only process multiple items in the same project; ") _SYS_STR("hecl package can only process multiple items in the same project; ")
_SYS_STR("'%s' and '%s' are different projects"), _SYS_STR("'%s' and '%s' are different projects"),
@ -136,12 +115,10 @@ public:
FindSelectedItems({*m_useProj, _SYS_STR("")}, true); FindSelectedItems({*m_useProj, _SYS_STR("")}, true);
} }
static void Help(HelpOutput& help) static void Help(HelpOutput& help) {
{
help.secHead(_SYS_STR("NAME")); help.secHead(_SYS_STR("NAME"));
help.beginWrap(); help.beginWrap();
help.wrap(_SYS_STR("hecl-pack\n") help.wrap(_SYS_STR("hecl-pack\n") _SYS_STR("hecl-package - Package objects within the project database\n"));
_SYS_STR("hecl-package - Package objects within the project database\n"));
help.endWrap(); help.endWrap();
help.secHead(_SYS_STR("SYNOPSIS")); help.secHead(_SYS_STR("SYNOPSIS"));
@ -152,8 +129,8 @@ public:
help.secHead(_SYS_STR("DESCRIPTION")); help.secHead(_SYS_STR("DESCRIPTION"));
help.beginWrap(); help.beginWrap();
help.wrap(_SYS_STR("This command initiates a packaging pass on the project database. Packaging ") help.wrap(_SYS_STR("This command initiates a packaging pass on the project database. Packaging ")
_SYS_STR("is analogous to linking in software development. All objects necessary to ") _SYS_STR("is analogous to linking in software development. All objects necessary to ") _SYS_STR(
_SYS_STR("generate a complete package are gathered, grouped, and indexed within a .upak file.\n")); "generate a complete package are gathered, grouped, and indexed within a .upak file.\n"));
help.endWrap(); help.endWrap();
help.secHead(_SYS_STR("OPTIONS")); help.secHead(_SYS_STR("OPTIONS"));
@ -161,8 +138,7 @@ public:
help.beginWrap(); help.beginWrap();
help.wrap(_SYS_STR("Specifies a DataSpec to use when cooking and generating the package. ") help.wrap(_SYS_STR("Specifies a DataSpec to use when cooking and generating the package. ")
_SYS_STR("This build of hecl supports the following values of <spec>:\n")); _SYS_STR("This build of hecl supports the following values of <spec>:\n"));
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
{
if (!spec->m_factory) if (!spec->m_factory)
continue; continue;
help.wrap(_SYS_STR(" ")); help.wrap(_SYS_STR(" "));
@ -180,10 +156,9 @@ public:
help.endWrap(); help.endWrap();
} }
hecl::SystemString toolName() const {return _SYS_STR("package");} hecl::SystemString toolName() const { return _SYS_STR("package"); }
int run() int run() {
{
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::Printf(_SYS_STR("" GREEN BOLD "ABOUT TO PACKAGE:" NORMAL "\n")); hecl::Printf(_SYS_STR("" GREEN BOLD "ABOUT TO PACKAGE:" NORMAL "\n"));
else else
@ -193,12 +168,10 @@ public:
hecl::Printf(_SYS_STR(" %s\n"), item.getRelativePath().data()); hecl::Printf(_SYS_STR(" %s\n"), item.getRelativePath().data());
fflush(stdout); fflush(stdout);
if (continuePrompt()) if (continuePrompt()) {
{
hecl::MultiProgressPrinter printer(true); hecl::MultiProgressPrinter printer(true);
hecl::ClientProcess cp(&printer); hecl::ClientProcess cp(&printer);
for (const hecl::ProjectPath& path : m_selectedItems) for (const hecl::ProjectPath& path : m_selectedItems) {
{
if (!m_useProj->packagePath(path, printer, m_fast, m_spec, &cp)) if (!m_useProj->packagePath(path, printer, m_fast, m_spec, &cp))
LogModule.report(logvisor::Error, _SYS_STR("Unable to package %s"), path.getAbsolutePath().data()); LogModule.report(logvisor::Error, _SYS_STR("Unable to package %s"), path.getAbsolutePath().data());
} }
@ -208,9 +181,5 @@ public:
return 0; return 0;
} }
void cancel() void cancel() { m_useProj->interruptCook(); }
{
m_useProj->interruptCook();
}
}; };

View File

@ -4,24 +4,16 @@
#include <cstdio> #include <cstdio>
#include <map> #include <map>
class ToolSpec final : public ToolBase class ToolSpec final : public ToolBase {
{ enum Mode { MLIST = 0, MENABLE, MDISABLE } mode = MLIST;
enum Mode
{
MLIST = 0,
MENABLE,
MDISABLE
} mode = MLIST;
public: public:
ToolSpec(const ToolPassInfo& info) ToolSpec(const ToolPassInfo& info) : ToolBase(info) {
: ToolBase(info)
{
if (info.args.empty()) if (info.args.empty())
return; return;
if (!info.project) if (!info.project)
LogModule.report(logvisor::Fatal, LogModule.report(logvisor::Fatal, "hecl spec must be ran within a project directory");
"hecl spec must be ran within a project directory");
const auto& specs = info.project->getDataSpecs(); const auto& specs = info.project->getDataSpecs();
hecl::SystemString firstArg = info.args.front(); hecl::SystemString firstArg = info.args.front();
@ -39,28 +31,21 @@ public:
auto it = info.args.begin(); auto it = info.args.begin();
++it; ++it;
for (;it != info.args.end(); for (; it != info.args.end(); ++it) {
++it)
{
bool found = false; bool found = false;
for (auto& spec : specs) for (auto& spec : specs) {
{ if (!it->compare(spec.spec.m_name)) {
if (!it->compare(spec.spec.m_name))
{
found = true; found = true;
break; break;
} }
} }
if (!found) if (!found)
LogModule.report(logvisor::Fatal, LogModule.report(logvisor::Fatal, _SYS_STR("'%s' is not found in the dataspec registry"), it->c_str());
_SYS_STR("'%s' is not found in the dataspec registry"),
it->c_str());
} }
} }
static void Help(HelpOutput& help) static void Help(HelpOutput& help) {
{
help.secHead(_SYS_STR("NAME")); help.secHead(_SYS_STR("NAME"));
help.beginWrap(); help.beginWrap();
help.wrap(_SYS_STR("hecl-spec - Configure target data options\n")); help.wrap(_SYS_STR("hecl-spec - Configure target data options\n"));
@ -73,7 +58,8 @@ public:
help.secHead(_SYS_STR("DESCRIPTION")); help.secHead(_SYS_STR("DESCRIPTION"));
help.beginWrap(); help.beginWrap();
help.wrap(_SYS_STR("This command configures the HECL project with the user's preferred target DataSpecs.\n\n") help.wrap(
_SYS_STR("This command configures the HECL project with the user's preferred target DataSpecs.\n\n")
_SYS_STR("Providing enable/disable argument will bulk-set the enable status of the provided spec(s)") _SYS_STR("Providing enable/disable argument will bulk-set the enable status of the provided spec(s)")
_SYS_STR("list. If enable/disable is not provided, a list of supported DataSpecs is printed.\n\n")); _SYS_STR("list. If enable/disable is not provided, a list of supported DataSpecs is printed.\n\n"));
help.endWrap(); help.endWrap();
@ -85,14 +71,11 @@ public:
help.endWrap(); help.endWrap();
} }
hecl::SystemString toolName() const {return _SYS_STR("spec");} hecl::SystemString toolName() const { return _SYS_STR("spec"); }
int run() int run() {
{ if (!m_info.project) {
if (!m_info.project) for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
{
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY)
{
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::Printf(_SYS_STR("" BOLD CYAN "%s" NORMAL "\n"), spec->m_name.data()); hecl::Printf(_SYS_STR("" BOLD CYAN "%s" NORMAL "\n"), spec->m_name.data());
else else
@ -103,16 +86,13 @@ public:
} }
const auto& specs = m_info.project->getDataSpecs(); const auto& specs = m_info.project->getDataSpecs();
if (mode == MLIST) if (mode == MLIST) {
{ for (auto& spec : specs) {
for (auto& spec : specs)
{
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::Printf(_SYS_STR("" BOLD CYAN "%s" NORMAL ""), spec.spec.m_name.data()); hecl::Printf(_SYS_STR("" BOLD CYAN "%s" NORMAL ""), spec.spec.m_name.data());
else else
hecl::Printf(_SYS_STR("%s"), spec.spec.m_name.data()); hecl::Printf(_SYS_STR("%s"), spec.spec.m_name.data());
if (spec.active) if (spec.active) {
{
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::Printf(_SYS_STR(" " BOLD GREEN "[ENABLED]" NORMAL "")); hecl::Printf(_SYS_STR(" " BOLD GREEN "[ENABLED]" NORMAL ""));
else else
@ -126,24 +106,20 @@ public:
std::vector<hecl::SystemString> opSpecs; std::vector<hecl::SystemString> opSpecs;
auto it = m_info.args.begin(); auto it = m_info.args.begin();
++it; ++it;
for (; it != m_info.args.end() ; ++it) for (; it != m_info.args.end(); ++it) {
{
hecl::SystemString itName = *it; hecl::SystemString itName = *it;
hecl::ToLower(itName); hecl::ToLower(itName);
for (auto& spec : specs) for (auto& spec : specs) {
{
hecl::SystemString compName(spec.spec.m_name); hecl::SystemString compName(spec.spec.m_name);
hecl::ToLower(compName); hecl::ToLower(compName);
if (!itName.compare(compName)) if (!itName.compare(compName)) {
{
opSpecs.emplace_back(spec.spec.m_name); opSpecs.emplace_back(spec.spec.m_name);
break; break;
} }
} }
} }
if (opSpecs.size()) if (opSpecs.size()) {
{
if (mode == MENABLE) if (mode == MENABLE)
m_info.project->enableDataSpecs(opSpecs); m_info.project->enableDataSpecs(opSpecs);
else if (mode == MDISABLE) else if (mode == MDISABLE)
@ -153,4 +129,3 @@ public:
return 0; return 0;
} }
}; };

View File

@ -35,7 +35,6 @@ logvisor::Module LogModule("hecl::Driver");
bool XTERM_COLOR = false; bool XTERM_COLOR = false;
/* /*
#define HECL_GIT 1234567 #define HECL_GIT 1234567
#define HECL_GIT_S "1234567" #define HECL_GIT_S "1234567"
@ -44,16 +43,15 @@ bool XTERM_COLOR = false;
*/ */
/* Main usage message */ /* Main usage message */
static void printHelp(const hecl::SystemChar* pname) static void printHelp(const hecl::SystemChar* pname) {
{
if (XTERM_COLOR) if (XTERM_COLOR)
hecl::Printf(_SYS_STR("" BOLD "HECL" NORMAL "")); hecl::Printf(_SYS_STR("" BOLD "HECL" NORMAL ""));
else else
hecl::Printf(_SYS_STR("HECL")); hecl::Printf(_SYS_STR("HECL"));
#if HECL_HAS_NOD #if HECL_HAS_NOD
# define TOOL_LIST "extract|init|cook|package|image|help" #define TOOL_LIST "extract|init|cook|package|image|help"
#else #else
# define TOOL_LIST "extract|init|cook|package|help" #define TOOL_LIST "extract|init|cook|package|help"
#endif #endif
#if HECL_GIT #if HECL_GIT
hecl::Printf(_SYS_STR(" Commit " HECL_GIT_S " " HECL_BRANCH_S "\nUsage: %s " TOOL_LIST "\n"), pname); hecl::Printf(_SYS_STR(" Commit " HECL_GIT_S " " HECL_BRANCH_S "\nUsage: %s " TOOL_LIST "\n"), pname);
@ -65,13 +63,12 @@ static void printHelp(const hecl::SystemChar* pname)
} }
/* Regex patterns */ /* Regex patterns */
static const hecl::SystemRegex regOPEN(_SYS_STR("-o([^\"]*|\\S*)"), std::regex::ECMAScript|std::regex::optimize); static const hecl::SystemRegex regOPEN(_SYS_STR("-o([^\"]*|\\S*)"), std::regex::ECMAScript | std::regex::optimize);
static ToolBase* ToolPtr = nullptr; static ToolBase* ToolPtr = nullptr;
/* SIGINT will gracefully close blender connections and delete blends in progress */ /* SIGINT will gracefully close blender connections and delete blends in progress */
static void SIGINTHandler(int sig) static void SIGINTHandler(int sig) {
{
if (ToolPtr) if (ToolPtr)
ToolPtr->cancel(); ToolPtr->cancel();
hecl::blender::Connection::Shutdown(); hecl::blender::Connection::Shutdown();
@ -80,9 +77,7 @@ static void SIGINTHandler(int sig)
} }
static logvisor::Module AthenaLog("Athena"); static logvisor::Module AthenaLog("Athena");
static void AthenaExc(athena::error::Level level, const char* file, static void AthenaExc(athena::error::Level level, const char* file, const char*, int line, const char* fmt, ...) {
const char*, int line, const char* fmt, ...)
{
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
AthenaLog.report(logvisor::Level(level), fmt, ap); AthenaLog.report(logvisor::Level(level), fmt, ap);
@ -100,8 +95,7 @@ static void SIGWINCHHandler(int sig) {}
int main(int argc, const char** argv) int main(int argc, const char** argv)
#endif #endif
{ {
if (argc > 1 && !hecl::StrCmp(argv[1], _SYS_STR("--dlpackage"))) if (argc > 1 && !hecl::StrCmp(argv[1], _SYS_STR("--dlpackage"))) {
{
printf("%s\n", HECL_DLPACKAGE); printf("%s\n", HECL_DLPACKAGE);
return 100; return 100;
} }
@ -130,16 +124,13 @@ int main(int argc, const char** argv)
atSetExceptionHandler(AthenaExc); atSetExceptionHandler(AthenaExc);
/* Basic usage check */ /* Basic usage check */
if (argc == 1) if (argc == 1) {
{
printHelp(argv[0]); printHelp(argv[0]);
#if WIN_PAUSE #if WIN_PAUSE
system("PAUSE"); system("PAUSE");
#endif #endif
return 0; return 0;
} } else if (argc == 0) {
else if (argc == 0)
{
printHelp(_SYS_STR("hecl")); printHelp(_SYS_STR("hecl"));
#if WIN_PAUSE #if WIN_PAUSE
system("PAUSE"); system("PAUSE");
@ -153,8 +144,7 @@ int main(int argc, const char** argv)
/* Assemble common tool pass info */ /* Assemble common tool pass info */
ToolPassInfo info; ToolPassInfo info;
info.pname = argv[0]; info.pname = argv[0];
if (hecl::Getcwd(cwdbuf, 1024)) if (hecl::Getcwd(cwdbuf, 1024)) {
{
info.cwd = cwdbuf; info.cwd = cwdbuf;
if (info.cwd.size() && info.cwd.back() != _SYS_STR('/') && info.cwd.back() != _SYS_STR('\\')) if (info.cwd.size() && info.cwd.back() != _SYS_STR('/') && info.cwd.back() != _SYS_STR('\\'))
#if _WIN32 #if _WIN32
@ -173,28 +163,22 @@ int main(int argc, const char** argv)
/* Concatenate args */ /* Concatenate args */
std::vector<hecl::SystemString> args; std::vector<hecl::SystemString> args;
args.reserve(argc-2); args.reserve(argc - 2);
for (int i=2 ; i<argc ; ++i) for (int i = 2; i < argc; ++i)
args.push_back(hecl::SystemString(argv[i])); args.push_back(hecl::SystemString(argv[i]));
if (!args.empty()) if (!args.empty()) {
{
/* Extract output argument */ /* Extract output argument */
for (auto it = args.cbegin() ; it != args.cend() ;) for (auto it = args.cbegin(); it != args.cend();) {
{
const hecl::SystemString& arg = *it; const hecl::SystemString& arg = *it;
hecl::SystemRegexMatch oMatch; hecl::SystemRegexMatch oMatch;
if (std::regex_search(arg, oMatch, regOPEN)) if (std::regex_search(arg, oMatch, regOPEN)) {
{
const hecl::SystemString& token = oMatch[1].str(); const hecl::SystemString& token = oMatch[1].str();
if (token.size()) if (token.size()) {
{
if (info.output.empty()) if (info.output.empty())
info.output = oMatch[1].str(); info.output = oMatch[1].str();
it = args.erase(it); it = args.erase(it);
} } else {
else
{
it = args.erase(it); it = args.erase(it);
if (it == args.end()) if (it == args.end())
break; break;
@ -208,17 +192,14 @@ int main(int argc, const char** argv)
} }
/* Iterate flags */ /* Iterate flags */
for (auto it = args.cbegin() ; it != args.cend() ;) for (auto it = args.cbegin(); it != args.cend();) {
{
const hecl::SystemString& arg = *it; const hecl::SystemString& arg = *it;
if (arg.size() < 2 || arg[0] != _SYS_STR('-') || arg[1] == _SYS_STR('-')) if (arg.size() < 2 || arg[0] != _SYS_STR('-') || arg[1] == _SYS_STR('-')) {
{
++it; ++it;
continue; continue;
} }
for (auto chit = arg.cbegin() + 1 ; chit != arg.cend() ; ++chit) for (auto chit = arg.cbegin() + 1; chit != arg.cend(); ++chit) {
{
if (*chit == _SYS_STR('v')) if (*chit == _SYS_STR('v'))
++info.verbosityLevel; ++info.verbosityLevel;
else if (*chit == _SYS_STR('f')) else if (*chit == _SYS_STR('f'))
@ -243,12 +224,10 @@ int main(int argc, const char** argv)
/* Attempt to find hecl project */ /* Attempt to find hecl project */
hecl::ProjectRootPath rootPath = hecl::SearchForProject(info.cwd); hecl::ProjectRootPath rootPath = hecl::SearchForProject(info.cwd);
std::unique_ptr<hecl::Database::Project> project; std::unique_ptr<hecl::Database::Project> project;
if (rootPath) if (rootPath) {
{
size_t ErrorRef = logvisor::ErrorCount; size_t ErrorRef = logvisor::ErrorCount;
hecl::Database::Project* newProj = new hecl::Database::Project(rootPath); hecl::Database::Project* newProj = new hecl::Database::Project(rootPath);
if (logvisor::ErrorCount > ErrorRef) if (logvisor::ErrorCount > ErrorRef) {
{
#if WIN_PAUSE #if WIN_PAUSE
system("PAUSE"); system("PAUSE");
#endif #endif
@ -281,13 +260,11 @@ int main(int argc, const char** argv)
#endif #endif
else if (toolName == _SYS_STR("help")) else if (toolName == _SYS_STR("help"))
tool.reset(new ToolHelp(info)); tool.reset(new ToolHelp(info));
else else {
{
FILE* fp = hecl::Fopen(argv[1], _SYS_STR("rb")); FILE* fp = hecl::Fopen(argv[1], _SYS_STR("rb"));
if (!fp) if (!fp)
LogModule.report(logvisor::Error, _SYS_STR("unrecognized tool '%s'"), toolName.c_str()); LogModule.report(logvisor::Error, _SYS_STR("unrecognized tool '%s'"), toolName.c_str());
else else {
{
/* Shortcut-case: implicit extract */ /* Shortcut-case: implicit extract */
fclose(fp); fclose(fp);
info.args.insert(info.args.begin(), argv[1]); info.args.insert(info.args.begin(), argv[1]);
@ -295,8 +272,7 @@ int main(int argc, const char** argv)
} }
} }
if (logvisor::ErrorCount > ErrorRef) if (logvisor::ErrorCount > ErrorRef) {
{
#if WIN_PAUSE #if WIN_PAUSE
system("PAUSE"); system("PAUSE");
#endif #endif
@ -304,16 +280,15 @@ int main(int argc, const char** argv)
} }
if (info.verbosityLevel) if (info.verbosityLevel)
LogModule.report(logvisor::Info, _SYS_STR("Constructed tool '%s' %d\n"), LogModule.report(logvisor::Info, _SYS_STR("Constructed tool '%s' %d\n"), tool->toolName().c_str(),
tool->toolName().c_str(), info.verbosityLevel); info.verbosityLevel);
/* Run tool */ /* Run tool */
ErrorRef = logvisor::ErrorCount; ErrorRef = logvisor::ErrorCount;
ToolPtr = tool.get(); ToolPtr = tool.get();
int retval = tool->run(); int retval = tool->run();
ToolPtr = nullptr; ToolPtr = nullptr;
if (logvisor::ErrorCount > ErrorRef) if (logvisor::ErrorCount > ErrorRef) {
{
hecl::blender::Connection::Shutdown(); hecl::blender::Connection::Shutdown();
#if WIN_PAUSE #if WIN_PAUSE
system("PAUSE"); system("PAUSE");
@ -327,5 +302,3 @@ int main(int argc, const char** argv)
#endif #endif
return retval; return retval;
} }

2
hecl/extern/athena vendored

@ -1 +1 @@
Subproject commit e1b29fda7acf3a17a297a02a63a5f11e94eb2328 Subproject commit 7243c687a82eef87a4df604eae6725fae2570573

2
hecl/extern/boo vendored

@ -1 +1 @@
Subproject commit 2c2c72bfd1e59815bfb90041974ef1e9f57325cb Subproject commit 058ea23a00ce01ac93bf9ad369fa80858b185a00

View File

@ -2,8 +2,7 @@
#include "hecl/Frontend.hpp" #include "hecl/Frontend.hpp"
namespace hecl::Backend namespace hecl::Backend {
{
struct ExtensionSlot; struct ExtensionSlot;
using IR = Frontend::IR; using IR = Frontend::IR;
@ -11,15 +10,9 @@ using Diagnostics = Frontend::Diagnostics;
using SourceLocation = Frontend::SourceLocation; using SourceLocation = Frontend::SourceLocation;
using ArithmeticOp = IR::Instruction::ArithmeticOpType; using ArithmeticOp = IR::Instruction::ArithmeticOpType;
enum class TexGenSrc : uint8_t enum class TexGenSrc : uint8_t { Position, Normal, UV };
{
Position,
Normal,
UV
};
enum class BlendFactor : uint8_t enum class BlendFactor : uint8_t {
{
Zero, Zero,
One, One,
SrcColor, SrcColor,
@ -35,26 +28,11 @@ enum class BlendFactor : uint8_t
Original = 0xff Original = 0xff
}; };
enum class ZTest : uint8_t enum class ZTest : uint8_t { None, LEqual, Greater, Equal, GEqual, Original = 0xff };
{
None,
LEqual,
Greater,
Equal,
GEqual,
Original = 0xff
};
enum class CullMode : uint8_t enum class CullMode : uint8_t { None, Backface, Frontface, Original = 0xff };
{
None,
Backface,
Frontface,
Original = 0xff
};
struct TextureInfo struct TextureInfo {
{
TexGenSrc src; TexGenSrc src;
int mapIdx; int mapIdx;
int uvIdx; int uvIdx;
@ -62,84 +40,98 @@ struct TextureInfo
bool normalize; bool normalize;
}; };
enum class ReflectionType enum class ReflectionType { None, Simple, Indirect };
{
None,
Simple,
Indirect
};
class IBackend class IBackend {
{
public: public:
virtual void reset(const IR& ir, Diagnostics& diag)=0; virtual void reset(const IR& ir, Diagnostics& diag) = 0;
}; };
/** /**
* @brief Hash subclass for identifying shaders and their metadata * @brief Hash subclass for identifying shaders and their metadata
*/ */
class ShaderTag : public Hash class ShaderTag : public Hash {
{ union {
union
{
uint64_t m_meta = 0; uint64_t m_meta = 0;
struct struct {
{
uint8_t m_colorCount; uint8_t m_colorCount;
uint8_t m_uvCount; uint8_t m_uvCount;
uint8_t m_weightCount; uint8_t m_weightCount;
uint8_t m_skinSlotCount; uint8_t m_skinSlotCount;
uint8_t m_primitiveType; uint8_t m_primitiveType;
uint8_t m_reflectionType; uint8_t m_reflectionType;
bool m_depthTest:1; bool m_depthTest : 1;
bool m_depthWrite:1; bool m_depthWrite : 1;
bool m_backfaceCulling:1; bool m_backfaceCulling : 1;
bool m_alphaTest:1; bool m_alphaTest : 1;
}; };
}; };
public: public:
ShaderTag() = default; ShaderTag() = default;
ShaderTag(std::string_view source, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt, ShaderTag(std::string_view source, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt,
Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling, Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling,
bool alphaTest) bool alphaTest)
: Hash(source), m_colorCount(c), m_uvCount(u), m_weightCount(w), m_skinSlotCount(s), : Hash(source)
m_primitiveType(uint8_t(pt)), m_reflectionType(uint8_t(reflectionType)), , m_colorCount(c)
m_depthTest(depthTest), m_depthWrite(depthWrite), m_backfaceCulling(backfaceCulling), , m_uvCount(u)
m_alphaTest(alphaTest) , m_weightCount(w)
{hash ^= m_meta;} , m_skinSlotCount(s)
, m_primitiveType(uint8_t(pt))
, m_reflectionType(uint8_t(reflectionType))
, m_depthTest(depthTest)
, m_depthWrite(depthWrite)
, m_backfaceCulling(backfaceCulling)
, m_alphaTest(alphaTest) {
hash ^= m_meta;
}
ShaderTag(const hecl::Frontend::IR& ir, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt, ShaderTag(const hecl::Frontend::IR& ir, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt,
Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling, Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling,
bool alphaTest) bool alphaTest)
: Hash(ir.m_hash), m_colorCount(c), m_uvCount(u), m_weightCount(w), m_skinSlotCount(s), : Hash(ir.m_hash)
m_primitiveType(uint8_t(pt)), m_reflectionType(uint8_t(reflectionType)), , m_colorCount(c)
m_depthTest(depthTest), m_depthWrite(depthWrite), m_backfaceCulling(backfaceCulling), , m_uvCount(u)
m_alphaTest(alphaTest) , m_weightCount(w)
{hash ^= m_meta;} , m_skinSlotCount(s)
, m_primitiveType(uint8_t(pt))
, m_reflectionType(uint8_t(reflectionType))
, m_depthTest(depthTest)
, m_depthWrite(depthWrite)
, m_backfaceCulling(backfaceCulling)
, m_alphaTest(alphaTest) {
hash ^= m_meta;
}
ShaderTag(uint64_t hashin, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt, ShaderTag(uint64_t hashin, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt,
Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling, Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling,
bool alphaTest) bool alphaTest)
: Hash(hashin), m_colorCount(c), m_uvCount(u), m_weightCount(w), m_skinSlotCount(s), : Hash(hashin)
m_primitiveType(uint8_t(pt)), m_reflectionType(uint8_t(reflectionType)), , m_colorCount(c)
m_depthTest(depthTest), m_depthWrite(depthWrite), m_backfaceCulling(backfaceCulling), , m_uvCount(u)
m_alphaTest(alphaTest) , m_weightCount(w)
{hash ^= m_meta;} , m_skinSlotCount(s)
ShaderTag(uint64_t comphashin, uint64_t meta) , m_primitiveType(uint8_t(pt))
: Hash(comphashin), m_meta(meta) {} , m_reflectionType(uint8_t(reflectionType))
, m_depthTest(depthTest)
, m_depthWrite(depthWrite)
, m_backfaceCulling(backfaceCulling)
, m_alphaTest(alphaTest) {
hash ^= m_meta;
}
ShaderTag(uint64_t comphashin, uint64_t meta) : Hash(comphashin), m_meta(meta) {}
ShaderTag(const ShaderTag& other) : Hash(other), m_meta(other.m_meta) {} ShaderTag(const ShaderTag& other) : Hash(other), m_meta(other.m_meta) {}
uint8_t getColorCount() const {return m_colorCount;} uint8_t getColorCount() const { return m_colorCount; }
uint8_t getUvCount() const {return m_uvCount;} uint8_t getUvCount() const { return m_uvCount; }
uint8_t getWeightCount() const {return m_weightCount;} uint8_t getWeightCount() const { return m_weightCount; }
uint8_t getSkinSlotCount() const {return m_skinSlotCount;} uint8_t getSkinSlotCount() const { return m_skinSlotCount; }
boo::Primitive getPrimType() const {return boo::Primitive(m_primitiveType);} boo::Primitive getPrimType() const { return boo::Primitive(m_primitiveType); }
Backend::ReflectionType getReflectionType() const {return Backend::ReflectionType(m_reflectionType);} Backend::ReflectionType getReflectionType() const { return Backend::ReflectionType(m_reflectionType); }
bool getDepthTest() const {return m_depthTest;} bool getDepthTest() const { return m_depthTest; }
bool getDepthWrite() const {return m_depthWrite;} bool getDepthWrite() const { return m_depthWrite; }
bool getBackfaceCulling() const {return m_backfaceCulling;} bool getBackfaceCulling() const { return m_backfaceCulling; }
bool getAlphaTest() const {return m_alphaTest;} bool getAlphaTest() const { return m_alphaTest; }
uint64_t getMetaData() const {return m_meta;} uint64_t getMetaData() const { return m_meta; }
std::vector<boo::VertexElementDescriptor> vertexFormat() const std::vector<boo::VertexElementDescriptor> vertexFormat() const {
{
std::vector<boo::VertexElementDescriptor> ret; std::vector<boo::VertexElementDescriptor> ret;
size_t elemCount = 2 + m_colorCount + m_uvCount + m_weightCount; size_t elemCount = 2 + m_colorCount + m_uvCount + m_weightCount;
ret.resize(elemCount); ret.resize(elemCount);
@ -148,20 +140,17 @@ public:
ret[1].semantic = boo::VertexSemantic::Normal3; ret[1].semantic = boo::VertexSemantic::Normal3;
size_t e = 2; size_t e = 2;
for (size_t i=0 ; i<m_colorCount ; ++i, ++e) for (size_t i = 0; i < m_colorCount; ++i, ++e) {
{
ret[e].semantic = boo::VertexSemantic::ColorUNorm; ret[e].semantic = boo::VertexSemantic::ColorUNorm;
ret[e].semanticIdx = i; ret[e].semanticIdx = i;
} }
for (size_t i=0 ; i<m_uvCount ; ++i, ++e) for (size_t i = 0; i < m_uvCount; ++i, ++e) {
{
ret[e].semantic = boo::VertexSemantic::UV2; ret[e].semantic = boo::VertexSemantic::UV2;
ret[e].semanticIdx = i; ret[e].semanticIdx = i;
} }
for (size_t i=0 ; i<m_weightCount ; ++i, ++e) for (size_t i = 0; i < m_weightCount; ++i, ++e) {
{
ret[e].semantic = boo::VertexSemantic::Weight; ret[e].semantic = boo::VertexSemantic::Weight;
ret[e].semanticIdx = i; ret[e].semanticIdx = i;
} }
@ -173,17 +162,14 @@ public:
std::pair<BlendFactor, BlendFactor> blendFactors) const; std::pair<BlendFactor, BlendFactor> blendFactors) const;
}; };
struct Function struct Function {
{
std::string_view m_source; std::string_view m_source;
std::string_view m_entry; std::string_view m_entry;
Function() = default; Function() = default;
Function(std::string_view source, std::string_view entry) Function(std::string_view source, std::string_view entry) : m_source(source), m_entry(entry) {}
: m_source(source), m_entry(entry) {}
}; };
struct ExtensionSlot struct ExtensionSlot {
{
Function lighting; Function lighting;
Function post; Function post;
size_t blockCount = 0; size_t blockCount = 0;
@ -201,44 +187,45 @@ struct ExtensionSlot
bool noReflection = false; bool noReflection = false;
bool forceAlphaTest = false; bool forceAlphaTest = false;
ExtensionSlot(size_t blockCount = 0, ExtensionSlot(size_t blockCount = 0, const char** blockNames = nullptr, size_t texCount = 0,
const char** blockNames = nullptr,
size_t texCount = 0,
const Backend::TextureInfo* texs = nullptr, const Backend::TextureInfo* texs = nullptr,
Backend::BlendFactor srcFactor = Backend::BlendFactor::Original, Backend::BlendFactor srcFactor = Backend::BlendFactor::Original,
Backend::BlendFactor dstFactor = Backend::BlendFactor::Original, Backend::BlendFactor dstFactor = Backend::BlendFactor::Original,
Backend::ZTest depthTest = Backend::ZTest::Original, Backend::ZTest depthTest = Backend::ZTest::Original,
Backend::CullMode cullMode = Backend::CullMode::Backface, Backend::CullMode cullMode = Backend::CullMode::Backface, bool noDepthWrite = false,
bool noDepthWrite = false, bool noColorWrite = false, bool noAlphaWrite = false, bool noAlphaOverwrite = false,
bool noColorWrite = false, bool noReflection = false, bool forceAlphaTest = false)
bool noAlphaWrite = false, : blockCount(blockCount)
bool noAlphaOverwrite = false, , blockNames(blockNames)
bool noReflection = false, , texCount(texCount)
bool forceAlphaTest = false) , texs(texs)
: blockCount(blockCount), blockNames(blockNames), texCount(texCount), texs(texs), , srcFactor(srcFactor)
srcFactor(srcFactor), dstFactor(dstFactor), depthTest(depthTest), cullMode(cullMode), , dstFactor(dstFactor)
noDepthWrite(noDepthWrite), noColorWrite(noColorWrite), noAlphaWrite(noAlphaWrite), , depthTest(depthTest)
noAlphaOverwrite(noAlphaOverwrite), noReflection(noReflection), forceAlphaTest(forceAlphaTest) {} , cullMode(cullMode)
, noDepthWrite(noDepthWrite)
, noColorWrite(noColorWrite)
, noAlphaWrite(noAlphaWrite)
, noAlphaOverwrite(noAlphaOverwrite)
, noReflection(noReflection)
, forceAlphaTest(forceAlphaTest) {}
mutable uint64_t m_hash = 0; mutable uint64_t m_hash = 0;
void calculateHash() const void calculateHash() const {
{
XXH64_state_t st; XXH64_state_t st;
XXH64_reset(&st, 0); XXH64_reset(&st, 0);
if (!lighting.m_source.empty()) if (!lighting.m_source.empty())
XXH64_update(&st, lighting.m_source.data(), lighting.m_source.size()); XXH64_update(&st, lighting.m_source.data(), lighting.m_source.size());
if (!post.m_source.empty()) if (!post.m_source.empty())
XXH64_update(&st, post.m_source.data(), post.m_source.size()); XXH64_update(&st, post.m_source.data(), post.m_source.size());
for (size_t i = 0; i < texCount; ++i) for (size_t i = 0; i < texCount; ++i) {
{
const Backend::TextureInfo& tinfo = texs[i]; const Backend::TextureInfo& tinfo = texs[i];
XXH64_update(&st, &tinfo, sizeof(tinfo)); XXH64_update(&st, &tinfo, sizeof(tinfo));
} }
XXH64_update(&st, &srcFactor, offsetof(ExtensionSlot, m_hash) - offsetof(ExtensionSlot, srcFactor)); XXH64_update(&st, &srcFactor, offsetof(ExtensionSlot, m_hash) - offsetof(ExtensionSlot, srcFactor));
m_hash = XXH64_digest(&st); m_hash = XXH64_digest(&st);
} }
uint64_t hash() const uint64_t hash() const {
{
if (m_hash == 0) if (m_hash == 0)
calculateHash(); calculateHash();
return m_hash; return m_hash;
@ -246,11 +233,9 @@ struct ExtensionSlot
}; };
inline boo::AdditionalPipelineInfo ShaderTag::additionalInfo(const ExtensionSlot& ext, inline boo::AdditionalPipelineInfo ShaderTag::additionalInfo(const ExtensionSlot& ext,
std::pair<BlendFactor, BlendFactor> blendFactors) const std::pair<BlendFactor, BlendFactor> blendFactors) const {
{
boo::ZTest zTest; boo::ZTest zTest;
switch (ext.depthTest) switch (ext.depthTest) {
{
case hecl::Backend::ZTest::Original: case hecl::Backend::ZTest::Original:
default: default:
zTest = getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None; zTest = getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None;
@ -272,25 +257,24 @@ inline boo::AdditionalPipelineInfo ShaderTag::additionalInfo(const ExtensionSlot
break; break;
} }
return { return {boo::BlendFactor((ext.srcFactor == BlendFactor::Original) ? blendFactors.first : ext.srcFactor),
boo::BlendFactor((ext.srcFactor == BlendFactor::Original) ? blendFactors.first : ext.srcFactor),
boo::BlendFactor((ext.dstFactor == BlendFactor::Original) ? blendFactors.second : ext.dstFactor), boo::BlendFactor((ext.dstFactor == BlendFactor::Original) ? blendFactors.second : ext.dstFactor),
getPrimType(), zTest, ext.noDepthWrite ? false : getDepthWrite(), getPrimType(),
!ext.noColorWrite, !ext.noAlphaWrite, zTest,
(ext.cullMode == hecl::Backend::CullMode::Original) ? ext.noDepthWrite ? false : getDepthWrite(),
(getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None) : !ext.noColorWrite,
boo::CullMode(ext.cullMode), !ext.noAlphaOverwrite !ext.noAlphaWrite,
}; (ext.cullMode == hecl::Backend::CullMode::Original)
? (getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None)
: boo::CullMode(ext.cullMode),
!ext.noAlphaOverwrite};
} }
} } // namespace hecl::Backend
namespace std namespace std {
{ template <>
template <> struct hash<hecl::Backend::ShaderTag> struct hash<hecl::Backend::ShaderTag> {
{ size_t operator()(const hecl::Backend::ShaderTag& val) const noexcept { return val.valSizeT(); }
size_t operator()(const hecl::Backend::ShaderTag& val) const noexcept
{return val.valSizeT();}
}; };
} } // namespace std

View File

@ -2,28 +2,19 @@
#include "ProgrammableCommon.hpp" #include "ProgrammableCommon.hpp"
namespace hecl::Backend namespace hecl::Backend {
{
#define HECL_GLSL_VERT_UNIFORM_BLOCK_NAME "HECLVertUniform" #define HECL_GLSL_VERT_UNIFORM_BLOCK_NAME "HECLVertUniform"
#define HECL_GLSL_TEXMTX_UNIFORM_BLOCK_NAME "HECLTexMtxUniform" #define HECL_GLSL_TEXMTX_UNIFORM_BLOCK_NAME "HECLTexMtxUniform"
struct GLSL : ProgrammableCommon struct GLSL : ProgrammableCommon {
{
void reset(const IR& ir, Diagnostics& diag); void reset(const IR& ir, Diagnostics& diag);
std::string makeVert(unsigned col, unsigned uv, unsigned w, std::string makeVert(unsigned col, unsigned uv, unsigned w, unsigned skinSlots, size_t extTexCount,
unsigned skinSlots, size_t extTexCount,
const TextureInfo* extTexs, ReflectionType reflectionType) const; const TextureInfo* extTexs, ReflectionType reflectionType) const;
std::string makeFrag(size_t blockCount, const char** blockNames, std::string makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
bool alphaTest, ReflectionType reflectionType, BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting = Function()) const;
BlendFactor srcFactor, BlendFactor dstFactor, std::string makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
const Function& lighting=Function()) const; BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting, const Function& post,
std::string makeFrag(size_t blockCount, const char** blockNames,
bool alphaTest,
ReflectionType reflectionType,
BlendFactor srcFactor, BlendFactor dstFactor,
const Function& lighting,
const Function& post,
size_t extTexCount, const TextureInfo* extTexs) const; size_t extTexCount, const TextureInfo* extTexs) const;
private: private:
@ -33,14 +24,12 @@ private:
std::string GenerateAlphaTest() const; std::string GenerateAlphaTest() const;
std::string GenerateReflectionExpr(ReflectionType type) const; std::string GenerateReflectionExpr(ReflectionType type) const;
std::string EmitVec3(const atVec4f& vec) const std::string EmitVec3(const atVec4f& vec) const {
{
athena::simd_floats f(vec.simd); athena::simd_floats f(vec.simd);
return hecl::Format("vec3(%g,%g,%g)", f[0], f[1], f[2]); return hecl::Format("vec3(%g,%g,%g)", f[0], f[1], f[2]);
} }
std::string EmitVec3(const std::string& a, const std::string& b, const std::string& c) const std::string EmitVec3(const std::string& a, const std::string& b, const std::string& c) const {
{
return hecl::Format("vec3(%s,%s,%s)", a.c_str(), b.c_str(), c.c_str()); return hecl::Format("vec3(%s,%s,%s)", a.c_str(), b.c_str(), c.c_str());
} }
@ -48,5 +37,4 @@ private:
std::string EmitTexGenSource4(TexGenSrc src, int uvIdx) const; std::string EmitTexGenSource4(TexGenSrc src, int uvIdx) const;
}; };
} } // namespace hecl::Backend

View File

@ -9,21 +9,12 @@
#undef min #undef min
#undef max #undef max
namespace hecl::Backend namespace hecl::Backend {
{
struct GX final : IBackend struct GX final : IBackend {
{ enum AttrType { NONE, DIRECT, INDEX8, INDEX16 };
enum AttrType
{
NONE,
DIRECT,
INDEX8,
INDEX16
};
enum TevOp enum TevOp {
{
TEV_ADD = 0, TEV_ADD = 0,
TEV_SUB = 1, TEV_SUB = 1,
TEV_COMP_R8_GT = 8, TEV_COMP_R8_GT = 8,
@ -38,23 +29,15 @@ struct GX final : IBackend
TEV_COMP_A8_EQ = TEV_COMP_RGB8_EQ // for alpha channel TEV_COMP_A8_EQ = TEV_COMP_RGB8_EQ // for alpha channel
}; };
enum TevBias enum TevBias {
{
TB_ZERO = 0, TB_ZERO = 0,
TB_ADDHALF = 1, TB_ADDHALF = 1,
TB_SUBHALF = 2, TB_SUBHALF = 2,
}; };
enum TevScale enum TevScale { CS_SCALE_1 = 0, CS_SCALE_2 = 1, CS_SCALE_4 = 2, CS_DIVIDE_2 = 3 };
{
CS_SCALE_1 = 0,
CS_SCALE_2 = 1,
CS_SCALE_4 = 2,
CS_DIVIDE_2 = 3
};
enum TexGenType enum TexGenType {
{
TG_MTX3x4 = 0, TG_MTX3x4 = 0,
TG_MTX2x4, TG_MTX2x4,
TG_BUMP0, TG_BUMP0,
@ -68,17 +51,9 @@ struct GX final : IBackend
TG_SRTG TG_SRTG
}; };
enum TevRegID enum TevRegID { TEVPREV = 0, TEVREG0 = 1, TEVREG1 = 2, TEVREG2 = 3, TEVLAZY = 5 };
{
TEVPREV = 0,
TEVREG0 = 1,
TEVREG1 = 2,
TEVREG2 = 3,
TEVLAZY = 5
};
enum TevColorArg enum TevColorArg {
{
CC_CPREV = 0, /*!< Use the color value from previous TEV stage */ CC_CPREV = 0, /*!< Use the color value from previous TEV stage */
CC_APREV = 1, /*!< Use the alpha value from previous TEV stage */ CC_APREV = 1, /*!< Use the alpha value from previous TEV stage */
CC_C0 = 2, /*!< Use the color value from the color/output register 0 */ CC_C0 = 2, /*!< Use the color value from the color/output register 0 */
@ -100,8 +75,7 @@ struct GX final : IBackend
CC_LAZY /*!< Lazy register allocation */ CC_LAZY /*!< Lazy register allocation */
}; };
enum TevAlphaArg enum TevAlphaArg {
{
CA_APREV = 0, /*!< Use the alpha value from previous TEV stage */ CA_APREV = 0, /*!< Use the alpha value from previous TEV stage */
CA_A0 = 1, /*!< Use the alpha value from the color/output register 0 */ CA_A0 = 1, /*!< Use the alpha value from the color/output register 0 */
CA_A1 = 2, /*!< Use the alpha value from the color/output register 1 */ CA_A1 = 2, /*!< Use the alpha value from the color/output register 1 */
@ -115,8 +89,7 @@ struct GX final : IBackend
CA_LAZY /*!< Lazy register allocation */ CA_LAZY /*!< Lazy register allocation */
}; };
enum TevKColorSel enum TevKColorSel {
{
TEV_KCSEL_8_8 = 0x00, TEV_KCSEL_8_8 = 0x00,
TEV_KCSEL_7_8 = 0x01, TEV_KCSEL_7_8 = 0x01,
TEV_KCSEL_6_8 = 0x02, TEV_KCSEL_6_8 = 0x02,
@ -153,8 +126,7 @@ struct GX final : IBackend
TEV_KCSEL_K3_A = 0x1F TEV_KCSEL_K3_A = 0x1F
}; };
enum TevKAlphaSel enum TevKAlphaSel {
{
TEV_KASEL_8_8 = 0x00, TEV_KASEL_8_8 = 0x00,
TEV_KASEL_7_8 = 0x01, TEV_KASEL_7_8 = 0x01,
TEV_KASEL_6_8 = 0x02, TEV_KASEL_6_8 = 0x02,
@ -187,8 +159,7 @@ struct GX final : IBackend
TEV_KASEL_K3_A = 0x1F TEV_KASEL_K3_A = 0x1F
}; };
enum ChannelID enum ChannelID {
{
GX_COLOR0, GX_COLOR0,
GX_COLOR1, GX_COLOR1,
GX_ALPHA0, GX_ALPHA0,
@ -201,8 +172,7 @@ struct GX final : IBackend
GX_COLOR_NULL = 0xff GX_COLOR_NULL = 0xff
}; };
enum TexGenSrc enum TexGenSrc {
{
TG_POS = 0, TG_POS = 0,
TG_NRM, TG_NRM,
TG_BINRM, TG_BINRM,
@ -226,8 +196,7 @@ struct GX final : IBackend
TG_COLOR1 TG_COLOR1
}; };
enum TexMtx enum TexMtx {
{
TEXMTX0 = 30, TEXMTX0 = 30,
TEXMTX1 = 33, TEXMTX1 = 33,
TEXMTX2 = 36, TEXMTX2 = 36,
@ -241,8 +210,7 @@ struct GX final : IBackend
IDENTITY = 60 IDENTITY = 60
}; };
enum PTTexMtx enum PTTexMtx {
{
PTTEXMTX0 = 64, PTTEXMTX0 = 64,
PTTEXMTX1 = 67, PTTEXMTX1 = 67,
PTTEXMTX2 = 70, PTTEXMTX2 = 70,
@ -266,22 +234,11 @@ struct GX final : IBackend
PTIDENTITY = 125 PTIDENTITY = 125
}; };
enum DiffuseFn enum DiffuseFn { DF_NONE = 0, DF_SIGN, DF_CLAMP };
{
DF_NONE = 0,
DF_SIGN,
DF_CLAMP
};
enum AttnFn enum AttnFn { AF_SPEC = 0, AF_SPOT = 1, AF_NONE };
{
AF_SPEC = 0,
AF_SPOT = 1,
AF_NONE
};
enum Primitive enum Primitive {
{
POINTS = 0xb8, POINTS = 0xb8,
LINES = 0xa8, LINES = 0xa8,
LINESTRIP = 0xb0, LINESTRIP = 0xb0,
@ -291,8 +248,7 @@ struct GX final : IBackend
QUADS = 0x80 QUADS = 0x80
}; };
struct TexCoordGen struct TexCoordGen {
{
TexGenSrc m_src = TG_TEX0; TexGenSrc m_src = TG_TEX0;
TexMtx m_mtx = IDENTITY; TexMtx m_mtx = IDENTITY;
bool m_norm = false; bool m_norm = false;
@ -309,8 +265,7 @@ struct GX final : IBackend
unsigned m_texMtxCount = 0; unsigned m_texMtxCount = 0;
TexCoordGen* m_texMtxRefs[8]; TexCoordGen* m_texMtxRefs[8];
struct TEVStage struct TEVStage {
{
TevOp m_cop = TEV_ADD; TevOp m_cop = TEV_ADD;
TevOp m_aop = TEV_ADD; TevOp m_aop = TEV_ADD;
TevColorArg m_color[4] = {CC_ZERO, CC_ZERO, CC_ZERO, CC_ZERO}; TevColorArg m_color[4] = {CC_ZERO, CC_ZERO, CC_ZERO, CC_ZERO};
@ -336,9 +291,8 @@ struct GX final : IBackend
unsigned m_tevCount = 0; unsigned m_tevCount = 0;
TEVStage m_tevs[16]; TEVStage m_tevs[16];
int getStageIdx(const TEVStage* stage) const int getStageIdx(const TEVStage* stage) const {
{ for (int i = 0; i < int(m_tevCount); ++i)
for (int i=0 ; i<int(m_tevCount) ; ++i)
if (&m_tevs[i] == stage) if (&m_tevs[i] == stage)
return i; return i;
return -1; return -1;
@ -350,14 +304,11 @@ struct GX final : IBackend
int m_aRegMask = 0; int m_aRegMask = 0;
int m_aRegLazy = 0; int m_aRegLazy = 0;
int pickCLazy(Diagnostics& diag, const SourceLocation& loc, int stageIdx) const int pickCLazy(Diagnostics& diag, const SourceLocation& loc, int stageIdx) const {
{
int regMask = m_cRegMask; int regMask = m_cRegMask;
for (int i=stageIdx+1 ; i<int(m_tevCount) ; ++i) for (int i = stageIdx + 1; i < int(m_tevCount); ++i) {
{
const TEVStage& stage = m_tevs[i]; const TEVStage& stage = m_tevs[i];
for (int c=0 ; c<4 ; ++c) for (int c = 0; c < 4; ++c) {
{
if (stage.m_color[c] == CC_C0) if (stage.m_color[c] == CC_C0)
regMask |= 1; regMask |= 1;
if (stage.m_color[c] == CC_C1) if (stage.m_color[c] == CC_C1)
@ -369,7 +320,7 @@ struct GX final : IBackend
/* Allocate from back for compatibility with Retro's /* Allocate from back for compatibility with Retro's
* extended shader arithmetic use */ * extended shader arithmetic use */
for (int i=2 ; i>=0 ; --i) for (int i = 2; i >= 0; --i)
if (!(regMask & (1 << i))) if (!(regMask & (1 << i)))
return i; return i;
@ -377,29 +328,23 @@ struct GX final : IBackend
return -1; return -1;
} }
int pickALazy(Diagnostics& diag, const SourceLocation& loc, int stageIdx) const int pickALazy(Diagnostics& diag, const SourceLocation& loc, int stageIdx) const {
{
int regMask = m_aRegMask; int regMask = m_aRegMask;
for (int i=stageIdx+1 ; i<int(m_tevCount) ; ++i) for (int i = stageIdx + 1; i < int(m_tevCount); ++i) {
{
const TEVStage& stage = m_tevs[i]; const TEVStage& stage = m_tevs[i];
for (int c=0 ; c<4 ; ++c) for (int c = 0; c < 4; ++c) {
{ if (stage.m_color[c] == CC_A0 || stage.m_alpha[c] == CA_A0)
if (stage.m_color[c] == CC_A0 ||
stage.m_alpha[c] == CA_A0)
regMask |= 1; regMask |= 1;
if (stage.m_color[c] == CC_A1 || if (stage.m_color[c] == CC_A1 || stage.m_alpha[c] == CA_A1)
stage.m_alpha[c] == CA_A1)
regMask |= 2; regMask |= 2;
if (stage.m_color[c] == CC_A2 || if (stage.m_color[c] == CC_A2 || stage.m_alpha[c] == CA_A2)
stage.m_alpha[c] == CA_A2)
regMask |= 4; regMask |= 4;
} }
} }
/* Allocate from back for compatibility with Retro's /* Allocate from back for compatibility with Retro's
* extended shader arithmetic use */ * extended shader arithmetic use */
for (int i=2 ; i>=0 ; --i) for (int i = 2; i >= 0; --i)
if (!(regMask & (1 << i))) if (!(regMask & (1 << i)))
return i; return i;
@ -407,8 +352,7 @@ struct GX final : IBackend
return -1; return -1;
} }
enum BlendFactor : uint16_t enum BlendFactor : uint16_t {
{
BL_ZERO, BL_ZERO,
BL_ONE, BL_ONE,
BL_SRCCLR, BL_SRCCLR,
@ -421,16 +365,13 @@ struct GX final : IBackend
BlendFactor m_blendSrc; BlendFactor m_blendSrc;
BlendFactor m_blendDst; BlendFactor m_blendDst;
struct Color : athena::io::DNA<athena::Big> struct Color : athena::io::DNA<athena::Big> {
{ union {
union
{
uint8_t color[4]; uint8_t color[4];
uint32_t num = 0; uint32_t num = 0;
}; };
Color() = default; Color() = default;
Color& operator=(const atVec4f& vec) Color& operator=(const atVec4f& vec) {
{
athena::simd_floats f(vec.simd); athena::simd_floats f(vec.simd);
color[0] = uint8_t(std::min(std::max(f[0] * 255.f, 0.f), 255.f)); color[0] = uint8_t(std::min(std::max(f[0] * 255.f, 0.f), 255.f));
color[1] = uint8_t(std::min(std::max(f[1] * 255.f, 0.f), 255.f)); color[1] = uint8_t(std::min(std::max(f[1] * 255.f, 0.f), 255.f));
@ -438,8 +379,7 @@ struct GX final : IBackend
color[3] = uint8_t(std::min(std::max(f[3] * 255.f, 0.f), 255.f)); color[3] = uint8_t(std::min(std::max(f[3] * 255.f, 0.f), 255.f));
return *this; return *this;
} }
Color& operator=(const atVec3f& vec) Color& operator=(const atVec3f& vec) {
{
athena::simd_floats f(vec.simd); athena::simd_floats f(vec.simd);
color[0] = uint8_t(std::min(std::max(f[0] * 255.f, 0.f), 255.f)); color[0] = uint8_t(std::min(std::max(f[0] * 255.f, 0.f), 255.f));
color[1] = uint8_t(std::min(std::max(f[1] * 255.f, 0.f), 255.f)); color[1] = uint8_t(std::min(std::max(f[1] * 255.f, 0.f), 255.f));
@ -447,16 +387,14 @@ struct GX final : IBackend
color[3] = 0xff; color[3] = 0xff;
return *this; return *this;
} }
Color& operator=(uint8_t val) Color& operator=(uint8_t val) {
{
color[0] = val; color[0] = val;
color[1] = val; color[1] = val;
color[2] = val; color[2] = val;
color[3] = val; color[3] = val;
return *this; return *this;
} }
atVec4f toVec4f() const atVec4f toVec4f() const {
{
atVec4f out; atVec4f out;
athena::simd_floats f; athena::simd_floats f;
f[0] = color[0] / 255.f; f[0] = color[0] / 255.f;
@ -466,13 +404,13 @@ struct GX final : IBackend
out.simd.copy_from(f); out.simd.copy_from(f);
return out; return out;
} }
Color(const atVec4f& vec) {*this = vec;} Color(const atVec4f& vec) { *this = vec; }
Color(const atVec3f& vec) {*this = vec;} Color(const atVec3f& vec) { *this = vec; }
Color(uint8_t val) {*this = val;} Color(uint8_t val) { *this = val; }
bool operator==(const Color& other) const {return num == other.num;} bool operator==(const Color& other) const { return num == other.num; }
bool operator!=(const Color& other) const {return num != other.num;} bool operator!=(const Color& other) const { return num != other.num; }
uint8_t operator[](size_t idx) const {return color[idx];} uint8_t operator[](size_t idx) const { return color[idx]; }
uint8_t& operator[](size_t idx) {return color[idx];} uint8_t& operator[](size_t idx) { return color[idx]; }
AT_DECL_EXPLICIT_DNA AT_DECL_EXPLICIT_DNA
}; };
unsigned m_kcolorCount = 0; unsigned m_kcolorCount = 0;
@ -480,8 +418,7 @@ struct GX final : IBackend
int m_alphaTraceStage = -1; int m_alphaTraceStage = -1;
bool operator==(const GX& other) const bool operator==(const GX& other) const {
{
if (m_tcgCount != other.m_tcgCount) if (m_tcgCount != other.m_tcgCount)
return false; return false;
if (m_tevCount != other.m_tevCount) if (m_tevCount != other.m_tevCount)
@ -492,8 +429,7 @@ struct GX final : IBackend
return false; return false;
if (m_kcolorCount != other.m_kcolorCount) if (m_kcolorCount != other.m_kcolorCount)
return false; return false;
for (unsigned i=0 ; i<m_tcgCount ; ++i) for (unsigned i = 0; i < m_tcgCount; ++i) {
{
const TexCoordGen& a = m_tcgs[i]; const TexCoordGen& a = m_tcgs[i];
const TexCoordGen& b = other.m_tcgs[i]; const TexCoordGen& b = other.m_tcgs[i];
if (a.m_src != b.m_src) if (a.m_src != b.m_src)
@ -505,14 +441,13 @@ struct GX final : IBackend
if (a.m_pmtx != b.m_pmtx) if (a.m_pmtx != b.m_pmtx)
return false; return false;
} }
for (unsigned i=0 ; i<m_tevCount ; ++i) for (unsigned i = 0; i < m_tevCount; ++i) {
{
const TEVStage& a = m_tevs[i]; const TEVStage& a = m_tevs[i];
const TEVStage& b = other.m_tevs[i]; const TEVStage& b = other.m_tevs[i];
for (unsigned j=0 ; j<4 ; ++j) for (unsigned j = 0; j < 4; ++j)
if (a.m_color[j] != b.m_color[j]) if (a.m_color[j] != b.m_color[j])
return false; return false;
for (unsigned j=0 ; j<4 ; ++j) for (unsigned j = 0; j < 4; ++j)
if (a.m_alpha[j] != b.m_alpha[j]) if (a.m_alpha[j] != b.m_alpha[j])
return false; return false;
if (a.m_cop != b.m_cop) if (a.m_cop != b.m_cop)
@ -532,8 +467,7 @@ struct GX final : IBackend
if (a.m_texGenIdx != b.m_texGenIdx) if (a.m_texGenIdx != b.m_texGenIdx)
return false; return false;
} }
for (unsigned i=0 ; i<m_kcolorCount ; ++i) for (unsigned i = 0; i < m_kcolorCount; ++i) {
{
const Color& a = m_kcolors[i]; const Color& a = m_kcolors[i];
const Color& b = other.m_kcolors[i]; const Color& b = other.m_kcolors[i];
if (a.num != b.num) if (a.num != b.num)
@ -541,27 +475,14 @@ struct GX final : IBackend
} }
return true; return true;
} }
bool operator!=(const GX& other) const bool operator!=(const GX& other) const { return !(*this == other); }
{
return !(*this == other);
}
void reset(const IR& ir, Diagnostics& diag); void reset(const IR& ir, Diagnostics& diag);
private: private:
struct TraceResult struct TraceResult {
{ enum class Type { Invalid, TEVStage, TEVColorArg, TEVAlphaArg, TEVKColorSel, TEVKAlphaSel } type;
enum class Type union {
{
Invalid,
TEVStage,
TEVColorArg,
TEVAlphaArg,
TEVKColorSel,
TEVKAlphaSel
} type;
union
{
GX::TEVStage* tevStage; GX::TEVStage* tevStage;
GX::TevColorArg tevColorArg; GX::TevColorArg tevColorArg;
GX::TevAlphaArg tevAlphaArg; GX::TevAlphaArg tevAlphaArg;
@ -578,19 +499,15 @@ private:
unsigned addKColor(Diagnostics& diag, const SourceLocation& loc, const Color& color); unsigned addKColor(Diagnostics& diag, const SourceLocation& loc, const Color& color);
unsigned addKAlpha(Diagnostics& diag, const SourceLocation& loc, float alpha); unsigned addKAlpha(Diagnostics& diag, const SourceLocation& loc, float alpha);
unsigned addTexCoordGen(Diagnostics& diag, const SourceLocation& loc, unsigned addTexCoordGen(Diagnostics& diag, const SourceLocation& loc, TexGenSrc src, TexMtx mtx, bool norm,
TexGenSrc src, TexMtx mtx, bool norm, PTTexMtx pmtx); PTTexMtx pmtx);
TEVStage& addTEVStage(Diagnostics& diag, const SourceLocation& loc); TEVStage& addTEVStage(Diagnostics& diag, const SourceLocation& loc);
TEVStage& addAlphaTEVStage(Diagnostics& diag, const SourceLocation& loc); TEVStage& addAlphaTEVStage(Diagnostics& diag, const SourceLocation& loc);
TraceResult RecursiveTraceColor(const IR& ir, Diagnostics& diag, TraceResult RecursiveTraceColor(const IR& ir, Diagnostics& diag, const IR::Instruction& inst,
const IR::Instruction& inst, bool swizzleAlpha = false);
bool swizzleAlpha=false); TraceResult RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const IR::Instruction& inst);
TraceResult RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, unsigned RecursiveTraceTexGen(const IR& ir, Diagnostics& diag, const IR::Instruction& inst, TexMtx mtx,
const IR::Instruction& inst); bool normalize, PTTexMtx pmtx);
unsigned RecursiveTraceTexGen(const IR& ir, Diagnostics& diag,
const IR::Instruction& inst,
TexMtx mtx, bool normalize, PTTexMtx pmtx);
}; };
} } // namespace hecl::Backend

View File

@ -2,25 +2,17 @@
#include "ProgrammableCommon.hpp" #include "ProgrammableCommon.hpp"
namespace hecl::Backend namespace hecl::Backend {
{
struct HLSL : ProgrammableCommon struct HLSL : ProgrammableCommon {
{
void reset(const IR& ir, Diagnostics& diag); void reset(const IR& ir, Diagnostics& diag);
std::string makeVert(unsigned col, unsigned uv, unsigned w, std::string makeVert(unsigned col, unsigned uv, unsigned w, unsigned skinSlots, size_t extTexCount,
unsigned skinSlots, size_t extTexCount,
const TextureInfo* extTexs, ReflectionType reflectionType) const; const TextureInfo* extTexs, ReflectionType reflectionType) const;
std::string makeFrag(size_t blockCount, const char** blockNames, std::string makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
bool alphaTest, ReflectionType reflectionType, BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting = Function()) const;
BlendFactor srcFactor, BlendFactor dstFactor, std::string makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
const Function& lighting=Function()) const; BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting, const Function& post,
std::string makeFrag(size_t blockCount, const char** blockNames, size_t extTexCount, const TextureInfo* extTexs) const;
bool alphaTest, ReflectionType reflectionType,
BlendFactor srcFactor, BlendFactor dstFactor,
const Function& lighting,
const Function& post, size_t extTexCount,
const TextureInfo* extTexs) const;
private: private:
std::string GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const; std::string GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const;
@ -29,14 +21,12 @@ private:
std::string GenerateAlphaTest() const; std::string GenerateAlphaTest() const;
std::string GenerateReflectionExpr(ReflectionType type) const; std::string GenerateReflectionExpr(ReflectionType type) const;
std::string EmitVec3(const atVec4f& vec) const std::string EmitVec3(const atVec4f& vec) const {
{
athena::simd_floats f(vec.simd); athena::simd_floats f(vec.simd);
return hecl::Format("float3(%g,%g,%g)", f[0], f[1], f[2]); return hecl::Format("float3(%g,%g,%g)", f[0], f[1], f[2]);
} }
std::string EmitVec3(const std::string& a, const std::string& b, const std::string& c) const std::string EmitVec3(const std::string& a, const std::string& b, const std::string& c) const {
{
return hecl::Format("float3(%s,%s,%s)", a.c_str(), b.c_str(), c.c_str()); return hecl::Format("float3(%s,%s,%s)", a.c_str(), b.c_str(), c.c_str());
} }
@ -44,5 +34,4 @@ private:
std::string EmitTexGenSource4(TexGenSrc src, int uvIdx) const; std::string EmitTexGenSource4(TexGenSrc src, int uvIdx) const;
}; };
} } // namespace hecl::Backend

View File

@ -2,25 +2,17 @@
#include "ProgrammableCommon.hpp" #include "ProgrammableCommon.hpp"
namespace hecl::Backend namespace hecl::Backend {
{
struct Metal : ProgrammableCommon struct Metal : ProgrammableCommon {
{
void reset(const IR& ir, Diagnostics& diag); void reset(const IR& ir, Diagnostics& diag);
std::string makeVert(unsigned col, unsigned uv, unsigned w, std::string makeVert(unsigned col, unsigned uv, unsigned w, unsigned skinSlots, size_t extTexCount,
unsigned skinSlots, size_t extTexCount,
const TextureInfo* extTexs, ReflectionType reflectionType) const; const TextureInfo* extTexs, ReflectionType reflectionType) const;
std::string makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, std::string makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
ReflectionType reflectionType, BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting = Function()) const;
BlendFactor srcFactor, BlendFactor dstFactor, std::string makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
const Function& lighting=Function()) const; BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting, const Function& post,
std::string makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, size_t extTexCount, const TextureInfo* extTexs) const;
ReflectionType reflectionType,
BlendFactor srcFactor, BlendFactor dstFactor,
const Function& lighting,
const Function& post, size_t extTexCount,
const TextureInfo* extTexs) const;
private: private:
std::string GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const; std::string GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const;
@ -30,14 +22,12 @@ private:
std::string GenerateAlphaTest() const; std::string GenerateAlphaTest() const;
std::string GenerateReflectionExpr(ReflectionType type) const; std::string GenerateReflectionExpr(ReflectionType type) const;
std::string EmitVec3(const atVec4f& vec) const std::string EmitVec3(const atVec4f& vec) const {
{
athena::simd_floats f(vec.simd); athena::simd_floats f(vec.simd);
return hecl::Format("float3(%g,%g,%g)", f[0], f[1], f[2]); return hecl::Format("float3(%g,%g,%g)", f[0], f[1], f[2]);
} }
std::string EmitVec3(const std::string& a, const std::string& b, const std::string& c) const std::string EmitVec3(const std::string& a, const std::string& b, const std::string& c) const {
{
return hecl::Format("float3(%s,%s,%s)", a.c_str(), b.c_str(), c.c_str()); return hecl::Format("float3(%s,%s,%s)", a.c_str(), b.c_str(), c.c_str());
} }
@ -45,5 +35,4 @@ private:
std::string EmitTexGenSource4(TexGenSrc src, int uvIdx) const; std::string EmitTexGenSource4(TexGenSrc src, int uvIdx) const;
}; };
} } // namespace hecl::Backend

View File

@ -7,19 +7,16 @@
#include <cstdlib> #include <cstdlib>
#include <algorithm> #include <algorithm>
namespace hecl::Backend namespace hecl::Backend {
{
struct ProgrammableCommon : IBackend struct ProgrammableCommon : IBackend {
{
std::string m_colorExpr; std::string m_colorExpr;
std::string m_alphaExpr; std::string m_alphaExpr;
BlendFactor m_blendSrc; BlendFactor m_blendSrc;
BlendFactor m_blendDst; BlendFactor m_blendDst;
bool m_lighting = false; bool m_lighting = false;
struct TexSampling struct TexSampling {
{
int mapIdx = -1; int mapIdx = -1;
int tcgIdx = -1; int tcgIdx = -1;
}; };
@ -27,8 +24,7 @@ struct ProgrammableCommon : IBackend
unsigned m_texMapEnd = 0; unsigned m_texMapEnd = 0;
unsigned m_extMapStart = 8; unsigned m_extMapStart = 8;
struct TexCoordGen struct TexCoordGen {
{
TexGenSrc m_src; TexGenSrc m_src;
int m_uvIdx = 0; int m_uvIdx = 0;
int m_mtx = -1; int m_mtx = -1;
@ -47,93 +43,46 @@ struct ProgrammableCommon : IBackend
private: private:
unsigned addTexCoordGen(TexGenSrc src, int uvIdx, int mtx, bool normalize); unsigned addTexCoordGen(TexGenSrc src, int uvIdx, int mtx, bool normalize);
unsigned addTexSampling(unsigned mapIdx, unsigned tcgIdx); unsigned addTexSampling(unsigned mapIdx, unsigned tcgIdx);
std::string RecursiveTraceColor(const IR& ir, Diagnostics& diag, std::string RecursiveTraceColor(const IR& ir, Diagnostics& diag, const IR::Instruction& inst, bool toSwizzle);
const IR::Instruction& inst, bool toSwizzle); std::string RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const IR::Instruction& inst, bool toSwizzle);
std::string RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, unsigned RecursiveTraceTexGen(const IR& ir, Diagnostics& diag, const IR::Instruction& inst, int mtx, bool normalize);
const IR::Instruction& inst, bool toSwizzle);
unsigned RecursiveTraceTexGen(const IR& ir, Diagnostics& diag,
const IR::Instruction& inst,
int mtx, bool normalize);
std::string EmitSamplingUseRaw(unsigned samplingIdx) const std::string EmitSamplingUseRaw(unsigned samplingIdx) const { return hecl::Format("sampling%u", samplingIdx); }
{
return hecl::Format("sampling%u", samplingIdx);
}
std::string EmitSamplingUseRGB(unsigned samplingIdx) const std::string EmitSamplingUseRGB(unsigned samplingIdx) const { return hecl::Format("sampling%u.rgb", samplingIdx); }
{
return hecl::Format("sampling%u.rgb", samplingIdx);
}
std::string EmitSamplingUseAlpha(unsigned samplingIdx) const std::string EmitSamplingUseAlpha(unsigned samplingIdx) const { return hecl::Format("sampling%u.a", samplingIdx); }
{
return hecl::Format("sampling%u.a", samplingIdx);
}
std::string EmitColorRegUseRaw(unsigned idx) const std::string EmitColorRegUseRaw(unsigned idx) const { return hecl::Format("colorReg%u", idx); }
{
return hecl::Format("colorReg%u", idx);
}
std::string EmitColorRegUseRGB(unsigned idx) const std::string EmitColorRegUseRGB(unsigned idx) const { return hecl::Format("colorReg%u.rgb", idx); }
{
return hecl::Format("colorReg%u.rgb", idx);
}
std::string EmitColorRegUseAlpha(unsigned idx) const std::string EmitColorRegUseAlpha(unsigned idx) const { return hecl::Format("colorReg%u.a", idx); }
{
return hecl::Format("colorReg%u.a", idx);
}
std::string EmitLightingRaw() const std::string EmitLightingRaw() const { return std::string("lighting"); }
{
return std::string("lighting");
}
std::string EmitLightingRGB() const std::string EmitLightingRGB() const { return std::string("lighting.rgb"); }
{
return std::string("lighting.rgb");
}
std::string EmitLightingAlpha() const std::string EmitLightingAlpha() const { return std::string("lighting.a"); }
{
return std::string("lighting.a");
}
virtual std::string EmitVec3(const atVec4f& vec) const=0; virtual std::string EmitVec3(const atVec4f& vec) const = 0;
virtual std::string EmitVec3(const std::string& a, const std::string& b, const std::string& c) const=0; virtual std::string EmitVec3(const std::string& a, const std::string& b, const std::string& c) const = 0;
std::string EmitVal(float val) const std::string EmitVal(float val) const { return hecl::Format("%g", val); }
{
return hecl::Format("%g", val);
}
std::string EmitAdd(const std::string& a, const std::string& b) const std::string EmitAdd(const std::string& a, const std::string& b) const { return '(' + a + '+' + b + ')'; }
{
return '(' + a + '+' + b + ')';
}
std::string EmitSub(const std::string& a, const std::string& b) const std::string EmitSub(const std::string& a, const std::string& b) const { return '(' + a + '-' + b + ')'; }
{
return '(' + a + '-' + b + ')';
}
std::string EmitMult(const std::string& a, const std::string& b) const std::string EmitMult(const std::string& a, const std::string& b) const { return '(' + a + '*' + b + ')'; }
{
return '(' + a + '*' + b + ')';
}
std::string EmitDiv(const std::string& a, const std::string& b) const std::string EmitDiv(const std::string& a, const std::string& b) const { return '(' + a + '/' + b + ')'; }
{
return '(' + a + '/' + b + ')';
}
std::string EmitSwizzle3(Diagnostics& diag, const SourceLocation& loc, std::string EmitSwizzle3(Diagnostics& diag, const SourceLocation& loc, const std::string& a,
const std::string& a, const atInt8 swiz[4]) const; const atInt8 swiz[4]) const;
std::string EmitSwizzle1(Diagnostics& diag, const SourceLocation& loc, std::string EmitSwizzle1(Diagnostics& diag, const SourceLocation& loc, const std::string& a,
const std::string& a, const atInt8 swiz[4]) const; const atInt8 swiz[4]) const;
}; };
} } // namespace hecl::Backend

View File

@ -29,10 +29,9 @@ class BitVector {
enum { BITWORD_SIZE = (unsigned)sizeof(BitWord) * CHAR_BIT }; enum { BITWORD_SIZE = (unsigned)sizeof(BitWord) * CHAR_BIT };
static_assert(BITWORD_SIZE == 64 || BITWORD_SIZE == 32, static_assert(BITWORD_SIZE == 64 || BITWORD_SIZE == 32, "Unsupported word size");
"Unsupported word size");
BitWord *Bits; // Actual bits. BitWord* Bits; // Actual bits.
unsigned Size; // Size of bitvector in bits. unsigned Size; // Size of bitvector in bits.
unsigned Capacity; // Number of BitWords allocated in the Bits array. unsigned Capacity; // Number of BitWords allocated in the Bits array.
@ -42,20 +41,20 @@ public:
class reference { class reference {
friend class BitVector; friend class BitVector;
BitWord *WordRef; BitWord* WordRef;
unsigned BitPos; unsigned BitPos;
reference(); // Undefined reference(); // Undefined
public: public:
reference(BitVector &b, unsigned Idx) { reference(BitVector& b, unsigned Idx) {
WordRef = &b.Bits[Idx / BITWORD_SIZE]; WordRef = &b.Bits[Idx / BITWORD_SIZE];
BitPos = Idx % BITWORD_SIZE; BitPos = Idx % BITWORD_SIZE;
} }
reference(const reference&) = default; reference(const reference&) = default;
reference &operator=(reference t) { reference& operator=(reference t) {
*this = bool(t); *this = bool(t);
return *this; return *this;
} }
@ -68,29 +67,24 @@ public:
return *this; return *this;
} }
operator bool() const { operator bool() const { return ((*WordRef) & (BitWord(1) << BitPos)) != 0; }
return ((*WordRef) & (BitWord(1) << BitPos)) != 0;
}
}; };
/// BitVector default ctor - Creates an empty bitvector. /// BitVector default ctor - Creates an empty bitvector.
BitVector() : Size(0), Capacity(0) { BitVector() : Size(0), Capacity(0) { Bits = nullptr; }
Bits = nullptr;
}
/// BitVector ctor - Creates a bitvector of specified number of bits. All /// BitVector ctor - Creates a bitvector of specified number of bits. All
/// bits are initialized to the specified value. /// bits are initialized to the specified value.
explicit BitVector(unsigned s, bool t = false) : Size(s) { explicit BitVector(unsigned s, bool t = false) : Size(s) {
Capacity = NumBitWords(s); Capacity = NumBitWords(s);
Bits = (BitWord *)std::malloc(Capacity * sizeof(BitWord)); Bits = (BitWord*)std::malloc(Capacity * sizeof(BitWord));
init_words(Bits, Capacity, t); init_words(Bits, Capacity, t);
if (t) if (t)
clear_unused_bits(); clear_unused_bits();
} }
/// BitVector copy ctor. /// BitVector copy ctor.
BitVector(const BitVector &RHS) : Size(RHS.size()) { BitVector(const BitVector& RHS) : Size(RHS.size()) {
if (Size == 0) { if (Size == 0) {
Bits = nullptr; Bits = nullptr;
Capacity = 0; Capacity = 0;
@ -98,19 +92,16 @@ public:
} }
Capacity = NumBitWords(RHS.size()); Capacity = NumBitWords(RHS.size());
Bits = (BitWord *)std::malloc(Capacity * sizeof(BitWord)); Bits = (BitWord*)std::malloc(Capacity * sizeof(BitWord));
std::memcpy(Bits, RHS.Bits, Capacity * sizeof(BitWord)); std::memcpy(Bits, RHS.Bits, Capacity * sizeof(BitWord));
} }
BitVector(BitVector &&RHS) BitVector(BitVector&& RHS) : Bits(RHS.Bits), Size(RHS.Size), Capacity(RHS.Capacity) {
: Bits(RHS.Bits), Size(RHS.Size), Capacity(RHS.Capacity) {
RHS.Bits = nullptr; RHS.Bits = nullptr;
RHS.Size = RHS.Capacity = 0; RHS.Size = RHS.Capacity = 0;
} }
~BitVector() { ~BitVector() { std::free(Bits); }
std::free(Bits);
}
/// empty - Tests whether there are no bits in this bitvector. /// empty - Tests whether there are no bits in this bitvector.
bool empty() const { return Size == 0; } bool empty() const { return Size == 0; }
@ -148,9 +139,7 @@ public:
} }
/// none - Returns true if none of the bits are set. /// none - Returns true if none of the bits are set.
bool none() const { bool none() const { return !any(); }
return !any();
}
/// find_first - Returns the index of the first set bit, -1 if none /// find_first - Returns the index of the first set bit, -1 if none
/// of the bits are set. /// of the bits are set.
@ -178,7 +167,7 @@ public:
return WordPos * BITWORD_SIZE + countTrailingZeros(Copy); return WordPos * BITWORD_SIZE + countTrailingZeros(Copy);
// Check subsequent words. // Check subsequent words.
for (unsigned i = WordPos+1; i < NumBitWords(size()); ++i) for (unsigned i = WordPos + 1; i < NumBitWords(size()); ++i)
if (Bits[i] != 0) if (Bits[i] != 0)
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]); return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
return -1; return -1;
@ -199,8 +188,7 @@ public:
break; break;
} }
} }
if (good) if (good) {
{
unsigned space = BucketSz - (idx % BucketSz); unsigned space = BucketSz - (idx % BucketSz);
if (space >= Length) if (space >= Length)
return idx; return idx;
@ -210,16 +198,14 @@ public:
} }
/// clear - Clear all bits. /// clear - Clear all bits.
void clear() { void clear() { Size = 0; }
Size = 0;
}
/// resize - Grow or shrink the bitvector. /// resize - Grow or shrink the bitvector.
void resize(unsigned N, bool t = false) { void resize(unsigned N, bool t = false) {
if (N > Capacity * BITWORD_SIZE) { if (N > Capacity * BITWORD_SIZE) {
unsigned OldCapacity = Capacity; unsigned OldCapacity = Capacity;
grow(N); grow(N);
init_words(&Bits[OldCapacity], (Capacity-OldCapacity), t); init_words(&Bits[OldCapacity], (Capacity - OldCapacity), t);
} }
// Set any old unused bits that are now included in the BitVector. This // Set any old unused bits that are now included in the BitVector. This
@ -241,24 +227,25 @@ public:
} }
// Set, reset, flip // Set, reset, flip
BitVector &set() { BitVector& set() {
init_words(Bits, Capacity, true); init_words(Bits, Capacity, true);
clear_unused_bits(); clear_unused_bits();
return *this; return *this;
} }
BitVector &set(unsigned Idx) { BitVector& set(unsigned Idx) {
assert(Bits && "Bits never allocated"); assert(Bits && "Bits never allocated");
Bits[Idx / BITWORD_SIZE] |= BitWord(1) << (Idx % BITWORD_SIZE); Bits[Idx / BITWORD_SIZE] |= BitWord(1) << (Idx % BITWORD_SIZE);
return *this; return *this;
} }
/// set - Efficiently set a range of bits in [I, E) /// set - Efficiently set a range of bits in [I, E)
BitVector &set(unsigned I, unsigned E) { BitVector& set(unsigned I, unsigned E) {
assert(I <= E && "Attempted to set backwards range!"); assert(I <= E && "Attempted to set backwards range!");
assert(E <= size() && "Attempted to set out-of-bounds range!"); assert(E <= size() && "Attempted to set out-of-bounds range!");
if (I == E) return *this; if (I == E)
return *this;
if (I / BITWORD_SIZE == E / BITWORD_SIZE) { if (I / BITWORD_SIZE == E / BITWORD_SIZE) {
BitWord EMask = 1UL << (E % BITWORD_SIZE); BitWord EMask = 1UL << (E % BITWORD_SIZE);
@ -282,22 +269,23 @@ public:
return *this; return *this;
} }
BitVector &reset() { BitVector& reset() {
init_words(Bits, Capacity, false); init_words(Bits, Capacity, false);
return *this; return *this;
} }
BitVector &reset(unsigned Idx) { BitVector& reset(unsigned Idx) {
Bits[Idx / BITWORD_SIZE] &= ~(BitWord(1) << (Idx % BITWORD_SIZE)); Bits[Idx / BITWORD_SIZE] &= ~(BitWord(1) << (Idx % BITWORD_SIZE));
return *this; return *this;
} }
/// reset - Efficiently reset a range of bits in [I, E) /// reset - Efficiently reset a range of bits in [I, E)
BitVector &reset(unsigned I, unsigned E) { BitVector& reset(unsigned I, unsigned E) {
assert(I <= E && "Attempted to reset backwards range!"); assert(I <= E && "Attempted to reset backwards range!");
assert(E <= size() && "Attempted to reset out-of-bounds range!"); assert(E <= size() && "Attempted to reset out-of-bounds range!");
if (I == E) return *this; if (I == E)
return *this;
if (I / BITWORD_SIZE == E / BITWORD_SIZE) { if (I / BITWORD_SIZE == E / BITWORD_SIZE) {
BitWord EMask = 1UL << (E % BITWORD_SIZE); BitWord EMask = 1UL << (E % BITWORD_SIZE);
@ -321,36 +309,34 @@ public:
return *this; return *this;
} }
BitVector &flip() { BitVector& flip() {
for (unsigned i = 0; i < NumBitWords(size()); ++i) for (unsigned i = 0; i < NumBitWords(size()); ++i)
Bits[i] = ~Bits[i]; Bits[i] = ~Bits[i];
clear_unused_bits(); clear_unused_bits();
return *this; return *this;
} }
BitVector &flip(unsigned Idx) { BitVector& flip(unsigned Idx) {
Bits[Idx / BITWORD_SIZE] ^= BitWord(1) << (Idx % BITWORD_SIZE); Bits[Idx / BITWORD_SIZE] ^= BitWord(1) << (Idx % BITWORD_SIZE);
return *this; return *this;
} }
// Indexing. // Indexing.
reference operator[](unsigned Idx) { reference operator[](unsigned Idx) {
assert (Idx < Size && "Out-of-bounds Bit access."); assert(Idx < Size && "Out-of-bounds Bit access.");
return reference(*this, Idx); return reference(*this, Idx);
} }
bool operator[](unsigned Idx) const { bool operator[](unsigned Idx) const {
assert (Idx < Size && "Out-of-bounds Bit access."); assert(Idx < Size && "Out-of-bounds Bit access.");
BitWord Mask = BitWord(1) << (Idx % BITWORD_SIZE); BitWord Mask = BitWord(1) << (Idx % BITWORD_SIZE);
return (Bits[Idx / BITWORD_SIZE] & Mask) != 0; return (Bits[Idx / BITWORD_SIZE] & Mask) != 0;
} }
bool test(unsigned Idx) const { bool test(unsigned Idx) const { return (*this)[Idx]; }
return (*this)[Idx];
}
/// Test if any common bits are set. /// Test if any common bits are set.
bool anyCommon(const BitVector &RHS) const { bool anyCommon(const BitVector& RHS) const {
unsigned ThisWords = NumBitWords(size()); unsigned ThisWords = NumBitWords(size());
unsigned RHSWords = NumBitWords(RHS.size()); unsigned RHSWords = NumBitWords(RHS.size());
for (unsigned i = 0, e = std::min(ThisWords, RHSWords); i != e; ++i) for (unsigned i = 0, e = std::min(ThisWords, RHSWords); i != e; ++i)
@ -360,7 +346,7 @@ public:
} }
// Comparison operators. // Comparison operators.
bool operator==(const BitVector &RHS) const { bool operator==(const BitVector& RHS) const {
unsigned ThisWords = NumBitWords(size()); unsigned ThisWords = NumBitWords(size());
unsigned RHSWords = NumBitWords(RHS.size()); unsigned RHSWords = NumBitWords(RHS.size());
unsigned i; unsigned i;
@ -381,12 +367,10 @@ public:
return true; return true;
} }
bool operator!=(const BitVector &RHS) const { bool operator!=(const BitVector& RHS) const { return !(*this == RHS); }
return !(*this == RHS);
}
/// Intersection, union, disjoint union. /// Intersection, union, disjoint union.
BitVector &operator&=(const BitVector &RHS) { BitVector& operator&=(const BitVector& RHS) {
unsigned ThisWords = NumBitWords(size()); unsigned ThisWords = NumBitWords(size());
unsigned RHSWords = NumBitWords(RHS.size()); unsigned RHSWords = NumBitWords(RHS.size());
unsigned i; unsigned i;
@ -403,7 +387,7 @@ public:
} }
/// reset - Reset bits that are set in RHS. Same as *this &= ~RHS. /// reset - Reset bits that are set in RHS. Same as *this &= ~RHS.
BitVector &reset(const BitVector &RHS) { BitVector& reset(const BitVector& RHS) {
unsigned ThisWords = NumBitWords(size()); unsigned ThisWords = NumBitWords(size());
unsigned RHSWords = NumBitWords(RHS.size()); unsigned RHSWords = NumBitWords(RHS.size());
unsigned i; unsigned i;
@ -414,7 +398,7 @@ public:
/// test - Check if (This - RHS) is zero. /// test - Check if (This - RHS) is zero.
/// This is the same as reset(RHS) and any(). /// This is the same as reset(RHS) and any().
bool test(const BitVector &RHS) const { bool test(const BitVector& RHS) const {
unsigned ThisWords = NumBitWords(size()); unsigned ThisWords = NumBitWords(size());
unsigned RHSWords = NumBitWords(RHS.size()); unsigned RHSWords = NumBitWords(RHS.size());
unsigned i; unsigned i;
@ -422,14 +406,14 @@ public:
if ((Bits[i] & ~RHS.Bits[i]) != 0) if ((Bits[i] & ~RHS.Bits[i]) != 0)
return true; return true;
for (; i != ThisWords ; ++i) for (; i != ThisWords; ++i)
if (Bits[i] != 0) if (Bits[i] != 0)
return true; return true;
return false; return false;
} }
BitVector &operator|=(const BitVector &RHS) { BitVector& operator|=(const BitVector& RHS) {
if (size() < RHS.size()) if (size() < RHS.size())
resize(RHS.size()); resize(RHS.size());
for (size_t i = 0, e = NumBitWords(RHS.size()); i != e; ++i) for (size_t i = 0, e = NumBitWords(RHS.size()); i != e; ++i)
@ -437,7 +421,7 @@ public:
return *this; return *this;
} }
BitVector &operator^=(const BitVector &RHS) { BitVector& operator^=(const BitVector& RHS) {
if (size() < RHS.size()) if (size() < RHS.size())
resize(RHS.size()); resize(RHS.size());
for (size_t i = 0, e = NumBitWords(RHS.size()); i != e; ++i) for (size_t i = 0, e = NumBitWords(RHS.size()); i != e; ++i)
@ -446,8 +430,9 @@ public:
} }
// Assignment operator. // Assignment operator.
const BitVector &operator=(const BitVector &RHS) { const BitVector& operator=(const BitVector& RHS) {
if (this == &RHS) return *this; if (this == &RHS)
return *this;
Size = RHS.size(); Size = RHS.size();
unsigned RHSWords = NumBitWords(Size); unsigned RHSWords = NumBitWords(Size);
@ -461,7 +446,7 @@ public:
// Grow the bitvector to have enough elements. // Grow the bitvector to have enough elements.
Capacity = RHSWords; Capacity = RHSWords;
assert(Capacity > 0 && "negative capacity?"); assert(Capacity > 0 && "negative capacity?");
BitWord *NewBits = (BitWord *)std::malloc(Capacity * sizeof(BitWord)); BitWord* NewBits = (BitWord*)std::malloc(Capacity * sizeof(BitWord));
std::memcpy(NewBits, RHS.Bits, Capacity * sizeof(BitWord)); std::memcpy(NewBits, RHS.Bits, Capacity * sizeof(BitWord));
// Destroy the old bits. // Destroy the old bits.
@ -471,8 +456,9 @@ public:
return *this; return *this;
} }
const BitVector &operator=(BitVector &&RHS) { const BitVector& operator=(BitVector&& RHS) {
if (this == &RHS) return *this; if (this == &RHS)
return *this;
std::free(Bits); std::free(Bits);
Bits = RHS.Bits; Bits = RHS.Bits;
@ -485,7 +471,7 @@ public:
return *this; return *this;
} }
void swap(BitVector &RHS) { void swap(BitVector& RHS) {
std::swap(Bits, RHS.Bits); std::swap(Bits, RHS.Bits);
std::swap(Size, RHS.Size); std::swap(Size, RHS.Size);
std::swap(Capacity, RHS.Capacity); std::swap(Capacity, RHS.Capacity);
@ -505,70 +491,56 @@ public:
/// setBitsInMask - Add '1' bits from Mask to this vector. Don't resize. /// setBitsInMask - Add '1' bits from Mask to this vector. Don't resize.
/// This computes "*this |= Mask". /// This computes "*this |= Mask".
void setBitsInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) { void setBitsInMask(const uint32_t* Mask, unsigned MaskWords = ~0u) { applyMask<true, false>(Mask, MaskWords); }
applyMask<true, false>(Mask, MaskWords);
}
/// clearBitsInMask - Clear any bits in this vector that are set in Mask. /// clearBitsInMask - Clear any bits in this vector that are set in Mask.
/// Don't resize. This computes "*this &= ~Mask". /// Don't resize. This computes "*this &= ~Mask".
void clearBitsInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) { void clearBitsInMask(const uint32_t* Mask, unsigned MaskWords = ~0u) { applyMask<false, false>(Mask, MaskWords); }
applyMask<false, false>(Mask, MaskWords);
}
/// setBitsNotInMask - Add a bit to this vector for every '0' bit in Mask. /// setBitsNotInMask - Add a bit to this vector for every '0' bit in Mask.
/// Don't resize. This computes "*this |= ~Mask". /// Don't resize. This computes "*this |= ~Mask".
void setBitsNotInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) { void setBitsNotInMask(const uint32_t* Mask, unsigned MaskWords = ~0u) { applyMask<true, true>(Mask, MaskWords); }
applyMask<true, true>(Mask, MaskWords);
}
/// clearBitsNotInMask - Clear a bit in this vector for every '0' bit in Mask. /// clearBitsNotInMask - Clear a bit in this vector for every '0' bit in Mask.
/// Don't resize. This computes "*this &= Mask". /// Don't resize. This computes "*this &= Mask".
void clearBitsNotInMask(const uint32_t *Mask, unsigned MaskWords = ~0u) { void clearBitsNotInMask(const uint32_t* Mask, unsigned MaskWords = ~0u) { applyMask<false, true>(Mask, MaskWords); }
applyMask<false, true>(Mask, MaskWords);
}
private: private:
unsigned NumBitWords(unsigned S) const { unsigned NumBitWords(unsigned S) const { return (S + BITWORD_SIZE - 1) / BITWORD_SIZE; }
return (S + BITWORD_SIZE-1) / BITWORD_SIZE;
}
// Set the unused bits in the high words. // Set the unused bits in the high words.
void set_unused_bits(bool t = true) { void set_unused_bits(bool t = true) {
// Set high words first. // Set high words first.
unsigned UsedWords = NumBitWords(Size); unsigned UsedWords = NumBitWords(Size);
if (Capacity > UsedWords) if (Capacity > UsedWords)
init_words(&Bits[UsedWords], (Capacity-UsedWords), t); init_words(&Bits[UsedWords], (Capacity - UsedWords), t);
// Then set any stray high bits of the last used word. // Then set any stray high bits of the last used word.
unsigned ExtraBits = Size % BITWORD_SIZE; unsigned ExtraBits = Size % BITWORD_SIZE;
if (ExtraBits) { if (ExtraBits) {
BitWord ExtraBitMask = ~0UL << ExtraBits; BitWord ExtraBitMask = ~0UL << ExtraBits;
if (t) if (t)
Bits[UsedWords-1] |= ExtraBitMask; Bits[UsedWords - 1] |= ExtraBitMask;
else else
Bits[UsedWords-1] &= ~ExtraBitMask; Bits[UsedWords - 1] &= ~ExtraBitMask;
} }
} }
// Clear the unused bits in the high words. // Clear the unused bits in the high words.
void clear_unused_bits() { void clear_unused_bits() { set_unused_bits(false); }
set_unused_bits(false);
}
void grow(unsigned NewSize) { void grow(unsigned NewSize) {
Capacity = std::max(NumBitWords(NewSize), Capacity * 2); Capacity = std::max(NumBitWords(NewSize), Capacity * 2);
assert(Capacity > 0 && "realloc-ing zero space"); assert(Capacity > 0 && "realloc-ing zero space");
Bits = (BitWord *)std::realloc(Bits, Capacity * sizeof(BitWord)); Bits = (BitWord*)std::realloc(Bits, Capacity * sizeof(BitWord));
clear_unused_bits(); clear_unused_bits();
} }
void init_words(BitWord *B, unsigned NumWords, bool t) { void init_words(BitWord* B, unsigned NumWords, bool t) { memset(B, 0 - (int)t, NumWords * sizeof(BitWord)); }
memset(B, 0 - (int)t, NumWords*sizeof(BitWord));
}
template<bool AddBits, bool InvertMask> template <bool AddBits, bool InvertMask>
void applyMask(const uint32_t *Mask, unsigned MaskWords) { void applyMask(const uint32_t* Mask, unsigned MaskWords) {
static_assert(BITWORD_SIZE % 32 == 0, "Unsupported BitWord size."); static_assert(BITWORD_SIZE % 32 == 0, "Unsupported BitWord size.");
MaskWords = std::min(MaskWords, (size() + 31) / 32); MaskWords = std::min(MaskWords, (size() + 31) / 32);
const unsigned Scale = BITWORD_SIZE / 32; const unsigned Scale = BITWORD_SIZE / 32;
@ -578,17 +550,23 @@ private:
// This inner loop should unroll completely when BITWORD_SIZE > 32. // This inner loop should unroll completely when BITWORD_SIZE > 32.
for (unsigned b = 0; b != BITWORD_SIZE; b += 32) { for (unsigned b = 0; b != BITWORD_SIZE; b += 32) {
uint32_t M = *Mask++; uint32_t M = *Mask++;
if (InvertMask) M = ~M; if (InvertMask)
if (AddBits) BW |= BitWord(M) << b; M = ~M;
else BW &= ~(BitWord(M) << b); if (AddBits)
BW |= BitWord(M) << b;
else
BW &= ~(BitWord(M) << b);
} }
Bits[i] = BW; Bits[i] = BW;
} }
for (unsigned b = 0; MaskWords; b += 32, --MaskWords) { for (unsigned b = 0; MaskWords; b += 32, --MaskWords) {
uint32_t M = *Mask++; uint32_t M = *Mask++;
if (InvertMask) M = ~M; if (InvertMask)
if (AddBits) Bits[i] |= BitWord(M) << b; M = ~M;
else Bits[i] &= ~(BitWord(M) << b); if (AddBits)
Bits[i] |= BitWord(M) << b;
else
Bits[i] &= ~(BitWord(M) << b);
} }
if (AddBits) if (AddBits)
clear_unused_bits(); clear_unused_bits();
@ -599,18 +577,12 @@ public:
size_t getMemorySize() const { return Capacity * sizeof(BitWord); } size_t getMemorySize() const { return Capacity * sizeof(BitWord); }
}; };
static inline size_t capacity_in_bytes(const BitVector &X) { static inline size_t capacity_in_bytes(const BitVector& X) { return X.getMemorySize(); }
return X.getMemorySize();
}
} // end namespace llvm } // end namespace llvm
} // end namespace hecl } // end namespace hecl
namespace std { namespace std {
/// Implement std::swap in terms of BitVector swap. /// Implement std::swap in terms of BitVector swap.
inline void inline void swap(hecl::llvm::BitVector& LHS, hecl::llvm::BitVector& RHS) { LHS.swap(RHS); }
swap(hecl::llvm::BitVector &LHS, hecl::llvm::BitVector &RHS) {
LHS.swap(RHS);
}
} // end namespace std } // end namespace std

View File

@ -28,39 +28,31 @@
#include "optional.hpp" #include "optional.hpp"
#include "Token.hpp" #include "Token.hpp"
namespace hecl::blender namespace hecl::blender {
{
extern logvisor::Module BlenderLog; extern logvisor::Module BlenderLog;
class HMDLBuffers; class HMDLBuffers;
class Connection; class Connection;
struct PoolSkinIndex struct PoolSkinIndex {
{
size_t m_poolSz = 0; size_t m_poolSz = 0;
std::unique_ptr<uint32_t[]> m_poolToSkinIndex; std::unique_ptr<uint32_t[]> m_poolToSkinIndex;
void allocate(size_t poolSz) void allocate(size_t poolSz) {
{
m_poolSz = poolSz; m_poolSz = poolSz;
if (poolSz) if (poolSz)
m_poolToSkinIndex.reset(new uint32_t[poolSz]); m_poolToSkinIndex.reset(new uint32_t[poolSz]);
} }
}; };
enum class ANIMCurveType enum class ANIMCurveType { Rotate, Translate, Scale };
{
Rotate,
Translate,
Scale
};
class ANIMOutStream class ANIMOutStream {
{
Connection* m_parent; Connection* m_parent;
unsigned m_curCount = 0; unsigned m_curCount = 0;
unsigned m_totalCount = 0; unsigned m_totalCount = 0;
bool m_inCurve = false; bool m_inCurve = false;
public: public:
using CurveType = ANIMCurveType; using CurveType = ANIMCurveType;
ANIMOutStream(Connection* parent); ANIMOutStream(Connection* parent);
@ -69,99 +61,88 @@ public:
void write(unsigned frame, float val); void write(unsigned frame, float val);
}; };
class PyOutStream : public std::ostream class PyOutStream : public std::ostream {
{
friend class Connection; friend class Connection;
Connection* m_parent; Connection* m_parent;
struct StreamBuf : std::streambuf struct StreamBuf : std::streambuf {
{
PyOutStream& m_parent; PyOutStream& m_parent;
std::string m_lineBuf; std::string m_lineBuf;
bool m_deleteOnError; bool m_deleteOnError;
StreamBuf(PyOutStream& parent, bool deleteOnError) StreamBuf(PyOutStream& parent, bool deleteOnError) : m_parent(parent), m_deleteOnError(deleteOnError) {}
: m_parent(parent), m_deleteOnError(deleteOnError) {}
StreamBuf(const StreamBuf& other) = delete; StreamBuf(const StreamBuf& other) = delete;
StreamBuf(StreamBuf&& other) = default; StreamBuf(StreamBuf&& other) = default;
int_type overflow(int_type ch); int_type overflow(int_type ch);
} m_sbuf; } m_sbuf;
PyOutStream(Connection* parent, bool deleteOnError); PyOutStream(Connection* parent, bool deleteOnError);
public: public:
PyOutStream(const PyOutStream& other) = delete; PyOutStream(const PyOutStream& other) = delete;
PyOutStream(PyOutStream&& other) PyOutStream(PyOutStream&& other) : std::ostream(&m_sbuf), m_parent(other.m_parent), m_sbuf(std::move(other.m_sbuf)) {
: std::ostream(&m_sbuf), m_parent(other.m_parent), m_sbuf(std::move(other.m_sbuf)) other.m_parent = nullptr;
{other.m_parent = nullptr;} }
~PyOutStream() {close();} ~PyOutStream() { close(); }
void close(); void close();
#if __GNUC__ #if __GNUC__
__attribute__((__format__ (__printf__, 2, 3))) __attribute__((__format__(__printf__, 2, 3)))
#endif #endif
void format(const char* fmt, ...); void
void linkBlend(const char* target, const char* objName, bool link=true); format(const char* fmt, ...);
void linkBackground(const char* target, const char* sceneName=nullptr); void linkBlend(const char* target, const char* objName, bool link = true);
void linkBackground(const char* target, const char* sceneName = nullptr);
void AABBToBMesh(const atVec3f& min, const atVec3f& max); void AABBToBMesh(const atVec3f& min, const atVec3f& max);
void centerView(); void centerView();
ANIMOutStream beginANIMCurve() ANIMOutStream beginANIMCurve() { return ANIMOutStream(m_parent); }
{ Connection& getConnection() { return *m_parent; }
return ANIMOutStream(m_parent);
}
Connection& getConnection() {return *m_parent;}
}; };
/* Vector types with integrated stream reading constructor */ /* Vector types with integrated stream reading constructor */
struct Vector2f struct Vector2f {
{
atVec2f val; atVec2f val;
Vector2f() = default; Vector2f() = default;
void read(Connection& conn); void read(Connection& conn);
Vector2f(Connection& conn) {read(conn);} Vector2f(Connection& conn) { read(conn); }
operator const atVec2f&() const {return val;} operator const atVec2f&() const { return val; }
}; };
struct Vector3f struct Vector3f {
{
atVec3f val; atVec3f val;
Vector3f() = default; Vector3f() = default;
void read(Connection& conn); void read(Connection& conn);
Vector3f(Connection& conn) {read(conn);} Vector3f(Connection& conn) { read(conn); }
operator const atVec3f&() const {return val;} operator const atVec3f&() const { return val; }
}; };
struct Vector4f struct Vector4f {
{
atVec4f val; atVec4f val;
Vector4f() = default; Vector4f() = default;
void read(Connection& conn); void read(Connection& conn);
Vector4f(Connection& conn) {read(conn);} Vector4f(Connection& conn) { read(conn); }
operator const atVec4f&() const {return val;} operator const atVec4f&() const { return val; }
}; };
struct Matrix3f struct Matrix3f {
{
atVec3f m[3]; atVec3f m[3];
inline atVec3f& operator[](size_t idx) {return m[idx];} inline atVec3f& operator[](size_t idx) { return m[idx]; }
inline const atVec3f& operator[](size_t idx) const {return m[idx];} inline const atVec3f& operator[](size_t idx) const { return m[idx]; }
}; };
struct Matrix4f struct Matrix4f {
{
atVec4f val[4]; atVec4f val[4];
Matrix4f() = default; Matrix4f() = default;
void read(Connection& conn); void read(Connection& conn);
Matrix4f(Connection& conn) {read(conn);} Matrix4f(Connection& conn) { read(conn); }
const atVec4f& operator[] (size_t idx) const {return val[idx];} const atVec4f& operator[](size_t idx) const { return val[idx]; }
}; };
struct Index struct Index {
{
uint32_t val; uint32_t val;
Index() = default; Index() = default;
void read(Connection& conn); void read(Connection& conn);
Index(Connection& conn) {read(conn);} Index(Connection& conn) { read(conn); }
operator const uint32_t&() const {return val;} operator const uint32_t&() const { return val; }
}; };
atVec3f MtxVecMul4RM(const Matrix4f& mtx, const Vector3f& vec); atVec3f MtxVecMul4RM(const Matrix4f& mtx, const Vector3f& vec);
atVec3f MtxVecMul3RM(const Matrix4f& mtx, const Vector3f& vec); atVec3f MtxVecMul3RM(const Matrix4f& mtx, const Vector3f& vec);
/** HECL source and metadata of each material */ /** HECL source and metadata of each material */
struct Material struct Material {
{
std::string name; std::string name;
std::string source; std::string source;
std::vector<ProjectPath> texs; std::vector<ProjectPath> texs;
@ -169,15 +150,13 @@ struct Material
bool transparent; bool transparent;
Material(Connection& conn); Material(Connection& conn);
bool operator==(const Material& other) const bool operator==(const Material& other) const {
{
return source == other.source && texs == other.texs && iprops == other.iprops; return source == other.source && texs == other.texs && iprops == other.iprops;
} }
}; };
/** Intermediate mesh representation prepared by blender from a single mesh object */ /** Intermediate mesh representation prepared by blender from a single mesh object */
struct Mesh struct Mesh {
{
HMDLTopology topology; HMDLTopology topology;
/* Object transform in scene */ /* Object transform in scene */
@ -201,8 +180,7 @@ struct Mesh
/* Skinning data */ /* Skinning data */
std::vector<std::string> boneNames; std::vector<std::string> boneNames;
struct SkinBind struct SkinBind {
{
uint32_t boneIdx; uint32_t boneIdx;
float weight; float weight;
SkinBind(Connection& conn); SkinBind(Connection& conn);
@ -213,8 +191,7 @@ struct Mesh
void normalizeSkinBinds(); void normalizeSkinBinds();
/** Islands of the same material/skinBank are represented here */ /** Islands of the same material/skinBank are represented here */
struct Surface struct Surface {
{
Vector3f centroid; Vector3f centroid;
Index materialIdx; Index materialIdx;
Vector3f aabbMin; Vector3f aabbMin;
@ -223,8 +200,7 @@ struct Mesh
uint32_t skinBankIdx; uint32_t skinBankIdx;
/** Vertex indexing data (all primitives joined as degenerate tri-strip) */ /** Vertex indexing data (all primitives joined as degenerate tri-strip) */
struct Vert struct Vert {
{
uint32_t iPos = 0xffffffff; uint32_t iPos = 0xffffffff;
uint32_t iNorm = 0xffffffff; uint32_t iNorm = 0xffffffff;
uint32_t iColor[4] = {0xffffffff}; uint32_t iColor[4] = {0xffffffff};
@ -243,10 +219,8 @@ struct Mesh
std::unordered_map<std::string, std::string> customProps; std::unordered_map<std::string, std::string> customProps;
struct SkinBanks struct SkinBanks {
{ struct Bank {
struct Bank
{
std::vector<uint32_t> m_skinIdxs; std::vector<uint32_t> m_skinIdxs;
std::vector<uint32_t> m_boneIdxs; std::vector<uint32_t> m_boneIdxs;
@ -270,11 +244,9 @@ struct Mesh
}; };
/** Intermediate collision mesh representation prepared by blender from a single mesh object */ /** Intermediate collision mesh representation prepared by blender from a single mesh object */
struct ColMesh struct ColMesh {
{
/** HECL source and metadata of each material */ /** HECL source and metadata of each material */
struct Material struct Material {
{
std::string name; std::string name;
bool unknown; bool unknown;
bool surfaceStone; bool surfaceStone;
@ -325,16 +297,14 @@ struct ColMesh
std::vector<Vector3f> verts; std::vector<Vector3f> verts;
struct Edge struct Edge {
{
uint32_t verts[2]; uint32_t verts[2];
bool seam; bool seam;
Edge(Connection& conn); Edge(Connection& conn);
}; };
std::vector<Edge> edges; std::vector<Edge> edges;
struct Triangle struct Triangle {
{
uint32_t edges[3]; uint32_t edges[3];
uint32_t matIdx; uint32_t matIdx;
bool flip; bool flip;
@ -346,15 +316,12 @@ struct ColMesh
}; };
/** Intermediate world representation */ /** Intermediate world representation */
struct World struct World {
{ struct Area {
struct Area
{
ProjectPath path; ProjectPath path;
Vector3f aabb[2]; Vector3f aabb[2];
Matrix4f transform; Matrix4f transform;
struct Dock struct Dock {
{
Vector3f verts[4]; Vector3f verts[4];
Index targetArea; Index targetArea;
Index targetDock; Index targetDock;
@ -368,21 +335,14 @@ struct World
}; };
/** Intermediate lamp representation */ /** Intermediate lamp representation */
struct Light struct Light {
{
/* Object transform in scene */ /* Object transform in scene */
Matrix4f sceneXf; Matrix4f sceneXf;
Vector3f color; Vector3f color;
uint32_t layer; uint32_t layer;
enum class Type : uint32_t enum class Type : uint32_t { Ambient, Directional, Custom, Spot } type;
{
Ambient,
Directional,
Custom,
Spot
} type;
float energy; float energy;
float spotCutoff; float spotCutoff;
@ -397,13 +357,11 @@ struct Light
}; };
/** Intermediate MapArea representation */ /** Intermediate MapArea representation */
struct MapArea struct MapArea {
{
Index visType; Index visType;
std::vector<Vector3f> verts; std::vector<Vector3f> verts;
std::vector<Index> indices; std::vector<Index> indices;
struct Surface struct Surface {
{
Vector3f normal; Vector3f normal;
Vector3f centerOfMass; Vector3f centerOfMass;
Index start; Index start;
@ -412,8 +370,7 @@ struct MapArea
Surface(Connection& conn); Surface(Connection& conn);
}; };
std::vector<Surface> surfaces; std::vector<Surface> surfaces;
struct POI struct POI {
{
uint32_t type; uint32_t type;
uint32_t visMode; uint32_t visMode;
uint32_t objid; uint32_t objid;
@ -425,11 +382,9 @@ struct MapArea
}; };
/** Intermediate MapUniverse representation */ /** Intermediate MapUniverse representation */
struct MapUniverse struct MapUniverse {
{
hecl::ProjectPath hexagonPath; hecl::ProjectPath hexagonPath;
struct World struct World {
{
std::string name; std::string name;
Matrix4f xf; Matrix4f xf;
std::vector<Matrix4f> hexagons; std::vector<Matrix4f> hexagons;
@ -442,8 +397,7 @@ struct MapUniverse
}; };
/** Intermediate bone representation used in Armature */ /** Intermediate bone representation used in Armature */
struct Bone struct Bone {
{
std::string name; std::string name;
Vector3f origin; Vector3f origin;
int32_t parent = -1; int32_t parent = -1;
@ -452,8 +406,7 @@ struct Bone
}; };
/** Intermediate armature representation used in Actor */ /** Intermediate armature representation used in Actor */
struct Armature struct Armature {
{
std::string name; std::string name;
std::vector<Bone> bones; std::vector<Bone> bones;
const Bone* lookupBone(const char* name) const; const Bone* lookupBone(const char* name) const;
@ -464,19 +417,16 @@ struct Armature
}; };
/** Intermediate action representation used in Actor */ /** Intermediate action representation used in Actor */
struct Action struct Action {
{
std::string name; std::string name;
float interval; float interval;
bool additive; bool additive;
bool looping; bool looping;
std::vector<int32_t> frames; std::vector<int32_t> frames;
struct Channel struct Channel {
{
std::string boneName; std::string boneName;
uint32_t attrMask; uint32_t attrMask;
struct Key struct Key {
{
Vector4f rotation; Vector4f rotation;
Vector3f position; Vector3f position;
Vector3f scale; Vector3f scale;
@ -491,12 +441,10 @@ struct Action
}; };
/** Intermediate actor representation prepared by blender from a single HECL actor blend */ /** Intermediate actor representation prepared by blender from a single HECL actor blend */
struct Actor struct Actor {
{
std::vector<Armature> armatures; std::vector<Armature> armatures;
struct Subtype struct Subtype {
{
std::string name; std::string name;
ProjectPath mesh; ProjectPath mesh;
int32_t armature = -1; int32_t armature = -1;
@ -504,8 +452,7 @@ struct Actor
Subtype(Connection& conn); Subtype(Connection& conn);
}; };
std::vector<Subtype> subtypes; std::vector<Subtype> subtypes;
struct Attachment struct Attachment {
{
std::string name; std::string name;
ProjectPath mesh; ProjectPath mesh;
int32_t armature = -1; int32_t armature = -1;
@ -518,22 +465,20 @@ struct Actor
}; };
/** Intermediate pathfinding representation prepared by blender */ /** Intermediate pathfinding representation prepared by blender */
struct PathMesh struct PathMesh {
{
std::vector<uint8_t> data; std::vector<uint8_t> data;
PathMesh(Connection& conn); PathMesh(Connection& conn);
}; };
class DataStream class DataStream {
{
friend class Connection; friend class Connection;
Connection* m_parent; Connection* m_parent;
DataStream(Connection* parent); DataStream(Connection* parent);
public: public:
DataStream(const DataStream& other) = delete; DataStream(const DataStream& other) = delete;
DataStream(DataStream&& other) DataStream(DataStream&& other) : m_parent(other.m_parent) { other.m_parent = nullptr; }
: m_parent(other.m_parent) {other.m_parent = nullptr;} ~DataStream() { close(); }
~DataStream() {close();}
void close(); void close();
std::vector<std::string> getMeshList(); std::vector<std::string> getMeshList();
std::vector<std::string> getLightList(); std::vector<std::string> getLightList();
@ -541,12 +486,11 @@ public:
static const char* MeshOutputModeString(HMDLTopology topology); static const char* MeshOutputModeString(HMDLTopology topology);
/** Compile mesh by context (MESH blends only) */ /** Compile mesh by context (MESH blends only) */
Mesh compileMesh(HMDLTopology topology, int skinSlotCount=10, Mesh compileMesh(HMDLTopology topology, int skinSlotCount = 10, Mesh::SurfProgFunc surfProg = [](int) {});
Mesh::SurfProgFunc surfProg=[](int){});
/** Compile mesh by name (AREA blends only) */ /** Compile mesh by name (AREA blends only) */
Mesh compileMesh(std::string_view name, HMDLTopology topology, int skinSlotCount=10, bool useLuv=false, Mesh compileMesh(std::string_view name, HMDLTopology topology, int skinSlotCount = 10, bool useLuv = false,
Mesh::SurfProgFunc surfProg=[](int){}); Mesh::SurfProgFunc surfProg = [](int) {});
/** Compile collision mesh by name (AREA blends only) */ /** Compile collision mesh by name (AREA blends only) */
ColMesh compileColMesh(std::string_view name); ColMesh compileColMesh(std::string_view name);
@ -555,8 +499,8 @@ public:
std::vector<ColMesh> compileColMeshes(); std::vector<ColMesh> compileColMeshes();
/** Compile all meshes into one (AREA blends only) */ /** Compile all meshes into one (AREA blends only) */
Mesh compileAllMeshes(HMDLTopology topology, int skinSlotCount=10, float maxOctantLength=5.0, Mesh compileAllMeshes(HMDLTopology topology, int skinSlotCount = 10, float maxOctantLength = 5.0,
Mesh::SurfProgFunc surfProg=[](int){}); Mesh::SurfProgFunc surfProg = [](int) {});
/** Compile world intermediate (WORLD blends only) */ /** Compile world intermediate (WORLD blends only) */
World compileWorld(); World compileWorld();
@ -591,8 +535,7 @@ public:
MapUniverse compileMapUniverse(); MapUniverse compileMapUniverse();
}; };
class Connection class Connection {
{
friend class DataStream; friend class DataStream;
friend class PyOutStream; friend class PyOutStream;
friend class ANIMOutStream; friend class ANIMOutStream;
@ -644,34 +587,32 @@ class Connection
void _blenderDied(); void _blenderDied();
public: public:
Connection(int verbosityLevel=1); Connection(int verbosityLevel = 1);
~Connection(); ~Connection();
Connection(const Connection&)=delete; Connection(const Connection&) = delete;
Connection& operator=(const Connection&)=delete; Connection& operator=(const Connection&) = delete;
Connection(Connection&&)=delete; Connection(Connection&&) = delete;
Connection& operator=(Connection&&)=delete; Connection& operator=(Connection&&) = delete;
bool hasSLERP() const {return m_hasSlerp;} bool hasSLERP() const { return m_hasSlerp; }
bool createBlend(const ProjectPath& path, BlendType type); bool createBlend(const ProjectPath& path, BlendType type);
BlendType getBlendType() const {return m_loadedType;} BlendType getBlendType() const { return m_loadedType; }
const ProjectPath& getBlendPath() const {return m_loadedBlend;} const ProjectPath& getBlendPath() const { return m_loadedBlend; }
bool getRigged() const {return m_loadedRigged;} bool getRigged() const { return m_loadedRigged; }
bool openBlend(const ProjectPath& path, bool force=false); bool openBlend(const ProjectPath& path, bool force = false);
bool saveBlend(); bool saveBlend();
void deleteBlend(); void deleteBlend();
PyOutStream beginPythonOut(bool deleteOnError=false) PyOutStream beginPythonOut(bool deleteOnError = false) {
{
bool expect = false; bool expect = false;
if (!m_lock.compare_exchange_strong(expect, true)) if (!m_lock.compare_exchange_strong(expect, true))
BlenderLog.report(logvisor::Fatal, "lock already held for blender::Connection::beginPythonOut()"); BlenderLog.report(logvisor::Fatal, "lock already held for blender::Connection::beginPythonOut()");
return PyOutStream(this, deleteOnError); return PyOutStream(this, deleteOnError);
} }
DataStream beginData() DataStream beginData() {
{
bool expect = false; bool expect = false;
if (!m_lock.compare_exchange_strong(expect, true)) if (!m_lock.compare_exchange_strong(expect, true))
BlenderLog.report(logvisor::Fatal, "lock already held for blender::Connection::beginDataIn()"); BlenderLog.report(logvisor::Fatal, "lock already held for blender::Connection::beginDataIn()");
@ -680,8 +621,7 @@ public:
void quitBlender(); void quitBlender();
void closeStream() void closeStream() {
{
if (m_lock) if (m_lock)
deleteBlend(); deleteBlend();
} }
@ -690,16 +630,15 @@ public:
static void Shutdown(); static void Shutdown();
}; };
class HMDLBuffers class HMDLBuffers {
{
public: public:
struct Surface; struct Surface;
private: private:
friend struct Mesh; friend struct Mesh;
HMDLBuffers(HMDLMeta&& meta, HMDLBuffers(HMDLMeta&& meta, size_t vboSz, const std::vector<atUint32>& iboData, std::vector<Surface>&& surfaces,
size_t vboSz, const std::vector<atUint32>& iboData,
std::vector<Surface>&& surfaces,
const Mesh::SkinBanks& skinBanks); const Mesh::SkinBanks& skinBanks);
public: public:
HMDLMeta m_meta; HMDLMeta m_meta;
size_t m_vboSz; size_t m_vboSz;
@ -707,10 +646,8 @@ public:
size_t m_iboSz; size_t m_iboSz;
std::unique_ptr<uint8_t[]> m_iboData; std::unique_ptr<uint8_t[]> m_iboData;
struct Surface struct Surface {
{ Surface(const Mesh::Surface& origSurf, atUint32 start, atUint32 count)
Surface(const Mesh::Surface& origSurf,
atUint32 start, atUint32 count)
: m_origSurf(origSurf), m_start(start), m_count(count) {} : m_origSurf(origSurf), m_start(start), m_count(count) {}
const Mesh::Surface& m_origSurf; const Mesh::Surface& m_origSurf;
atUint32 m_start; atUint32 m_start;
@ -721,5 +658,4 @@ public:
const Mesh::SkinBanks& m_skinBanks; const Mesh::SkinBanks& m_skinBanks;
}; };
} } // namespace hecl::blender

View File

@ -4,11 +4,9 @@
#include "athena/DNA.hpp" #include "athena/DNA.hpp"
#include "athena/MemoryReader.hpp" #include "athena/MemoryReader.hpp"
namespace hecl::blender namespace hecl::blender {
{
struct SDNABlock : public athena::io::DNA<athena::Little> struct SDNABlock : public athena::io::DNA<athena::Little> {
{
AT_DECL_DNA AT_DECL_DNA
DNAFourCC magic; DNAFourCC magic;
DNAFourCC nameMagic; DNAFourCC nameMagic;
@ -24,13 +22,11 @@ struct SDNABlock : public athena::io::DNA<athena::Little>
Align<4> align3; Align<4> align3;
DNAFourCC strcMagic; DNAFourCC strcMagic;
Value<atUint32> numStrcs; Value<atUint32> numStrcs;
struct SDNAStruct : public athena::io::DNA<athena::Little> struct SDNAStruct : public athena::io::DNA<athena::Little> {
{
AT_DECL_DNA AT_DECL_DNA
Value<atUint16> type; Value<atUint16> type;
Value<atUint16> numFields; Value<atUint16> numFields;
struct SDNAField : public athena::io::DNA<athena::Little> struct SDNAField : public athena::io::DNA<athena::Little> {
{
AT_DECL_DNA AT_DECL_DNA
Value<atUint16> type; Value<atUint16> type;
Value<atUint16> name; Value<atUint16> name;
@ -46,8 +42,7 @@ struct SDNABlock : public athena::io::DNA<athena::Little>
const SDNAStruct* lookupStruct(const char* n, int& idx) const; const SDNAStruct* lookupStruct(const char* n, int& idx) const;
}; };
struct FileBlock : public athena::io::DNA<athena::Little> struct FileBlock : public athena::io::DNA<athena::Little> {
{
AT_DECL_DNA AT_DECL_DNA
DNAFourCC type; DNAFourCC type;
Value<atUint32> size; Value<atUint32> size;
@ -56,10 +51,10 @@ struct FileBlock : public athena::io::DNA<athena::Little>
Value<atUint32> count; Value<atUint32> count;
}; };
class SDNARead class SDNARead {
{
std::vector<uint8_t> m_data; std::vector<uint8_t> m_data;
SDNABlock m_sdnaBlock; SDNABlock m_sdnaBlock;
public: public:
explicit SDNARead(SystemStringView path); explicit SDNARead(SystemStringView path);
operator bool() const { return !m_data.empty(); } operator bool() const { return !m_data.empty(); }
@ -69,4 +64,4 @@ public:
BlendType GetBlendType(SystemStringView path); BlendType GetBlendType(SystemStringView path);
} } // namespace hecl::blender

View File

@ -2,24 +2,22 @@
#include <memory> #include <memory>
namespace hecl::blender namespace hecl::blender {
{
class Connection; class Connection;
class Token class Token {
{
std::unique_ptr<Connection> m_conn; std::unique_ptr<Connection> m_conn;
public: public:
Connection& getBlenderConnection(); Connection& getBlenderConnection();
void shutdown(); void shutdown();
Token() = default; Token() = default;
~Token(); ~Token();
Token(const Token&)=delete; Token(const Token&) = delete;
Token& operator=(const Token&)=delete; Token& operator=(const Token&) = delete;
Token(Token&&)=default; Token(Token&&) = default;
Token& operator=(Token&&)=default; Token& operator=(Token&&) = default;
}; };
} } // namespace hecl::blender

50
hecl/include/hecl/CVar.hpp Executable file → Normal file
View File

@ -6,21 +6,11 @@
#include <athena/Global.hpp> #include <athena/Global.hpp>
#include <athena/DNAYaml.hpp> #include <athena/DNAYaml.hpp>
namespace hecl namespace hecl {
{ namespace DNACVAR {
namespace DNACVAR enum class EType : atUint8 { Boolean, Integer, Float, Literal, Vec4f };
{
enum class EType : atUint8
{
Boolean,
Integer,
Float,
Literal,
Vec4f
};
enum EFlags enum EFlags {
{
None = -1, None = -1,
System = (1 << 0), System = (1 << 0),
Game = (1 << 1), Game = (1 << 1),
@ -36,27 +26,24 @@ enum EFlags
}; };
ENABLE_BITWISE_ENUM(EFlags) ENABLE_BITWISE_ENUM(EFlags)
class CVar : public athena::io::DNA<athena::Big> class CVar : public athena::io::DNA<athena::Big> {
{
public: public:
AT_DECL_DNA AT_DECL_DNA
String<-1> m_name; String<-1> m_name;
String<-1> m_value; String<-1> m_value;
}; };
struct CVarContainer : public athena::io::DNA<athena::Big> struct CVarContainer : public athena::io::DNA<athena::Big> {
{
AT_DECL_DNA AT_DECL_DNA
Value<atUint32> magic = 'CVAR'; Value<atUint32> magic = 'CVAR';
Value<atUint32> cvarCount; Value<atUint32> cvarCount;
Vector<CVar, AT_DNA_COUNT(cvarCount)> cvars; Vector<CVar, AT_DNA_COUNT(cvarCount)> cvars;
}; };
} } // namespace DNACVAR
class CVarManager; class CVarManager;
class CVar : protected DNACVAR::CVar class CVar : protected DNACVAR::CVar {
{
friend class CVarManager; friend class CVarManager;
Delete _d; Delete _d;
@ -66,14 +53,14 @@ public:
using EType = DNACVAR::EType; using EType = DNACVAR::EType;
using EFlags = DNACVAR::EFlags; using EFlags = DNACVAR::EFlags;
CVar(std::string_view name, std::string_view value, std::string_view help, EType type, EFlags flags, CVarManager& parent); CVar(std::string_view name, std::string_view value, std::string_view help, EType type, EFlags flags,
CVarManager& parent);
CVar(std::string_view name, std::string_view value, std::string_view help, EFlags flags, CVarManager& parent); CVar(std::string_view name, std::string_view value, std::string_view help, EFlags flags, CVarManager& parent);
CVar(std::string_view name, float value, std::string_view help, EFlags flags, CVarManager& parent); CVar(std::string_view name, float value, std::string_view help, EFlags flags, CVarManager& parent);
CVar(std::string_view name, bool value, std::string_view help, EFlags flags, CVarManager& parent); CVar(std::string_view name, bool value, std::string_view help, EFlags flags, CVarManager& parent);
CVar(std::string_view name, int value, std::string_view help, EFlags flags, CVarManager& parent); CVar(std::string_view name, int value, std::string_view help, EFlags flags, CVarManager& parent);
CVar(std::string_view name, const atVec4f& value, std::string_view help, EFlags flags, CVarManager& parent); CVar(std::string_view name, const atVec4f& value, std::string_view help, EFlags flags, CVarManager& parent);
std::string_view name() const { return m_name; } std::string_view name() const { return m_name; }
std::string_view rawHelp() const { return m_help; } std::string_view rawHelp() const { return m_help; }
std::string help() const; std::string help() const;
@ -147,13 +134,18 @@ private:
std::vector<ListenerFunc> m_listeners; std::vector<ListenerFunc> m_listeners;
}; };
class CVarUnlocker class CVarUnlocker {
{
CVar* m_cvar; CVar* m_cvar;
public: public:
CVarUnlocker(CVar* cvar) : m_cvar(cvar) { if (m_cvar) m_cvar->unlock(); } CVarUnlocker(CVar* cvar) : m_cvar(cvar) {
~CVarUnlocker() { if (m_cvar) m_cvar->lock(); } if (m_cvar)
m_cvar->unlock();
}
~CVarUnlocker() {
if (m_cvar)
m_cvar->lock();
}
}; };
} } // namespace hecl

View File

@ -5,8 +5,7 @@
#undef min #undef min
#undef max #undef max
namespace hecl namespace hecl {
{
using namespace std::literals; using namespace std::literals;
@ -18,75 +17,45 @@ using namespace std::literals;
#define DEFAULT_GRAPHICS_API "OpenGL"sv #define DEFAULT_GRAPHICS_API "OpenGL"sv
#endif #endif
struct CVarCommons struct CVarCommons {
{
CVarManager& m_mgr; CVarManager& m_mgr;
CVar* m_graphicsApi = nullptr; CVar* m_graphicsApi = nullptr;
CVar* m_drawSamples = nullptr; CVar* m_drawSamples = nullptr;
CVar* m_texAnisotropy = nullptr; CVar* m_texAnisotropy = nullptr;
CVar* m_deepColor = nullptr; CVar* m_deepColor = nullptr;
CVarCommons(CVarManager& manager) : m_mgr(manager) CVarCommons(CVarManager& manager) : m_mgr(manager) {
{ m_graphicsApi = m_mgr.findOrMakeCVar("graphicsApi"sv, "API to use for rendering graphics"sv, DEFAULT_GRAPHICS_API,
m_graphicsApi = m_mgr.findOrMakeCVar("graphicsApi"sv, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive |
"API to use for rendering graphics"sv, hecl::CVar::EFlags::ModifyRestart);
DEFAULT_GRAPHICS_API, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart); m_drawSamples = m_mgr.findOrMakeCVar("drawSamples"sv, "Number of MSAA samples to use for render targets"sv, 1,
m_drawSamples = m_mgr.findOrMakeCVar("drawSamples"sv, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive |
"Number of MSAA samples to use for render targets"sv, hecl::CVar::EFlags::ModifyRestart);
1, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart); m_texAnisotropy = m_mgr.findOrMakeCVar(
m_texAnisotropy = m_mgr.findOrMakeCVar("texAnisotropy"sv, "texAnisotropy"sv, "Number of anisotropic samples to use for sampling textures"sv, 1,
"Number of anisotropic samples to use for sampling textures"sv, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart);
1, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart); m_deepColor = m_mgr.findOrMakeCVar(
m_deepColor = m_mgr.findOrMakeCVar("deepColor"sv, "deepColor"sv, "Allow framebuffer with color depth greater-then 24-bits"sv, false,
"Allow framebuffer with color depth greater-then 24-bits"sv, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart);
false, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart);
} }
std::string getGraphicsApi() const std::string getGraphicsApi() const { return m_graphicsApi->toLiteral(); }
{
return m_graphicsApi->toLiteral();
}
void setGraphicsApi(std::string_view api) void setGraphicsApi(std::string_view api) { m_graphicsApi->fromLiteral(api); }
{
m_graphicsApi->fromLiteral(api);
}
uint32_t getSamples() const uint32_t getSamples() const { return std::max(uint32_t(1), uint32_t(m_drawSamples->toInteger())); }
{
return std::max(uint32_t(1), uint32_t(m_drawSamples->toInteger()));
}
void setSamples(uint32_t v) void setSamples(uint32_t v) { m_drawSamples->fromInteger(std::max(uint32_t(1), v)); }
{
m_drawSamples->fromInteger(std::max(uint32_t(1), v));
}
uint32_t getAnisotropy() const uint32_t getAnisotropy() const { return std::max(uint32_t(1), uint32_t(m_texAnisotropy->toInteger())); }
{
return std::max(uint32_t(1), uint32_t(m_texAnisotropy->toInteger()));
}
void setAnisotropy(uint32_t v) void setAnisotropy(uint32_t v) { m_texAnisotropy->fromInteger(std::max(uint32_t(1), v)); }
{
m_texAnisotropy->fromInteger(std::max(uint32_t(1), v));
}
bool getDeepColor() const bool getDeepColor() const { return m_deepColor->toBoolean(); }
{
return m_deepColor->toBoolean();
}
void setDeepColor(bool b) void setDeepColor(bool b) { m_deepColor->fromBoolean(b); }
{
m_deepColor->fromBoolean(b);
}
void serialize() void serialize() { m_mgr.serialize(); }
{
m_mgr.serialize();
}
}; };
} } // namespace hecl

53
hecl/include/hecl/CVarManager.hpp Executable file → Normal file
View File

@ -5,23 +5,18 @@
#include "CVar.hpp" #include "CVar.hpp"
#include "hecl/SystemChar.hpp" #include "hecl/SystemChar.hpp"
namespace hecl namespace hecl {
{ namespace Runtime {
namespace Runtime
{
class FileStoreManager; class FileStoreManager;
} }
extern CVar* com_developer; extern CVar* com_developer;
extern CVar* com_configfile; extern CVar* com_configfile;
extern CVar* com_enableCheats; extern CVar* com_enableCheats;
class CVarManager final class CVarManager final {
{
using CVarContainer = DNACVAR::CVarContainer; using CVarContainer = DNACVAR::CVarContainer;
template <typename T> template <typename T>
CVar* _newCVar(std::string_view name, std::string_view help, const T& value, CVar::EFlags flags) CVar* _newCVar(std::string_view name, std::string_view help, const T& value, CVar::EFlags flags) {
{ if (CVar* ret = registerCVar(std::make_unique<CVar>(name, value, help, flags, *this))) {
if (CVar* ret = registerCVar(std::make_unique<CVar>(name, value, help, flags, *this)))
{
deserialize(ret); deserialize(ret);
return ret; return ret;
} }
@ -31,6 +26,7 @@ class CVarManager final
hecl::Runtime::FileStoreManager& m_store; hecl::Runtime::FileStoreManager& m_store;
bool m_useBinary; bool m_useBinary;
static CVarManager* m_instance; static CVarManager* m_instance;
public: public:
CVarManager() = delete; CVarManager() = delete;
CVarManager(const CVarManager&) = delete; CVarManager(const CVarManager&) = delete;
@ -39,23 +35,27 @@ public:
CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary = false); CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary = false);
~CVarManager(); ~CVarManager();
CVar* newCVar(std::string_view name, std::string_view help, const atVec4f& value, CVar::EFlags flags) CVar* newCVar(std::string_view name, std::string_view help, const atVec4f& value, CVar::EFlags flags) {
{ return _newCVar<atVec4f>(name, help, value, flags); } return _newCVar<atVec4f>(name, help, value, flags);
CVar* newCVar(std::string_view name, std::string_view help, std::string_view value, CVar::EFlags flags) }
{ return _newCVar<std::string_view>(name, help, value, flags); } CVar* newCVar(std::string_view name, std::string_view help, std::string_view value, CVar::EFlags flags) {
CVar* newCVar(std::string_view name, std::string_view help, bool value, CVar::EFlags flags) return _newCVar<std::string_view>(name, help, value, flags);
{ return _newCVar<bool>(name, help, value, flags); } }
CVar* newCVar(std::string_view name, std::string_view help, float value, CVar::EFlags flags) CVar* newCVar(std::string_view name, std::string_view help, bool value, CVar::EFlags flags) {
{ return _newCVar<float>(name, help, value, flags); } return _newCVar<bool>(name, help, value, flags);
CVar* newCVar(std::string_view name, std::string_view help, int value, CVar::EFlags flags) }
{ return _newCVar<int>(name, help, value, flags); } CVar* newCVar(std::string_view name, std::string_view help, float value, CVar::EFlags flags) {
return _newCVar<float>(name, help, value, flags);
}
CVar* newCVar(std::string_view name, std::string_view help, int value, CVar::EFlags flags) {
return _newCVar<int>(name, help, value, flags);
}
CVar* registerCVar(std::unique_ptr<CVar>&& cvar); CVar* registerCVar(std::unique_ptr<CVar>&& cvar);
CVar* findCVar(std::string_view name); CVar* findCVar(std::string_view name);
template<class... _Args> template <class... _Args>
CVar* findOrMakeCVar(std::string_view name, _Args&&... args) CVar* findOrMakeCVar(std::string_view name, _Args&&... args) {
{
if (CVar* cv = findCVar(name)) if (CVar* cv = findCVar(name))
return cv; return cv;
return newCVar(name, std::forward<_Args>(args)...); return newCVar(name, std::forward<_Args>(args)...);
@ -73,11 +73,11 @@ public:
void setCVar(class Console* con, const std::vector<std::string>& args); void setCVar(class Console* con, const std::vector<std::string>& args);
void getCVar(class Console* con, const std::vector<std::string>& args); void getCVar(class Console* con, const std::vector<std::string>& args);
void setDeveloperMode(bool v, bool setDeserialized = false);
void setDeveloperMode(bool v, bool setDeserialized=false);
bool restartRequired() const; bool restartRequired() const;
void parseCommandLine(const std::vector<SystemString>& args); void parseCommandLine(const std::vector<SystemString>& args);
private: private:
bool suppressDeveloper(); bool suppressDeveloper();
void restoreDeveloper(bool oldDeveloper); void restoreDeveloper(bool oldDeveloper);
@ -86,5 +86,4 @@ private:
std::unordered_map<std::string, std::string> m_deferedCVars; std::unordered_map<std::string, std::string> m_deferedCVars;
}; };
} } // namespace hecl

View File

@ -9,11 +9,9 @@
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
namespace hecl namespace hecl {
{
class ClientProcess class ClientProcess {
{
std::mutex m_mutex; std::mutex m_mutex;
std::condition_variable m_cv; std::condition_variable m_cv;
std::condition_variable m_initCv; std::condition_variable m_initCv;
@ -23,60 +21,46 @@ class ClientProcess
int m_addedCooks = 0; int m_addedCooks = 0;
public: public:
struct Transaction struct Transaction {
{
ClientProcess& m_parent; ClientProcess& m_parent;
enum class Type enum class Type { Buffer, Cook, Lambda } m_type;
{
Buffer,
Cook,
Lambda
} m_type;
bool m_complete = false; bool m_complete = false;
virtual void run(blender::Token& btok)=0; virtual void run(blender::Token& btok) = 0;
Transaction(ClientProcess& parent, Type tp) : m_parent(parent), m_type(tp) {} Transaction(ClientProcess& parent, Type tp) : m_parent(parent), m_type(tp) {}
}; };
struct BufferTransaction final : Transaction struct BufferTransaction final : Transaction {
{
ProjectPath m_path; ProjectPath m_path;
void* m_targetBuf; void* m_targetBuf;
size_t m_maxLen; size_t m_maxLen;
size_t m_offset; size_t m_offset;
void run(blender::Token& btok); void run(blender::Token& btok);
BufferTransaction(ClientProcess& parent, const ProjectPath& path, BufferTransaction(ClientProcess& parent, const ProjectPath& path, void* target, size_t maxLen, size_t offset)
void* target, size_t maxLen, size_t offset) : Transaction(parent, Type::Buffer), m_path(path), m_targetBuf(target), m_maxLen(maxLen), m_offset(offset) {}
: Transaction(parent, Type::Buffer),
m_path(path), m_targetBuf(target),
m_maxLen(maxLen), m_offset(offset) {}
}; };
struct CookTransaction final : Transaction struct CookTransaction final : Transaction {
{
ProjectPath m_path; ProjectPath m_path;
Database::IDataSpec* m_dataSpec; Database::IDataSpec* m_dataSpec;
bool m_returnResult = false; bool m_returnResult = false;
bool m_force; bool m_force;
bool m_fast; bool m_fast;
void run(blender::Token& btok); void run(blender::Token& btok);
CookTransaction(ClientProcess& parent, const ProjectPath& path, CookTransaction(ClientProcess& parent, const ProjectPath& path, bool force, bool fast, Database::IDataSpec* spec)
bool force, bool fast, Database::IDataSpec* spec) : Transaction(parent, Type::Cook), m_path(path), m_dataSpec(spec), m_force(force), m_fast(fast) {}
: Transaction(parent, Type::Cook), m_path(path), m_dataSpec(spec),
m_force(force), m_fast(fast) {}
}; };
struct LambdaTransaction final : Transaction struct LambdaTransaction final : Transaction {
{
std::function<void(blender::Token&)> m_func; std::function<void(blender::Token&)> m_func;
void run(blender::Token& btok); void run(blender::Token& btok);
LambdaTransaction(ClientProcess& parent, std::function<void(blender::Token&)>&& func) LambdaTransaction(ClientProcess& parent, std::function<void(blender::Token&)>&& func)
: Transaction(parent, Type::Lambda), m_func(std::move(func)) {} : Transaction(parent, Type::Lambda), m_func(std::move(func)) {}
}; };
private: private:
std::list<std::shared_ptr<Transaction>> m_pendingQueue; std::list<std::shared_ptr<Transaction>> m_pendingQueue;
std::list<std::shared_ptr<Transaction>> m_completedQueue; std::list<std::shared_ptr<Transaction>> m_completedQueue;
int m_inProgress = 0; int m_inProgress = 0;
bool m_running = true; bool m_running = true;
struct Worker struct Worker {
{
ClientProcess& m_proc; ClientProcess& m_proc;
int m_idx; int m_idx;
std::thread m_thr; std::thread m_thr;
@ -89,25 +73,20 @@ private:
static ThreadLocalPtr<ClientProcess::Worker> ThreadWorker; static ThreadLocalPtr<ClientProcess::Worker> ThreadWorker;
public: public:
ClientProcess(const MultiProgressPrinter* progPrinter=nullptr); ClientProcess(const MultiProgressPrinter* progPrinter = nullptr);
~ClientProcess() {shutdown();} ~ClientProcess() { shutdown(); }
std::shared_ptr<const BufferTransaction> std::shared_ptr<const BufferTransaction> addBufferTransaction(const hecl::ProjectPath& path, void* target,
addBufferTransaction(const hecl::ProjectPath& path, void* target,
size_t maxLen, size_t offset); size_t maxLen, size_t offset);
std::shared_ptr<const CookTransaction> std::shared_ptr<const CookTransaction> addCookTransaction(const hecl::ProjectPath& path, bool force, bool fast,
addCookTransaction(const hecl::ProjectPath& path, bool force, Database::IDataSpec* spec);
bool fast, Database::IDataSpec* spec); std::shared_ptr<const LambdaTransaction> addLambdaTransaction(std::function<void(blender::Token&)>&& func);
std::shared_ptr<const LambdaTransaction> bool syncCook(const hecl::ProjectPath& path, Database::IDataSpec* spec, blender::Token& btok, bool force, bool fast);
addLambdaTransaction(std::function<void(blender::Token&)>&& func);
bool syncCook(const hecl::ProjectPath& path, Database::IDataSpec* spec, blender::Token& btok,
bool force, bool fast);
void swapCompletedQueue(std::list<std::shared_ptr<Transaction>>& queue); void swapCompletedQueue(std::list<std::shared_ptr<Transaction>>& queue);
void waitUntilComplete(); void waitUntilComplete();
void shutdown(); void shutdown();
bool isBusy() const { return m_pendingQueue.size() || m_inProgress; } bool isBusy() const { return m_pendingQueue.size() || m_inProgress; }
static int GetThreadWorkerIdx() static int GetThreadWorkerIdx() {
{
Worker* w = ThreadWorker.get(); Worker* w = ThreadWorker.get();
if (w) if (w)
return w->m_idx; return w->m_idx;
@ -115,5 +94,4 @@ public:
} }
}; };
} } // namespace hecl

View File

@ -5,66 +5,87 @@
#include "boo/graphicsdev/D3D.hpp" #include "boo/graphicsdev/D3D.hpp"
#include "boo/graphicsdev/Metal.hpp" #include "boo/graphicsdev/Metal.hpp"
namespace hecl namespace hecl {
{
namespace PlatformType namespace PlatformType {
{
using PlatformEnum = boo::IGraphicsDataFactory::Platform; using PlatformEnum = boo::IGraphicsDataFactory::Platform;
struct Null {}; struct Null {};
struct OpenGL { static constexpr PlatformEnum Enum = PlatformEnum::OpenGL; static const char* Name; struct OpenGL {
static constexpr PlatformEnum Enum = PlatformEnum::OpenGL;
static const char* Name;
#if BOO_HAS_GL #if BOO_HAS_GL
using Context = boo::GLDataFactory::Context; using Context = boo::GLDataFactory::Context;
#endif #endif
}; };
struct D3D11 { static constexpr PlatformEnum Enum = PlatformEnum::D3D11; static const char* Name; struct D3D11 {
static constexpr PlatformEnum Enum = PlatformEnum::D3D11;
static const char* Name;
#if _WIN32 #if _WIN32
using Context = boo::D3D11DataFactory::Context; using Context = boo::D3D11DataFactory::Context;
#endif #endif
}; };
struct Metal { static constexpr PlatformEnum Enum = PlatformEnum::Metal; static const char* Name; struct Metal {
static constexpr PlatformEnum Enum = PlatformEnum::Metal;
static const char* Name;
#if BOO_HAS_METAL #if BOO_HAS_METAL
using Context = boo::MetalDataFactory::Context; using Context = boo::MetalDataFactory::Context;
#endif #endif
}; };
struct Vulkan { static constexpr PlatformEnum Enum = PlatformEnum::Vulkan; static const char* Name; struct Vulkan {
static constexpr PlatformEnum Enum = PlatformEnum::Vulkan;
static const char* Name;
#if BOO_HAS_VULKAN #if BOO_HAS_VULKAN
using Context = boo::VulkanDataFactory::Context; using Context = boo::VulkanDataFactory::Context;
#endif #endif
}; };
struct NX { static constexpr PlatformEnum Enum = PlatformEnum::NX; static const char* Name; struct NX {
static constexpr PlatformEnum Enum = PlatformEnum::NX;
static const char* Name;
#if BOO_HAS_NX #if BOO_HAS_NX
using Context = boo::NXDataFactory::Context; using Context = boo::NXDataFactory::Context;
#endif #endif
}; };
} } // namespace PlatformType
namespace PipelineStage namespace PipelineStage {
{
using StageEnum = boo::PipelineStage; using StageEnum = boo::PipelineStage;
struct Null { static constexpr StageEnum Enum = StageEnum::Null; static const char* Name; }; struct Null {
struct Vertex { static constexpr StageEnum Enum = StageEnum::Vertex; static const char* Name; }; static constexpr StageEnum Enum = StageEnum::Null;
struct Fragment { static constexpr StageEnum Enum = StageEnum::Fragment; static const char* Name; }; static const char* Name;
struct Geometry { static constexpr StageEnum Enum = StageEnum::Geometry; static const char* Name; }; };
struct Control { static constexpr StageEnum Enum = StageEnum::Control; static const char* Name; }; struct Vertex {
struct Evaluation { static constexpr StageEnum Enum = StageEnum::Evaluation; static const char* Name; }; static constexpr StageEnum Enum = StageEnum::Vertex;
} static const char* Name;
};
struct Fragment {
static constexpr StageEnum Enum = StageEnum::Fragment;
static const char* Name;
};
struct Geometry {
static constexpr StageEnum Enum = StageEnum::Geometry;
static const char* Name;
};
struct Control {
static constexpr StageEnum Enum = StageEnum::Control;
static const char* Name;
};
struct Evaluation {
static constexpr StageEnum Enum = StageEnum::Evaluation;
static const char* Name;
};
} // namespace PipelineStage
#ifdef __APPLE__ #ifdef __APPLE__
using StageBinaryData = std::shared_ptr<uint8_t>; using StageBinaryData = std::shared_ptr<uint8_t>;
static inline StageBinaryData MakeStageBinaryData(size_t sz) static inline StageBinaryData MakeStageBinaryData(size_t sz) {
{
return StageBinaryData(new uint8_t[sz], std::default_delete<uint8_t[]>{}); return StageBinaryData(new uint8_t[sz], std::default_delete<uint8_t[]>{});
} }
#else #else
using StageBinaryData = std::shared_ptr<uint8_t[]>; using StageBinaryData = std::shared_ptr<uint8_t[]>;
static inline StageBinaryData MakeStageBinaryData(size_t sz) static inline StageBinaryData MakeStageBinaryData(size_t sz) { return StageBinaryData(new uint8_t[sz]); }
{
return StageBinaryData(new uint8_t[sz]);
}
#endif #endif
template<typename P, typename S> template <typename P, typename S>
std::pair<StageBinaryData, size_t> CompileShader(std::string_view text); std::pair<StageBinaryData, size_t> CompileShader(std::string_view text);
} } // namespace hecl

View File

@ -7,18 +7,11 @@
#include "boo/IWindow.hpp" #include "boo/IWindow.hpp"
#include "logvisor/logvisor.hpp" #include "logvisor/logvisor.hpp"
namespace hecl namespace hecl {
{
class CVarManager; class CVarManager;
class CVar; class CVar;
struct SConsoleCommand struct SConsoleCommand {
{ enum class ECommandFlags { Normal = 0, Cheat = (1 << 0), Developer = (1 << 1) };
enum class ECommandFlags
{
Normal = 0,
Cheat = (1 << 0),
Developer = (1 << 1)
};
std::string m_displayName; std::string m_displayName;
std::string m_helpString; std::string m_helpString;
std::string m_usage; std::string m_usage;
@ -27,45 +20,31 @@ struct SConsoleCommand
}; };
ENABLE_BITWISE_ENUM(SConsoleCommand::ECommandFlags) ENABLE_BITWISE_ENUM(SConsoleCommand::ECommandFlags)
class Console class Console {
{
friend class LogVisorAdapter; friend class LogVisorAdapter;
struct LogVisorAdapter : logvisor::ILogger struct LogVisorAdapter : logvisor::ILogger {
{
Console* m_con; Console* m_con;
LogVisorAdapter(Console* con) LogVisorAdapter(Console* con) : m_con(con) {}
: m_con(con) {}
~LogVisorAdapter() {} ~LogVisorAdapter() {}
void report(const char* modName, logvisor::Level severity, void report(const char* modName, logvisor::Level severity, const char* format, va_list ap);
void report(const char* modName, logvisor::Level severity, const wchar_t* format, va_list ap);
void reportSource(const char* modName, logvisor::Level severity, const char* file, unsigned linenum,
const char* format, va_list ap); const char* format, va_list ap);
void report(const char* modName, logvisor::Level severity, void reportSource(const char* modName, logvisor::Level severity, const char* file, unsigned linenum,
const wchar_t* format, va_list ap);
void reportSource(const char* modName, logvisor::Level severity,
const char* file, unsigned linenum,
const char* format, va_list ap);
void reportSource(const char* modName, logvisor::Level severity,
const char* file, unsigned linenum,
const wchar_t* format, va_list ap); const wchar_t* format, va_list ap);
}; };
public: public:
static Console* m_instance; static Console* m_instance;
enum class Level enum class Level {
{
Info, /**< Non-error informative message */ Info, /**< Non-error informative message */
Warning, /**< Non-error warning message */ Warning, /**< Non-error warning message */
Error, /**< Recoverable error message */ Error, /**< Recoverable error message */
Fatal /**< Non-recoverable error message (Kept for compatibility with logvisor) */ Fatal /**< Non-recoverable error message (Kept for compatibility with logvisor) */
}; };
enum State enum State { Closed, Closing, Opened, Opening };
{
Closed,
Closing,
Opened,
Opening
};
private: private:
CVarManager* m_cvarMgr; CVarManager* m_cvarMgr;
@ -86,9 +65,12 @@ private:
float m_cachedConHeight; float m_cachedConHeight;
bool m_showCursor = true; bool m_showCursor = true;
float m_cursorTime = 0.f; float m_cursorTime = 0.f;
public: public:
Console(CVarManager*); Console(CVarManager*);
void registerCommand(std::string_view name, std::string_view helpText, std::string_view usage, const std::function<void(Console*, const std::vector<std::string>&)>&& func, SConsoleCommand::ECommandFlags cmdFlags = SConsoleCommand::ECommandFlags::Normal); void registerCommand(std::string_view name, std::string_view helpText, std::string_view usage,
const std::function<void(Console*, const std::vector<std::string>&)>&& func,
SConsoleCommand::ECommandFlags cmdFlags = SConsoleCommand::ECommandFlags::Normal);
void unregisterCommand(std::string_view name); void unregisterCommand(std::string_view name);
void executeString(const std::string& strToExec); void executeString(const std::string& strToExec);
@ -97,7 +79,7 @@ public:
void listCommands(Console* con, const std::vector<std::string>& args); void listCommands(Console* con, const std::vector<std::string>& args);
bool commandExists(std::string_view cmd); bool commandExists(std::string_view cmd);
void report(Level level, const char *fmt, va_list list); void report(Level level, const char* fmt, va_list list);
void report(Level level, const char* fmt, ...); void report(Level level, const char* fmt, ...);
void proc(); void proc();
@ -110,5 +92,4 @@ public:
static void RegisterLogger(Console* con); static void RegisterLogger(Console* con);
bool isOpen() { return m_state == State::Opened; } bool isOpen() { return m_state == State::Opened; }
}; };
} } // namespace hecl

View File

@ -21,12 +21,10 @@
#define RUNTIME_ORIGINAL_IDS 0 #define RUNTIME_ORIGINAL_IDS 0
namespace hecl namespace hecl {
{
class ClientProcess; class ClientProcess;
namespace Database namespace Database {
{
class Project; class Project;
extern logvisor::Module LogModule; extern logvisor::Module LogModule;
@ -34,27 +32,23 @@ extern logvisor::Module LogModule;
/** /**
* @brief Nodegraph class for gathering dependency-resolved objects for packaging * @brief Nodegraph class for gathering dependency-resolved objects for packaging
*/ */
class PackageDepsgraph class PackageDepsgraph {
{
public: public:
struct Node struct Node {
{ enum class Type { Data, Group } type;
enum class Type
{
Data,
Group
} type;
ProjectPath path; ProjectPath path;
ProjectPath cookedPath; ProjectPath cookedPath;
class ObjectBase* projectObj; class ObjectBase* projectObj;
Node* sub; Node* sub;
Node* next; Node* next;
}; };
private: private:
friend class Project; friend class Project;
std::vector<Node> m_nodes; std::vector<Node> m_nodes;
public: public:
const Node* getRootNode() const {return &m_nodes[0];} const Node* getRootNode() const { return &m_nodes[0]; }
}; };
/** /**
@ -63,9 +57,9 @@ public:
* The DataSpec class manages interfaces for unpackaging, cooking, and packaging * The DataSpec class manages interfaces for unpackaging, cooking, and packaging
* of data for interacting with a specific system/game-engine. * of data for interacting with a specific system/game-engine.
*/ */
class IDataSpec class IDataSpec {
{
const DataSpecEntry* m_specEntry; const DataSpecEntry* m_specEntry;
public: public:
IDataSpec(const DataSpecEntry* specEntry) : m_specEntry(specEntry) {} IDataSpec(const DataSpecEntry* specEntry) : m_specEntry(specEntry) {}
virtual ~IDataSpec() {} virtual ~IDataSpec() {}
@ -77,8 +71,7 @@ public:
* An extract pass iterates through a source package or image and * An extract pass iterates through a source package or image and
* reverses the cooking process by emitting editable resources * reverses the cooking process by emitting editable resources
*/ */
struct ExtractPassInfo struct ExtractPassInfo {
{
SystemString srcpath; SystemString srcpath;
std::vector<SystemString> extractArgs; std::vector<SystemString> extractArgs;
bool force; bool force;
@ -90,8 +83,7 @@ public:
* Constructed by canExtract() to advise the user of the content about * Constructed by canExtract() to advise the user of the content about
* to be extracted * to be extracted
*/ */
struct ExtractReport struct ExtractReport {
{
SystemString name; SystemString name;
SystemString desc; SystemString desc;
std::vector<ExtractReport> childOpts; std::vector<ExtractReport> childOpts;
@ -99,42 +91,54 @@ public:
virtual void setThreadProject() {} virtual void setThreadProject() {}
virtual bool canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps) virtual bool canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps) {
{(void)info;(void)reps;LogModule.report(logvisor::Error, "not implemented");return false;} (void)info;
virtual void doExtract(const ExtractPassInfo& info, const MultiProgressPrinter& progress) (void)reps;
{(void)info;(void)progress;} LogModule.report(logvisor::Error, "not implemented");
return false;
}
virtual void doExtract(const ExtractPassInfo& info, const MultiProgressPrinter& progress) {
(void)info;
(void)progress;
}
virtual bool canCook(const ProjectPath& path, blender::Token& btok, int cookPass = -1) virtual bool canCook(const ProjectPath& path, blender::Token& btok, int cookPass = -1) {
{(void)path;LogModule.report(logvisor::Error, "not implemented");(void)cookPass;return false;} (void)path;
virtual const DataSpecEntry* overrideDataSpec(const ProjectPath& path, LogModule.report(logvisor::Error, "not implemented");
const Database::DataSpecEntry* oldEntry, (void)cookPass;
blender::Token& btok) const return false;
{(void)path;return oldEntry;} }
virtual void doCook(const ProjectPath& path, const ProjectPath& cookedPath, virtual const DataSpecEntry* overrideDataSpec(const ProjectPath& path, const Database::DataSpecEntry* oldEntry,
bool fast, blender::Token& btok, FCookProgress progress) blender::Token& btok) const {
{(void)path;(void)cookedPath;(void)fast;(void)progress;} (void)path;
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 bool canPackage(const ProjectPath& path) virtual bool canPackage(const ProjectPath& path) {
{(void)path;return false;} (void)path;
virtual void doPackage(const ProjectPath& path, const Database::DataSpecEntry* entry, return false;
bool fast, blender::Token& btok, const MultiProgressPrinter& progress, }
ClientProcess* cp=nullptr) virtual void doPackage(const ProjectPath& path, const Database::DataSpecEntry* entry, bool fast, blender::Token& btok,
{(void)path;} const MultiProgressPrinter& progress, ClientProcess* cp = nullptr) {
(void)path;
}
virtual void interruptCook() {} virtual void interruptCook() {}
const DataSpecEntry* getDataSpecEntry() const {return m_specEntry;} const DataSpecEntry* getDataSpecEntry() const { return m_specEntry; }
}; };
/** /**
* @brief Pre-emptive indication of what the constructed DataSpec is used for * @brief Pre-emptive indication of what the constructed DataSpec is used for
*/ */
enum class DataSpecTool enum class DataSpecTool { Extract, Cook, Package };
{
Extract,
Cook,
Package
};
extern std::vector<const struct DataSpecEntry*> DATA_SPEC_REGISTRY; extern std::vector<const struct DataSpecEntry*> DATA_SPEC_REGISTRY;
@ -143,8 +147,7 @@ extern std::vector<const struct DataSpecEntry*> DATA_SPEC_REGISTRY;
* *
* Auto-registers with data spec registry * Auto-registers with data spec registry
*/ */
struct DataSpecEntry struct DataSpecEntry {
{
SystemStringView m_name; SystemStringView m_name;
SystemStringView m_desc; SystemStringView m_desc;
SystemStringView m_pakExt; SystemStringView m_pakExt;
@ -153,8 +156,7 @@ struct DataSpecEntry
DataSpecEntry(SystemStringView name, SystemStringView desc, SystemStringView pakExt, int numCookPasses, DataSpecEntry(SystemStringView name, SystemStringView desc, SystemStringView pakExt, int numCookPasses,
std::function<std::unique_ptr<IDataSpec>(Project& project, DataSpecTool)>&& factory) std::function<std::unique_ptr<IDataSpec>(Project& project, DataSpecTool)>&& factory)
: m_name(name), m_desc(desc), m_pakExt(pakExt), m_numCookPasses(numCookPasses), : m_name(name), m_desc(desc), m_pakExt(pakExt), m_numCookPasses(numCookPasses), m_factory(std::move(factory)) {}
m_factory(std::move(factory)) {}
}; };
/** /**
@ -166,17 +168,15 @@ struct DataSpecEntry
* *
* DO NOT CONSTRUCT THIS OR SUBCLASSES DIRECTLY!! * DO NOT CONSTRUCT THIS OR SUBCLASSES DIRECTLY!!
*/ */
class ObjectBase class ObjectBase {
{
friend class Project; friend class Project;
SystemString m_path; SystemString m_path;
protected:
protected:
/** /**
* @brief Byte-order of target system * @brief Byte-order of target system
*/ */
enum class DataEndianness enum class DataEndianness {
{
None, None,
Big, /**< Big-endian (PowerPC) */ Big, /**< Big-endian (PowerPC) */
Little /**< Little-endian (Intel) */ Little /**< Little-endian (Intel) */
@ -185,8 +185,7 @@ protected:
/** /**
* @brief Data-formats of target system * @brief Data-formats of target system
*/ */
enum class DataPlatform enum class DataPlatform {
{
None, None,
Generic, /**< Scanline textures and 3-way shader bundle (GLSL, HLSL, SPIR-V) */ Generic, /**< Scanline textures and 3-way shader bundle (GLSL, HLSL, SPIR-V) */
Revolution, /**< Tiled textures and GX register buffers */ Revolution, /**< Tiled textures and GX register buffers */
@ -206,9 +205,12 @@ protected:
* Part of the cooking process may include embedding database-refs to dependencies. * Part of the cooking process may include embedding database-refs to dependencies.
* This method should store the 64-bit value provided by IDataObject::id() when doing this. * This method should store the 64-bit value provided by IDataObject::id() when doing this.
*/ */
virtual bool cookObject(FDataAppender dataAppender, virtual bool cookObject(FDataAppender dataAppender, DataEndianness endianness, DataPlatform platform) {
DataEndianness endianness, DataPlatform platform) (void)dataAppender;
{(void)dataAppender;(void)endianness;(void)platform;return true;} (void)endianness;
(void)platform;
return true;
}
typedef std::function<void(ObjectBase*)> FDepAdder; typedef std::function<void(ObjectBase*)> FDepAdder;
@ -220,25 +222,20 @@ protected:
* Dependencies registered via this method will eventually have this method called on themselves * Dependencies registered via this method will eventually have this method called on themselves
* as well. This is a non-recursive operation, no need for subclasses to implement recursion-control. * as well. This is a non-recursive operation, no need for subclasses to implement recursion-control.
*/ */
virtual void gatherDeps(FDepAdder depAdder) virtual void gatherDeps(FDepAdder depAdder) { (void)depAdder; }
{(void)depAdder;}
/** /**
* @brief Get a packagable FourCC representation of the object's type * @brief Get a packagable FourCC representation of the object's type
* @return FourCC of the type * @return FourCC of the type
*/ */
virtual FourCC getType() const virtual FourCC getType() const { return FourCC("NULL"); }
{return FourCC("NULL");}
public: public:
ObjectBase(SystemStringView path) ObjectBase(SystemStringView path) : m_path(path) {}
: m_path(path) {}
SystemStringView getPath() const {return m_path;}
SystemStringView getPath() const { return m_path; }
}; };
/** /**
* @brief Main project interface * @brief Main project interface
* *
@ -246,15 +243,14 @@ public:
* resources in their ideal editor-formats. This interface exposes all * resources in their ideal editor-formats. This interface exposes all
* primary operations to perform on a given project. * primary operations to perform on a given project.
*/ */
class Project class Project {
{
public: public:
struct ProjectDataSpec struct ProjectDataSpec {
{
const DataSpecEntry& spec; const DataSpecEntry& spec;
ProjectPath cookedPath; ProjectPath cookedPath;
bool active; bool active;
}; };
private: private:
ProjectRootPath m_rootPath; ProjectRootPath m_rootPath;
ProjectPath m_workRoot; ProjectPath m_workRoot;
@ -265,9 +261,10 @@ private:
std::vector<std::unique_ptr<IDataSpec>> m_cookSpecs; std::vector<std::unique_ptr<IDataSpec>> m_cookSpecs;
std::unique_ptr<IDataSpec> m_lastPackageSpec; std::unique_ptr<IDataSpec> m_lastPackageSpec;
bool m_valid = false; bool m_valid = false;
public: public:
Project(const ProjectRootPath& rootPath); Project(const ProjectRootPath& rootPath);
operator bool() const {return m_valid;} operator bool() const { return m_valid; }
/** /**
* @brief Configuration file handle * @brief Configuration file handle
@ -275,14 +272,13 @@ public:
* Holds a path to a line-delimited textual configuration file; * Holds a path to a line-delimited textual configuration file;
* opening a locked handle for read/write transactions * opening a locked handle for read/write transactions
*/ */
class ConfigFile class ConfigFile {
{
SystemString m_filepath; SystemString m_filepath;
std::vector<std::string> m_lines; std::vector<std::string> m_lines;
FILE* m_lockedFile = NULL; FILE* m_lockedFile = NULL;
public: public:
ConfigFile(const Project& project, SystemStringView name, ConfigFile(const Project& project, SystemStringView name, SystemStringView subdir = _SYS_STR("/.hecl/"));
SystemStringView subdir=_SYS_STR("/.hecl/"));
std::vector<std::string>& lockAndRead(); std::vector<std::string>& lockAndRead();
void addLine(std::string_view line); void addLine(std::string_view line);
void removeLine(std::string_view refLine); void removeLine(std::string_view refLine);
@ -299,13 +295,7 @@ public:
* *
* This is used to provide pretty colors during the cook operation * This is used to provide pretty colors during the cook operation
*/ */
enum class Cost enum class Cost { None, Light, Medium, Heavy };
{
None,
Light,
Medium,
Heavy
};
/** /**
* @brief Get the path of the project's root-directory * @brief Get the path of the project's root-directory
@ -313,13 +303,13 @@ public:
* *
* Self explanatory * Self explanatory
*/ */
const ProjectRootPath& getProjectRootPath() const {return m_rootPath;} const ProjectRootPath& getProjectRootPath() const { return m_rootPath; }
/** /**
* @brief Get the path of project's working directory * @brief Get the path of project's working directory
* @return project working path * @return project working path
*/ */
const ProjectPath& getProjectWorkingPath() const {return m_workRoot;} const ProjectPath& getProjectWorkingPath() const { return m_workRoot; }
/** /**
* @brief Get the path of project's cooked directory for a specific DataSpec * @brief Get the path of project's cooked directory for a specific DataSpec
@ -348,7 +338,7 @@ public:
* This method will not delete actual working files from the project * This method will not delete actual working files from the project
* directory. It will delete associated cooked objects though. * directory. It will delete associated cooked objects though.
*/ */
bool removePaths(const std::vector<ProjectPath>& paths, bool recursive=false); bool removePaths(const std::vector<ProjectPath>& paths, bool recursive = false);
/** /**
* @brief Register a working sub-directory as a Dependency Group * @brief Register a working sub-directory as a Dependency Group
@ -385,7 +375,7 @@ public:
* @brief Return map populated with dataspecs targetable by this project interface * @brief Return map populated with dataspecs targetable by this project interface
* @return Platform map with name-string keys and enable-status values * @return Platform map with name-string keys and enable-status values
*/ */
const std::vector<ProjectDataSpec>& getDataSpecs() const {return m_compiledSpecs;} const std::vector<ProjectDataSpec>& getDataSpecs() const { return m_compiledSpecs; }
/** /**
* @brief Enable persistent user preference for particular spec string(s) * @brief Enable persistent user preference for particular spec string(s)
@ -419,9 +409,8 @@ public:
* This method blocks execution during the procedure, with periodic * This method blocks execution during the procedure, with periodic
* feedback delivered via feedbackCb. * feedback delivered via feedbackCb.
*/ */
bool cookPath(const ProjectPath& path, const MultiProgressPrinter& feedbackCb, bool cookPath(const ProjectPath& path, const MultiProgressPrinter& feedbackCb, bool recursive = false,
bool recursive=false, bool force=false, bool fast=false, bool force = false, bool fast = false, const DataSpecEntry* spec = nullptr, ClientProcess* cp = nullptr,
const DataSpecEntry* spec=nullptr, ClientProcess* cp=nullptr,
int cookPass = -1); int cookPass = -1);
/** /**
@ -432,9 +421,8 @@ public:
* @param spec if non-null, cook using a manually-selected dataspec * @param spec if non-null, cook using a manually-selected dataspec
* @param cp if non-null, cook asynchronously via the ClientProcess * @param cp if non-null, cook asynchronously via the ClientProcess
*/ */
bool packagePath(const ProjectPath& path, const MultiProgressPrinter& feedbackCb, bool packagePath(const ProjectPath& path, const MultiProgressPrinter& feedbackCb, bool fast = false,
bool fast=false, const DataSpecEntry* spec=nullptr, const DataSpecEntry* spec = nullptr, ClientProcess* cp = nullptr);
ClientProcess* cp=nullptr);
/** /**
* @brief Interrupts a cook in progress (call from SIGINT handler) * @brief Interrupts a cook in progress (call from SIGINT handler)
@ -457,7 +445,7 @@ public:
* Developers understand how useful 'clean' is. While ideally not required, * Developers understand how useful 'clean' is. While ideally not required,
* it's useful for verifying that a rebuild from ground-up is doable. * it's useful for verifying that a rebuild from ground-up is doable.
*/ */
bool cleanPath(const ProjectPath& path, bool recursive=false); bool cleanPath(const ProjectPath& path, bool recursive = false);
/** /**
* @brief Constructs a full depsgraph of the project-subpath provided * @brief Constructs a full depsgraph of the project-subpath provided
@ -474,9 +462,7 @@ public:
/** Lookup ProjectPath from bridge cache */ /** Lookup ProjectPath from bridge cache */
const ProjectPath* lookupBridgePath(uint64_t id) const; const ProjectPath* lookupBridgePath(uint64_t id) const;
}; };
} } // namespace Database
} } // namespace hecl

View File

@ -5,8 +5,7 @@
#include <string> #include <string>
#include "athena/DNA.hpp" #include "athena/DNA.hpp"
namespace hecl namespace hecl {
{
/** /**
* @brief FourCC representation used within HECL's database * @brief FourCC representation used within HECL's database
@ -15,73 +14,73 @@ namespace hecl
* while fitting comfortably in a 32-bit word. HECL uses a four-char array * while fitting comfortably in a 32-bit word. HECL uses a four-char array
* to remain endian-independent. * to remain endian-independent.
*/ */
class FourCC class FourCC {
{
protected: protected:
union union {
{
char fcc[4]; char fcc[4];
uint32_t num; uint32_t num;
}; };
public: public:
FourCC() /* Sentinel FourCC */ FourCC() /* Sentinel FourCC */
: num(0) {} : num(0) {}
FourCC(const FourCC& other) FourCC(const FourCC& other) { num = other.num; }
{num = other.num;} FourCC(const char* name) : num(*(uint32_t*)name) {}
FourCC(const char* name) FourCC(uint32_t n) : num(n) {}
: num(*(uint32_t*)name) {} bool operator==(const FourCC& other) const { return num == other.num; }
FourCC(uint32_t n) bool operator!=(const FourCC& other) const { return num != other.num; }
: num(n) {} bool operator==(const char* other) const { return num == *(uint32_t*)other; }
bool operator==(const FourCC& other) const {return num == other.num;} bool operator!=(const char* other) const { return num != *(uint32_t*)other; }
bool operator!=(const FourCC& other) const {return num != other.num;} bool operator==(int32_t other) const { return num == other; }
bool operator==(const char* other) const {return num == *(uint32_t*)other;} bool operator!=(int32_t other) const { return num != other; }
bool operator!=(const char* other) const {return num != *(uint32_t*)other;} bool operator==(uint32_t other) const { return num == other; }
bool operator==(int32_t other) const { return num == other;} bool operator!=(uint32_t other) const { return num != other; }
bool operator!=(int32_t other) const { return num != other;} std::string toString() const { return std::string(fcc, 4); }
bool operator==(uint32_t other) const {return num == other;} uint32_t toUint32() const { return num; }
bool operator!=(uint32_t other) const {return num != other;} operator uint32_t() const { return num; }
std::string toString() const {return std::string(fcc, 4);} const char* getChars() const { return fcc; }
uint32_t toUint32() const {return num;} char* getChars() { return fcc; }
operator uint32_t() const {return num;}
const char* getChars() const {return fcc;}
char* getChars() {return fcc;}
}; };
#define FOURCC(chars) FourCC(SBIG(chars)) #define FOURCC(chars) FourCC(SBIG(chars))
using BigDNA = athena::io::DNA<athena::Big>; using BigDNA = athena::io::DNA<athena::Big>;
/** FourCC with DNA read/write */ /** FourCC with DNA read/write */
class DNAFourCC final : public BigDNA, public FourCC class DNAFourCC final : public BigDNA, public FourCC {
{
public: public:
DNAFourCC() : FourCC() {} DNAFourCC() : FourCC() {}
DNAFourCC(const FourCC& other) DNAFourCC(const FourCC& other) : FourCC() { num = other.toUint32(); }
: FourCC() {num = other.toUint32();} DNAFourCC(const char* name) : FourCC(name) {}
DNAFourCC(const char* name) DNAFourCC(uint32_t n) : FourCC(n) {}
: FourCC(name) {}
DNAFourCC(uint32_t n)
: FourCC(n) {}
AT_DECL_EXPLICIT_DNA_YAML AT_DECL_EXPLICIT_DNA_YAML
}; };
template <> inline void DNAFourCC::Enumerate<BigDNA::Read>(typename Read::StreamT& r) template <>
{ r.readUBytesToBuf(fcc, 4); } inline void DNAFourCC::Enumerate<BigDNA::Read>(typename Read::StreamT& r) {
template <> inline void DNAFourCC::Enumerate<BigDNA::Write>(typename Write::StreamT& w) r.readUBytesToBuf(fcc, 4);
{ w.writeUBytes((atUint8*)fcc, 4); } }
template <> inline void DNAFourCC::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& r) template <>
{ std::string rs = r.readString(nullptr); strncpy(fcc, rs.c_str(), 4); } inline void DNAFourCC::Enumerate<BigDNA::Write>(typename Write::StreamT& w) {
template <> inline void DNAFourCC::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& w) w.writeUBytes((atUint8*)fcc, 4);
{ w.writeString(nullptr, std::string(fcc, 4)); } }
template <> inline void DNAFourCC::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) template <>
{ s += 4; } inline void DNAFourCC::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& r) {
std::string rs = r.readString(nullptr);
strncpy(fcc, rs.c_str(), 4);
}
template <>
inline void DNAFourCC::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& w) {
w.writeString(nullptr, std::string(fcc, 4));
}
template <>
inline void DNAFourCC::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 4;
} }
namespace std } // namespace hecl
{
template <> struct hash<hecl::FourCC> namespace std {
{ template <>
size_t operator()(const hecl::FourCC& val) const noexcept struct hash<hecl::FourCC> {
{return val.toUint32();} size_t operator()(const hecl::FourCC& val) const noexcept { return val.toUint32(); }
}; };
} } // namespace std

View File

@ -8,75 +8,73 @@
#include <hecl/hecl.hpp> #include <hecl/hecl.hpp>
#include <boo/graphicsdev/IGraphicsDataFactory.hpp> #include <boo/graphicsdev/IGraphicsDataFactory.hpp>
namespace hecl::Frontend namespace hecl::Frontend {
{
using namespace std::literals; using namespace std::literals;
struct SourceLocation struct SourceLocation {
{
int line = -1; int line = -1;
int col = -1; int col = -1;
SourceLocation() = default; SourceLocation() = default;
SourceLocation(int l, int c) : line(l), col(c) {} SourceLocation(int l, int c) : line(l), col(c) {}
}; };
class Diagnostics class Diagnostics {
{
std::string m_name; std::string m_name;
std::string m_source; std::string m_source;
std::string m_backend = "Backend"; std::string m_backend = "Backend";
std::string sourceDiagString(const SourceLocation& l, bool ansi=false) const; std::string sourceDiagString(const SourceLocation& l, bool ansi = false) const;
public: public:
void reset(std::string_view name, std::string_view source) {m_name = name; m_source = source;} void reset(std::string_view name, std::string_view source) {
void reset(std::string_view name) {m_name = name; m_source.clear();} m_name = name;
void setBackend(std::string_view backend) {m_backend = backend;} m_source = source;
}
void reset(std::string_view name) {
m_name = name;
m_source.clear();
}
void setBackend(std::string_view backend) { m_backend = backend; }
void reportScannerErr(const SourceLocation& l, const char* format, ...); void reportScannerErr(const SourceLocation& l, const char* format, ...);
void reportParserErr(const SourceLocation& l, const char* format, ...); void reportParserErr(const SourceLocation& l, const char* format, ...);
void reportBackendErr(const SourceLocation& l, const char* format, ...); void reportBackendErr(const SourceLocation& l, const char* format, ...);
std::string_view getName() const {return m_name;} std::string_view getName() const { return m_name; }
std::string_view getSource() const {return m_source;} std::string_view getSource() const { return m_source; }
}; };
struct Token struct Token {
{ enum class Kind { None, Eof, Lf, Plus, Minus, Times, Div, Lpar, Rpar, Comma, Period, Ident, Number };
enum class Kind
{
None,
Eof,
Lf,
Plus,
Minus,
Times,
Div,
Lpar,
Rpar,
Comma,
Period,
Ident,
Number
};
static std::string_view KindToStr(Kind k) static std::string_view KindToStr(Kind k) {
{ switch (k) {
switch (k)
{
case Kind::None: case Kind::None:
default: default:
return "none"sv; return "none"sv;
case Kind::Eof: return "eof"sv; case Kind::Eof:
case Kind::Lf: return "lf"sv; return "eof"sv;
case Kind::Plus: return "+"sv; case Kind::Lf:
case Kind::Minus: return "-"sv; return "lf"sv;
case Kind::Times: return "*"sv; case Kind::Plus:
case Kind::Div: return "/"sv; return "+"sv;
case Kind::Lpar: return "("sv; case Kind::Minus:
case Kind::Rpar: return ")"sv; return "-"sv;
case Kind::Comma: return ","sv; case Kind::Times:
case Kind::Period: return "."sv; return "*"sv;
case Kind::Ident: return "ident"sv; case Kind::Div:
case Kind::Number: return "number"sv; return "/"sv;
case Kind::Lpar:
return "("sv;
case Kind::Rpar:
return ")"sv;
case Kind::Comma:
return ","sv;
case Kind::Period:
return "."sv;
case Kind::Ident:
return "ident"sv;
case Kind::Number:
return "number"sv;
} }
} }
@ -85,13 +83,10 @@ struct Token
SourceLocation loc; SourceLocation loc;
Token() = default; Token() = default;
Token(Kind kind, const SourceLocation& loc) Token(Kind kind, const SourceLocation& loc) : kind(kind), loc(loc) {}
: kind(kind), loc(loc) {} Token(Kind kind, std::string&& str, const SourceLocation& loc) : kind(kind), str(std::move(str)), loc(loc) {}
Token(Kind kind, std::string&& str, const SourceLocation& loc)
: kind(kind), str(std::move(str)), loc(loc) {}
std::string toString() const std::string toString() const {
{
if (str.empty()) if (str.empty())
return hecl::Format("%d:%d: %s", loc.line, loc.col, KindToStr(kind).data()); return hecl::Format("%d:%d: %s", loc.line, loc.col, KindToStr(kind).data());
else else
@ -99,8 +94,7 @@ struct Token
} }
}; };
class Scanner class Scanner {
{
friend class Parser; friend class Parser;
static constexpr char LF = '\n'; static constexpr char LF = '\n';
static constexpr char COMMENT = '#'; static constexpr char COMMENT = '#';
@ -115,43 +109,40 @@ class Scanner
std::string lastLine; std::string lastLine;
std::string currentLine; std::string currentLine;
Token::Kind CharToTokenKind(char ch) Token::Kind CharToTokenKind(char ch) {
{ switch (ch) {
switch (ch) case '(':
{ return Token::Kind::Lpar;
case '(': return Token::Kind::Lpar; case ')':
case ')': return Token::Kind::Rpar; return Token::Kind::Rpar;
case ',': return Token::Kind::Comma; case ',':
case '.': return Token::Kind::Period; return Token::Kind::Comma;
case '+': return Token::Kind::Plus; case '.':
case '-': return Token::Kind::Minus; return Token::Kind::Period;
case '*': return Token::Kind::Times; case '+':
case '/': return Token::Kind::Div; return Token::Kind::Plus;
default: return Token::Kind::None; case '-':
return Token::Kind::Minus;
case '*':
return Token::Kind::Times;
case '/':
return Token::Kind::Div;
default:
return Token::Kind::None;
} }
} }
template <class... Args> template <class... Args>
void error(const SourceLocation& loc, const char* s, Args&&... args) void error(const SourceLocation& loc, const char* s, Args&&... args) {
{
m_diag.reportScannerErr(loc, s, args...); m_diag.reportScannerErr(loc, s, args...);
} }
static bool isDigit(char c) static bool isDigit(char c) { return c >= '0' && c <= '9'; }
{
return c >= '0' && c <= '9';
}
static bool isStartIdent(char c) static bool isStartIdent(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_'); }
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(c == '_');
}
static bool isMidIdent(char c) static bool isMidIdent(char c) {
{ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_') || isDigit(c);
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(c == '_') || isDigit(c);
} }
int _read(); int _read();
@ -162,8 +153,7 @@ class Scanner
public: public:
Scanner(Diagnostics& diag) : m_diag(diag) {} Scanner(Diagnostics& diag) : m_diag(diag) {}
void reset(std::string_view in) void reset(std::string_view in) {
{
m_source = in; m_source = in;
m_sourceIt = in.cbegin(); m_sourceIt = in.cbegin();
ch = 0; ch = 0;
@ -178,18 +168,11 @@ public:
Token next(); Token next();
}; };
struct IRNode struct IRNode {
{
friend struct IR; friend struct IR;
enum class Op enum class Op { Add, Sub, Mul, Div };
{ enum class Kind { None, Call, Imm, Binop, Swizzle };
Add, Sub, Mul, Div
};
enum class Kind
{
None, Call, Imm, Binop, Swizzle
};
Kind kind = Kind::None; Kind kind = Kind::None;
std::string str; std::string str;
float val; float val;
@ -199,37 +182,40 @@ struct IRNode
std::list<IRNode> children; std::list<IRNode> children;
SourceLocation loc; SourceLocation loc;
static std::string_view OpToStr(Op op) static std::string_view OpToStr(Op op) {
{ switch (op) {
switch (op) case Op::Add:
{ return "+"sv;
case Op::Add: return "+"sv; case Op::Sub:
case Op::Sub: return "-"sv; return "-"sv;
case Op::Mul: return "*"sv; case Op::Mul:
case Op::Div: return "/"sv; return "*"sv;
default: return ""sv; case Op::Div:
return "/"sv;
default:
return ""sv;
} }
} }
static std::string_view KindToStr(Kind k) static std::string_view KindToStr(Kind k) {
{ switch (k) {
switch (k)
{
case Kind::None: case Kind::None:
default: default:
return "none"sv; return "none"sv;
case Kind::Call: return "call"sv; case Kind::Call:
case Kind::Imm: return "imm"sv; return "call"sv;
case Kind::Binop: return "binop"sv; case Kind::Imm:
case Kind::Swizzle: return "swizzle"sv; return "imm"sv;
case Kind::Binop:
return "binop"sv;
case Kind::Swizzle:
return "swizzle"sv;
} }
} }
IRNode() = default; IRNode() = default;
IRNode(Kind kind, std::string&& str, const SourceLocation& loc) IRNode(Kind kind, std::string&& str, const SourceLocation& loc) : kind(kind), str(std::move(str)), loc(loc) {}
: kind(kind), str(std::move(str)), loc(loc) {} IRNode(Kind kind, float val, const SourceLocation& loc) : kind(kind), val(val), loc(loc) {}
IRNode(Kind kind, float val, const SourceLocation& loc)
: kind(kind), val(val), loc(loc) {}
IRNode(Kind kind, std::string&& str, std::list<IRNode>&& children, const SourceLocation& loc) IRNode(Kind kind, std::string&& str, std::list<IRNode>&& children, const SourceLocation& loc)
: kind(kind), str(std::move(str)), children(std::move(children)), loc(loc) {} : kind(kind), str(std::move(str)), children(std::move(children)), loc(loc) {}
IRNode(Op op, IRNode&& left, IRNode&& right, const SourceLocation& loc) IRNode(Op op, IRNode&& left, IRNode&& right, const SourceLocation& loc)
@ -245,24 +231,21 @@ private:
std::string describe() const; std::string describe() const;
}; };
class Parser class Parser {
{
Scanner m_scanner; Scanner m_scanner;
Token t; Token t;
Token la; Token la;
Token::Kind sym; Token::Kind sym;
void scan() void scan() {
{
t = la; t = la;
la = m_scanner.next(); la = m_scanner.next();
sym = la.kind; sym = la.kind;
} }
template <class... Args> template <class... Args>
void error(const char* s, Args&&... args) void error(const char* s, Args&&... args) {
{
m_scanner.m_diag.reportParserErr(la.loc, s, args...); m_scanner.m_diag.reportParserErr(la.loc, s, args...);
} }
@ -275,21 +258,21 @@ class Parser
IRNode value(); IRNode value();
public: public:
Parser(Diagnostics& diag) Parser(Diagnostics& diag) : m_scanner(diag) {}
: m_scanner(diag) {}
void reset(std::string_view in) { la = Token(); m_scanner.reset(in); } void reset(std::string_view in) {
la = Token();
m_scanner.reset(in);
}
std::list<IRNode> parse(); std::list<IRNode> parse();
}; };
using BigDNA = athena::io::DNA<athena::Big>; using BigDNA = athena::io::DNA<athena::Big>;
struct IR : BigDNA struct IR : BigDNA {
{
AT_DECL_EXPLICIT_DNA AT_DECL_EXPLICIT_DNA
enum OpType : uint8_t enum OpType : uint8_t {
{
None, /**< NOP */ None, /**< NOP */
Call, /**< Deferred function insertion for HECL backend using specified I/O regs */ Call, /**< Deferred function insertion for HECL backend using specified I/O regs */
LoadImm, /**< Load a constant (numeric literal) into register */ LoadImm, /**< Load a constant (numeric literal) into register */
@ -299,58 +282,45 @@ struct IR : BigDNA
using RegID = atUint16; using RegID = atUint16;
struct Instruction : BigDNA struct Instruction : BigDNA {
{
AT_DECL_EXPLICIT_DNA AT_DECL_EXPLICIT_DNA
OpType m_op = OpType::None; OpType m_op = OpType::None;
RegID m_target = RegID(-1); RegID m_target = RegID(-1);
SourceLocation m_loc; SourceLocation m_loc;
struct Call : BigDNA struct Call : BigDNA {
{
AT_DECL_DNA AT_DECL_DNA
String<-1> m_name; String<-1> m_name;
Value<atUint16> m_argInstCount; Value<atUint16> m_argInstCount;
Vector<atUint16, AT_DNA_COUNT(m_argInstCount)> m_argInstIdxs; Vector<atUint16, AT_DNA_COUNT(m_argInstCount)> m_argInstIdxs;
} m_call; } m_call;
struct LoadImm : BigDNA struct LoadImm : BigDNA {
{
AT_DECL_DNA AT_DECL_DNA
Value<atVec4f> m_immVec = {}; Value<atVec4f> m_immVec = {};
} m_loadImm; } m_loadImm;
enum ArithmeticOpType : uint8_t enum ArithmeticOpType : uint8_t { None, Add, Subtract, Multiply, Divide };
{
None,
Add,
Subtract,
Multiply,
Divide
};
struct Arithmetic : BigDNA struct Arithmetic : BigDNA {
{
AT_DECL_DNA AT_DECL_DNA
Value<ArithmeticOpType> m_op = ArithmeticOpType::None; Value<ArithmeticOpType> m_op = ArithmeticOpType::None;
Value<atUint16> m_instIdxs[2]; Value<atUint16> m_instIdxs[2];
} m_arithmetic; } m_arithmetic;
struct Swizzle : BigDNA struct Swizzle : BigDNA {
{
AT_DECL_DNA AT_DECL_DNA
Value<atInt8> m_idxs[4] = {-1, -1, -1, -1}; Value<atInt8> m_idxs[4] = {-1, -1, -1, -1};
Value<atUint16> m_instIdx; Value<atUint16> m_instIdx;
} m_swizzle; } m_swizzle;
Instruction(OpType type, RegID target, const SourceLocation& loc) Instruction(OpType type, RegID target, const SourceLocation& loc) : m_op(type), m_target(target), m_loc(loc) {}
: m_op(type), m_target(target), m_loc(loc) {}
int getChildCount() const; int getChildCount() const;
const IR::Instruction& getChildInst(const IR& ir, size_t idx) const; const IR::Instruction& getChildInst(const IR& ir, size_t idx) const;
const atVec4f& getImmVec() const; const atVec4f& getImmVec() const;
Instruction(athena::io::IStreamReader& reader) {read(reader);} Instruction(athena::io::IStreamReader& reader) { read(reader); }
}; };
atUint64 m_hash = 0; atUint64 m_hash = 0;
@ -365,15 +335,14 @@ struct IR : BigDNA
int addInstruction(const IRNode& n, IR::RegID target); int addInstruction(const IRNode& n, IR::RegID target);
}; };
class Frontend class Frontend {
{
Diagnostics m_diag; Diagnostics m_diag;
Parser m_parser; Parser m_parser;
public: public:
IR compileSource(std::string_view source, std::string_view diagName); IR compileSource(std::string_view source, std::string_view diagName);
Diagnostics& getDiagnostics() { return m_diag; } Diagnostics& getDiagnostics() { return m_diag; }
Frontend() : m_parser(m_diag) {} Frontend() : m_parser(m_diag) {}
}; };
} } // namespace hecl::Frontend

View File

@ -3,19 +3,16 @@
#include "hecl/hecl.hpp" #include "hecl/hecl.hpp"
#include "athena/DNA.hpp" #include "athena/DNA.hpp"
namespace hecl namespace hecl {
{
enum class HMDLTopology : atUint32 enum class HMDLTopology : atUint32 {
{
Triangles, Triangles,
TriStrips, TriStrips,
}; };
#define HECL_HMDL_META_SZ 32 #define HECL_HMDL_META_SZ 32
struct HMDLMeta : athena::io::DNA<athena::Big> struct HMDLMeta : athena::io::DNA<athena::Big> {
{
AT_DECL_DNA AT_DECL_DNA
Value<atUint32> magic = 'TACO'; Value<atUint32> magic = 'TACO';
Value<HMDLTopology> topology; Value<HMDLTopology> topology;
@ -28,5 +25,4 @@ struct HMDLMeta : athena::io::DNA<athena::Big>
Value<atUint16> bankCount; Value<atUint16> bankCount;
}; };
} } // namespace hecl

View File

@ -17,20 +17,18 @@
/// \brief Extend the default __GNUC_PREREQ even if glibc's features.h isn't /// \brief Extend the default __GNUC_PREREQ even if glibc's features.h isn't
/// available. /// available.
#ifndef LLVM_GNUC_PREREQ #ifndef LLVM_GNUC_PREREQ
# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) #if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
# define LLVM_GNUC_PREREQ(maj, min, patch) \ #define LLVM_GNUC_PREREQ(maj, min, patch) \
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \ ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= ((maj) << 20) + ((min) << 10) + (patch))
((maj) << 20) + ((min) << 10) + (patch)) #elif defined(__GNUC__) && defined(__GNUC_MINOR__)
# elif defined(__GNUC__) && defined(__GNUC_MINOR__) #define LLVM_GNUC_PREREQ(maj, min, patch) ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
# define LLVM_GNUC_PREREQ(maj, min, patch) \ #else
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10)) #define LLVM_GNUC_PREREQ(maj, min, patch) 0
# else #endif
# define LLVM_GNUC_PREREQ(maj, min, patch) 0
# endif
#endif #endif
#ifndef __has_builtin #ifndef __has_builtin
# define __has_builtin(x) 0 #define __has_builtin(x) 0
#endif #endif
#include "hecl.hpp" #include "hecl.hpp"
@ -61,7 +59,8 @@ enum ZeroBehavior {
}; };
namespace detail { namespace detail {
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter { template <typename T, std::size_t SizeOfT>
struct TrailingZerosCounter {
static std::size_t count(T Val, ZeroBehavior) { static std::size_t count(T Val, ZeroBehavior) {
if (!Val) if (!Val)
return std::numeric_limits<T>::digits; return std::numeric_limits<T>::digits;
@ -85,7 +84,8 @@ template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
}; };
#if __GNUC__ >= 4 || defined(_MSC_VER) #if __GNUC__ >= 4 || defined(_MSC_VER)
template <typename T> struct TrailingZerosCounter<T, 4> { template <typename T>
struct TrailingZerosCounter<T, 4> {
static std::size_t count(T Val, ZeroBehavior ZB) { static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0) if (ZB != ZB_Undefined && Val == 0)
return 32; return 32;
@ -101,7 +101,8 @@ template <typename T> struct TrailingZerosCounter<T, 4> {
}; };
#if !defined(_MSC_VER) || defined(_M_X64) #if !defined(_MSC_VER) || defined(_M_X64)
template <typename T> struct TrailingZerosCounter<T, 8> { template <typename T>
struct TrailingZerosCounter<T, 8> {
static std::size_t count(T Val, ZeroBehavior ZB) { static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0) if (ZB != ZB_Undefined && Val == 0)
return 64; return 64;
@ -128,14 +129,14 @@ template <typename T> struct TrailingZerosCounter<T, 8> {
/// valid arguments. /// valid arguments.
template <typename T> template <typename T>
std::size_t countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) { std::size_t countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer && static_assert(std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed."); "Only unsigned integral types are allowed.");
return detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB); return detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB);
} }
namespace detail { namespace detail {
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter { template <typename T, std::size_t SizeOfT>
struct LeadingZerosCounter {
static std::size_t count(T Val, ZeroBehavior) { static std::size_t count(T Val, ZeroBehavior) {
if (!Val) if (!Val)
return std::numeric_limits<T>::digits; return std::numeric_limits<T>::digits;
@ -154,7 +155,8 @@ template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
}; };
#if __GNUC__ >= 4 || defined(_MSC_VER) #if __GNUC__ >= 4 || defined(_MSC_VER)
template <typename T> struct LeadingZerosCounter<T, 4> { template <typename T>
struct LeadingZerosCounter<T, 4> {
static std::size_t count(T Val, ZeroBehavior ZB) { static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0) if (ZB != ZB_Undefined && Val == 0)
return 32; return 32;
@ -170,7 +172,8 @@ template <typename T> struct LeadingZerosCounter<T, 4> {
}; };
#if !defined(_MSC_VER) || defined(_M_X64) #if !defined(_MSC_VER) || defined(_M_X64)
template <typename T> struct LeadingZerosCounter<T, 8> { template <typename T>
struct LeadingZerosCounter<T, 8> {
static std::size_t count(T Val, ZeroBehavior ZB) { static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0) if (ZB != ZB_Undefined && Val == 0)
return 64; return 64;
@ -197,8 +200,7 @@ template <typename T> struct LeadingZerosCounter<T, 8> {
/// valid arguments. /// valid arguments.
template <typename T> template <typename T>
std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) { std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer && static_assert(std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed."); "Only unsigned integral types are allowed.");
return detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB); return detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
} }
@ -210,7 +212,8 @@ std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
/// ///
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are /// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
/// valid arguments. /// valid arguments.
template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) { template <typename T>
T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
if (ZB == ZB_Max && Val == 0) if (ZB == ZB_Max && Val == 0)
return std::numeric_limits<T>::max(); return std::numeric_limits<T>::max();
@ -224,14 +227,14 @@ template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
/// ///
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are /// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
/// valid arguments. /// valid arguments.
template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) { template <typename T>
T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
if (ZB == ZB_Max && Val == 0) if (ZB == ZB_Max && Val == 0)
return std::numeric_limits<T>::max(); return std::numeric_limits<T>::max();
// Use ^ instead of - because both gcc and llvm can remove the associated ^ // Use ^ instead of - because both gcc and llvm can remove the associated ^
// in the __builtin_clz intrinsic on x86. // in the __builtin_clz intrinsic on x86.
return countLeadingZeros(Val, ZB_Undefined) ^ return countLeadingZeros(Val, ZB_Undefined) ^ (std::numeric_limits<T>::digits - 1);
(std::numeric_limits<T>::digits - 1);
} }
/// \brief Macro compressed bit reversal table for 256 bits. /// \brief Macro compressed bit reversal table for 256 bits.
@ -264,33 +267,31 @@ T reverseBits(T Val) {
// ambiguity. // ambiguity.
/// Hi_32 - This function returns the high 32 bits of a 64 bit value. /// Hi_32 - This function returns the high 32 bits of a 64 bit value.
constexpr inline uint32_t Hi_32(uint64_t Value) { constexpr inline uint32_t Hi_32(uint64_t Value) { return static_cast<uint32_t>(Value >> 32); }
return static_cast<uint32_t>(Value >> 32);
}
/// Lo_32 - This function returns the low 32 bits of a 64 bit value. /// Lo_32 - This function returns the low 32 bits of a 64 bit value.
constexpr inline uint32_t Lo_32(uint64_t Value) { constexpr inline uint32_t Lo_32(uint64_t Value) { return static_cast<uint32_t>(Value); }
return static_cast<uint32_t>(Value);
}
/// Make_64 - This functions makes a 64-bit integer from a high / low pair of /// Make_64 - This functions makes a 64-bit integer from a high / low pair of
/// 32-bit integers. /// 32-bit integers.
constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) { constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) { return ((uint64_t)High << 32) | (uint64_t)Low; }
return ((uint64_t)High << 32) | (uint64_t)Low;
}
/// isInt - Checks if an integer fits into the given bit width. /// isInt - Checks if an integer fits into the given bit width.
template <unsigned N> constexpr inline bool isInt(int64_t x) { template <unsigned N>
return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1))); constexpr inline bool isInt(int64_t x) {
return N >= 64 || (-(INT64_C(1) << (N - 1)) <= x && x < (INT64_C(1) << (N - 1)));
} }
// Template specializations to get better code for common cases. // Template specializations to get better code for common cases.
template <> constexpr inline bool isInt<8>(int64_t x) { template <>
constexpr inline bool isInt<8>(int64_t x) {
return static_cast<int8_t>(x) == x; return static_cast<int8_t>(x) == x;
} }
template <> constexpr inline bool isInt<16>(int64_t x) { template <>
constexpr inline bool isInt<16>(int64_t x) {
return static_cast<int16_t>(x) == x; return static_cast<int16_t>(x) == x;
} }
template <> constexpr inline bool isInt<32>(int64_t x) { template <>
constexpr inline bool isInt<32>(int64_t x) {
return static_cast<int32_t>(x) == x; return static_cast<int32_t>(x) == x;
} }
@ -298,8 +299,7 @@ template <> constexpr inline bool isInt<32>(int64_t x) {
/// left by S. /// left by S.
template <unsigned N, unsigned S> template <unsigned N, unsigned S>
constexpr inline bool isShiftedInt(int64_t x) { constexpr inline bool isShiftedInt(int64_t x) {
static_assert( static_assert(N > 0, "isShiftedInt<0> doesn't make sense (refers to a 0-bit number.");
N > 0, "isShiftedInt<0> doesn't make sense (refers to a 0-bit number.");
static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide."); static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide.");
return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0); return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
} }
@ -313,35 +313,34 @@ constexpr inline bool isShiftedInt(int64_t x) {
/// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting /// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting
/// left too many places. /// left too many places.
template <unsigned N> template <unsigned N>
constexpr inline typename std::enable_if<(N < 64), bool>::type constexpr inline typename std::enable_if<(N < 64), bool>::type isUInt(uint64_t X) {
isUInt(uint64_t X) {
static_assert(N > 0, "isUInt<0> doesn't make sense"); static_assert(N > 0, "isUInt<0> doesn't make sense");
return X < (UINT64_C(1) << (N)); return X < (UINT64_C(1) << (N));
} }
template <unsigned N> template <unsigned N>
constexpr inline typename std::enable_if<N >= 64, bool>::type constexpr inline typename std::enable_if<N >= 64, bool>::type isUInt(uint64_t X) {
isUInt(uint64_t X) {
return true; return true;
} }
// Template specializations to get better code for common cases. // Template specializations to get better code for common cases.
template <> constexpr inline bool isUInt<8>(uint64_t x) { template <>
constexpr inline bool isUInt<8>(uint64_t x) {
return static_cast<uint8_t>(x) == x; return static_cast<uint8_t>(x) == x;
} }
template <> constexpr inline bool isUInt<16>(uint64_t x) { template <>
constexpr inline bool isUInt<16>(uint64_t x) {
return static_cast<uint16_t>(x) == x; return static_cast<uint16_t>(x) == x;
} }
template <> constexpr inline bool isUInt<32>(uint64_t x) { template <>
constexpr inline bool isUInt<32>(uint64_t x) {
return static_cast<uint32_t>(x) == x; return static_cast<uint32_t>(x) == x;
} }
/// Checks if a unsigned integer is an N bit number shifted left by S. /// Checks if a unsigned integer is an N bit number shifted left by S.
template <unsigned N, unsigned S> template <unsigned N, unsigned S>
constexpr inline bool isShiftedUInt(uint64_t x) { constexpr inline bool isShiftedUInt(uint64_t x) {
static_assert( static_assert(N > 0, "isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)");
N > 0, "isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)"); static_assert(N + S <= 64, "isShiftedUInt<N, S> with N + S > 64 is too wide.");
static_assert(N + S <= 64,
"isShiftedUInt<N, S> with N + S > 64 is too wide.");
// Per the two static_asserts above, S must be strictly less than 64. So // Per the two static_asserts above, S must be strictly less than 64. So
// 1 << S is not undefined behavior. // 1 << S is not undefined behavior.
return isUInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0); return isUInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
@ -362,7 +361,7 @@ inline uint64_t maxUIntN(uint64_t N) {
inline int64_t minIntN(int64_t N) { inline int64_t minIntN(int64_t N) {
assert(N > 0 && N <= 64 && "integer width out of range"); assert(N > 0 && N <= 64 && "integer width out of range");
return -(UINT64_C(1)<<(N-1)); return -(UINT64_C(1) << (N - 1));
} }
/// Gets the maximum value for a N-bit signed integer. /// Gets the maximum value for a N-bit signed integer.
@ -376,72 +375,50 @@ inline int64_t maxIntN(int64_t N) {
/// isUIntN - Checks if an unsigned integer fits into the given (dynamic) /// isUIntN - Checks if an unsigned integer fits into the given (dynamic)
/// bit width. /// bit width.
inline bool isUIntN(unsigned N, uint64_t x) { inline bool isUIntN(unsigned N, uint64_t x) { return N >= 64 || x <= maxUIntN(N); }
return N >= 64 || x <= maxUIntN(N);
}
/// isIntN - Checks if an signed integer fits into the given (dynamic) /// isIntN - Checks if an signed integer fits into the given (dynamic)
/// bit width. /// bit width.
inline bool isIntN(unsigned N, int64_t x) { inline bool isIntN(unsigned N, int64_t x) { return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N)); }
return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N));
}
/// isMask_32 - This function returns true if the argument is a non-empty /// isMask_32 - This function returns true if the argument is a non-empty
/// sequence of ones starting at the least significant bit with the remainder /// sequence of ones starting at the least significant bit with the remainder
/// zero (32 bit version). Ex. isMask_32(0x0000FFFFU) == true. /// zero (32 bit version). Ex. isMask_32(0x0000FFFFU) == true.
constexpr inline bool isMask_32(uint32_t Value) { constexpr inline bool isMask_32(uint32_t Value) { return Value && ((Value + 1) & Value) == 0; }
return Value && ((Value + 1) & Value) == 0;
}
/// isMask_64 - This function returns true if the argument is a non-empty /// isMask_64 - This function returns true if the argument is a non-empty
/// sequence of ones starting at the least significant bit with the remainder /// sequence of ones starting at the least significant bit with the remainder
/// zero (64 bit version). /// zero (64 bit version).
constexpr inline bool isMask_64(uint64_t Value) { constexpr inline bool isMask_64(uint64_t Value) { return Value && ((Value + 1) & Value) == 0; }
return Value && ((Value + 1) & Value) == 0;
}
/// isShiftedMask_32 - This function returns true if the argument contains a /// isShiftedMask_32 - This function returns true if the argument contains a
/// non-empty sequence of ones with the remainder zero (32 bit version.) /// non-empty sequence of ones with the remainder zero (32 bit version.)
/// Ex. isShiftedMask_32(0x0000FF00U) == true. /// Ex. isShiftedMask_32(0x0000FF00U) == true.
constexpr inline bool isShiftedMask_32(uint32_t Value) { constexpr inline bool isShiftedMask_32(uint32_t Value) { return Value && isMask_32((Value - 1) | Value); }
return Value && isMask_32((Value - 1) | Value);
}
/// isShiftedMask_64 - This function returns true if the argument contains a /// isShiftedMask_64 - This function returns true if the argument contains a
/// non-empty sequence of ones with the remainder zero (64 bit version.) /// non-empty sequence of ones with the remainder zero (64 bit version.)
constexpr inline bool isShiftedMask_64(uint64_t Value) { constexpr inline bool isShiftedMask_64(uint64_t Value) { return Value && isMask_64((Value - 1) | Value); }
return Value && isMask_64((Value - 1) | Value);
}
/// isPowerOf2_32 - This function returns true if the argument is a power of /// isPowerOf2_32 - This function returns true if the argument is a power of
/// two > 0. Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.) /// two > 0. Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
constexpr inline bool isPowerOf2_32(uint32_t Value) { constexpr inline bool isPowerOf2_32(uint32_t Value) { return Value && !(Value & (Value - 1)); }
return Value && !(Value & (Value - 1));
}
/// isPowerOf2_64 - This function returns true if the argument is a power of two /// isPowerOf2_64 - This function returns true if the argument is a power of two
/// > 0 (64 bit edition.) /// > 0 (64 bit edition.)
constexpr inline bool isPowerOf2_64(uint64_t Value) { constexpr inline bool isPowerOf2_64(uint64_t Value) { return Value && !(Value & (Value - int64_t(1L))); }
return Value && !(Value & (Value - int64_t(1L)));
}
/// ByteSwap_16 - This function returns a byte-swapped representation of the /// ByteSwap_16 - This function returns a byte-swapped representation of the
/// 16-bit argument, Value. /// 16-bit argument, Value.
inline uint16_t ByteSwap_16(uint16_t Value) { inline uint16_t ByteSwap_16(uint16_t Value) { return hecl::bswap16(Value); }
return hecl::bswap16(Value);
}
/// ByteSwap_32 - This function returns a byte-swapped representation of the /// ByteSwap_32 - This function returns a byte-swapped representation of the
/// 32-bit argument, Value. /// 32-bit argument, Value.
inline uint32_t ByteSwap_32(uint32_t Value) { inline uint32_t ByteSwap_32(uint32_t Value) { return hecl::bswap32(Value); }
return hecl::bswap32(Value);
}
/// ByteSwap_64 - This function returns a byte-swapped representation of the /// ByteSwap_64 - This function returns a byte-swapped representation of the
/// 64-bit argument, Value. /// 64-bit argument, Value.
inline uint64_t ByteSwap_64(uint64_t Value) { inline uint64_t ByteSwap_64(uint64_t Value) { return hecl::bswap64(Value); }
return hecl::bswap64(Value);
}
/// \brief Count the number of ones from the most significant bit to the first /// \brief Count the number of ones from the most significant bit to the first
/// zero bit. /// zero bit.
@ -453,8 +430,7 @@ inline uint64_t ByteSwap_64(uint64_t Value) {
/// ZB_Undefined are valid arguments. /// ZB_Undefined are valid arguments.
template <typename T> template <typename T>
std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) { std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer && static_assert(std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed."); "Only unsigned integral types are allowed.");
return countLeadingZeros(~Value, ZB); return countLeadingZeros(~Value, ZB);
} }
@ -469,14 +445,14 @@ std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
/// ZB_Undefined are valid arguments. /// ZB_Undefined are valid arguments.
template <typename T> template <typename T>
std::size_t countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) { std::size_t countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer && static_assert(std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed."); "Only unsigned integral types are allowed.");
return countTrailingZeros(~Value, ZB); return countTrailingZeros(~Value, ZB);
} }
namespace detail { namespace detail {
template <typename T, std::size_t SizeOfT> struct PopulationCounter { template <typename T, std::size_t SizeOfT>
struct PopulationCounter {
static unsigned count(T Value) { static unsigned count(T Value) {
// Generic version, forward to 32 bits. // Generic version, forward to 32 bits.
static_assert(SizeOfT <= 4, "Not implemented!"); static_assert(SizeOfT <= 4, "Not implemented!");
@ -491,7 +467,8 @@ template <typename T, std::size_t SizeOfT> struct PopulationCounter {
} }
}; };
template <typename T> struct PopulationCounter<T, 8> { template <typename T>
struct PopulationCounter<T, 8> {
static unsigned count(T Value) { static unsigned count(T Value) {
#if __GNUC__ >= 4 #if __GNUC__ >= 4
return __builtin_popcountll(Value); return __builtin_popcountll(Value);
@ -511,8 +488,7 @@ template <typename T> struct PopulationCounter<T, 8> {
/// Returns 0 if the word is zero. /// Returns 0 if the word is zero.
template <typename T> template <typename T>
inline unsigned countPopulation(T Value) { inline unsigned countPopulation(T Value) {
static_assert(std::numeric_limits<T>::is_integer && static_assert(std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed."); "Only unsigned integral types are allowed.");
return detail::PopulationCounter<T, sizeof(T)>::count(Value); return detail::PopulationCounter<T, sizeof(T)>::count(Value);
} }
@ -529,28 +505,20 @@ inline double Log2(double Value) {
/// Log2_32 - This function returns the floor log base 2 of the specified value, /// Log2_32 - This function returns the floor log base 2 of the specified value,
/// -1 if the value is zero. (32 bit edition.) /// -1 if the value is zero. (32 bit edition.)
/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2 /// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
inline unsigned Log2_32(uint32_t Value) { inline unsigned Log2_32(uint32_t Value) { return 31 - countLeadingZeros(Value); }
return 31 - countLeadingZeros(Value);
}
/// Log2_64 - This function returns the floor log base 2 of the specified value, /// Log2_64 - This function returns the floor log base 2 of the specified value,
/// -1 if the value is zero. (64 bit edition.) /// -1 if the value is zero. (64 bit edition.)
inline unsigned Log2_64(uint64_t Value) { inline unsigned Log2_64(uint64_t Value) { return 63 - countLeadingZeros(Value); }
return 63 - countLeadingZeros(Value);
}
/// Log2_32_Ceil - This function returns the ceil log base 2 of the specified /// Log2_32_Ceil - This function returns the ceil log base 2 of the specified
/// value, 32 if the value is zero. (32 bit edition). /// value, 32 if the value is zero. (32 bit edition).
/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3 /// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
inline unsigned Log2_32_Ceil(uint32_t Value) { inline unsigned Log2_32_Ceil(uint32_t Value) { return 32 - countLeadingZeros(Value - 1); }
return 32 - countLeadingZeros(Value - 1);
}
/// Log2_64_Ceil - This function returns the ceil log base 2 of the specified /// Log2_64_Ceil - This function returns the ceil log base 2 of the specified
/// value, 64 if the value is zero. (64 bit edition.) /// value, 64 if the value is zero. (64 bit edition.)
inline unsigned Log2_64_Ceil(uint64_t Value) { inline unsigned Log2_64_Ceil(uint64_t Value) { return 64 - countLeadingZeros(Value - 1); }
return 64 - countLeadingZeros(Value - 1);
}
/// GreatestCommonDivisor64 - Return the greatest common divisor of the two /// GreatestCommonDivisor64 - Return the greatest common divisor of the two
/// values using Euclid's algorithm. /// values using Euclid's algorithm.
@ -626,9 +594,8 @@ constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
/// ///
/// Alignment should be a power of two. This method rounds up, so /// Alignment should be a power of two. This method rounds up, so
/// alignAddr(7, 4) == 8 and alignAddr(8, 4) == 8. /// alignAddr(7, 4) == 8 and alignAddr(8, 4) == 8.
inline uintptr_t alignAddr(const void *Addr, size_t Alignment) { inline uintptr_t alignAddr(const void* Addr, size_t Alignment) {
assert(Alignment && isPowerOf2_64((uint64_t)Alignment) && assert(Alignment && isPowerOf2_64((uint64_t)Alignment) && "Alignment is not a power of two!");
"Alignment is not a power of two!");
assert((uintptr_t)Addr + Alignment - 1 >= (uintptr_t)Addr); assert((uintptr_t)Addr + Alignment - 1 >= (uintptr_t)Addr);
@ -637,7 +604,7 @@ inline uintptr_t alignAddr(const void *Addr, size_t Alignment) {
/// \brief Returns the necessary adjustment for aligning \c Ptr to \c Alignment /// \brief Returns the necessary adjustment for aligning \c Ptr to \c Alignment
/// bytes, rounding up. /// bytes, rounding up.
inline size_t alignmentAdjustment(const void *Ptr, size_t Alignment) { inline size_t alignmentAdjustment(const void* Ptr, size_t Alignment) {
return alignAddr(Ptr, Alignment) - (uintptr_t)Ptr; return alignAddr(Ptr, Alignment) - (uintptr_t)Ptr;
} }
@ -656,7 +623,8 @@ inline uint64_t NextPowerOf2(uint64_t A) {
/// Returns the power of two which is less than or equal to the given value. /// Returns the power of two which is less than or equal to the given value.
/// Essentially, it is a floor operation across the domain of powers of two. /// Essentially, it is a floor operation across the domain of powers of two.
inline uint64_t PowerOf2Floor(uint64_t A) { inline uint64_t PowerOf2Floor(uint64_t A) {
if (!A) return 0; if (!A)
return 0;
return 1ull << (63 - countLeadingZeros(A, ZB_Undefined)); return 1ull << (63 - countLeadingZeros(A, ZB_Undefined));
} }
@ -696,7 +664,8 @@ inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
/// Returns the next integer (mod 2**64) that is greater than or equal to /// Returns the next integer (mod 2**64) that is greater than or equal to
/// \p Value and is a multiple of \c Align. \c Align must be non-zero. /// \p Value and is a multiple of \c Align. \c Align must be non-zero.
template <uint64_t Align> constexpr inline uint64_t alignTo(uint64_t Value) { template <uint64_t Align>
constexpr inline uint64_t alignTo(uint64_t Value) {
static_assert(Align != 0u, "Align must be non-zero"); static_assert(Align != 0u, "Align must be non-zero");
return (Value + Align - 1) / Align * Align; return (Value + Align - 1) / Align * Align;
} }
@ -725,13 +694,12 @@ inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
/// Returns the offset to the next integer (mod 2**64) that is greater than /// Returns the offset to the next integer (mod 2**64) that is greater than
/// or equal to \p Value and is a multiple of \p Align. \p Align must be /// or equal to \p Value and is a multiple of \p Align. \p Align must be
/// non-zero. /// non-zero.
inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) { inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) { return alignTo(Value, Align) - Value; }
return alignTo(Value, Align) - Value;
}
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer. /// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
/// Requires 0 < B <= 32. /// Requires 0 < B <= 32.
template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) { template <unsigned B>
constexpr inline int32_t SignExtend32(uint32_t X) {
static_assert(B > 0, "Bit width can't be 0."); static_assert(B > 0, "Bit width can't be 0.");
static_assert(B <= 32, "Bit width out of range."); static_assert(B <= 32, "Bit width out of range.");
return int32_t(X << (32 - B)) >> (32 - B); return int32_t(X << (32 - B)) >> (32 - B);
@ -747,7 +715,8 @@ inline int32_t SignExtend32(uint32_t X, unsigned B) {
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer. /// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
/// Requires 0 < B < 64. /// Requires 0 < B < 64.
template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) { template <unsigned B>
constexpr inline int64_t SignExtend64(uint64_t x) {
static_assert(B > 0, "Bit width can't be 0."); static_assert(B > 0, "Bit width can't be 0.");
static_assert(B <= 64, "Bit width out of range."); static_assert(B <= 64, "Bit width out of range.");
return int64_t(x << (64 - B)) >> (64 - B); return int64_t(x << (64 - B)) >> (64 - B);
@ -764,8 +733,7 @@ inline int64_t SignExtend64(uint64_t X, unsigned B) {
/// Subtract two unsigned integers, X and Y, of type T and return the absolute /// Subtract two unsigned integers, X and Y, of type T and return the absolute
/// value of the result. /// value of the result.
template <typename T> template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type typename std::enable_if<std::is_unsigned<T>::value, T>::type AbsoluteDifference(T X, T Y) {
AbsoluteDifference(T X, T Y) {
return std::max(X, Y) - std::min(X, Y); return std::max(X, Y) - std::min(X, Y);
} }
@ -773,10 +741,9 @@ AbsoluteDifference(T X, T Y) {
/// maximum representable value of T on overflow. ResultOverflowed indicates if /// maximum representable value of T on overflow. ResultOverflowed indicates if
/// the result is larger than the maximum representable value of type T. /// the result is larger than the maximum representable value of type T.
template <typename T> template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type typename std::enable_if<std::is_unsigned<T>::value, T>::type SaturatingAdd(T X, T Y, bool* ResultOverflowed = nullptr) {
SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
bool Dummy; bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; bool& Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
// Hacker's Delight, p. 29 // Hacker's Delight, p. 29
T Z = X + Y; T Z = X + Y;
Overflowed = (Z < X || Z < Y); Overflowed = (Z < X || Z < Y);
@ -790,10 +757,10 @@ SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
/// maximum representable value of T on overflow. ResultOverflowed indicates if /// maximum representable value of T on overflow. ResultOverflowed indicates if
/// the result is larger than the maximum representable value of type T. /// the result is larger than the maximum representable value of type T.
template <typename T> template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type typename std::enable_if<std::is_unsigned<T>::value, T>::type SaturatingMultiply(T X, T Y,
SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) { bool* ResultOverflowed = nullptr) {
bool Dummy; bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; bool& Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
// Hacker's Delight, p. 30 has a different algorithm, but we don't use that // Hacker's Delight, p. 30 has a different algorithm, but we don't use that
// because it fails for uint16_t (where multiplication can have undefined // because it fails for uint16_t (where multiplication can have undefined
@ -836,10 +803,10 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
/// overflow. ResultOverflowed indicates if the result is larger than the /// overflow. ResultOverflowed indicates if the result is larger than the
/// maximum representable value of type T. /// maximum representable value of type T.
template <typename T> template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type typename std::enable_if<std::is_unsigned<T>::value, T>::type SaturatingMultiplyAdd(T X, T Y, T A,
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) { bool* ResultOverflowed = nullptr) {
bool Dummy; bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy; bool& Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
T Product = SaturatingMultiply(X, Y, &Overflowed); T Product = SaturatingMultiply(X, Y, &Overflowed);
if (Overflowed) if (Overflowed)
@ -850,6 +817,5 @@ SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC. /// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
extern const float huge_valf; extern const float huge_valf;
} // End llvm namespace } // namespace llvm
} // End hecl namespace } // namespace hecl

View File

@ -3,17 +3,14 @@
#include "hecl.hpp" #include "hecl.hpp"
#include <thread> #include <thread>
namespace hecl namespace hecl {
{
class MultiProgressPrinter class MultiProgressPrinter {
{
std::thread m_logThread; std::thread m_logThread;
mutable std::mutex m_logLock; mutable std::mutex m_logLock;
bool m_newLineAfter; bool m_newLineAfter;
struct TermInfo struct TermInfo {
{
#if _WIN32 #if _WIN32
HANDLE console; HANDLE console;
#endif #endif
@ -22,8 +19,7 @@ class MultiProgressPrinter
bool truncate = false; bool truncate = false;
} m_termInfo; } m_termInfo;
struct ThreadStat struct ThreadStat {
{
hecl::SystemString m_message, m_submessage; hecl::SystemString m_message, m_submessage;
float m_factor = 0.f; float m_factor = 0.f;
bool m_active = false; bool m_active = false;
@ -44,16 +40,16 @@ class MultiProgressPrinter
void DoPrint(); void DoPrint();
void DrawIndeterminateBar(); void DrawIndeterminateBar();
void MoveCursorUp(int n); void MoveCursorUp(int n);
public: public:
MultiProgressPrinter(bool activate = false); MultiProgressPrinter(bool activate = false);
~MultiProgressPrinter(); ~MultiProgressPrinter();
void print(const hecl::SystemChar* message, const hecl::SystemChar* submessage, void print(const hecl::SystemChar* message, const hecl::SystemChar* submessage, float factor = -1.f,
float factor = -1.f, int threadIdx = 0) const; int threadIdx = 0) const;
void setMainFactor(float factor) const; void setMainFactor(float factor) const;
void setMainIndeterminate(bool indeterminate) const; void setMainIndeterminate(bool indeterminate) const;
void startNewLine() const; void startNewLine() const;
void flush() const; void flush() const;
}; };
} } // namespace hecl

View File

@ -11,38 +11,35 @@
/* CMake-curated rep classes for the application */ /* CMake-curated rep classes for the application */
#include "ApplicationReps.hpp" #include "ApplicationReps.hpp"
namespace hecl namespace hecl {
{
#if HECL_RUNTIME #if HECL_RUNTIME
template<typename P, typename S> template <typename P, typename S>
class StageRuntimeObject : public StageRep<P, S> class StageRuntimeObject : public StageRep<P, S> {
{
boo::ObjToken<boo::IShaderStage> m_stage; boo::ObjToken<boo::IShaderStage> m_stage;
public: public:
static constexpr StageTargetType TargetType = StageTargetType::Runtime; static constexpr StageTargetType TargetType = StageTargetType::Runtime;
static constexpr PipelineTargetType PipelineTarget = PipelineTargetType::StageRuntimeCollection; static constexpr PipelineTargetType PipelineTarget = PipelineTargetType::StageRuntimeCollection;
static constexpr bool HasHash = false; static constexpr bool HasHash = false;
StageRuntimeObject() = default; StageRuntimeObject() = default;
StageRuntimeObject(StageConverter<P, S>& conv, FactoryCtx& ctx, const StageBinary<P, S>& in) StageRuntimeObject(StageConverter<P, S>& conv, FactoryCtx& ctx, const StageBinary<P, S>& in) {
{
m_stage = static_cast<typename P::Context&>(ctx).newShaderStage(in.data(), in.size(), S::Enum); m_stage = static_cast<typename P::Context&>(ctx).newShaderStage(in.data(), in.size(), S::Enum);
} }
boo::ObjToken<boo::IShaderStage> stage() const { return m_stage; } boo::ObjToken<boo::IShaderStage> stage() const { return m_stage; }
}; };
#endif #endif
class HECLIR : public PipelineRep<PlatformType::Null> class HECLIR : public PipelineRep<PlatformType::Null> {
{
const hecl::Backend::IR& m_ir; const hecl::Backend::IR& m_ir;
const hecl::Backend::ShaderTag& m_tag; const hecl::Backend::ShaderTag& m_tag;
const hecl::Backend::ExtensionSlot& m_extension; const hecl::Backend::ExtensionSlot& m_extension;
uint64_t m_hash; uint64_t m_hash;
public: public:
HECLIR(const hecl::Backend::IR& ir, const hecl::Backend::ShaderTag& tag, HECLIR(const hecl::Backend::IR& ir, const hecl::Backend::ShaderTag& tag,
const hecl::Backend::ExtensionSlot& extension) const hecl::Backend::ExtensionSlot& extension)
: m_ir(ir), m_tag(tag), m_extension(extension) : m_ir(ir), m_tag(tag), m_extension(extension) {
{
m_hash = tag.val64(); m_hash = tag.val64();
m_hash ^= extension.hash(); m_hash ^= extension.hash();
} }
@ -54,86 +51,75 @@ public:
const hecl::Backend::ExtensionSlot& extension() const { return m_extension; } const hecl::Backend::ExtensionSlot& extension() const { return m_extension; }
}; };
template<typename P, class BackendTp> template <typename P, class BackendTp>
class HECLBackendImpl : public PipelineRep<P> class HECLBackendImpl : public PipelineRep<P> {
{
hecl::Backend::ShaderTag m_tag; hecl::Backend::ShaderTag m_tag;
BackendTp m_backend; BackendTp m_backend;
const hecl::Backend::ExtensionSlot& m_extension; const hecl::Backend::ExtensionSlot& m_extension;
public: public:
static constexpr bool HasHash = false; static constexpr bool HasHash = false;
HECLBackendImpl(PipelineConverter<P>& conv, FactoryCtx& ctx, const HECLIR& in) HECLBackendImpl(PipelineConverter<P>& conv, FactoryCtx& ctx, const HECLIR& in)
: m_tag(in.tag()), m_extension(in.extension()) : m_tag(in.tag()), m_extension(in.extension()) {
{
hecl::Backend::Diagnostics diag; hecl::Backend::Diagnostics diag;
m_backend.reset(in.ir(), diag); m_backend.reset(in.ir(), diag);
} }
std::string makeVert() const std::string makeVert() const {
{ return m_backend.makeVert(m_tag.getColorCount(), m_tag.getUvCount(), m_tag.getWeightCount(),
return m_backend.makeVert( m_tag.getSkinSlotCount(), m_extension.texCount, m_extension.texs,
m_tag.getColorCount(), m_tag.getUvCount(), m_tag.getWeightCount(), m_tag.getReflectionType());
m_tag.getSkinSlotCount(), m_extension.texCount,
m_extension.texs, m_tag.getReflectionType());
} }
std::string makeFrag() const std::string makeFrag() const {
{
return m_backend.makeFrag(m_extension.blockCount, m_extension.blockNames, return m_backend.makeFrag(m_extension.blockCount, m_extension.blockNames,
m_tag.getAlphaTest() || m_extension.forceAlphaTest, m_tag.getReflectionType(), m_tag.getAlphaTest() || m_extension.forceAlphaTest, m_tag.getReflectionType(),
m_backend.m_blendSrc, m_backend.m_blendDst, m_backend.m_blendSrc, m_backend.m_blendDst, m_extension.lighting, m_extension.post,
m_extension.lighting, m_extension.post,
m_extension.texCount, m_extension.texs); m_extension.texCount, m_extension.texs);
} }
const hecl::Backend::ShaderTag& getTag() const { return m_tag; } const hecl::Backend::ShaderTag& getTag() const { return m_tag; }
const hecl::Backend::ExtensionSlot& extension() const { return m_extension; } const hecl::Backend::ExtensionSlot& extension() const { return m_extension; }
std::pair<hecl::Backend::BlendFactor, hecl::Backend::BlendFactor> blendFactors() const std::pair<hecl::Backend::BlendFactor, hecl::Backend::BlendFactor> blendFactors() const {
{ return {m_backend.m_blendSrc, m_backend.m_blendDst}; } return {m_backend.m_blendSrc, m_backend.m_blendDst};
}
}; };
template<typename P> template <typename P>
class HECLBackend : public PipelineRep<P> class HECLBackend : public PipelineRep<P> {
{
public: public:
static constexpr bool HasHash = false; static constexpr bool HasHash = false;
}; };
template<> template <>
class HECLBackend<PlatformType::OpenGL> : public HECLBackendImpl<PlatformType::OpenGL, hecl::Backend::GLSL> class HECLBackend<PlatformType::OpenGL> : public HECLBackendImpl<PlatformType::OpenGL, hecl::Backend::GLSL> {
{
public: public:
using HECLBackendImpl::HECLBackendImpl; using HECLBackendImpl::HECLBackendImpl;
}; };
template<> template <>
class HECLBackend<PlatformType::Vulkan> : public HECLBackendImpl<PlatformType::Vulkan, hecl::Backend::GLSL> class HECLBackend<PlatformType::Vulkan> : public HECLBackendImpl<PlatformType::Vulkan, hecl::Backend::GLSL> {
{
public: public:
using HECLBackendImpl::HECLBackendImpl; using HECLBackendImpl::HECLBackendImpl;
}; };
template<> template <>
class HECLBackend<PlatformType::D3D11> : public HECLBackendImpl<PlatformType::D3D11, hecl::Backend::HLSL> class HECLBackend<PlatformType::D3D11> : public HECLBackendImpl<PlatformType::D3D11, hecl::Backend::HLSL> {
{
public: public:
using HECLBackendImpl::HECLBackendImpl; using HECLBackendImpl::HECLBackendImpl;
}; };
template<> template <>
class HECLBackend<PlatformType::Metal> : public HECLBackendImpl<PlatformType::Metal, hecl::Backend::Metal> class HECLBackend<PlatformType::Metal> : public HECLBackendImpl<PlatformType::Metal, hecl::Backend::Metal> {
{
public: public:
using HECLBackendImpl::HECLBackendImpl; using HECLBackendImpl::HECLBackendImpl;
}; };
template<> template <>
class HECLBackend<PlatformType::NX> : public HECLBackendImpl<PlatformType::NX, hecl::Backend::GLSL> class HECLBackend<PlatformType::NX> : public HECLBackendImpl<PlatformType::NX, hecl::Backend::GLSL> {
{
public: public:
using HECLBackendImpl::HECLBackendImpl; using HECLBackendImpl::HECLBackendImpl;
}; };
template<template<typename, typename> class T, typename P, typename... Rest> template <template <typename, typename> class T, typename P, typename... Rest>
StageCollection<T<P, Rest...>>::StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const HECLBackend<P>& in) StageCollection<T<P, Rest...>>::StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const HECLBackend<P>& in) {
{
m_vertex = conv.getVertexConverter().convert(ctx, StageSourceText<P, PipelineStage::Vertex>(in.makeVert())); m_vertex = conv.getVertexConverter().convert(ctx, StageSourceText<P, PipelineStage::Vertex>(in.makeVert()));
m_fragment = conv.getFragmentConverter().convert(ctx, StageSourceText<P, PipelineStage::Fragment>(in.makeFrag())); m_fragment = conv.getFragmentConverter().convert(ctx, StageSourceText<P, PipelineStage::Fragment>(in.makeFrag()));
m_vtxFmtData = in.getTag().vertexFormat(); m_vtxFmtData = in.getTag().vertexFormat();
@ -143,109 +129,90 @@ StageCollection<T<P, Rest...>>::StageCollection(PipelineConverter<P>& conv, Fact
} }
#if HECL_RUNTIME #if HECL_RUNTIME
template<typename P> template <typename P>
class FinalPipeline : public PipelineRep<P> class FinalPipeline : public PipelineRep<P> {
{
boo::ObjToken<boo::IShaderPipeline> m_pipeline; boo::ObjToken<boo::IShaderPipeline> m_pipeline;
public: public:
static constexpr PipelineTargetType TargetType = PipelineTargetType::FinalPipeline; static constexpr PipelineTargetType TargetType = PipelineTargetType::FinalPipeline;
static constexpr bool HasHash = false; static constexpr bool HasHash = false;
FinalPipeline(PipelineConverter<P>& conv, FactoryCtx& ctx, FinalPipeline(PipelineConverter<P>& conv, FactoryCtx& ctx,
const StageCollection<StageRuntimeObject<P, PipelineStage::Null>>& in) const StageCollection<StageRuntimeObject<P, PipelineStage::Null>>& in) {
{
m_pipeline = static_cast<typename P::Context&>(ctx).newShaderPipeline( m_pipeline = static_cast<typename P::Context&>(ctx).newShaderPipeline(
in.m_vertex.stage(), in.m_fragment.stage(), in.m_geometry.stage(), in.m_vertex.stage(), in.m_fragment.stage(), in.m_geometry.stage(), in.m_control.stage(),
in.m_control.stage(), in.m_evaluation.stage(), in.m_vtxFmt, in.m_additionalInfo); in.m_evaluation.stage(), in.m_vtxFmt, in.m_additionalInfo);
} }
boo::ObjToken<boo::IShaderPipeline> pipeline() const { return m_pipeline; } boo::ObjToken<boo::IShaderPipeline> pipeline() const { return m_pipeline; }
}; };
#endif #endif
template<typename... Args> struct pack {}; template <typename... Args>
struct pack {};
struct null_t {}; struct null_t {};
template<typename P> struct ShaderDB {}; template <typename P>
struct ShaderDB {};
#define STAGE_COLLECTION_SPECIALIZATIONS(T, P) StageCollection<T<P, PipelineStage::Null>>, #define STAGE_COLLECTION_SPECIALIZATIONS(T, P) StageCollection<T<P, PipelineStage::Null>>,
#define PIPELINE_RUNTIME_SPECIALIZATIONS(P) \ #define PIPELINE_RUNTIME_SPECIALIZATIONS(P) \
HECLBackend<P>, \ HECLBackend<P>, \
STAGE_COLLECTION_SPECIALIZATIONS(StageSourceText, P) \ STAGE_COLLECTION_SPECIALIZATIONS(StageSourceText, P) STAGE_COLLECTION_SPECIALIZATIONS(StageBinary, P) \
STAGE_COLLECTION_SPECIALIZATIONS(StageBinary, P) \ STAGE_COLLECTION_SPECIALIZATIONS(StageRuntimeObject, P) FinalPipeline<P>,
STAGE_COLLECTION_SPECIALIZATIONS(StageRuntimeObject, P) \ #define PIPELINE_OFFLINE_SPECIALIZATIONS(P) HECLBackend<P>, STAGE_COLLECTION_SPECIALIZATIONS(StageSourceText, P)
FinalPipeline<P>,
#define PIPELINE_OFFLINE_SPECIALIZATIONS(P) \
HECLBackend<P>, \
STAGE_COLLECTION_SPECIALIZATIONS(StageSourceText, P)
#define STAGE_RUNTIME_SPECIALIZATIONS(P, S) \ #define STAGE_RUNTIME_SPECIALIZATIONS(P, S) \
StageBinary<P, S>, \ StageBinary<P, S>, HECL_APPLICATION_STAGE_REPS(P, S) StageRuntimeObject<P, S>,
HECL_APPLICATION_STAGE_REPS(P, S) \ #define STAGE_OFFLINE_SPECIALIZATIONS(P, S) HECL_APPLICATION_STAGE_REPS(P, S)
StageRuntimeObject<P, S>,
#define STAGE_OFFLINE_SPECIALIZATIONS(P, S) \
HECL_APPLICATION_STAGE_REPS(P, S)
#define SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, S) \ #define SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, S) \
template<> struct ShaderDB<P>::StageDB<S> \ template <> \
{ \ struct ShaderDB<P>::StageDB<S> { \
using StageTypes = pack< \ using StageTypes = pack<STAGE_RUNTIME_SPECIALIZATIONS(P, S) null_t>; \
STAGE_RUNTIME_SPECIALIZATIONS(P, S) \ };
null_t \
>; \
};
#define SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, S) \ #define SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, S) \
template<> struct ShaderDB<P>::StageDB<S> \ template <> \
{ \ struct ShaderDB<P>::StageDB<S> { \
using StageTypes = pack< \ using StageTypes = pack<null_t>; \
null_t \ };
>; \
};
#define SPECIALIZE_OFFLINE_STAGE(P, S) \ #define SPECIALIZE_OFFLINE_STAGE(P, S) \
template<> struct ShaderDB<P>::StageDB<S> \ template <> \
{ \ struct ShaderDB<P>::StageDB<S> { \
using StageTypes = pack< \ using StageTypes = pack<STAGE_OFFLINE_SPECIALIZATIONS(P, S) null_t>; \
STAGE_OFFLINE_SPECIALIZATIONS(P, S) \ };
null_t \
>; \
};
#define SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(P) \ #define SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(P) \
template<> struct ShaderDB<P> \ template <> \
{ \ struct ShaderDB<P> { \
using PipelineTypes = pack< \ using PipelineTypes = pack<PIPELINE_RUNTIME_SPECIALIZATIONS(P) null_t>; \
PIPELINE_RUNTIME_SPECIALIZATIONS(P) \ template <typename S> \
null_t \ struct StageDB {}; \
>; \ }; \
template<typename S> struct StageDB {}; \ SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Vertex) \
}; \ SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Fragment) \
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Vertex) \ SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Geometry) \
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Fragment) \ SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Control) \
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Geometry) \ SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Evaluation)
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Control) \
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Evaluation)
#define SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(P) \ #define SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(P) \
template<> struct ShaderDB<P> \ template <> \
{ \ struct ShaderDB<P> { \
using PipelineTypes = pack< \ using PipelineTypes = pack<null_t>; \
null_t \ template <typename S> \
>; \ struct StageDB {}; \
template<typename S> struct StageDB {}; \ }; \
}; \ SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Vertex) \
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Vertex) \ SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Fragment) \
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Fragment) \ SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Geometry) \
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Geometry) \ SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Control) \
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Control) \ SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Evaluation)
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Evaluation)
#define SPECIALIZE_OFFLINE_PLATFORM(P) \ #define SPECIALIZE_OFFLINE_PLATFORM(P) \
template<> struct ShaderDB<P> \ template <> \
{ \ struct ShaderDB<P> { \
using PipelineTypes = pack< \ using PipelineTypes = pack<PIPELINE_OFFLINE_SPECIALIZATIONS(P) null_t>; \
PIPELINE_OFFLINE_SPECIALIZATIONS(P) \ template <typename S> \
null_t \ struct StageDB {}; \
>; \ }; \
template<typename S> struct StageDB {}; \ SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Vertex) \
}; \ SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Fragment) \
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Vertex) \ SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Geometry) \
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Fragment) \ SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Control) \
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Geometry) \ SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Evaluation)
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Control) \
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Evaluation)
#if HECL_RUNTIME #if HECL_RUNTIME
#if BOO_HAS_GL #if BOO_HAS_GL
@ -283,9 +250,8 @@ SPECIALIZE_OFFLINE_PLATFORM(hecl::PlatformType::NX)
class ShaderCacheZipStream; class ShaderCacheZipStream;
template<typename P, typename S> template <typename P, typename S>
class StageConverter class StageConverter {
{
friend class PipelineConverter<P>; friend class PipelineConverter<P>;
#if HECL_RUNTIME #if HECL_RUNTIME
using StageTargetTp = StageRuntimeObject<P, S>; using StageTargetTp = StageRuntimeObject<P, S>;
@ -353,79 +319,76 @@ class StageConverter
static constexpr bool is_stage_constructible_v = static constexpr bool is_stage_constructible_v =
std::is_constructible<ToTp, StageConverter<P, S>&, FactoryCtx&, FromTp>::value; std::is_constructible<ToTp, StageConverter<P, S>&, FactoryCtx&, FromTp>::value;
template<typename OriginTp, typename ToTp, typename T, typename... Targs> template <typename OriginTp, typename ToTp, typename T, typename... Targs>
struct _next_type { using type = std::conditional_t<is_stage_constructible_v<ToTp, OriginTp>, struct _next_type {
ToTp, using type = std::conditional_t<is_stage_constructible_v<ToTp, OriginTp>, ToTp,
typename _next_type<OriginTp, T, Targs...>::type>; }; typename _next_type<OriginTp, T, Targs...>::type>;
template<typename OriginTp, typename ToTp> };
struct _next_type<OriginTp, ToTp, null_t> { using type = null_t; }; template <typename OriginTp, typename ToTp>
template<typename OriginTp, typename... AllTypes> struct _next_type<OriginTp, ToTp, null_t> {
struct next_type { using type = null_t; }; using type = null_t;
template<typename OriginTp, typename... AllTypes> };
template <typename OriginTp, typename... AllTypes>
struct next_type {
using type = null_t;
};
template <typename OriginTp, typename... AllTypes>
struct next_type<OriginTp, pack<AllTypes...>> : _next_type<OriginTp, AllTypes...> {}; struct next_type<OriginTp, pack<AllTypes...>> : _next_type<OriginTp, AllTypes...> {};
template <typename OriginTp> template <typename OriginTp>
using next_type_t = typename next_type<OriginTp, StageTypes>::type; using next_type_t = typename next_type<OriginTp, StageTypes>::type;
/* StageSourceText derivative -> StageBinary */ /* StageSourceText derivative -> StageBinary */
template<class ToTp, class FromTp, class NextTp> template <class ToTp, class FromTp, class NextTp>
std::enable_if_t<std::is_same_v<ToTp, StageBinary<P, S>> && std::enable_if_t<std::is_same_v<ToTp, StageBinary<P, S>> && std::is_base_of_v<StageSourceText<P, S>, NextTp>,
std::is_base_of_v<StageSourceText<P, S>, NextTp>, StageBinary<P, S>> StageBinary<P, S>>
_DoDerivative(FactoryCtx& ctx, const FromTp& in) _DoDerivative(FactoryCtx& ctx, const FromTp& in) {
{
return StageBinary<P, S>(*this, ctx, NextTp(*this, ctx, in)); return StageBinary<P, S>(*this, ctx, NextTp(*this, ctx, in));
} }
/* StageBinary derivative -> StageBinary */ /* StageBinary derivative -> StageBinary */
template<class ToTp, class FromTp, class NextTp> template <class ToTp, class FromTp, class NextTp>
std::enable_if_t<std::is_same_v<ToTp, StageBinary<P, S>> && std::enable_if_t<std::is_same_v<ToTp, StageBinary<P, S>> && std::is_base_of_v<StageBinary<P, S>, NextTp>,
std::is_base_of_v<StageBinary<P, S>, NextTp>, StageBinary<P, S>> StageBinary<P, S>>
_DoDerivative(FactoryCtx& ctx, const FromTp& in) _DoDerivative(FactoryCtx& ctx, const FromTp& in) {
{
return NextTp(*this, ctx, in); return NextTp(*this, ctx, in);
} }
/* Non-StageSourceText derivative -> StageBinary */ /* Non-StageSourceText derivative -> StageBinary */
template<class ToTp, class FromTp> template <class ToTp, class FromTp>
std::enable_if_t<std::is_same_v<ToTp, StageBinary<P, S>> && std::enable_if_t<std::is_same_v<ToTp, StageBinary<P, S>> && !std::is_base_of_v<StageSourceText<P, S>, FromTp>,
!std::is_base_of_v<StageSourceText<P, S>, FromTp>, StageBinary<P, S>> StageBinary<P, S>>
_Do(FactoryCtx& ctx, const FromTp& in) _Do(FactoryCtx& ctx, const FromTp& in) {
{
using NextTp = next_type_t<FromTp>; using NextTp = next_type_t<FromTp>;
static_assert(!std::is_same_v<NextTp, null_t>, static_assert(!std::is_same_v<NextTp, null_t>, "Unable to resolve StageBinary or StageSourceText derivative");
"Unable to resolve StageBinary or StageSourceText derivative");
return _DoDerivative<ToTp, FromTp, NextTp>(ctx, in); return _DoDerivative<ToTp, FromTp, NextTp>(ctx, in);
} }
/* StageSourceText derivative -> StageBinary */ /* StageSourceText derivative -> StageBinary */
template<class ToTp, class FromTp> template <class ToTp, class FromTp>
std::enable_if_t<std::is_same_v<ToTp, StageBinary<P, S>> && std::enable_if_t<std::is_same_v<ToTp, StageBinary<P, S>> && std::is_base_of_v<StageSourceText<P, S>, FromTp>,
std::is_base_of_v<StageSourceText<P, S>, FromTp>, StageBinary<P, S>> StageBinary<P, S>>
_Do(FactoryCtx& ctx, const FromTp& in) _Do(FactoryCtx& ctx, const FromTp& in) {
{
return StageBinary<P, S>(*this, ctx, in); return StageBinary<P, S>(*this, ctx, in);
} }
/* Non-StageBinary derivative -> StageRuntimeObject */ /* Non-StageBinary derivative -> StageRuntimeObject */
template<class ToTp, class FromTp> template <class ToTp, class FromTp>
std::enable_if_t<std::is_same_v<ToTp, StageRuntimeObject<P, S>> && std::enable_if_t<std::is_same_v<ToTp, StageRuntimeObject<P, S>> && !std::is_base_of_v<StageBinary<P, S>, FromTp>,
!std::is_base_of_v<StageBinary<P, S>, FromTp>, StageRuntimeObject<P, S>> StageRuntimeObject<P, S>>
_Do(FactoryCtx& ctx, const FromTp& in) _Do(FactoryCtx& ctx, const FromTp& in) {
{
return StageRuntimeObject<P, S>(*this, ctx, _Do<StageBinary<P, S>, FromTp>(ctx, in)); return StageRuntimeObject<P, S>(*this, ctx, _Do<StageBinary<P, S>, FromTp>(ctx, in));
} }
/* StageBinary derivative -> StageRuntimeObject */ /* StageBinary derivative -> StageRuntimeObject */
template<class ToTp, class FromTp> template <class ToTp, class FromTp>
std::enable_if_t<std::is_same_v<ToTp, StageRuntimeObject<P, S>> && std::enable_if_t<std::is_same_v<ToTp, StageRuntimeObject<P, S>> && std::is_base_of_v<StageBinary<P, S>, FromTp>,
std::is_base_of_v<StageBinary<P, S>, FromTp>, StageRuntimeObject<P, S>> StageRuntimeObject<P, S>>
_Do(FactoryCtx& ctx, const FromTp& in) _Do(FactoryCtx& ctx, const FromTp& in) {
{
return StageRuntimeObject<P, S>(*this, ctx, in); return StageRuntimeObject<P, S>(*this, ctx, in);
} }
template<class ToTp, class FromTp> template <class ToTp, class FromTp>
ToTp Do(FactoryCtx& ctx, const FromTp& in) ToTp Do(FactoryCtx& ctx, const FromTp& in) {
{
return _Do<ToTp, FromTp>(ctx, in); return _Do<ToTp, FromTp>(ctx, in);
} }
@ -434,11 +397,9 @@ public:
void loadFromStream(FactoryCtx& ctx, ShaderCacheZipStream& r); void loadFromStream(FactoryCtx& ctx, ShaderCacheZipStream& r);
#endif #endif
template<class FromTp> template <class FromTp>
StageTargetTp convert(FactoryCtx& ctx, const FromTp& in) StageTargetTp convert(FactoryCtx& ctx, const FromTp& in) {
{ if (FromTp::HasHash) {
if (FromTp::HasHash)
{
uint64_t hash = in.Hash(); uint64_t hash = in.Hash();
auto search = m_stageCache.find(hash); auto search = m_stageCache.find(hash);
if (search != m_stageCache.end()) if (search != m_stageCache.end())
@ -449,26 +410,26 @@ public:
} }
}; };
class PipelineConverterBase class PipelineConverterBase {
{
boo::IGraphicsDataFactory* m_gfxF; boo::IGraphicsDataFactory* m_gfxF;
boo::IGraphicsDataFactory::Platform m_platform; boo::IGraphicsDataFactory::Platform m_platform;
protected: protected:
PipelineConverterBase(boo::IGraphicsDataFactory* gfxF, boo::IGraphicsDataFactory::Platform platform) PipelineConverterBase(boo::IGraphicsDataFactory* gfxF, boo::IGraphicsDataFactory::Platform platform)
: m_gfxF(gfxF), m_platform(platform) {} : m_gfxF(gfxF), m_platform(platform) {}
public: public:
virtual ~PipelineConverterBase() = default; virtual ~PipelineConverterBase() = default;
#if HECL_RUNTIME #if HECL_RUNTIME
template<class FromTp> template <class FromTp>
boo::ObjToken<boo::IShaderPipeline> convert(FactoryCtx& ctx, const FromTp& in); boo::ObjToken<boo::IShaderPipeline> convert(FactoryCtx& ctx, const FromTp& in);
template<class FromTp> template <class FromTp>
boo::ObjToken<boo::IShaderPipeline> convert(const FromTp& in); boo::ObjToken<boo::IShaderPipeline> convert(const FromTp& in);
#endif #endif
}; };
template<typename P> template <typename P>
class PipelineConverter : public PipelineConverterBase class PipelineConverter : public PipelineConverterBase {
{
#if HECL_RUNTIME #if HECL_RUNTIME
using PipelineTargetTp = FinalPipeline<P>; using PipelineTargetTp = FinalPipeline<P>;
#else #else
@ -487,58 +448,57 @@ class PipelineConverter : public PipelineConverterBase
static constexpr bool is_pipeline_constructible_v = static constexpr bool is_pipeline_constructible_v =
std::is_constructible<ToTp, PipelineConverter<P>&, FactoryCtx&, FromTp>::value; std::is_constructible<ToTp, PipelineConverter<P>&, FactoryCtx&, FromTp>::value;
template<typename FinalTp, typename OriginTp, typename... AllTypes> template <typename FinalTp, typename OriginTp, typename... AllTypes>
struct is_eventually_constructible : std::false_type {}; struct is_eventually_constructible : std::false_type {};
template<typename FinalTp, typename OriginTp, typename ToTp, typename T, typename... Targs> template <typename FinalTp, typename OriginTp, typename ToTp, typename T, typename... Targs>
struct _is_eventually_constructible struct _is_eventually_constructible
: std::conditional_t<is_pipeline_constructible_v<FinalTp, OriginTp>, : std::conditional_t<is_pipeline_constructible_v<FinalTp, OriginTp>, std::true_type,
std::true_type,
std::conditional_t<is_pipeline_constructible_v<ToTp, OriginTp>, std::conditional_t<is_pipeline_constructible_v<ToTp, OriginTp>,
is_eventually_constructible<FinalTp, ToTp, PipelineTypes>, is_eventually_constructible<FinalTp, ToTp, PipelineTypes>,
_is_eventually_constructible<FinalTp, OriginTp, T, Targs...>>> {}; _is_eventually_constructible<FinalTp, OriginTp, T, Targs...>>> {};
template<typename FinalTp, typename OriginTp, typename ToTp> template <typename FinalTp, typename OriginTp, typename ToTp>
struct _is_eventually_constructible<FinalTp, OriginTp, ToTp, null_t> : std::false_type {}; struct _is_eventually_constructible<FinalTp, OriginTp, ToTp, null_t> : std::false_type {};
template<typename FinalTp, typename OriginTp, typename... AllTypes> template <typename FinalTp, typename OriginTp, typename... AllTypes>
struct is_eventually_constructible<FinalTp, OriginTp, pack<AllTypes...>> struct is_eventually_constructible<FinalTp, OriginTp, pack<AllTypes...>>
: _is_eventually_constructible<FinalTp, OriginTp, AllTypes...> {}; : _is_eventually_constructible<FinalTp, OriginTp, AllTypes...> {};
template <typename FinalTp, typename OriginTp> template <typename FinalTp, typename OriginTp>
static constexpr bool is_eventually_constructible_v = static constexpr bool is_eventually_constructible_v =
is_eventually_constructible<FinalTp, OriginTp, PipelineTypes>::value; is_eventually_constructible<FinalTp, OriginTp, PipelineTypes>::value;
template<typename FinalTp, typename OriginTp, typename ToTp, typename T, typename... Targs> template <typename FinalTp, typename OriginTp, typename ToTp, typename T, typename... Targs>
struct _next_type { using type = std::conditional_t<is_pipeline_constructible_v<FinalTp, ToTp> && struct _next_type {
is_eventually_constructible_v<ToTp, OriginTp>, using type =
ToTp, std::conditional_t<is_pipeline_constructible_v<FinalTp, ToTp> && is_eventually_constructible_v<ToTp, OriginTp>,
typename _next_type<FinalTp, OriginTp, T, Targs...>::type>; }; ToTp, typename _next_type<FinalTp, OriginTp, T, Targs...>::type>;
template<typename FinalTp, typename OriginTp, typename ToTp> };
struct _next_type<FinalTp, OriginTp, ToTp, null_t> { using type = null_t; }; template <typename FinalTp, typename OriginTp, typename ToTp>
template<typename FinalTp, typename OriginTp, typename... AllTypes> struct _next_type<FinalTp, OriginTp, ToTp, null_t> {
struct next_type { using type = null_t; }; using type = null_t;
template<typename FinalTp, typename OriginTp, typename... AllTypes> };
template <typename FinalTp, typename OriginTp, typename... AllTypes>
struct next_type {
using type = null_t;
};
template <typename FinalTp, typename OriginTp, typename... AllTypes>
struct next_type<FinalTp, OriginTp, pack<AllTypes...>> : _next_type<FinalTp, OriginTp, AllTypes...> {}; struct next_type<FinalTp, OriginTp, pack<AllTypes...>> : _next_type<FinalTp, OriginTp, AllTypes...> {};
template <typename FinalTp, typename OriginTp> template <typename FinalTp, typename OriginTp>
using next_type_t = typename next_type<FinalTp, OriginTp, PipelineTypes>::type; using next_type_t = typename next_type<FinalTp, OriginTp, PipelineTypes>::type;
template<class ToTp, class FromTp> template <class ToTp, class FromTp>
std::enable_if_t<!is_pipeline_constructible_v<ToTp, FromTp>, ToTp> std::enable_if_t<!is_pipeline_constructible_v<ToTp, FromTp>, ToTp> _Do(FactoryCtx& ctx, const FromTp& in) {
_Do(FactoryCtx& ctx, const FromTp& in)
{
using NextTp = next_type_t<ToTp, FromTp>; using NextTp = next_type_t<ToTp, FromTp>;
return ToTp(*this, ctx, _Do<NextTp, FromTp>(ctx, in)); return ToTp(*this, ctx, _Do<NextTp, FromTp>(ctx, in));
} }
template<class ToTp, class FromTp> template <class ToTp, class FromTp>
std::enable_if_t<is_pipeline_constructible_v<ToTp, FromTp>, ToTp> std::enable_if_t<is_pipeline_constructible_v<ToTp, FromTp>, ToTp> _Do(FactoryCtx& ctx, const FromTp& in) {
_Do(FactoryCtx& ctx, const FromTp& in)
{
return ToTp(*this, ctx, in); return ToTp(*this, ctx, in);
} }
template<class ToTp, class FromTp> template <class ToTp, class FromTp>
ToTp Do(FactoryCtx& ctx, const FromTp& in) ToTp Do(FactoryCtx& ctx, const FromTp& in) {
{
/* No idea why this fails; it works fine with manual template arguments (clang bug?) */ /* No idea why this fails; it works fine with manual template arguments (clang bug?) */
//static_assert(is_eventually_constructible_v<ToTp, FromTp>, "Unable to resolve pipeline conversion chain"); // static_assert(is_eventually_constructible_v<ToTp, FromTp>, "Unable to resolve pipeline conversion chain");
return _Do<ToTp, FromTp>(ctx, in); return _Do<ToTp, FromTp>(ctx, in);
} }
@ -548,11 +508,9 @@ public:
bool loadFromFile(FactoryCtx& ctx, const hecl::SystemChar* path); bool loadFromFile(FactoryCtx& ctx, const hecl::SystemChar* path);
#endif #endif
template<class FromTp> template <class FromTp>
PipelineTargetTp convert(FactoryCtx& ctx, const FromTp& in) PipelineTargetTp convert(FactoryCtx& ctx, const FromTp& in) {
{ if (FromTp::HasHash) {
if (FromTp::HasHash)
{
uint64_t hash = in.Hash(); uint64_t hash = in.Hash();
auto search = m_pipelineCache.find(hash); auto search = m_pipelineCache.find(hash);
if (search != m_pipelineCache.end()) if (search != m_pipelineCache.end())
@ -571,12 +529,10 @@ public:
#if HECL_RUNTIME #if HECL_RUNTIME
template<class FromTp> template <class FromTp>
inline boo::ObjToken<boo::IShaderPipeline> PipelineConverterBase::convert(FactoryCtx& ctx, const FromTp& in) inline boo::ObjToken<boo::IShaderPipeline> PipelineConverterBase::convert(FactoryCtx& ctx, const FromTp& in) {
{
assert(ctx.platform() == m_platform && "PipelineConverterBase platform mismatch"); assert(ctx.platform() == m_platform && "PipelineConverterBase platform mismatch");
switch (m_platform) switch (m_platform) {
{
#if BOO_HAS_GL #if BOO_HAS_GL
case boo::IGraphicsDataFactory::Platform::OpenGL: case boo::IGraphicsDataFactory::Platform::OpenGL:
return static_cast<PipelineConverter<PlatformType::OpenGL>&>(*this).convert(ctx, in).pipeline(); return static_cast<PipelineConverter<PlatformType::OpenGL>&>(*this).convert(ctx, in).pipeline();
@ -602,22 +558,18 @@ inline boo::ObjToken<boo::IShaderPipeline> PipelineConverterBase::convert(Factor
} }
} }
template<class FromTp> template <class FromTp>
inline boo::ObjToken<boo::IShaderPipeline> PipelineConverterBase::convert(const FromTp& in) inline boo::ObjToken<boo::IShaderPipeline> PipelineConverterBase::convert(const FromTp& in) {
{
boo::ObjToken<boo::IShaderPipeline> ret; boo::ObjToken<boo::IShaderPipeline> ret;
m_gfxF->commitTransaction([this, &ret, &in](boo::IGraphicsDataFactory::Context& ctx) m_gfxF->commitTransaction([this, &ret, &in](boo::IGraphicsDataFactory::Context& ctx) {
{
ret = convert(ctx, in); ret = convert(ctx, in);
return true; return true;
} BooTrace); } BooTrace);
return ret; return ret;
} }
inline std::unique_ptr<PipelineConverterBase> NewPipelineConverter(boo::IGraphicsDataFactory* gfxF) inline std::unique_ptr<PipelineConverterBase> NewPipelineConverter(boo::IGraphicsDataFactory* gfxF) {
{ switch (gfxF->platform()) {
switch (gfxF->platform())
{
#if BOO_HAS_GL #if BOO_HAS_GL
case boo::IGraphicsDataFactory::Platform::OpenGL: case boo::IGraphicsDataFactory::Platform::OpenGL:
return std::make_unique<PipelineConverter<PlatformType::OpenGL>>(gfxF); return std::make_unique<PipelineConverter<PlatformType::OpenGL>>(gfxF);
@ -648,4 +600,4 @@ extern PipelineConverterBase* conv;
#endif #endif
} } // namespace hecl

View File

@ -1,33 +1,26 @@
#pragma once #pragma once
#include "Compilers.hpp" #include "Compilers.hpp"
extern "C" unsigned long long XXH64 (const void* input, size_t length, unsigned long long seed); extern "C" unsigned long long XXH64(const void* input, size_t length, unsigned long long seed);
#define HECL_RUNTIME 1 #define HECL_RUNTIME 1
namespace hecl namespace hecl {
{
using AdditionalPipelineInfo = boo::AdditionalPipelineInfo; using AdditionalPipelineInfo = boo::AdditionalPipelineInfo;
enum class StageTargetType enum class StageTargetType { SourceText, Binary, Runtime };
{
SourceText,
Binary,
Runtime
};
enum class PipelineTargetType enum class PipelineTargetType {
{
StageSourceTextCollection, StageSourceTextCollection,
StageBinaryCollection, StageBinaryCollection,
StageRuntimeCollection, StageRuntimeCollection,
FinalPipeline FinalPipeline
}; };
template<typename P, typename S> template <typename P, typename S>
class StageConverter; class StageConverter;
template<typename P> template <typename P>
class PipelineConverter; class PipelineConverter;
#if HECL_RUNTIME #if HECL_RUNTIME
@ -36,17 +29,15 @@ using FactoryCtx = boo::IGraphicsDataFactory::Context;
struct FactoryCtx {}; struct FactoryCtx {};
#endif #endif
template<typename P, typename S> template <typename P, typename S>
class StageRep class StageRep {
{
public: public:
using Platform = P; using Platform = P;
using Stage = S; using Stage = S;
}; };
template<typename P> template <typename P>
class PipelineRep class PipelineRep {
{
public: public:
using Platform = P; using Platform = P;
}; };
@ -54,59 +45,55 @@ public:
class GeneralShader : public hecl::PipelineRep<hecl::PlatformType::Null> {}; class GeneralShader : public hecl::PipelineRep<hecl::PlatformType::Null> {};
class TessellationShader : public hecl::PipelineRep<hecl::PlatformType::Null> {}; class TessellationShader : public hecl::PipelineRep<hecl::PlatformType::Null> {};
template<typename P, typename S> template <typename P, typename S>
class StageSourceText : public StageRep<P, S> class StageSourceText : public StageRep<P, S> {
{
std::string_view m_text; std::string_view m_text;
uint64_t m_hash; uint64_t m_hash;
public: public:
static constexpr StageTargetType TargetType = StageTargetType::SourceText; static constexpr StageTargetType TargetType = StageTargetType::SourceText;
static constexpr PipelineTargetType PipelineTarget = PipelineTargetType::StageSourceTextCollection; static constexpr PipelineTargetType PipelineTarget = PipelineTargetType::StageSourceTextCollection;
static constexpr bool HasHash = true; static constexpr bool HasHash = true;
uint64_t Hash() const { return m_hash; } uint64_t Hash() const { return m_hash; }
explicit StageSourceText(std::string_view text) explicit StageSourceText(std::string_view text) : m_text(text), m_hash(XXH64(m_text.data(), m_text.size(), 0)) {}
: m_text(text), m_hash(XXH64(m_text.data(), m_text.size(), 0)) {}
std::string_view text() const { return m_text; } std::string_view text() const { return m_text; }
}; };
template<typename P, typename S> template <typename P, typename S>
class StageBinary : public StageRep<P, S> class StageBinary : public StageRep<P, S> {
{
StageBinaryData m_ownedData; StageBinaryData m_ownedData;
const uint8_t* m_data = nullptr; const uint8_t* m_data = nullptr;
size_t m_size = 0; size_t m_size = 0;
uint64_t m_hash = 0; uint64_t m_hash = 0;
public: public:
static constexpr StageTargetType TargetType = StageTargetType::Binary; static constexpr StageTargetType TargetType = StageTargetType::Binary;
static constexpr PipelineTargetType PipelineTarget = PipelineTargetType::StageBinaryCollection; static constexpr PipelineTargetType PipelineTarget = PipelineTargetType::StageBinaryCollection;
static constexpr bool HasHash = true; static constexpr bool HasHash = true;
uint64_t Hash() const { return m_hash; } uint64_t Hash() const { return m_hash; }
StageBinary(const uint8_t* data, size_t size) StageBinary(const uint8_t* data, size_t size) : m_data(data), m_size(size) { m_hash = XXH64(m_data, m_size, 0); }
: m_data(data), m_size(size)
{ m_hash = XXH64(m_data, m_size, 0); }
StageBinary(StageBinaryData data, size_t size) StageBinary(StageBinaryData data, size_t size)
: m_ownedData(std::move(data)), : m_ownedData(std::move(data)), m_data(m_ownedData.get()), m_size(size) {
m_data(m_ownedData.get()), m_size(size) m_hash = XXH64(m_data, m_size, 0);
{ m_hash = XXH64(m_data, m_size, 0); } }
explicit StageBinary(std::pair<StageBinaryData, size_t> data) explicit StageBinary(std::pair<StageBinaryData, size_t> data) : StageBinary(data.first, data.second) {}
: StageBinary(data.first, data.second) {}
StageBinary(StageConverter<P, S>& conv, FactoryCtx& ctx, const StageSourceText<P, S>& in) StageBinary(StageConverter<P, S>& conv, FactoryCtx& ctx, const StageSourceText<P, S>& in)
: StageBinary(CompileShader<P, S>(in.text())) {} : StageBinary(CompileShader<P, S>(in.text())) {}
const uint8_t* data() const { return m_data; } const uint8_t* data() const { return m_data; }
size_t size() const { return m_size; } size_t size() const { return m_size; }
}; };
template<typename P> template <typename P>
class FinalPipeline; class FinalPipeline;
template<typename P> template <typename P>
class HECLBackend; class HECLBackend;
template <class T> template <class T>
using __IsStageSubclass = typename std::disjunction< using __IsStageSubclass =
std::is_base_of<StageRep<typename T::Platform, PipelineStage::Vertex>, T>, typename std::disjunction<std::is_base_of<StageRep<typename T::Platform, PipelineStage::Vertex>, T>,
std::is_base_of<StageRep<typename T::Platform, PipelineStage::Fragment>, T>, std::is_base_of<StageRep<typename T::Platform, PipelineStage::Fragment>, T>,
std::is_base_of<StageRep<typename T::Platform, PipelineStage::Geometry>, T>, std::is_base_of<StageRep<typename T::Platform, PipelineStage::Geometry>, T>,
std::is_base_of<StageRep<typename T::Platform, PipelineStage::Control>, T>, std::is_base_of<StageRep<typename T::Platform, PipelineStage::Control>, T>,
@ -114,10 +101,10 @@ using __IsStageSubclass = typename std::disjunction<
template <class T> template <class T>
inline constexpr bool __IsStageSubclass_v = __IsStageSubclass<T>::value; inline constexpr bool __IsStageSubclass_v = __IsStageSubclass<T>::value;
template<typename T> class StageCollection; template <typename T>
template<template<typename, typename> class T, typename P, typename... Rest> class StageCollection;
class StageCollection<T<P, Rest...>> : public PipelineRep<P> template <template <typename, typename> class T, typename P, typename... Rest>
{ class StageCollection<T<P, Rest...>> : public PipelineRep<P> {
using base = PipelineRep<P>; using base = PipelineRep<P>;
friend class FinalPipeline<P>; friend class FinalPipeline<P>;
static_assert(__IsStageSubclass_v<T<P, PipelineStage::Vertex>>, static_assert(__IsStageSubclass_v<T<P, PipelineStage::Vertex>>,
@ -131,16 +118,18 @@ class StageCollection<T<P, Rest...>> : public PipelineRep<P>
std::vector<boo::VertexElementDescriptor> m_vtxFmtData; std::vector<boo::VertexElementDescriptor> m_vtxFmtData;
boo::VertexFormatInfo m_vtxFmt; boo::VertexFormatInfo m_vtxFmt;
uint64_t m_hash; uint64_t m_hash;
public: public:
static constexpr PipelineTargetType TargetType = T<P, PipelineStage::Vertex>::PipelineTarget; static constexpr PipelineTargetType TargetType = T<P, PipelineStage::Vertex>::PipelineTarget;
static constexpr bool HasHash = T<P, PipelineStage::Vertex>::HasHash; static constexpr bool HasHash = T<P, PipelineStage::Vertex>::HasHash;
template<typename U = StageCollection<T<P, Rest...>>> template <typename U = StageCollection<T<P, Rest...>>>
std::enable_if_t<U::HasHash, uint64_t> Hash() const { return m_hash; } std::enable_if_t<U::HasHash, uint64_t> Hash() const {
template<typename U = StageCollection<T<P, Rest...>>> return m_hash;
}
template <typename U = StageCollection<T<P, Rest...>>>
void MakeHash(std::enable_if_t<!U::HasHash>* = 0) {} void MakeHash(std::enable_if_t<!U::HasHash>* = 0) {}
template<typename U = StageCollection<T<P, Rest...>>> template <typename U = StageCollection<T<P, Rest...>>>
void MakeHash(std::enable_if_t<U::HasHash>* = 0) void MakeHash(std::enable_if_t<U::HasHash>* = 0) {
{
m_hash = 0; m_hash = 0;
m_hash ^= m_vertex.Hash(); m_hash ^= m_vertex.Hash();
m_hash ^= m_fragment.Hash(); m_hash ^= m_fragment.Hash();
@ -150,26 +139,23 @@ public:
m_hash ^= XXH64(&m_additionalInfo, sizeof(m_additionalInfo), 0); m_hash ^= XXH64(&m_additionalInfo, sizeof(m_additionalInfo), 0);
} }
StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const HECLBackend<P>& in); StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const HECLBackend<P>& in);
template<typename I> template <typename I>
StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const I& in, StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const I& in,
typename std::enable_if_t<std::is_base_of_v<GeneralShader, I>>* = 0) typename std::enable_if_t<std::is_base_of_v<GeneralShader, I>>* = 0) {
{
m_vertex = conv.getVertexConverter().convert(ctx, in); m_vertex = conv.getVertexConverter().convert(ctx, in);
m_fragment = conv.getFragmentConverter().convert(ctx, in); m_fragment = conv.getFragmentConverter().convert(ctx, in);
m_vtxFmt = in.VtxFmt; m_vtxFmt = in.VtxFmt;
m_additionalInfo = in.PipelineInfo; m_additionalInfo = in.PipelineInfo;
MakeHash(); MakeHash();
} }
template<typename I> template <typename I>
StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const I& in, StageCollection(
typename std::enable_if_t<std::conjunction_v< PipelineConverter<P>& conv, FactoryCtx& ctx, const I& in,
std::is_base_of<TessellationShader, I>, typename std::enable_if_t<std::conjunction_v<std::is_base_of<TessellationShader, I>,
std::negation<std::is_same<P, PlatformType::Metal>>>>* = 0) std::negation<std::is_same<P, PlatformType::Metal>>>>* = 0) {
{
m_vertex = conv.getVertexConverter().convert(ctx, in); m_vertex = conv.getVertexConverter().convert(ctx, in);
m_fragment = conv.getFragmentConverter().convert(ctx, in); m_fragment = conv.getFragmentConverter().convert(ctx, in);
if (in.HasTessellation) if (in.HasTessellation) {
{
m_control = conv.getControlConverter().convert(ctx, in); m_control = conv.getControlConverter().convert(ctx, in);
m_evaluation = conv.getEvaluationConverter().convert(ctx, in); m_evaluation = conv.getEvaluationConverter().convert(ctx, in);
} }
@ -177,19 +163,14 @@ public:
m_additionalInfo = in.PipelineInfo; m_additionalInfo = in.PipelineInfo;
MakeHash(); MakeHash();
} }
template<typename I> template <typename I>
StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const I& in, StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const I& in,
typename std::enable_if_t<std::conjunction_v< typename std::enable_if_t<std::conjunction_v<std::is_base_of<TessellationShader, I>,
std::is_base_of<TessellationShader, I>, std::is_same<P, PlatformType::Metal>>>* = 0) {
std::is_same<P, PlatformType::Metal>>>* = 0) if (in.HasTessellation) {
{
if (in.HasTessellation)
{
m_control = conv.getControlConverter().convert(ctx, in); m_control = conv.getControlConverter().convert(ctx, in);
m_evaluation = conv.getEvaluationConverter().convert(ctx, in); m_evaluation = conv.getEvaluationConverter().convert(ctx, in);
} } else {
else
{
m_vertex = conv.getVertexConverter().convert(ctx, in); m_vertex = conv.getVertexConverter().convert(ctx, in);
} }
m_fragment = conv.getFragmentConverter().convert(ctx, in); m_fragment = conv.getFragmentConverter().convert(ctx, in);
@ -197,39 +178,40 @@ public:
m_additionalInfo = in.PipelineInfo; m_additionalInfo = in.PipelineInfo;
MakeHash(); MakeHash();
} }
StageCollection(const T<P, PipelineStage::Vertex>& vertex, StageCollection(const T<P, PipelineStage::Vertex>& vertex, const T<P, PipelineStage::Fragment>& fragment,
const T<P, PipelineStage::Fragment>& fragment, const T<P, PipelineStage::Geometry>& geometry, const T<P, PipelineStage::Control>& control,
const T<P, PipelineStage::Geometry>& geometry, const T<P, PipelineStage::Evaluation>& evaluation, const AdditionalPipelineInfo& info,
const T<P, PipelineStage::Control>& control,
const T<P, PipelineStage::Evaluation>& evaluation,
const AdditionalPipelineInfo& info,
const boo::VertexFormatInfo& vtxFmt) const boo::VertexFormatInfo& vtxFmt)
: m_vertex(vertex), m_fragment(fragment), m_geometry(geometry), : m_vertex(vertex)
m_control(control), m_evaluation(evaluation), m_additionalInfo(info), , m_fragment(fragment)
m_vtxFmt(vtxFmt) {} , m_geometry(geometry)
, m_control(control)
, m_evaluation(evaluation)
, m_additionalInfo(info)
, m_vtxFmt(vtxFmt) {}
}; };
} } // namespace hecl
#ifndef _WIN32 #ifndef _WIN32
#define _STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, P) \ #define _STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, P) \
template <> const hecl::StageBinary<P, hecl::PipelineStage::Vertex> \ template <> \
T<P, hecl::PipelineStage::Vertex>::Prototype; \ const hecl::StageBinary<P, hecl::PipelineStage::Vertex> T<P, hecl::PipelineStage::Vertex>::Prototype; \
template <> const hecl::StageBinary<P, hecl::PipelineStage::Fragment> \ template <> \
T<P, hecl::PipelineStage::Fragment>::Prototype; \ const hecl::StageBinary<P, hecl::PipelineStage::Fragment> T<P, hecl::PipelineStage::Fragment>::Prototype; \
template <> const hecl::StageBinary<P, hecl::PipelineStage::Geometry> \ template <> \
T<P, hecl::PipelineStage::Geometry>::Prototype; \ const hecl::StageBinary<P, hecl::PipelineStage::Geometry> T<P, hecl::PipelineStage::Geometry>::Prototype; \
template <> const hecl::StageBinary<P, hecl::PipelineStage::Control> \ template <> \
T<P, hecl::PipelineStage::Control>::Prototype; \ const hecl::StageBinary<P, hecl::PipelineStage::Control> T<P, hecl::PipelineStage::Control>::Prototype; \
template <> const hecl::StageBinary<P, hecl::PipelineStage::Evaluation> \ template <> \
T<P, hecl::PipelineStage::Evaluation>::Prototype; const hecl::StageBinary<P, hecl::PipelineStage::Evaluation> T<P, hecl::PipelineStage::Evaluation>::Prototype;
#else #else
#define _STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, P) #define _STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, P)
#endif #endif
#define STAGEOBJECT_PROTOTYPE_DECLARATIONS(T) \ #define STAGEOBJECT_PROTOTYPE_DECLARATIONS(T) \
_STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::OpenGL) \ _STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::OpenGL) \
_STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::Vulkan) \ _STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::Vulkan) \
_STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::D3D11) \ _STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::D3D11) \
_STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::Metal) \ _STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::Metal) \
_STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::NX) _STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::NX)

View File

@ -4,54 +4,49 @@
#include "boo/graphicsdev/IGraphicsDataFactory.hpp" #include "boo/graphicsdev/IGraphicsDataFactory.hpp"
#include <unordered_map> #include <unordered_map>
namespace hecl namespace hecl {
{
struct HMDLMeta; struct HMDLMeta;
namespace Runtime namespace Runtime {
{
/** /**
* @brief Per-platform file store resolution * @brief Per-platform file store resolution
*/ */
class FileStoreManager class FileStoreManager {
{
SystemString m_domain; SystemString m_domain;
SystemString m_storeRoot; SystemString m_storeRoot;
public: public:
FileStoreManager(SystemStringView domain); FileStoreManager(SystemStringView domain);
SystemStringView getDomain() const {return m_domain;} SystemStringView getDomain() const { return m_domain; }
/** /**
* @brief Returns the full path to the file store, including domain * @brief Returns the full path to the file store, including domain
* @return Full path to store e.g /home/foo/.hecl/bar * @return Full path to store e.g /home/foo/.hecl/bar
*/ */
SystemStringView getStoreRoot() const {return m_storeRoot;} SystemStringView getStoreRoot() const { return m_storeRoot; }
}; };
/** /**
* @brief Integrated reader/constructor/container for HMDL data * @brief Integrated reader/constructor/container for HMDL data
*/ */
struct HMDLData struct HMDLData {
{
boo::ObjToken<boo::IGraphicsBufferS> m_vbo; boo::ObjToken<boo::IGraphicsBufferS> m_vbo;
boo::ObjToken<boo::IGraphicsBufferS> m_ibo; boo::ObjToken<boo::IGraphicsBufferS> m_ibo;
std::unique_ptr<boo::VertexElementDescriptor[]> m_vtxFmtData; std::unique_ptr<boo::VertexElementDescriptor[]> m_vtxFmtData;
boo::VertexFormatInfo m_vtxFmt; boo::VertexFormatInfo m_vtxFmt;
HMDLData(boo::IGraphicsDataFactory::Context& ctx, HMDLData(boo::IGraphicsDataFactory::Context& ctx, const void* metaData, const void* vbo, const void* ibo);
const void* metaData, const void* vbo, const void* ibo);
boo::ObjToken<boo::IShaderDataBinding> boo::ObjToken<boo::IShaderDataBinding> newShaderDataBindng(boo::IGraphicsDataFactory::Context& ctx,
newShaderDataBindng(boo::IGraphicsDataFactory::Context& ctx,
const boo::ObjToken<boo::IShaderPipeline>& shader, const boo::ObjToken<boo::IShaderPipeline>& shader,
size_t ubufCount, const boo::ObjToken<boo::IGraphicsBuffer>* ubufs, size_t ubufCount,
const boo::PipelineStage* ubufStages, const boo::ObjToken<boo::IGraphicsBuffer>* ubufs,
size_t texCount, const boo::ObjToken<boo::ITexture>* texs) const boo::PipelineStage* ubufStages, size_t texCount,
{return ctx.newShaderDataBinding(shader, m_vbo.get(), nullptr, m_ibo.get(), const boo::ObjToken<boo::ITexture>* texs) {
ubufCount, ubufs, ubufStages, nullptr, nullptr, return ctx.newShaderDataBinding(shader, m_vbo.get(), nullptr, m_ibo.get(), ubufCount, ubufs, ubufStages, nullptr,
texCount, texs, nullptr, nullptr);} nullptr, texCount, texs, nullptr, nullptr);
}
}; };
} } // namespace Runtime
} } // namespace hecl

View File

@ -2,11 +2,8 @@
#include "hecl/SystemChar.hpp" #include "hecl/SystemChar.hpp"
namespace hecl namespace hecl {
{
hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name); hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name);
} }

View File

@ -18,8 +18,7 @@
#include <cstring> #include <cstring>
#include <algorithm> #include <algorithm>
namespace hecl namespace hecl {
{
#if _WIN32 && UNICODE #if _WIN32 && UNICODE
#define HECL_UCS2 1 #define HECL_UCS2 1
@ -27,15 +26,13 @@ namespace hecl
#if HECL_UCS2 #if HECL_UCS2
typedef wchar_t SystemChar; typedef wchar_t SystemChar;
static inline size_t StrLen(const SystemChar* str) {return wcslen(str);} static inline size_t StrLen(const SystemChar* str) { return wcslen(str); }
typedef std::wstring SystemString; typedef std::wstring SystemString;
typedef std::wstring_view SystemStringView; typedef std::wstring_view SystemStringView;
static inline void ToLower(SystemString& str) static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towlower); }
{std::transform(str.begin(), str.end(), str.begin(), towlower);} static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towupper); }
static inline void ToUpper(SystemString& str)
{std::transform(str.begin(), str.end(), str.begin(), towupper);}
#ifndef _SYS_STR #ifndef _SYS_STR
#define _SYS_STR(val) L ## val #define _SYS_STR(val) L##val
#endif #endif
#ifndef FMT_CSTR_SYS #ifndef FMT_CSTR_SYS
#define FMT_CSTR_SYS "S" #define FMT_CSTR_SYS "S"
@ -43,13 +40,11 @@ static inline void ToUpper(SystemString& str)
typedef struct _stat Sstat; typedef struct _stat Sstat;
#else #else
typedef char SystemChar; typedef char SystemChar;
static inline size_t StrLen(const SystemChar* str) {return strlen(str);} static inline size_t StrLen(const SystemChar* str) { return strlen(str); }
typedef std::string SystemString; typedef std::string SystemString;
typedef std::string_view SystemStringView; typedef std::string_view SystemStringView;
static inline void ToLower(SystemString& str) static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), tolower); }
{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 ToUpper(SystemString& str)
{std::transform(str.begin(), str.end(), str.begin(), toupper);}
#ifndef _SYS_STR #ifndef _SYS_STR
#define _SYS_STR(val) val #define _SYS_STR(val) val
#endif #endif
@ -59,5 +54,4 @@ static inline void ToUpper(SystemString& str)
typedef struct stat Sstat; typedef struct stat Sstat;
#endif #endif
} } // namespace hecl

View File

@ -6,8 +6,7 @@
#include <atomic> #include <atomic>
#include "BitVector.hpp" #include "BitVector.hpp"
namespace hecl namespace hecl {
{
#define HECL_UBUFPOOL_ALLOCATION_BLOCK 262144 #define HECL_UBUFPOOL_ALLOCATION_BLOCK 262144
@ -18,8 +17,7 @@ namespace hecl
* widgets. These can potentially have numerous binding instances, so this avoids * widgets. These can potentially have numerous binding instances, so this avoids
* allocating a full GPU buffer object for each. */ * allocating a full GPU buffer object for each. */
template <typename UniformStruct> template <typename UniformStruct>
class UniformBufferPool class UniformBufferPool {
{
public: public:
/* Resolve div_t type using ssize_t as basis */ /* Resolve div_t type using ssize_t as basis */
#if _WIN32 #if _WIN32
@ -29,7 +27,8 @@ public:
#endif #endif
private: private:
struct InvalidTp {}; struct InvalidTp {};
using DivTp = std::conditional_t<std::is_same<IndexTp, long long>::value, std::lldiv_t, using DivTp = std::conditional_t<
std::is_same<IndexTp, long long>::value, std::lldiv_t,
std::conditional_t<std::is_same<IndexTp, long>::value, std::ldiv_t, std::conditional_t<std::is_same<IndexTp, long>::value, std::ldiv_t,
std::conditional_t<std::is_same<IndexTp, int>::value, std::div_t, InvalidTp>>>; std::conditional_t<std::is_same<IndexTp, int>::value, std::div_t, InvalidTp>>>;
static_assert(!std::is_same<DivTp, InvalidTp>::value, "unsupported IndexTp for DivTp resolution"); static_assert(!std::is_same<DivTp, InvalidTp>::value, "unsupported IndexTp for DivTp resolution");
@ -54,8 +53,7 @@ private:
boo::IGraphicsDataFactory* m_factory = nullptr; boo::IGraphicsDataFactory* m_factory = nullptr;
/** Private bucket info */ /** Private bucket info */
struct Bucket struct Bucket {
{
boo::ObjToken<boo::IGraphicsBufferD> buffer; boo::ObjToken<boo::IGraphicsBufferD> buffer;
uint8_t* cpuBuffer = nullptr; uint8_t* cpuBuffer = nullptr;
std::atomic_size_t useCount = {}; std::atomic_size_t useCount = {};
@ -66,29 +64,22 @@ private:
Bucket(Bucket&& other) = default; Bucket(Bucket&& other) = default;
Bucket& operator=(Bucket&& other) = default; Bucket& operator=(Bucket&& other) = default;
void updateBuffer() void updateBuffer() {
{ if (cpuBuffer) {
if (cpuBuffer)
{
buffer->unmap(); buffer->unmap();
cpuBuffer = nullptr; cpuBuffer = nullptr;
} }
dirty = false; dirty = false;
} }
void increment(UniformBufferPool& pool) void increment(UniformBufferPool& pool) {
{
if (useCount.fetch_add(1) == 0) if (useCount.fetch_add(1) == 0)
buffer = pool.m_factory->newPoolBuffer(boo::BufferUse::Uniform, buffer = pool.m_factory->newPoolBuffer(boo::BufferUse::Uniform, pool.m_stride, pool.m_countPerBucket BooTrace);
pool.m_stride, pool.m_countPerBucket BooTrace);
} }
void decrement(UniformBufferPool& pool) void decrement(UniformBufferPool& pool) {
{ if (useCount.fetch_sub(1) == 1) {
if (useCount.fetch_sub(1) == 1) if (cpuBuffer) {
{
if (cpuBuffer)
{
buffer->unmap(); buffer->unmap();
cpuBuffer = nullptr; cpuBuffer = nullptr;
} }
@ -100,25 +91,19 @@ private:
public: public:
/** User block-owning token */ /** User block-owning token */
class Token class Token {
{
friend class UniformBufferPool; friend class UniformBufferPool;
UniformBufferPool* m_pool = nullptr; UniformBufferPool* m_pool = nullptr;
IndexTp m_index = -1; IndexTp m_index = -1;
DivTp m_div; DivTp m_div;
Token(UniformBufferPool* pool) Token(UniformBufferPool* pool) : m_pool(pool) {
: m_pool(pool)
{
auto& freeSpaces = pool->m_freeBlocks; auto& freeSpaces = pool->m_freeBlocks;
int idx = freeSpaces.find_first(); int idx = freeSpaces.find_first();
if (idx == -1) if (idx == -1) {
{
pool->m_buckets.push_back(std::make_unique<Bucket>()); pool->m_buckets.push_back(std::make_unique<Bucket>());
m_index = freeSpaces.size(); m_index = freeSpaces.size();
freeSpaces.resize(freeSpaces.size() + pool->m_countPerBucket, true); freeSpaces.resize(freeSpaces.size() + pool->m_countPerBucket, true);
} } else {
else
{
m_index = idx; m_index = idx;
} }
freeSpaces.reset(m_index); freeSpaces.reset(m_index);
@ -132,33 +117,24 @@ public:
Token() = default; Token() = default;
Token(const Token& other) = delete; Token(const Token& other) = delete;
Token& operator=(const Token& other) = delete; Token& operator=(const Token& other) = delete;
Token& operator=(Token&& other) Token& operator=(Token&& other) {
{
m_pool = other.m_pool; m_pool = other.m_pool;
m_index = other.m_index; m_index = other.m_index;
m_div = other.m_div; m_div = other.m_div;
other.m_index = -1; other.m_index = -1;
return *this; return *this;
} }
Token(Token&& other) Token(Token&& other) : m_pool(other.m_pool), m_index(other.m_index), m_div(other.m_div) { other.m_index = -1; }
: m_pool(other.m_pool), m_index(other.m_index),
m_div(other.m_div)
{
other.m_index = -1;
}
~Token() ~Token() {
{ if (m_index != -1) {
if (m_index != -1)
{
m_pool->m_freeBlocks.set(m_index); m_pool->m_freeBlocks.set(m_index);
Bucket& bucket = *m_pool->m_buckets[m_div.quot]; Bucket& bucket = *m_pool->m_buckets[m_div.quot];
bucket.decrement(*m_pool); bucket.decrement(*m_pool);
} }
} }
UniformStruct& access() UniformStruct& access() {
{
Bucket& bucket = *m_pool->m_buckets[m_div.quot]; Bucket& bucket = *m_pool->m_buckets[m_div.quot];
if (!bucket.cpuBuffer) if (!bucket.cpuBuffer)
bucket.cpuBuffer = reinterpret_cast<uint8_t*>(bucket.buffer->map(m_sizePerBucket)); bucket.cpuBuffer = reinterpret_cast<uint8_t*>(bucket.buffer->map(m_sizePerBucket));
@ -166,8 +142,7 @@ public:
return reinterpret_cast<UniformStruct&>(bucket.cpuBuffer[m_div.rem * m_pool->m_stride]); return reinterpret_cast<UniformStruct&>(bucket.cpuBuffer[m_div.rem * m_pool->m_stride]);
} }
std::pair<boo::ObjToken<boo::IGraphicsBufferD>, IndexTp> getBufferInfo() const std::pair<boo::ObjToken<boo::IGraphicsBufferD>, IndexTp> getBufferInfo() const {
{
Bucket& bucket = *m_pool->m_buckets[m_div.quot]; Bucket& bucket = *m_pool->m_buckets[m_div.quot];
return {bucket.buffer, m_div.rem * m_pool->m_stride}; return {bucket.buffer, m_div.rem * m_pool->m_stride};
} }
@ -180,26 +155,22 @@ public:
UniformBufferPool& operator=(const UniformBufferPool& other) = delete; UniformBufferPool& operator=(const UniformBufferPool& other) = delete;
/** Load dirty buffer data into GPU */ /** Load dirty buffer data into GPU */
void updateBuffers() void updateBuffers() {
{
for (auto& bucket : m_buckets) for (auto& bucket : m_buckets)
if (bucket->dirty) if (bucket->dirty)
bucket->updateBuffer(); bucket->updateBuffer();
} }
/** Allocate free block into client-owned Token */ /** Allocate free block into client-owned Token */
Token allocateBlock(boo::IGraphicsDataFactory* factory) Token allocateBlock(boo::IGraphicsDataFactory* factory) {
{
m_factory = factory; m_factory = factory;
return Token(this); return Token(this);
} }
void doDestroy() void doDestroy() {
{
for (auto& bucket : m_buckets) for (auto& bucket : m_buckets)
bucket->buffer.reset(); bucket->buffer.reset();
} }
}; };
} } // namespace hecl

View File

@ -6,8 +6,7 @@
#include <atomic> #include <atomic>
#include "BitVector.hpp" #include "BitVector.hpp"
namespace hecl namespace hecl {
{
#define HECL_VBUFPOOL_ALLOCATION_BLOCK 262144 #define HECL_VBUFPOOL_ALLOCATION_BLOCK 262144
@ -18,8 +17,7 @@ namespace hecl
* widgets. These can potentially have numerous binding instances, so this avoids * widgets. These can potentially have numerous binding instances, so this avoids
* allocating a full GPU buffer object for each. */ * allocating a full GPU buffer object for each. */
template <typename VertStruct> template <typename VertStruct>
class VertexBufferPool class VertexBufferPool {
{
public: public:
/* Resolve div_t type using ssize_t as basis */ /* Resolve div_t type using ssize_t as basis */
#if _WIN32 #if _WIN32
@ -29,7 +27,8 @@ public:
#endif #endif
private: private:
struct InvalidTp {}; struct InvalidTp {};
using DivTp = std::conditional_t<std::is_same<IndexTp, long long>::value, std::lldiv_t, using DivTp = std::conditional_t<
std::is_same<IndexTp, long long>::value, std::lldiv_t,
std::conditional_t<std::is_same<IndexTp, long>::value, std::ldiv_t, std::conditional_t<std::is_same<IndexTp, long>::value, std::ldiv_t,
std::conditional_t<std::is_same<IndexTp, int>::value, std::div_t, InvalidTp>>>; std::conditional_t<std::is_same<IndexTp, int>::value, std::div_t, InvalidTp>>>;
static_assert(!std::is_same<DivTp, InvalidTp>::value, "unsupported IndexTp for DivTp resolution"); static_assert(!std::is_same<DivTp, InvalidTp>::value, "unsupported IndexTp for DivTp resolution");
@ -54,8 +53,7 @@ private:
boo::IGraphicsDataFactory* m_factory = nullptr; boo::IGraphicsDataFactory* m_factory = nullptr;
/** Private bucket info */ /** Private bucket info */
struct Bucket struct Bucket {
{
boo::ObjToken<boo::IGraphicsBufferD> buffer; boo::ObjToken<boo::IGraphicsBufferD> buffer;
uint8_t* cpuBuffer = nullptr; uint8_t* cpuBuffer = nullptr;
std::atomic_size_t useCount = {}; std::atomic_size_t useCount = {};
@ -66,29 +64,22 @@ private:
Bucket(Bucket&& other) = delete; Bucket(Bucket&& other) = delete;
Bucket& operator=(Bucket&& other) = delete; Bucket& operator=(Bucket&& other) = delete;
void updateBuffer() void updateBuffer() {
{ if (cpuBuffer) {
if (cpuBuffer)
{
buffer->unmap(); buffer->unmap();
cpuBuffer = nullptr; cpuBuffer = nullptr;
} }
dirty = false; dirty = false;
} }
void increment(VertexBufferPool& pool) void increment(VertexBufferPool& pool) {
{
if (useCount.fetch_add(1) == 0) if (useCount.fetch_add(1) == 0)
buffer = pool.m_factory->newPoolBuffer(boo::BufferUse::Vertex, buffer = pool.m_factory->newPoolBuffer(boo::BufferUse::Vertex, pool.m_stride, pool.m_countPerBucket BooTrace);
pool.m_stride, pool.m_countPerBucket BooTrace);
} }
void decrement(VertexBufferPool& pool) void decrement(VertexBufferPool& pool) {
{ if (useCount.fetch_sub(1) == 1) {
if (useCount.fetch_sub(1) == 1) if (cpuBuffer) {
{
if (cpuBuffer)
{
buffer->unmap(); buffer->unmap();
cpuBuffer = nullptr; cpuBuffer = nullptr;
} }
@ -100,27 +91,21 @@ private:
public: public:
/** User element-owning token */ /** User element-owning token */
class Token class Token {
{
friend class VertexBufferPool; friend class VertexBufferPool;
VertexBufferPool* m_pool = nullptr; VertexBufferPool* m_pool = nullptr;
IndexTp m_index = -1; IndexTp m_index = -1;
IndexTp m_count = 0; IndexTp m_count = 0;
DivTp m_div; DivTp m_div;
Token(VertexBufferPool* pool, IndexTp count) Token(VertexBufferPool* pool, IndexTp count) : m_pool(pool), m_count(count) {
: m_pool(pool), m_count(count)
{
assert(count <= pool->m_countPerBucket && "unable to fit in bucket"); assert(count <= pool->m_countPerBucket && "unable to fit in bucket");
auto& freeSpaces = pool->m_freeElements; auto& freeSpaces = pool->m_freeElements;
int idx = freeSpaces.find_first_contiguous(count, pool->m_countPerBucket); int idx = freeSpaces.find_first_contiguous(count, pool->m_countPerBucket);
if (idx == -1) if (idx == -1) {
{
pool->m_buckets.push_back(std::make_unique<Bucket>()); pool->m_buckets.push_back(std::make_unique<Bucket>());
m_index = freeSpaces.size(); m_index = freeSpaces.size();
freeSpaces.resize(freeSpaces.size() + pool->m_countPerBucket, true); freeSpaces.resize(freeSpaces.size() + pool->m_countPerBucket, true);
} } else {
else
{
m_index = idx; m_index = idx;
} }
freeSpaces.reset(m_index, m_index + count); freeSpaces.reset(m_index, m_index + count);
@ -129,12 +114,12 @@ public:
Bucket& bucket = *m_pool->m_buckets[m_div.quot]; Bucket& bucket = *m_pool->m_buckets[m_div.quot];
bucket.increment(*pool); bucket.increment(*pool);
} }
public: public:
Token() = default; Token() = default;
Token(const Token& other) = delete; Token(const Token& other) = delete;
Token& operator=(const Token& other) = delete; Token& operator=(const Token& other) = delete;
Token& operator=(Token&& other) Token& operator=(Token&& other) {
{
m_pool = other.m_pool; m_pool = other.m_pool;
m_index = other.m_index; m_index = other.m_index;
m_count = other.m_count; m_count = other.m_count;
@ -142,25 +127,19 @@ public:
other.m_index = -1; other.m_index = -1;
return *this; return *this;
} }
Token(Token&& other) Token(Token&& other) : m_pool(other.m_pool), m_index(other.m_index), m_count(other.m_count), m_div(other.m_div) {
: m_pool(other.m_pool), m_index(other.m_index),
m_count(other.m_count), m_div(other.m_div)
{
other.m_index = -1; other.m_index = -1;
} }
~Token() ~Token() {
{ if (m_index != -1) {
if (m_index != -1)
{
m_pool->m_freeElements.set(m_index, m_index + m_count); m_pool->m_freeElements.set(m_index, m_index + m_count);
Bucket& bucket = *m_pool->m_buckets[m_div.quot]; Bucket& bucket = *m_pool->m_buckets[m_div.quot];
bucket.decrement(*m_pool); bucket.decrement(*m_pool);
} }
} }
VertStruct* access() VertStruct* access() {
{
Bucket& bucket = *m_pool->m_buckets[m_div.quot]; Bucket& bucket = *m_pool->m_buckets[m_div.quot];
if (!bucket.cpuBuffer) if (!bucket.cpuBuffer)
bucket.cpuBuffer = reinterpret_cast<uint8_t*>(bucket.buffer->map(m_sizePerBucket)); bucket.cpuBuffer = reinterpret_cast<uint8_t*>(bucket.buffer->map(m_sizePerBucket));
@ -168,8 +147,7 @@ public:
return reinterpret_cast<VertStruct*>(&bucket.cpuBuffer[m_div.rem * m_pool->m_stride]); return reinterpret_cast<VertStruct*>(&bucket.cpuBuffer[m_div.rem * m_pool->m_stride]);
} }
std::pair<boo::ObjToken<boo::IGraphicsBufferD>, IndexTp> getBufferInfo() const std::pair<boo::ObjToken<boo::IGraphicsBufferD>, IndexTp> getBufferInfo() const {
{
Bucket& bucket = *m_pool->m_buckets[m_div.quot]; Bucket& bucket = *m_pool->m_buckets[m_div.quot];
return {bucket.buffer, m_div.rem}; return {bucket.buffer, m_div.rem};
} }
@ -182,22 +160,19 @@ public:
VertexBufferPool& operator=(const VertexBufferPool& other) = delete; VertexBufferPool& operator=(const VertexBufferPool& other) = delete;
/** Load dirty buffer data into GPU */ /** Load dirty buffer data into GPU */
void updateBuffers() void updateBuffers() {
{
for (auto& bucket : m_buckets) for (auto& bucket : m_buckets)
if (bucket->dirty) if (bucket->dirty)
bucket->updateBuffer(); bucket->updateBuffer();
} }
/** Allocate free block into client-owned Token */ /** Allocate free block into client-owned Token */
Token allocateBlock(boo::IGraphicsDataFactory* factory, IndexTp count) Token allocateBlock(boo::IGraphicsDataFactory* factory, IndexTp count) {
{
m_factory = factory; m_factory = factory;
return Token(this, count); return Token(this, count);
} }
void doDestroy() void doDestroy() {
{
for (auto& bucket : m_buckets) for (auto& bucket : m_buckets)
bucket->buffer.reset(); bucket->buffer.reset();
} }
@ -205,5 +180,4 @@ public:
static constexpr IndexTp bucketCapacity() { return m_countPerBucket; } static constexpr IndexTp bucketCapacity() { return m_countPerBucket; }
}; };
} } // namespace hecl

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,5 @@
#endif #endif
#include "windows.h" #include "windows.h"
void* memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen); void* memmem(const void* haystack, size_t hlen, const void* needle, size_t nlen);
int asprintf(char** buf, const char* format, ...); int asprintf(char** buf, const char* format, ...);

View File

@ -6,68 +6,60 @@
static logvisor::Module Log("hecl::Backend::GLSL"); static logvisor::Module Log("hecl::Backend::GLSL");
namespace hecl::Backend namespace hecl::Backend {
{
std::string GLSL::EmitTexGenSource2(TexGenSrc src, int uvIdx) const std::string GLSL::EmitTexGenSource2(TexGenSrc src, int uvIdx) const {
{ switch (src) {
switch (src)
{
case TexGenSrc::Position: case TexGenSrc::Position:
return "objPos.xy"; return "objPos.xy";
case TexGenSrc::Normal: case TexGenSrc::Normal:
return "objNorm.xy"; return "objNorm.xy";
case TexGenSrc::UV: case TexGenSrc::UV:
return hecl::Format("uvIn[%u]", uvIdx); return hecl::Format("uvIn[%u]", uvIdx);
default: break; default:
break;
} }
return std::string(); return std::string();
} }
std::string GLSL::EmitTexGenSource4(TexGenSrc src, int uvIdx) const std::string GLSL::EmitTexGenSource4(TexGenSrc src, int uvIdx) const {
{ switch (src) {
switch (src)
{
case TexGenSrc::Position: case TexGenSrc::Position:
return "vec4(objPos.xyz, 1.0)"; return "vec4(objPos.xyz, 1.0)";
case TexGenSrc::Normal: case TexGenSrc::Normal:
return "vec4(objNorm.xyz, 1.0)"; return "vec4(objNorm.xyz, 1.0)";
case TexGenSrc::UV: case TexGenSrc::UV:
return hecl::Format("vec4(uvIn[%u], 0.0, 1.0)", uvIdx); return hecl::Format("vec4(uvIn[%u], 0.0, 1.0)", uvIdx);
default: break; default:
break;
} }
return std::string(); return std::string();
} }
std::string GLSL::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const std::string GLSL::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const {
{
std::string retval = std::string retval =
"layout(location=0) in vec3 posIn;\n" "layout(location=0) in vec3 posIn;\n"
"layout(location=1) in vec3 normIn;\n"; "layout(location=1) in vec3 normIn;\n";
unsigned idx = 2; unsigned idx = 2;
if (col) if (col) {
{
retval += hecl::Format("layout(location=%u) in vec4 colIn[%u];\n", idx, col); retval += hecl::Format("layout(location=%u) in vec4 colIn[%u];\n", idx, col);
idx += col; idx += col;
} }
if (uv) if (uv) {
{
retval += hecl::Format("layout(location=%u) in vec2 uvIn[%u];\n", idx, uv); retval += hecl::Format("layout(location=%u) in vec2 uvIn[%u];\n", idx, uv);
idx += uv; idx += uv;
} }
if (w) if (w) {
{
retval += hecl::Format("layout(location=%u) in vec4 weightIn[%u];\n", idx, w); retval += hecl::Format("layout(location=%u) in vec4 weightIn[%u];\n", idx, w);
} }
return retval; return retval;
} }
std::string GLSL::GenerateVertToFragStruct(size_t extTexCount, bool reflectionCoords) const std::string GLSL::GenerateVertToFragStruct(size_t extTexCount, bool reflectionCoords) const {
{
std::string retval = std::string retval =
"struct VertToFrag\n" "struct VertToFrag\n"
"{\n" "{\n"
@ -80,27 +72,26 @@ std::string GLSL::GenerateVertToFragStruct(size_t extTexCount, bool reflectionCo
retval += hecl::Format(" vec2 extTcgs[%u];\n", unsigned(extTexCount)); retval += hecl::Format(" vec2 extTcgs[%u];\n", unsigned(extTexCount));
if (reflectionCoords) if (reflectionCoords)
retval += " vec2 reflectTcgs[2];\n" retval +=
" vec2 reflectTcgs[2];\n"
" float reflectAlpha;\n"; " float reflectAlpha;\n";
return retval + "};\n"; return retval + "};\n";
} }
std::string GLSL::GenerateVertUniformStruct(unsigned skinSlots, bool reflectionCoords) const std::string GLSL::GenerateVertUniformStruct(unsigned skinSlots, bool reflectionCoords) const {
{
std::string retval; std::string retval;
if (skinSlots == 0) if (skinSlots == 0) {
{ retval =
retval = "UBINDING0 uniform HECLVertUniform\n" "UBINDING0 uniform HECLVertUniform\n"
"{\n" "{\n"
" mat4 mv;\n" " mat4 mv;\n"
" mat4 mvInv;\n" " mat4 mvInv;\n"
" mat4 proj;\n" " mat4 proj;\n"
"};\n"; "};\n";
} } else {
else retval = hecl::Format(
{ "UBINDING0 uniform HECLVertUniform\n"
retval = hecl::Format("UBINDING0 uniform HECLVertUniform\n"
"{\n" "{\n"
" mat4 objs[%u];\n" " mat4 objs[%u];\n"
" mat4 objsInv[%u];\n" " mat4 objsInv[%u];\n"
@ -111,7 +102,8 @@ std::string GLSL::GenerateVertUniformStruct(unsigned skinSlots, bool reflectionC
skinSlots, skinSlots); skinSlots, skinSlots);
} }
retval += "struct HECLTCGMatrix\n" retval +=
"struct HECLTCGMatrix\n"
"{\n" "{\n"
" mat4 mtx;\n" " mat4 mtx;\n"
" mat4 postMtx;\n" " mat4 postMtx;\n"
@ -122,7 +114,8 @@ std::string GLSL::GenerateVertUniformStruct(unsigned skinSlots, bool reflectionC
"};\n"; "};\n";
if (reflectionCoords) if (reflectionCoords)
retval += "UBINDING3 uniform HECLReflectMtx\n" retval +=
"UBINDING3 uniform HECLReflectMtx\n"
"{\n" "{\n"
" mat4 indMtx;\n" " mat4 indMtx;\n"
" mat4 reflectMtx;\n" " mat4 reflectMtx;\n"
@ -133,18 +126,15 @@ std::string GLSL::GenerateVertUniformStruct(unsigned skinSlots, bool reflectionC
return retval; return retval;
} }
std::string GLSL::GenerateAlphaTest() const std::string GLSL::GenerateAlphaTest() const {
{
return " if (colorOut.a < 0.01)\n" return " if (colorOut.a < 0.01)\n"
" {\n" " {\n"
" discard;\n" " discard;\n"
" }\n"; " }\n";
} }
std::string GLSL::GenerateReflectionExpr(ReflectionType type) const std::string GLSL::GenerateReflectionExpr(ReflectionType type) const {
{ switch (type) {
switch (type)
{
case ReflectionType::None: case ReflectionType::None:
default: default:
return "vec3(0.0, 0.0, 0.0)"; return "vec3(0.0, 0.0, 0.0)";
@ -156,43 +146,41 @@ std::string GLSL::GenerateReflectionExpr(ReflectionType type) const
} }
} }
void GLSL::reset(const IR& ir, Diagnostics& diag) void GLSL::reset(const IR& ir, Diagnostics& diag) {
{
/* Common programmable interpretation */ /* Common programmable interpretation */
ProgrammableCommon::reset(ir, diag, "GLSL"); ProgrammableCommon::reset(ir, diag, "GLSL");
} }
std::string GLSL::makeVert(unsigned col, unsigned uv, unsigned w, std::string GLSL::makeVert(unsigned col, unsigned uv, unsigned w, unsigned s, size_t extTexCount,
unsigned s, size_t extTexCount, const TextureInfo* extTexs, ReflectionType reflectionType) const {
const TextureInfo* extTexs, ReflectionType reflectionType) const
{
extTexCount = std::min(int(extTexCount), BOO_GLSL_MAX_TEXTURE_COUNT - int(m_tcgs.size())); extTexCount = std::min(int(extTexCount), BOO_GLSL_MAX_TEXTURE_COUNT - int(m_tcgs.size()));
std::string retval = std::string retval = GenerateVertInStruct(col, uv, w) + "\n" +
GenerateVertInStruct(col, uv, w) + "\n" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" + GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" +
GenerateVertUniformStruct(s, reflectionType != ReflectionType::None) + GenerateVertUniformStruct(s, reflectionType != ReflectionType::None) +
"SBINDING(0) out VertToFrag vtf;\n\n" "SBINDING(0) out VertToFrag vtf;\n\n"
"void main()\n{\n"; "void main()\n{\n";
if (s) if (s) {
{
/* skinned */ /* skinned */
retval += " vec4 objPos = vec4(0.0,0.0,0.0,0.0);\n" retval +=
" vec4 objPos = vec4(0.0,0.0,0.0,0.0);\n"
" vec4 objNorm = vec4(0.0,0.0,0.0,0.0);\n"; " vec4 objNorm = vec4(0.0,0.0,0.0,0.0);\n";
for (size_t i=0 ; i<s ; ++i) for (size_t i = 0; i < s; ++i)
retval += hecl::Format(" objPos += (objs[%" PRISize "] * vec4(posIn, 1.0)) * weightIn[%" PRISize "][%" PRISize "];\n" retval += hecl::Format(" objPos += (objs[%" PRISize "] * vec4(posIn, 1.0)) * weightIn[%" PRISize "][%" PRISize
" objNorm += (objsInv[%" PRISize "] * vec4(normIn, 1.0)) * weightIn[%" PRISize "][%" PRISize "];\n", "];\n"
i, i/4, i%4, i, i/4, i%4); " objNorm += (objsInv[%" PRISize "] * vec4(normIn, 1.0)) * weightIn[%" PRISize
retval += " objPos[3] = 1.0;\n" "][%" PRISize "];\n",
i, i / 4, i % 4, i, i / 4, i % 4);
retval +=
" objPos[3] = 1.0;\n"
" objNorm = vec4(normalize(objNorm.xyz), 0.0);\n" " objNorm = vec4(normalize(objNorm.xyz), 0.0);\n"
" vtf.mvPos = mv * objPos;\n" " vtf.mvPos = mv * objPos;\n"
" vtf.mvNorm = vec4(normalize((mvInv * objNorm).xyz), 0.0);\n" " vtf.mvNorm = vec4(normalize((mvInv * objNorm).xyz), 0.0);\n"
" gl_Position = proj * vtf.mvPos;\n"; " gl_Position = proj * vtf.mvPos;\n";
} } else {
else
{
/* non-skinned */ /* non-skinned */
retval += " vec4 objPos = vec4(posIn, 1.0);\n" retval +=
" vec4 objPos = vec4(posIn, 1.0);\n"
" vec4 objNorm = vec4(normIn, 0.0);\n" " vec4 objNorm = vec4(normIn, 0.0);\n"
" vtf.mvPos = mv * objPos;\n" " vtf.mvPos = mv * objPos;\n"
" vtf.mvNorm = mvInv * objNorm;\n" " vtf.mvNorm = mvInv * objNorm;\n"
@ -202,94 +190,86 @@ std::string GLSL::makeVert(unsigned col, unsigned uv, unsigned w,
retval += " vec4 tmpProj;\n"; retval += " vec4 tmpProj;\n";
int tcgIdx = 0; int tcgIdx = 0;
for (const TexCoordGen& tcg : m_tcgs) for (const TexCoordGen& tcg : m_tcgs) {
{
if (tcg.m_mtx < 0) if (tcg.m_mtx < 0)
retval += hecl::Format(" vtf.tcgs[%u] = %s;\n", tcgIdx, retval += hecl::Format(" vtf.tcgs[%u] = %s;\n", tcgIdx, EmitTexGenSource2(tcg.m_src, tcg.m_uvIdx).c_str());
EmitTexGenSource2(tcg.m_src, tcg.m_uvIdx).c_str());
else else
retval += hecl::Format(" tmpProj = texMtxs[%u].postMtx * vec4(%s((texMtxs[%u].mtx * %s).xyz), 1.0);\n" retval += hecl::Format(
" tmpProj = texMtxs[%u].postMtx * vec4(%s((texMtxs[%u].mtx * %s).xyz), 1.0);\n"
" vtf.tcgs[%u] = (tmpProj / tmpProj.w).xy;\n", " vtf.tcgs[%u] = (tmpProj / tmpProj.w).xy;\n",
tcg.m_mtx, tcg.m_norm ? "normalize" : "", tcg.m_mtx, tcg.m_norm ? "normalize" : "", tcg.m_mtx, EmitTexGenSource4(tcg.m_src, tcg.m_uvIdx).c_str(),
tcg.m_mtx, EmitTexGenSource4(tcg.m_src, tcg.m_uvIdx).c_str(), tcgIdx); tcgIdx);
++tcgIdx; ++tcgIdx;
} }
for (int i=0 ; i<extTexCount ; ++i) for (int i = 0; i < extTexCount; ++i) {
{
const TextureInfo& extTex = extTexs[i]; const TextureInfo& extTex = extTexs[i];
if (extTex.mtxIdx < 0) if (extTex.mtxIdx < 0)
retval += hecl::Format(" vtf.extTcgs[%u] = %s;\n", i, retval += hecl::Format(" vtf.extTcgs[%u] = %s;\n", i, EmitTexGenSource2(extTex.src, extTex.uvIdx).c_str());
EmitTexGenSource2(extTex.src, extTex.uvIdx).c_str());
else else
retval += hecl::Format(" tmpProj = texMtxs[%u].postMtx * vec4(%s((texMtxs[%u].mtx * %s).xyz), 1.0);\n" retval += hecl::Format(
" tmpProj = texMtxs[%u].postMtx * vec4(%s((texMtxs[%u].mtx * %s).xyz), 1.0);\n"
" vtf.extTcgs[%u] = (tmpProj / tmpProj.w).xy;\n", " vtf.extTcgs[%u] = (tmpProj / tmpProj.w).xy;\n",
extTex.mtxIdx, extTex.normalize ? "normalize" : "", extTex.mtxIdx, extTex.normalize ? "normalize" : "", extTex.mtxIdx,
extTex.mtxIdx, EmitTexGenSource4(extTex.src, extTex.uvIdx).c_str(), i); EmitTexGenSource4(extTex.src, extTex.uvIdx).c_str(), i);
} }
if (reflectionType != ReflectionType::None) if (reflectionType != ReflectionType::None)
retval += " vtf.reflectTcgs[0] = normalize((indMtx * vec4(posIn, 1.0)).xz) * vec2(0.5, 0.5) + vec2(0.5, 0.5);\n" retval +=
" vtf.reflectTcgs[0] = normalize((indMtx * vec4(posIn, 1.0)).xz) * vec2(0.5, 0.5) + vec2(0.5, 0.5);\n"
" vtf.reflectTcgs[1] = (reflectMtx * vec4(posIn, 1.0)).xy;\n" " vtf.reflectTcgs[1] = (reflectMtx * vec4(posIn, 1.0)).xy;\n"
" vtf.reflectAlpha = reflectAlpha;\n"; " vtf.reflectAlpha = reflectAlpha;\n";
return retval + "}\n"; return retval + "}\n";
} }
std::string GLSL::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, std::string GLSL::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
ReflectionType reflectionType, BlendFactor srcFactor, BlendFactor dstFactor, BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting) const {
const Function& lighting) const
{
std::string lightingSrc; std::string lightingSrc;
if (!lighting.m_source.empty()) if (!lighting.m_source.empty())
lightingSrc = lighting.m_source; lightingSrc = lighting.m_source;
else else
lightingSrc = "const vec4 colorReg0 = vec4(1.0);\n" lightingSrc =
"const vec4 colorReg0 = vec4(1.0);\n"
"const vec4 colorReg1 = vec4(1.0);\n" "const vec4 colorReg1 = vec4(1.0);\n"
"const vec4 colorReg2 = vec4(1.0);\n" "const vec4 colorReg2 = vec4(1.0);\n"
"const vec4 mulColor = vec4(1.0);\n" "const vec4 mulColor = vec4(1.0);\n"
"\n"; "\n";
std::string texMapDecl; std::string texMapDecl;
for (unsigned i=0 ; i<m_texMapEnd ; ++i) for (unsigned i = 0; i < m_texMapEnd; ++i)
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D tex%u;\n", i, i); texMapDecl += hecl::Format("TBINDING%u uniform sampler2D tex%u;\n", i, i);
if (reflectionType == ReflectionType::Indirect) if (reflectionType == ReflectionType::Indirect)
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D reflectionIndTex;\n" texMapDecl += hecl::Format(
"TBINDING%u uniform sampler2D reflectionIndTex;\n"
"TBINDING%u uniform sampler2D reflectionTex;\n", "TBINDING%u uniform sampler2D reflectionTex;\n",
m_texMapEnd, m_texMapEnd+1); m_texMapEnd, m_texMapEnd + 1);
else if (reflectionType == ReflectionType::Simple) else if (reflectionType == ReflectionType::Simple)
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D reflectionTex;\n", texMapDecl += hecl::Format("TBINDING%u uniform sampler2D reflectionTex;\n", m_texMapEnd);
m_texMapEnd);
std::string retval = std::string retval = std::string("#extension GL_ARB_shader_image_load_store: enable\n") + "#define BLEND_SRC_" +
std::string("#extension GL_ARB_shader_image_load_store: enable\n") + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" + "#define BLEND_DST_" +
"#define BLEND_SRC_" + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
"#define BLEND_DST_" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
GenerateVertToFragStruct(0, reflectionType != ReflectionType::None) + GenerateVertToFragStruct(0, reflectionType != ReflectionType::None) +
(!alphaTest ? (!alphaTest ? "#ifdef GL_ARB_shader_image_load_store\n"
"#ifdef GL_ARB_shader_image_load_store\n"
"layout(early_fragment_tests) in;\n" "layout(early_fragment_tests) in;\n"
"#endif\n" : "") + "#endif\n"
"layout(location=0) out vec4 colorOut;\n" + : "") +
texMapDecl + "layout(location=0) out vec4 colorOut;\n" + texMapDecl + "SBINDING(0) in VertToFrag vtf;\n\n" +
"SBINDING(0) in VertToFrag vtf;\n\n" + lightingSrc + "\n" + "void main()\n{\n";
lightingSrc + "\n" +
"void main()\n{\n";
if (m_lighting) {
if (m_lighting)
{
if (!lighting.m_entry.empty()) if (!lighting.m_entry.empty())
retval += hecl::Format(" vec4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz));\n", retval +=
lighting.m_entry.data()); hecl::Format(" vec4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz));\n", lighting.m_entry.data());
else else
retval += " vec4 lighting = vec4(1.0,1.0,1.0,1.0);\n"; retval += " vec4 lighting = vec4(1.0,1.0,1.0,1.0);\n";
} }
unsigned sampIdx = 0; unsigned sampIdx = 0;
for (const TexSampling& sampling : m_texSamplings) for (const TexSampling& sampling : m_texSamplings)
retval += hecl::Format(" vec4 sampling%u = texture(tex%u, vtf.tcgs[%u]);\n", retval += hecl::Format(" vec4 sampling%u = texture(tex%u, vtf.tcgs[%u]);\n", sampIdx++, sampling.mapIdx,
sampIdx++, sampling.mapIdx, sampling.tcgIdx); sampling.tcgIdx);
std::string reflectionExpr = GenerateReflectionExpr(reflectionType); std::string reflectionExpr = GenerateReflectionExpr(reflectionType);
@ -301,19 +281,15 @@ std::string GLSL::makeFrag(size_t blockCount, const char** blockNames, bool alph
return retval + (alphaTest ? GenerateAlphaTest() : "") + "}\n"; return retval + (alphaTest ? GenerateAlphaTest() : "") + "}\n";
} }
std::string GLSL::makeFrag(size_t blockCount, const char** blockNames, std::string GLSL::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
bool alphaTest, BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting, const Function& post,
ReflectionType reflectionType, size_t extTexCount, const TextureInfo* extTexs) const {
BlendFactor srcFactor, BlendFactor dstFactor,
const Function& lighting,
const Function& post,
size_t extTexCount, const TextureInfo* extTexs) const
{
std::string lightingSrc; std::string lightingSrc;
if (!lighting.m_source.empty()) if (!lighting.m_source.empty())
lightingSrc = lighting.m_source; lightingSrc = lighting.m_source;
else else
lightingSrc = "const vec4 colorReg0 = vec4(1.0);\n" lightingSrc =
"const vec4 colorReg0 = vec4(1.0);\n"
"const vec4 colorReg1 = vec4(1.0);\n" "const vec4 colorReg1 = vec4(1.0);\n"
"const vec4 colorReg2 = vec4(1.0);\n" "const vec4 colorReg2 = vec4(1.0);\n"
"const vec4 mulColor = vec4(1.0);\n" "const vec4 mulColor = vec4(1.0);\n"
@ -328,67 +304,58 @@ std::string GLSL::makeFrag(size_t blockCount, const char** blockNames,
postEntry = post.m_entry; postEntry = post.m_entry;
std::string texMapDecl; std::string texMapDecl;
for (unsigned i=0 ; i<m_texMapEnd ; ++i) for (unsigned i = 0; i < m_texMapEnd; ++i)
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D tex%u;\n", i, i); texMapDecl += hecl::Format("TBINDING%u uniform sampler2D tex%u;\n", i, i);
if (reflectionType == ReflectionType::Indirect) if (reflectionType == ReflectionType::Indirect)
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D reflectionIndTex;\n" texMapDecl += hecl::Format(
"TBINDING%u uniform sampler2D reflectionIndTex;\n"
"TBINDING%u uniform sampler2D reflectionTex;\n", "TBINDING%u uniform sampler2D reflectionTex;\n",
m_texMapEnd, m_texMapEnd+1); m_texMapEnd, m_texMapEnd + 1);
else if (reflectionType == ReflectionType::Simple) else if (reflectionType == ReflectionType::Simple)
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D reflectionTex;\n", texMapDecl += hecl::Format("TBINDING%u uniform sampler2D reflectionTex;\n", m_texMapEnd);
m_texMapEnd);
uint32_t extTexBits = 0; uint32_t extTexBits = 0;
for (int i=0 ; i<extTexCount ; ++i) for (int i = 0; i < extTexCount; ++i) {
{
const TextureInfo& extTex = extTexs[i]; const TextureInfo& extTex = extTexs[i];
if (!(extTexBits & (1 << extTex.mapIdx))) if (!(extTexBits & (1 << extTex.mapIdx))) {
{ texMapDecl += hecl::Format("TBINDING%u uniform sampler2D extTex%u;\n", extTex.mapIdx, extTex.mapIdx);
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D extTex%u;\n",
extTex.mapIdx, extTex.mapIdx);
extTexBits |= (1 << extTex.mapIdx); extTexBits |= (1 << extTex.mapIdx);
} }
} }
std::string retval = std::string retval = std::string("#extension GL_ARB_shader_image_load_store: enable\n") + "#define BLEND_SRC_" +
std::string("#extension GL_ARB_shader_image_load_store: enable\n") + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" + "#define BLEND_DST_" +
"#define BLEND_SRC_" + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
"#define BLEND_DST_" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) +
(!alphaTest ? (!alphaTest ? "\n#ifdef GL_ARB_shader_image_load_store\n"
"\n#ifdef GL_ARB_shader_image_load_store\n"
"layout(early_fragment_tests) in;\n" "layout(early_fragment_tests) in;\n"
"#endif\n" : "") + "#endif\n"
"\nlayout(location=0) out vec4 colorOut;\n" + : "") +
texMapDecl + "\nlayout(location=0) out vec4 colorOut;\n" + texMapDecl + "SBINDING(0) in VertToFrag vtf;\n\n" +
"SBINDING(0) in VertToFrag vtf;\n\n" + lightingSrc + "\n" + postSrc + "\nvoid main()\n{\n";
lightingSrc + "\n" +
postSrc +
"\nvoid main()\n{\n";
if (m_lighting) if (m_lighting) {
{
if (!lighting.m_entry.empty()) if (!lighting.m_entry.empty())
retval += hecl::Format(" vec4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz));\n", retval +=
lighting.m_entry.data()); hecl::Format(" vec4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz));\n", lighting.m_entry.data());
else else
retval += " vec4 lighting = vec4(1.0,1.0,1.0,1.0);\n"; retval += " vec4 lighting = vec4(1.0,1.0,1.0,1.0);\n";
} }
unsigned sampIdx = 0; unsigned sampIdx = 0;
for (const TexSampling& sampling : m_texSamplings) for (const TexSampling& sampling : m_texSamplings)
retval += hecl::Format(" vec4 sampling%u = texture(tex%u, vtf.tcgs[%u]);\n", retval += hecl::Format(" vec4 sampling%u = texture(tex%u, vtf.tcgs[%u]);\n", sampIdx++, sampling.mapIdx,
sampIdx++, sampling.mapIdx, sampling.tcgIdx); sampling.tcgIdx);
std::string reflectionExpr = GenerateReflectionExpr(reflectionType); std::string reflectionExpr = GenerateReflectionExpr(reflectionType);
if (m_alphaExpr.size()) if (m_alphaExpr.size())
retval += " colorOut = " + postEntry + "(vec4(" + m_colorExpr + " + " + reflectionExpr + ", " + m_alphaExpr + ")) * mulColor;\n"; retval += " colorOut = " + postEntry + "(vec4(" + m_colorExpr + " + " + reflectionExpr + ", " + m_alphaExpr +
")) * mulColor;\n";
else else
retval += " colorOut = " + postEntry + "(vec4(" + m_colorExpr + " + " + reflectionExpr + ", 1.0)) * mulColor;\n"; retval += " colorOut = " + postEntry + "(vec4(" + m_colorExpr + " + " + reflectionExpr + ", 1.0)) * mulColor;\n";
return retval + (alphaTest ? GenerateAlphaTest() : "") + "}\n"; return retval + (alphaTest ? GenerateAlphaTest() : "") + "}\n";
} }
} } // namespace hecl::Backend

View File

@ -1,21 +1,22 @@
#include "hecl/Backend/GX.hpp" #include "hecl/Backend/GX.hpp"
namespace hecl::Backend namespace hecl::Backend {
{
template <> template <>
void GX::Color::Enumerate<athena::io::DNA<athena::Big>::Read>(typename Read::StreamT& reader) void GX::Color::Enumerate<athena::io::DNA<athena::Big>::Read>(typename Read::StreamT& reader) {
{ reader.readUBytesToBuf(&num, 4); } reader.readUBytesToBuf(&num, 4);
}
template <> template <>
void GX::Color::Enumerate<athena::io::DNA<athena::Big>::Write>(typename Write::StreamT& writer) void GX::Color::Enumerate<athena::io::DNA<athena::Big>::Write>(typename Write::StreamT& writer) {
{ writer.writeUBytes(reinterpret_cast<const atUint8*>(&num), 4); } writer.writeUBytes(reinterpret_cast<const atUint8*>(&num), 4);
}
template <> template <>
void GX::Color::Enumerate<athena::io::DNA<athena::Big>::BinarySize>(typename BinarySize::StreamT& s) void GX::Color::Enumerate<athena::io::DNA<athena::Big>::BinarySize>(typename BinarySize::StreamT& s) {
{ s += 4; } s += 4;
}
unsigned GX::addKColor(Diagnostics& diag, const SourceLocation& loc, const Color& color) unsigned GX::addKColor(Diagnostics& diag, const SourceLocation& loc, const Color& color) {
{ for (unsigned i = 0; i < m_kcolorCount; ++i)
for (unsigned i=0 ; i<m_kcolorCount ; ++i)
if (m_kcolors[i] == color) if (m_kcolors[i] == color)
return i; return i;
if (m_kcolorCount >= 4) if (m_kcolorCount >= 4)
@ -25,15 +26,12 @@ unsigned GX::addKColor(Diagnostics& diag, const SourceLocation& loc, const Color
return m_kcolorCount++; return m_kcolorCount++;
} }
unsigned GX::addKAlpha(Diagnostics& diag, const SourceLocation& loc, float alpha) unsigned GX::addKAlpha(Diagnostics& diag, const SourceLocation& loc, float alpha) {
{
uint8_t ai = uint8_t(std::min(std::max(alpha * 255.f, 0.f), 255.f)); uint8_t ai = uint8_t(std::min(std::max(alpha * 255.f, 0.f), 255.f));
for (unsigned i=0 ; i<m_kcolorCount ; ++i) for (unsigned i = 0; i < m_kcolorCount; ++i) {
{
if (m_kcolors[i].color[3] == ai) if (m_kcolors[i].color[3] == ai)
return i; return i;
else if (m_kcolors[i].color[3] == 0) else if (m_kcolors[i].color[3] == 0) {
{
m_kcolors[i].color[3] = ai; m_kcolors[i].color[3] = ai;
return i; return i;
} }
@ -44,14 +42,11 @@ unsigned GX::addKAlpha(Diagnostics& diag, const SourceLocation& loc, float alpha
return m_kcolorCount++; return m_kcolorCount++;
} }
unsigned GX::addTexCoordGen(Diagnostics& diag, const SourceLocation& loc, unsigned GX::addTexCoordGen(Diagnostics& diag, const SourceLocation& loc, TexGenSrc src, TexMtx mtx, bool norm,
TexGenSrc src, TexMtx mtx, bool norm, PTTexMtx pmtx) PTTexMtx pmtx) {
{ for (unsigned i = 0; i < m_tcgCount; ++i) {
for (unsigned i=0 ; i<m_tcgCount ; ++i)
{
TexCoordGen& tcg = m_tcgs[i]; TexCoordGen& tcg = m_tcgs[i];
if (tcg.m_src == src && tcg.m_mtx == mtx && if (tcg.m_src == src && tcg.m_mtx == mtx && tcg.m_norm == norm && tcg.m_pmtx == pmtx)
tcg.m_norm == norm && tcg.m_pmtx == pmtx)
return i; return i;
} }
if (m_tcgCount >= 8) if (m_tcgCount >= 8)
@ -64,26 +59,22 @@ unsigned GX::addTexCoordGen(Diagnostics& diag, const SourceLocation& loc,
return m_tcgCount++; return m_tcgCount++;
} }
GX::TEVStage& GX::addTEVStage(Diagnostics& diag, const SourceLocation& loc) GX::TEVStage& GX::addTEVStage(Diagnostics& diag, const SourceLocation& loc) {
{
if (m_tevCount >= 16) if (m_tevCount >= 16)
diag.reportBackendErr(loc, "GX TEV stage overflow"); diag.reportBackendErr(loc, "GX TEV stage overflow");
GX::TEVStage& newTEV = m_tevs[m_tevCount]; GX::TEVStage& newTEV = m_tevs[m_tevCount];
newTEV.m_loc = loc; newTEV.m_loc = loc;
if (m_tevCount) if (m_tevCount) {
{ newTEV.m_prev = &m_tevs[m_tevCount - 1];
newTEV.m_prev = &m_tevs[m_tevCount-1];
newTEV.m_prev->m_next = &newTEV; newTEV.m_prev->m_next = &newTEV;
} }
++m_tevCount; ++m_tevCount;
return newTEV; return newTEV;
} }
GX::TEVStage& GX::addAlphaTEVStage(Diagnostics& diag, const SourceLocation& loc) GX::TEVStage& GX::addAlphaTEVStage(Diagnostics& diag, const SourceLocation& loc) {
{
++m_alphaTraceStage; ++m_alphaTraceStage;
while (m_tevCount < m_alphaTraceStage + 1) while (m_tevCount < m_alphaTraceStage + 1) {
{
TEVStage& stage = addTEVStage(diag, loc); TEVStage& stage = addTEVStage(diag, loc);
stage.m_color[3] = CC_CPREV; stage.m_color[3] = CC_CPREV;
stage.m_alpha[3] = CA_APREV; stage.m_alpha[3] = CA_APREV;
@ -92,21 +83,18 @@ GX::TEVStage& GX::addAlphaTEVStage(Diagnostics& diag, const SourceLocation& loc)
} }
unsigned GX::RecursiveTraceTexGen(const IR& ir, Diagnostics& diag, const IR::Instruction& inst, TexMtx mtx, unsigned GX::RecursiveTraceTexGen(const IR& ir, Diagnostics& diag, const IR::Instruction& inst, TexMtx mtx,
bool normalize, PTTexMtx pmtx) bool normalize, PTTexMtx pmtx) {
{
if (inst.m_op != IR::OpType::Call) if (inst.m_op != IR::OpType::Call)
diag.reportBackendErr(inst.m_loc, "TexCoordGen resolution requires function"); diag.reportBackendErr(inst.m_loc, "TexCoordGen resolution requires function");
const std::string& tcgName = inst.m_call.m_name; const std::string& tcgName = inst.m_call.m_name;
if (!tcgName.compare("UV")) if (!tcgName.compare("UV")) {
{
if (inst.getChildCount() < 1) if (inst.getChildCount() < 1)
diag.reportBackendErr(inst.m_loc, "TexCoordGen UV(layerIdx) requires one argument"); diag.reportBackendErr(inst.m_loc, "TexCoordGen UV(layerIdx) requires one argument");
const IR::Instruction& idxInst = inst.getChildInst(ir, 0); const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
auto& idxImm = idxInst.getImmVec(); auto& idxImm = idxInst.getImmVec();
return addTexCoordGen(diag, inst.m_loc, TexGenSrc(TG_TEX0 + unsigned(idxImm.simd[0])), mtx, normalize, pmtx); return addTexCoordGen(diag, inst.m_loc, TexGenSrc(TG_TEX0 + unsigned(idxImm.simd[0])), mtx, normalize, pmtx);
} } else if (!tcgName.compare("Normal"))
else if (!tcgName.compare("Normal"))
return addTexCoordGen(diag, inst.m_loc, TG_NRM, mtx, normalize, pmtx); return addTexCoordGen(diag, inst.m_loc, TG_NRM, mtx, normalize, pmtx);
else if (!tcgName.compare("View")) else if (!tcgName.compare("View"))
return addTexCoordGen(diag, inst.m_loc, TG_POS, mtx, normalize, pmtx); return addTexCoordGen(diag, inst.m_loc, TG_POS, mtx, normalize, pmtx);
@ -114,15 +102,14 @@ unsigned GX::RecursiveTraceTexGen(const IR& ir, Diagnostics& diag, const IR::Ins
/* Otherwise treat as game-specific function */ /* Otherwise treat as game-specific function */
const IR::Instruction& tcgSrcInst = inst.getChildInst(ir, 0); const IR::Instruction& tcgSrcInst = inst.getChildInst(ir, 0);
bool doNorm = normalize || tcgName.back() == 'N'; bool doNorm = normalize || tcgName.back() == 'N';
unsigned idx = RecursiveTraceTexGen(ir, diag, tcgSrcInst, TexMtx(TEXMTX0 + m_texMtxCount * 3), unsigned idx = RecursiveTraceTexGen(ir, diag, tcgSrcInst, TexMtx(TEXMTX0 + m_texMtxCount * 3), doNorm,
doNorm, doNorm ? PTTexMtx(PTTEXMTX0 + m_texMtxCount * 3) : PTIDENTITY); doNorm ? PTTexMtx(PTTEXMTX0 + m_texMtxCount * 3) : PTIDENTITY);
GX::TexCoordGen& tcg = m_tcgs[idx]; GX::TexCoordGen& tcg = m_tcgs[idx];
m_texMtxRefs[m_texMtxCount] = &tcg; m_texMtxRefs[m_texMtxCount] = &tcg;
++m_texMtxCount; ++m_texMtxCount;
tcg.m_gameFunction = tcgName; tcg.m_gameFunction = tcgName;
tcg.m_gameArgs.clear(); tcg.m_gameArgs.clear();
for (int i=1 ; i<inst.getChildCount() ; ++i) for (int i = 1; i < inst.getChildCount(); ++i) {
{
const IR::Instruction& ci = inst.getChildInst(ir, i); const IR::Instruction& ci = inst.getChildInst(ir, i);
tcg.m_gameArgs.push_back(ci.getImmVec()); tcg.m_gameArgs.push_back(ci.getImmVec());
} }
@ -130,16 +117,12 @@ unsigned GX::RecursiveTraceTexGen(const IR& ir, Diagnostics& diag, const IR::Ins
} }
GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const IR::Instruction& inst, GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const IR::Instruction& inst,
bool swizzleAlpha) bool swizzleAlpha) {
{ switch (inst.m_op) {
switch (inst.m_op) case IR::OpType::Call: {
{
case IR::OpType::Call:
{
const std::string& name = inst.m_call.m_name; const std::string& name = inst.m_call.m_name;
bool normalize = false; bool normalize = false;
if (!name.compare("Texture") || (normalize = true && !name.compare("TextureN"))) if (!name.compare("Texture") || (normalize = true && !name.compare("TextureN"))) {
{
TEVStage& newStage = addTEVStage(diag, inst.m_loc); TEVStage& newStage = addTEVStage(diag, inst.m_loc);
if (inst.getChildCount() < 2) if (inst.getChildCount() < 2)
@ -154,9 +137,7 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
newStage.m_texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, IDENTITY, normalize, PTIDENTITY); newStage.m_texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, IDENTITY, normalize, PTIDENTITY);
return TraceResult(&newStage); return TraceResult(&newStage);
} } else if (!name.compare("ColorReg")) {
else if (!name.compare("ColorReg"))
{
const IR::Instruction& idxInst = inst.getChildInst(ir, 0); const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
unsigned idx = unsigned(idxInst.getImmVec().simd[0]); unsigned idx = unsigned(idxInst.getImmVec().simd[0]);
if (swizzleAlpha) if (swizzleAlpha)
@ -164,17 +145,13 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
else else
m_cRegMask |= 1 << idx; m_cRegMask |= 1 << idx;
return TraceResult(TevColorArg((swizzleAlpha ? CC_A0 : CC_C0) + idx * 2)); return TraceResult(TevColorArg((swizzleAlpha ? CC_A0 : CC_C0) + idx * 2));
} } else if (!name.compare("Lighting")) {
else if (!name.compare("Lighting"))
{
return TraceResult(swizzleAlpha ? CC_RASA : CC_RASC); return TraceResult(swizzleAlpha ? CC_RASA : CC_RASC);
} } else
else
diag.reportBackendErr(inst.m_loc, "GX backend unable to interpret '%s'", name.c_str()); diag.reportBackendErr(inst.m_loc, "GX backend unable to interpret '%s'", name.c_str());
break; break;
} }
case IR::OpType::LoadImm: case IR::OpType::LoadImm: {
{
const atVec4f& vec = inst.m_loadImm.m_immVec; const atVec4f& vec = inst.m_loadImm.m_immVec;
if (vec.simd[0] == 0.f && vec.simd[1] == 0.f && vec.simd[2] == 0.f) if (vec.simd[0] == 0.f && vec.simd[1] == 0.f && vec.simd[2] == 0.f)
return TraceResult(CC_ZERO); return TraceResult(CC_ZERO);
@ -183,96 +160,69 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
unsigned idx = addKColor(diag, inst.m_loc, vec); unsigned idx = addKColor(diag, inst.m_loc, vec);
return TraceResult(TevKColorSel(TEV_KCSEL_K0 + idx)); return TraceResult(TevKColorSel(TEV_KCSEL_K0 + idx));
} }
case IR::OpType::Arithmetic: case IR::OpType::Arithmetic: {
{
ArithmeticOp op = inst.m_arithmetic.m_op; ArithmeticOp op = inst.m_arithmetic.m_op;
const IR::Instruction& aInst = inst.getChildInst(ir, 0); const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1); const IR::Instruction& bInst = inst.getChildInst(ir, 1);
TraceResult aTrace; TraceResult aTrace;
TraceResult bTrace; TraceResult bTrace;
if (aInst.m_op != IR::OpType::Arithmetic && bInst.m_op == IR::OpType::Arithmetic) if (aInst.m_op != IR::OpType::Arithmetic && bInst.m_op == IR::OpType::Arithmetic) {
{
bTrace = RecursiveTraceColor(ir, diag, bInst); bTrace = RecursiveTraceColor(ir, diag, bInst);
aTrace = RecursiveTraceColor(ir, diag, aInst); aTrace = RecursiveTraceColor(ir, diag, aInst);
} } else {
else
{
aTrace = RecursiveTraceColor(ir, diag, aInst); aTrace = RecursiveTraceColor(ir, diag, aInst);
bTrace = RecursiveTraceColor(ir, diag, bInst); bTrace = RecursiveTraceColor(ir, diag, bInst);
} }
if (aTrace.type == TraceResult::Type::TEVStage && if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVStage &&
getStageIdx(aTrace.tevStage) > getStageIdx(bTrace.tevStage)) getStageIdx(aTrace.tevStage) > getStageIdx(bTrace.tevStage))
std::swap(aTrace, bTrace); std::swap(aTrace, bTrace);
TevKColorSel newKColor = TEV_KCSEL_1; TevKColorSel newKColor = TEV_KCSEL_1;
if (aTrace.type == TraceResult::Type::TEVKColorSel && if (aTrace.type == TraceResult::Type::TEVKColorSel && bTrace.type == TraceResult::Type::TEVKColorSel)
bTrace.type == TraceResult::Type::TEVKColorSel)
diag.reportBackendErr(inst.m_loc, "unable to handle 2 KColors in one stage"); diag.reportBackendErr(inst.m_loc, "unable to handle 2 KColors in one stage");
else if (aTrace.type == TraceResult::Type::TEVKColorSel) else if (aTrace.type == TraceResult::Type::TEVKColorSel) {
{
newKColor = aTrace.tevKColorSel; newKColor = aTrace.tevKColorSel;
aTrace.type = TraceResult::Type::TEVColorArg; aTrace.type = TraceResult::Type::TEVColorArg;
aTrace.tevColorArg = CC_KONST; aTrace.tevColorArg = CC_KONST;
} } else if (bTrace.type == TraceResult::Type::TEVKColorSel) {
else if (bTrace.type == TraceResult::Type::TEVKColorSel)
{
newKColor = bTrace.tevKColorSel; newKColor = bTrace.tevKColorSel;
bTrace.type = TraceResult::Type::TEVColorArg; bTrace.type = TraceResult::Type::TEVColorArg;
bTrace.tevColorArg = CC_KONST; bTrace.tevColorArg = CC_KONST;
} }
switch (op) switch (op) {
{ case ArithmeticOp::Add: {
case ArithmeticOp::Add: if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage) {
{
if (aTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVStage)
{
TEVStage* a = aTrace.tevStage; TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage; TEVStage* b = bTrace.tevStage;
if (b->m_prev != a) if (b->m_prev != a) {
{
a->m_cRegOut = TEVLAZY; a->m_cRegOut = TEVLAZY;
b->m_color[3] = CC_LAZY; b->m_color[3] = CC_LAZY;
b->m_lazyCInIdx = m_cRegLazy; b->m_lazyCInIdx = m_cRegLazy;
a->m_lazyCOutIdx = m_cRegLazy++; a->m_lazyCOutIdx = m_cRegLazy++;
} } else if (b == &m_tevs[m_tevCount - 1] && a->m_texMapIdx == b->m_texMapIdx &&
else if (b == &m_tevs[m_tevCount-1] && a->m_texGenIdx == b->m_texGenIdx && a->m_color[3] == CC_ZERO && b->m_color[0] != CC_ZERO) {
a->m_texMapIdx == b->m_texMapIdx && a->m_texGenIdx == b->m_texGenIdx &&
a->m_color[3] == CC_ZERO && b->m_color[0] != CC_ZERO)
{
a->m_color[3] = b->m_color[0]; a->m_color[3] = b->m_color[0];
--m_tevCount; --m_tevCount;
return TraceResult(a); return TraceResult(a);
} } else
else
b->m_color[3] = CC_CPREV; b->m_color[3] = CC_CPREV;
return TraceResult(b); return TraceResult(b);
} } else if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVColorArg) {
else if (aTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVColorArg)
{
TEVStage* a = aTrace.tevStage; TEVStage* a = aTrace.tevStage;
if (a->m_color[3] != CC_ZERO) if (a->m_color[3] != CC_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine"); diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
a->m_color[3] = bTrace.tevColorArg; a->m_color[3] = bTrace.tevColorArg;
a->m_kColor = newKColor; a->m_kColor = newKColor;
return TraceResult(a); return TraceResult(a);
} } else if (aTrace.type == TraceResult::Type::TEVColorArg && bTrace.type == TraceResult::Type::TEVStage) {
else if (aTrace.type == TraceResult::Type::TEVColorArg &&
bTrace.type == TraceResult::Type::TEVStage)
{
TEVStage* b = bTrace.tevStage; TEVStage* b = bTrace.tevStage;
if (b->m_color[3] != CC_ZERO) if (b->m_color[3] != CC_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine"); diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
b->m_color[3] = aTrace.tevColorArg; b->m_color[3] = aTrace.tevColorArg;
b->m_kColor = newKColor; b->m_kColor = newKColor;
return TraceResult(b); return TraceResult(b);
} } else if (aTrace.type == TraceResult::Type::TEVColorArg && bTrace.type == TraceResult::Type::TEVColorArg) {
else if (aTrace.type == TraceResult::Type::TEVColorArg &&
bTrace.type == TraceResult::Type::TEVColorArg)
{
TEVStage& stage = addTEVStage(diag, inst.m_loc); TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[0] = aTrace.tevColorArg; stage.m_color[0] = aTrace.tevColorArg;
stage.m_color[3] = bTrace.tevColorArg; stage.m_color[3] = bTrace.tevColorArg;
@ -281,28 +231,20 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
} }
break; break;
} }
case ArithmeticOp::Subtract: case ArithmeticOp::Subtract: {
{ if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage) {
if (aTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVStage)
{
TEVStage* a = aTrace.tevStage; TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage; TEVStage* b = bTrace.tevStage;
if (b->m_prev != a) if (b->m_prev != a) {
{
a->m_cRegOut = TEVLAZY; a->m_cRegOut = TEVLAZY;
b->m_color[3] = CC_LAZY; b->m_color[3] = CC_LAZY;
b->m_lazyCInIdx = m_cRegLazy; b->m_lazyCInIdx = m_cRegLazy;
a->m_lazyCOutIdx = m_cRegLazy++; a->m_lazyCOutIdx = m_cRegLazy++;
} } else
else
b->m_color[3] = CC_CPREV; b->m_color[3] = CC_CPREV;
b->m_cop = TEV_SUB; b->m_cop = TEV_SUB;
return TraceResult(b); return TraceResult(b);
} } else if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVColorArg) {
else if (aTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVColorArg)
{
TEVStage* a = aTrace.tevStage; TEVStage* a = aTrace.tevStage;
if (a->m_color[3] != CC_ZERO) if (a->m_color[3] != CC_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for subtract combine"); diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for subtract combine");
@ -310,10 +252,7 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
a->m_kColor = newKColor; a->m_kColor = newKColor;
a->m_cop = TEV_SUB; a->m_cop = TEV_SUB;
return TraceResult(a); return TraceResult(a);
} } else if (aTrace.type == TraceResult::Type::TEVColorArg && bTrace.type == TraceResult::Type::TEVColorArg) {
else if (aTrace.type == TraceResult::Type::TEVColorArg &&
bTrace.type == TraceResult::Type::TEVColorArg)
{
TEVStage& stage = addTEVStage(diag, inst.m_loc); TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[0] = aTrace.tevColorArg; stage.m_color[0] = aTrace.tevColorArg;
stage.m_color[3] = bTrace.tevColorArg; stage.m_color[3] = bTrace.tevColorArg;
@ -323,44 +262,32 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
} }
break; break;
} }
case ArithmeticOp::Multiply: case ArithmeticOp::Multiply: {
{ if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage) {
if (aTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVStage)
{
TEVStage* a = aTrace.tevStage; TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage; TEVStage* b = bTrace.tevStage;
if (b->m_color[2] != CC_ZERO) if (b->m_color[2] != CC_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine"); diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
if (b->m_prev != a) if (b->m_prev != a) {
{
a->m_cRegOut = TEVLAZY; a->m_cRegOut = TEVLAZY;
b->m_color[2] = CC_LAZY; b->m_color[2] = CC_LAZY;
b->m_lazyCInIdx = m_cRegLazy; b->m_lazyCInIdx = m_cRegLazy;
a->m_lazyCOutIdx = m_cRegLazy++; a->m_lazyCOutIdx = m_cRegLazy++;
} } else
else
b->m_color[2] = CC_CPREV; b->m_color[2] = CC_CPREV;
b->m_color[1] = b->m_color[0]; b->m_color[1] = b->m_color[0];
b->m_color[0] = CC_ZERO; b->m_color[0] = CC_ZERO;
b->m_color[3] = CC_ZERO; b->m_color[3] = CC_ZERO;
return TraceResult(b); return TraceResult(b);
} } else if (aTrace.type == TraceResult::Type::TEVColorArg && bTrace.type == TraceResult::Type::TEVColorArg) {
else if (aTrace.type == TraceResult::Type::TEVColorArg &&
bTrace.type == TraceResult::Type::TEVColorArg)
{
TEVStage& stage = addTEVStage(diag, inst.m_loc); TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[1] = aTrace.tevColorArg; stage.m_color[1] = aTrace.tevColorArg;
stage.m_color[2] = bTrace.tevColorArg; stage.m_color[2] = bTrace.tevColorArg;
stage.m_kColor = newKColor; stage.m_kColor = newKColor;
return TraceResult(&stage); return TraceResult(&stage);
} } else if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVColorArg) {
else if (aTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVColorArg)
{
TEVStage* a = aTrace.tevStage; TEVStage* a = aTrace.tevStage;
if (a->m_color[1] != CC_ZERO) if (a->m_color[1] != CC_ZERO) {
{
if (a->m_cRegOut != TEVPREV) if (a->m_cRegOut != TEVPREV)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine"); diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
TEVStage& stage = addTEVStage(diag, inst.m_loc); TEVStage& stage = addTEVStage(diag, inst.m_loc);
@ -374,13 +301,9 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
a->m_color[2] = bTrace.tevColorArg; a->m_color[2] = bTrace.tevColorArg;
a->m_kColor = newKColor; a->m_kColor = newKColor;
return TraceResult(a); return TraceResult(a);
} } else if (aTrace.type == TraceResult::Type::TEVColorArg && bTrace.type == TraceResult::Type::TEVStage) {
else if (aTrace.type == TraceResult::Type::TEVColorArg &&
bTrace.type == TraceResult::Type::TEVStage)
{
TEVStage* b = bTrace.tevStage; TEVStage* b = bTrace.tevStage;
if (b->m_color[1] != CC_ZERO) if (b->m_color[1] != CC_ZERO) {
{
if (b->m_cRegOut != TEVPREV) if (b->m_cRegOut != TEVPREV)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine"); diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
TEVStage& stage = addTEVStage(diag, inst.m_loc); TEVStage& stage = addTEVStage(diag, inst.m_loc);
@ -403,17 +326,14 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
diag.reportBackendErr(inst.m_loc, "unable to convert arithmetic to TEV stage"); diag.reportBackendErr(inst.m_loc, "unable to convert arithmetic to TEV stage");
} }
case IR::OpType::Swizzle: case IR::OpType::Swizzle: {
{ if (inst.m_swizzle.m_idxs[0] == 3 && inst.m_swizzle.m_idxs[1] == 3 && inst.m_swizzle.m_idxs[2] == 3 &&
if (inst.m_swizzle.m_idxs[0] == 3 && inst.m_swizzle.m_idxs[1] == 3 && inst.m_swizzle.m_idxs[3] == -1) {
inst.m_swizzle.m_idxs[2] == 3 && inst.m_swizzle.m_idxs[3] == -1)
{
const IR::Instruction& cInst = inst.getChildInst(ir, 0); const IR::Instruction& cInst = inst.getChildInst(ir, 0);
if (cInst.m_op != IR::OpType::Call) if (cInst.m_op != IR::OpType::Call)
diag.reportBackendErr(inst.m_loc, "only functions accepted for alpha swizzle"); diag.reportBackendErr(inst.m_loc, "only functions accepted for alpha swizzle");
return RecursiveTraceColor(ir, diag, cInst, true); return RecursiveTraceColor(ir, diag, cInst, true);
} } else
else
diag.reportBackendErr(inst.m_loc, "only alpha extract may be performed with swizzle operation"); diag.reportBackendErr(inst.m_loc, "only alpha extract may be performed with swizzle operation");
} }
default: default:
@ -423,16 +343,12 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
return TraceResult(); return TraceResult();
} }
GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const IR::Instruction& inst) GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const IR::Instruction& inst) {
{ switch (inst.m_op) {
switch (inst.m_op) case IR::OpType::Call: {
{
case IR::OpType::Call:
{
const std::string& name = inst.m_call.m_name; const std::string& name = inst.m_call.m_name;
bool normalize = false; bool normalize = false;
if (!name.compare("Texture") || (normalize = true && !name.compare("TextureN"))) if (!name.compare("Texture") || (normalize = true && !name.compare("TextureN"))) {
{
if (inst.getChildCount() < 2) if (inst.getChildCount() < 2)
diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments"); diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments");
@ -441,18 +357,15 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
unsigned mapIdx = unsigned(mapImm.simd[0]); unsigned mapIdx = unsigned(mapImm.simd[0]);
int foundStage = -1; int foundStage = -1;
for (int i=m_alphaTraceStage+1 ; i<int(m_tevCount) ; ++i) for (int i = m_alphaTraceStage + 1; i < int(m_tevCount); ++i) {
{
TEVStage& testStage = m_tevs[i]; TEVStage& testStage = m_tevs[i];
if (testStage.m_texMapIdx == mapIdx) if (testStage.m_texMapIdx == mapIdx) {
{
foundStage = i; foundStage = i;
break; break;
} }
} }
if (foundStage >= 0) if (foundStage >= 0) {
{
m_alphaTraceStage = foundStage; m_alphaTraceStage = foundStage;
TEVStage& stage = m_tevs[foundStage]; TEVStage& stage = m_tevs[foundStage];
stage.m_alpha[0] = CA_TEXA; stage.m_alpha[0] = CA_TEXA;
@ -469,24 +382,18 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
newStage.m_texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, IDENTITY, normalize, PTIDENTITY); newStage.m_texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, IDENTITY, normalize, PTIDENTITY);
return TraceResult(&newStage); return TraceResult(&newStage);
} } else if (!name.compare("ColorReg")) {
else if (!name.compare("ColorReg"))
{
const IR::Instruction& idxInst = inst.getChildInst(ir, 0); const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
unsigned idx = unsigned(idxInst.getImmVec().simd[0]); unsigned idx = unsigned(idxInst.getImmVec().simd[0]);
m_aRegMask |= 1 << idx; m_aRegMask |= 1 << idx;
return TraceResult(TevAlphaArg(CA_A0 + idx)); return TraceResult(TevAlphaArg(CA_A0 + idx));
} } else if (!name.compare("Lighting")) {
else if (!name.compare("Lighting"))
{
return TraceResult(CA_RASA); return TraceResult(CA_RASA);
} } else
else
diag.reportBackendErr(inst.m_loc, "GX backend unable to interpret '%s'", name.c_str()); diag.reportBackendErr(inst.m_loc, "GX backend unable to interpret '%s'", name.c_str());
break; break;
} }
case IR::OpType::LoadImm: case IR::OpType::LoadImm: {
{
const atVec4f& vec = inst.m_loadImm.m_immVec; const atVec4f& vec = inst.m_loadImm.m_immVec;
if (vec.simd[0] == 0.f) if (vec.simd[0] == 0.f)
return TraceResult(CA_ZERO); return TraceResult(CA_ZERO);
@ -495,93 +402,68 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
unsigned idx = addKAlpha(diag, inst.m_loc, vec.simd[0]); unsigned idx = addKAlpha(diag, inst.m_loc, vec.simd[0]);
return TraceResult(TevKAlphaSel(TEV_KASEL_K0_A + idx)); return TraceResult(TevKAlphaSel(TEV_KASEL_K0_A + idx));
} }
case IR::OpType::Arithmetic: case IR::OpType::Arithmetic: {
{
ArithmeticOp op = inst.m_arithmetic.m_op; ArithmeticOp op = inst.m_arithmetic.m_op;
const IR::Instruction& aInst = inst.getChildInst(ir, 0); const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1); const IR::Instruction& bInst = inst.getChildInst(ir, 1);
TraceResult aTrace; TraceResult aTrace;
TraceResult bTrace; TraceResult bTrace;
if (aInst.m_op != IR::OpType::Arithmetic && bInst.m_op == IR::OpType::Arithmetic) if (aInst.m_op != IR::OpType::Arithmetic && bInst.m_op == IR::OpType::Arithmetic) {
{
bTrace = RecursiveTraceAlpha(ir, diag, bInst); bTrace = RecursiveTraceAlpha(ir, diag, bInst);
aTrace = RecursiveTraceAlpha(ir, diag, aInst); aTrace = RecursiveTraceAlpha(ir, diag, aInst);
} } else {
else
{
aTrace = RecursiveTraceAlpha(ir, diag, aInst); aTrace = RecursiveTraceAlpha(ir, diag, aInst);
bTrace = RecursiveTraceAlpha(ir, diag, bInst); bTrace = RecursiveTraceAlpha(ir, diag, bInst);
} }
if (aTrace.type == TraceResult::Type::TEVStage && if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVStage &&
getStageIdx(aTrace.tevStage) > getStageIdx(bTrace.tevStage)) getStageIdx(aTrace.tevStage) > getStageIdx(bTrace.tevStage))
std::swap(aTrace, bTrace); std::swap(aTrace, bTrace);
TevKAlphaSel newKAlpha = TEV_KASEL_1; TevKAlphaSel newKAlpha = TEV_KASEL_1;
if (aTrace.type == TraceResult::Type::TEVKAlphaSel && if (aTrace.type == TraceResult::Type::TEVKAlphaSel && bTrace.type == TraceResult::Type::TEVKAlphaSel)
bTrace.type == TraceResult::Type::TEVKAlphaSel)
diag.reportBackendErr(inst.m_loc, "unable to handle 2 KAlphas in one stage"); diag.reportBackendErr(inst.m_loc, "unable to handle 2 KAlphas in one stage");
else if (aTrace.type == TraceResult::Type::TEVKAlphaSel) else if (aTrace.type == TraceResult::Type::TEVKAlphaSel) {
{
newKAlpha = aTrace.tevKAlphaSel; newKAlpha = aTrace.tevKAlphaSel;
aTrace.type = TraceResult::Type::TEVAlphaArg; aTrace.type = TraceResult::Type::TEVAlphaArg;
aTrace.tevAlphaArg = CA_KONST; aTrace.tevAlphaArg = CA_KONST;
} } else if (bTrace.type == TraceResult::Type::TEVKAlphaSel) {
else if (bTrace.type == TraceResult::Type::TEVKAlphaSel)
{
newKAlpha = bTrace.tevKAlphaSel; newKAlpha = bTrace.tevKAlphaSel;
bTrace.type = TraceResult::Type::TEVAlphaArg; bTrace.type = TraceResult::Type::TEVAlphaArg;
bTrace.tevAlphaArg = CA_KONST; bTrace.tevAlphaArg = CA_KONST;
} }
switch (op) switch (op) {
{ case ArithmeticOp::Add: {
case ArithmeticOp::Add: if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage) {
{
if (aTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVStage)
{
TEVStage* a = aTrace.tevStage; TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage; TEVStage* b = bTrace.tevStage;
if (b->m_prev != a) if (b->m_prev != a) {
{
a->m_aRegOut = TEVLAZY; a->m_aRegOut = TEVLAZY;
b->m_alpha[3] = CA_LAZY; b->m_alpha[3] = CA_LAZY;
if (a->m_lazyAOutIdx != -1) if (a->m_lazyAOutIdx != -1)
b->m_lazyAInIdx = a->m_lazyAOutIdx; b->m_lazyAInIdx = a->m_lazyAOutIdx;
else else {
{
b->m_lazyAInIdx = m_aRegLazy; b->m_lazyAInIdx = m_aRegLazy;
a->m_lazyAOutIdx = m_aRegLazy++; a->m_lazyAOutIdx = m_aRegLazy++;
} }
} } else
else
b->m_alpha[3] = CA_APREV; b->m_alpha[3] = CA_APREV;
return TraceResult(b); return TraceResult(b);
} } else if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVAlphaArg) {
else if (aTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVAlphaArg)
{
TEVStage* a = aTrace.tevStage; TEVStage* a = aTrace.tevStage;
if (a->m_alpha[3] != CA_ZERO) if (a->m_alpha[3] != CA_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine"); diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
a->m_alpha[3] = bTrace.tevAlphaArg; a->m_alpha[3] = bTrace.tevAlphaArg;
a->m_kAlpha = newKAlpha; a->m_kAlpha = newKAlpha;
return TraceResult(a); return TraceResult(a);
} } else if (aTrace.type == TraceResult::Type::TEVAlphaArg && bTrace.type == TraceResult::Type::TEVStage) {
else if (aTrace.type == TraceResult::Type::TEVAlphaArg &&
bTrace.type == TraceResult::Type::TEVStage)
{
TEVStage* b = bTrace.tevStage; TEVStage* b = bTrace.tevStage;
if (b->m_alpha[3] != CA_ZERO) if (b->m_alpha[3] != CA_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine"); diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
b->m_alpha[3] = aTrace.tevAlphaArg; b->m_alpha[3] = aTrace.tevAlphaArg;
b->m_kAlpha = newKAlpha; b->m_kAlpha = newKAlpha;
return TraceResult(b); return TraceResult(b);
} } else if (aTrace.type == TraceResult::Type::TEVAlphaArg && bTrace.type == TraceResult::Type::TEVAlphaArg) {
else if (aTrace.type == TraceResult::Type::TEVAlphaArg &&
bTrace.type == TraceResult::Type::TEVAlphaArg)
{
TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc); TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc);
stage.m_alpha[0] = aTrace.tevAlphaArg; stage.m_alpha[0] = aTrace.tevAlphaArg;
stage.m_alpha[3] = bTrace.tevAlphaArg; stage.m_alpha[3] = bTrace.tevAlphaArg;
@ -590,34 +472,25 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
} }
break; break;
} }
case ArithmeticOp::Subtract: case ArithmeticOp::Subtract: {
{ if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage) {
if (aTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVStage)
{
TEVStage* a = aTrace.tevStage; TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage; TEVStage* b = bTrace.tevStage;
if (b->m_aop != TEV_SUB) if (b->m_aop != TEV_SUB)
diag.reportBackendErr(inst.m_loc, "unable to integrate alpha subtraction into stage chain"); diag.reportBackendErr(inst.m_loc, "unable to integrate alpha subtraction into stage chain");
if (b->m_prev != a) if (b->m_prev != a) {
{
a->m_aRegOut = TEVLAZY; a->m_aRegOut = TEVLAZY;
b->m_alpha[3] = CA_LAZY; b->m_alpha[3] = CA_LAZY;
if (a->m_lazyAOutIdx != -1) if (a->m_lazyAOutIdx != -1)
b->m_lazyAInIdx = a->m_lazyAOutIdx; b->m_lazyAInIdx = a->m_lazyAOutIdx;
else else {
{
b->m_lazyAInIdx = m_aRegLazy; b->m_lazyAInIdx = m_aRegLazy;
a->m_lazyAOutIdx = m_aRegLazy++; a->m_lazyAOutIdx = m_aRegLazy++;
} }
} } else
else
b->m_alpha[3] = CA_APREV; b->m_alpha[3] = CA_APREV;
return TraceResult(b); return TraceResult(b);
} } else if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVAlphaArg) {
else if (aTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVAlphaArg)
{
TEVStage* a = aTrace.tevStage; TEVStage* a = aTrace.tevStage;
if (a->m_aop != TEV_SUB) if (a->m_aop != TEV_SUB)
diag.reportBackendErr(inst.m_loc, "unable to integrate alpha subtraction into stage chain"); diag.reportBackendErr(inst.m_loc, "unable to integrate alpha subtraction into stage chain");
@ -626,10 +499,7 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
a->m_alpha[3] = bTrace.tevAlphaArg; a->m_alpha[3] = bTrace.tevAlphaArg;
a->m_kAlpha = newKAlpha; a->m_kAlpha = newKAlpha;
return TraceResult(a); return TraceResult(a);
} } else if (aTrace.type == TraceResult::Type::TEVAlphaArg && bTrace.type == TraceResult::Type::TEVAlphaArg) {
else if (aTrace.type == TraceResult::Type::TEVAlphaArg &&
bTrace.type == TraceResult::Type::TEVAlphaArg)
{
TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc); TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc);
stage.m_alpha[0] = aTrace.tevAlphaArg; stage.m_alpha[0] = aTrace.tevAlphaArg;
stage.m_alpha[3] = bTrace.tevAlphaArg; stage.m_alpha[3] = bTrace.tevAlphaArg;
@ -639,45 +509,33 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
} }
break; break;
} }
case ArithmeticOp::Multiply: case ArithmeticOp::Multiply: {
{ if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage) {
if (aTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVStage)
{
TEVStage* a = aTrace.tevStage; TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage; TEVStage* b = bTrace.tevStage;
if (b->m_alpha[2] != CA_ZERO) if (b->m_alpha[2] != CA_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine"); diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
if (b->m_prev != a) if (b->m_prev != a) {
{
a->m_aRegOut = TEVLAZY; a->m_aRegOut = TEVLAZY;
b->m_alpha[2] = CA_LAZY; b->m_alpha[2] = CA_LAZY;
b->m_lazyAInIdx = m_aRegLazy; b->m_lazyAInIdx = m_aRegLazy;
a->m_lazyAOutIdx = m_aRegLazy++; a->m_lazyAOutIdx = m_aRegLazy++;
} } else
else
b->m_alpha[2] = CA_APREV; b->m_alpha[2] = CA_APREV;
b->m_alpha[1] = b->m_alpha[0]; b->m_alpha[1] = b->m_alpha[0];
b->m_alpha[0] = CA_ZERO; b->m_alpha[0] = CA_ZERO;
b->m_alpha[3] = CA_ZERO; b->m_alpha[3] = CA_ZERO;
return TraceResult(b); return TraceResult(b);
} } else if (aTrace.type == TraceResult::Type::TEVAlphaArg && bTrace.type == TraceResult::Type::TEVAlphaArg) {
else if (aTrace.type == TraceResult::Type::TEVAlphaArg &&
bTrace.type == TraceResult::Type::TEVAlphaArg)
{
TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc); TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc);
stage.m_color[3] = CC_CPREV; stage.m_color[3] = CC_CPREV;
stage.m_alpha[1] = aTrace.tevAlphaArg; stage.m_alpha[1] = aTrace.tevAlphaArg;
stage.m_alpha[2] = bTrace.tevAlphaArg; stage.m_alpha[2] = bTrace.tevAlphaArg;
stage.m_kAlpha = newKAlpha; stage.m_kAlpha = newKAlpha;
return TraceResult(&stage); return TraceResult(&stage);
} } else if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVAlphaArg) {
else if (aTrace.type == TraceResult::Type::TEVStage &&
bTrace.type == TraceResult::Type::TEVAlphaArg)
{
TEVStage* a = aTrace.tevStage; TEVStage* a = aTrace.tevStage;
if (a->m_alpha[1] != CA_ZERO) if (a->m_alpha[1] != CA_ZERO) {
{
if (a->m_aRegOut != TEVPREV) if (a->m_aRegOut != TEVPREV)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine"); diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc); TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc);
@ -691,13 +549,9 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
a->m_alpha[2] = bTrace.tevAlphaArg; a->m_alpha[2] = bTrace.tevAlphaArg;
a->m_kAlpha = newKAlpha; a->m_kAlpha = newKAlpha;
return TraceResult(a); return TraceResult(a);
} } else if (aTrace.type == TraceResult::Type::TEVAlphaArg && bTrace.type == TraceResult::Type::TEVStage) {
else if (aTrace.type == TraceResult::Type::TEVAlphaArg &&
bTrace.type == TraceResult::Type::TEVStage)
{
TEVStage* b = bTrace.tevStage; TEVStage* b = bTrace.tevStage;
if (b->m_alpha[1] != CA_ZERO) if (b->m_alpha[1] != CA_ZERO) {
{
if (b->m_aRegOut != TEVPREV) if (b->m_aRegOut != TEVPREV)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine"); diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc); TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc);
@ -720,17 +574,14 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
diag.reportBackendErr(inst.m_loc, "unable to convert arithmetic to TEV stage"); diag.reportBackendErr(inst.m_loc, "unable to convert arithmetic to TEV stage");
} }
case IR::OpType::Swizzle: case IR::OpType::Swizzle: {
{ if (inst.m_swizzle.m_idxs[0] == 3 && inst.m_swizzle.m_idxs[1] == 3 && inst.m_swizzle.m_idxs[2] == 3 &&
if (inst.m_swizzle.m_idxs[0] == 3 && inst.m_swizzle.m_idxs[1] == 3 && inst.m_swizzle.m_idxs[3] == -1) {
inst.m_swizzle.m_idxs[2] == 3 && inst.m_swizzle.m_idxs[3] == -1)
{
const IR::Instruction& cInst = inst.getChildInst(ir, 0); const IR::Instruction& cInst = inst.getChildInst(ir, 0);
if (cInst.m_op != IR::OpType::Call) if (cInst.m_op != IR::OpType::Call)
diag.reportBackendErr(inst.m_loc, "only functions accepted for alpha swizzle"); diag.reportBackendErr(inst.m_loc, "only functions accepted for alpha swizzle");
return RecursiveTraceAlpha(ir, diag, cInst); return RecursiveTraceAlpha(ir, diag, cInst);
} } else
else
diag.reportBackendErr(inst.m_loc, "only alpha extract may be performed with swizzle operation"); diag.reportBackendErr(inst.m_loc, "only alpha extract may be performed with swizzle operation");
} }
default: default:
@ -740,8 +591,7 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
return TraceResult(); return TraceResult();
} }
void GX::reset(const IR& ir, Diagnostics& diag) void GX::reset(const IR& ir, Diagnostics& diag) {
{
diag.setBackend("GX"); diag.setBackend("GX");
m_tevCount = 0; m_tevCount = 0;
@ -756,109 +606,88 @@ void GX::reset(const IR& ir, Diagnostics& diag)
/* Final instruction is the root call by hecl convention */ /* Final instruction is the root call by hecl convention */
const IR::Instruction& rootCall = ir.m_instructions.back(); const IR::Instruction& rootCall = ir.m_instructions.back();
if (!rootCall.m_call.m_name.compare("HECLOpaque")) if (!rootCall.m_call.m_name.compare("HECLOpaque")) {
{
m_blendSrc = BL_ONE; m_blendSrc = BL_ONE;
m_blendDst = BL_ZERO; m_blendDst = BL_ZERO;
} } else if (!rootCall.m_call.m_name.compare("HECLAlpha")) {
else if (!rootCall.m_call.m_name.compare("HECLAlpha"))
{
m_blendSrc = BL_SRCALPHA; m_blendSrc = BL_SRCALPHA;
m_blendDst = BL_INVSRCALPHA; m_blendDst = BL_INVSRCALPHA;
} } else if (!rootCall.m_call.m_name.compare("HECLAdditive")) {
else if (!rootCall.m_call.m_name.compare("HECLAdditive"))
{
m_blendSrc = BL_SRCALPHA; m_blendSrc = BL_SRCALPHA;
m_blendDst = BL_ONE; m_blendDst = BL_ONE;
} } else {
else diag.reportBackendErr(rootCall.m_loc, "GX backend doesn't handle '%s' root", rootCall.m_call.m_name.c_str());
{
diag.reportBackendErr(rootCall.m_loc, "GX backend doesn't handle '%s' root",
rootCall.m_call.m_name.c_str());
return; return;
} }
/* Follow Color Chain */ /* Follow Color Chain */
const IR::Instruction& colorRoot = const IR::Instruction& colorRoot = ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(0));
ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(0));
TraceResult result = RecursiveTraceColor(ir, diag, colorRoot); TraceResult result = RecursiveTraceColor(ir, diag, colorRoot);
switch (result.type) switch (result.type) {
{ case TraceResult::Type::TEVColorArg: {
case TraceResult::Type::TEVColorArg:
{
TEVStage& stage = addTEVStage(diag, colorRoot.m_loc); TEVStage& stage = addTEVStage(diag, colorRoot.m_loc);
stage.m_color[3] = result.tevColorArg; stage.m_color[3] = result.tevColorArg;
break; break;
} }
case TraceResult::Type::TEVKColorSel: case TraceResult::Type::TEVKColorSel: {
{
TEVStage& stage = addTEVStage(diag, colorRoot.m_loc); TEVStage& stage = addTEVStage(diag, colorRoot.m_loc);
stage.m_color[3] = CC_KONST; stage.m_color[3] = CC_KONST;
stage.m_kColor = result.tevKColorSel; stage.m_kColor = result.tevKColorSel;
break; break;
} }
default: break; default:
break;
} }
/* Follow Alpha Chain */ /* Follow Alpha Chain */
if (rootCall.m_call.m_argInstIdxs.size() > 1) if (rootCall.m_call.m_argInstIdxs.size() > 1) {
{ const IR::Instruction& alphaRoot = ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(1));
const IR::Instruction& alphaRoot =
ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(1));
TraceResult result = RecursiveTraceAlpha(ir, diag, alphaRoot); TraceResult result = RecursiveTraceAlpha(ir, diag, alphaRoot);
switch (result.type) switch (result.type) {
{ case TraceResult::Type::TEVAlphaArg: {
case TraceResult::Type::TEVAlphaArg:
{
TEVStage& stage = addAlphaTEVStage(diag, alphaRoot.m_loc); TEVStage& stage = addAlphaTEVStage(diag, alphaRoot.m_loc);
stage.m_alpha[3] = result.tevAlphaArg; stage.m_alpha[3] = result.tevAlphaArg;
break; break;
} }
case TraceResult::Type::TEVKAlphaSel: case TraceResult::Type::TEVKAlphaSel: {
{
TEVStage& stage = addAlphaTEVStage(diag, alphaRoot.m_loc); TEVStage& stage = addAlphaTEVStage(diag, alphaRoot.m_loc);
stage.m_alpha[3] = CA_KONST; stage.m_alpha[3] = CA_KONST;
stage.m_kAlpha = result.tevKAlphaSel; stage.m_kAlpha = result.tevKAlphaSel;
break; break;
} }
default: break; default:
break;
} }
/* Ensure Alpha reaches end of chain */ /* Ensure Alpha reaches end of chain */
if (m_alphaTraceStage >= 0) if (m_alphaTraceStage >= 0)
for (unsigned i=m_alphaTraceStage+1 ; i<m_tevCount ; ++i) for (unsigned i = m_alphaTraceStage + 1; i < m_tevCount; ++i)
m_tevs[i].m_alpha[3] = CA_APREV; m_tevs[i].m_alpha[3] = CA_APREV;
} }
/* Resolve lazy color/alpha regs */ /* Resolve lazy color/alpha regs */
if (m_cRegLazy) if (m_cRegLazy) {
{ for (int i = 0; i < int(m_tevCount); ++i) {
for (int i=0 ; i<int(m_tevCount) ; ++i)
{
TEVStage& stage = m_tevs[i]; TEVStage& stage = m_tevs[i];
if (stage.m_cRegOut == TEVLAZY) if (stage.m_cRegOut == TEVLAZY) {
{
int picked = pickCLazy(diag, stage.m_loc, i); int picked = pickCLazy(diag, stage.m_loc, i);
stage.m_cRegOut = TevRegID(TEVREG0 + picked); stage.m_cRegOut = TevRegID(TEVREG0 + picked);
for (int j=i+1 ; j<int(m_tevCount) ; ++j) for (int j = i + 1; j < int(m_tevCount); ++j) {
{
TEVStage& nstage = m_tevs[j]; TEVStage& nstage = m_tevs[j];
if (nstage.m_lazyCInIdx == stage.m_lazyCOutIdx) if (nstage.m_lazyCInIdx == stage.m_lazyCOutIdx)
for (int c=0 ; c<4 ; ++c) for (int c = 0; c < 4; ++c)
if (nstage.m_color[c] == CC_LAZY) if (nstage.m_color[c] == CC_LAZY)
nstage.m_color[c] = TevColorArg(CC_C0 + picked * 2); nstage.m_color[c] = TevColorArg(CC_C0 + picked * 2);
} }
} }
if (stage.m_aRegOut == TEVLAZY) if (stage.m_aRegOut == TEVLAZY) {
{
int picked = pickALazy(diag, stage.m_loc, i); int picked = pickALazy(diag, stage.m_loc, i);
stage.m_aRegOut = TevRegID(TEVREG0 + picked); stage.m_aRegOut = TevRegID(TEVREG0 + picked);
for (int j=i+1 ; j<int(m_tevCount) ; ++j) for (int j = i + 1; j < int(m_tevCount); ++j) {
{
TEVStage& nstage = m_tevs[j]; TEVStage& nstage = m_tevs[j];
if (nstage.m_lazyAInIdx == stage.m_lazyAOutIdx) if (nstage.m_lazyAInIdx == stage.m_lazyAOutIdx)
for (int c=0 ; c<4 ; ++c) for (int c = 0; c < 4; ++c)
if (nstage.m_alpha[c] == CA_LAZY) if (nstage.m_alpha[c] == CA_LAZY)
nstage.m_alpha[c] = TevAlphaArg(CA_A0 + picked); nstage.m_alpha[c] = TevAlphaArg(CA_A0 + picked);
} }
@ -867,4 +696,4 @@ void GX::reset(const IR& ir, Diagnostics& diag)
} }
} }
} } // namespace hecl::Backend

View File

@ -6,41 +6,37 @@
static logvisor::Module Log("hecl::Backend::HLSL"); static logvisor::Module Log("hecl::Backend::HLSL");
namespace hecl::Backend namespace hecl::Backend {
{
std::string HLSL::EmitTexGenSource2(TexGenSrc src, int uvIdx) const std::string HLSL::EmitTexGenSource2(TexGenSrc src, int uvIdx) const {
{ switch (src) {
switch (src)
{
case TexGenSrc::Position: case TexGenSrc::Position:
return "objPos.xy\n"; return "objPos.xy\n";
case TexGenSrc::Normal: case TexGenSrc::Normal:
return "objNorm.xy\n"; return "objNorm.xy\n";
case TexGenSrc::UV: case TexGenSrc::UV:
return hecl::Format("v.uvIn[%u]", uvIdx); return hecl::Format("v.uvIn[%u]", uvIdx);
default: break; default:
break;
} }
return std::string(); return std::string();
} }
std::string HLSL::EmitTexGenSource4(TexGenSrc src, int uvIdx) const std::string HLSL::EmitTexGenSource4(TexGenSrc src, int uvIdx) const {
{ switch (src) {
switch (src)
{
case TexGenSrc::Position: case TexGenSrc::Position:
return "float4(objPos.xyz, 1.0)\n"; return "float4(objPos.xyz, 1.0)\n";
case TexGenSrc::Normal: case TexGenSrc::Normal:
return "float4(objNorm.xyz, 1.0)\n"; return "float4(objNorm.xyz, 1.0)\n";
case TexGenSrc::UV: case TexGenSrc::UV:
return hecl::Format("float4(v.uvIn[%u], 0.0, 1.0)", uvIdx); return hecl::Format("float4(v.uvIn[%u], 0.0, 1.0)", uvIdx);
default: break; default:
break;
} }
return std::string(); return std::string();
} }
std::string HLSL::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const std::string HLSL::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const {
{
std::string retval = std::string retval =
"struct VertData\n" "struct VertData\n"
"{\n" "{\n"
@ -59,8 +55,7 @@ std::string HLSL::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) co
return retval + "};\n"; return retval + "};\n";
} }
std::string HLSL::GenerateVertToFragStruct(size_t extTexCount, bool reflectionCoords) const std::string HLSL::GenerateVertToFragStruct(size_t extTexCount, bool reflectionCoords) const {
{
std::string retval = std::string retval =
"struct VertToFrag\n" "struct VertToFrag\n"
"{\n" "{\n"
@ -74,27 +69,26 @@ std::string HLSL::GenerateVertToFragStruct(size_t extTexCount, bool reflectionCo
retval += hecl::Format(" float2 extTcgs[%u] : EXTUV;\n", unsigned(extTexCount)); retval += hecl::Format(" float2 extTcgs[%u] : EXTUV;\n", unsigned(extTexCount));
if (reflectionCoords) if (reflectionCoords)
retval += " float2 reflectTcgs[2] : REFLECTUV;\n" retval +=
" float2 reflectTcgs[2] : REFLECTUV;\n"
" float reflectAlpha : REFLECTALPHA;\n"; " float reflectAlpha : REFLECTALPHA;\n";
return retval + "};\n"; return retval + "};\n";
} }
std::string HLSL::GenerateVertUniformStruct(unsigned skinSlots, bool reflectionCoords) const std::string HLSL::GenerateVertUniformStruct(unsigned skinSlots, bool reflectionCoords) const {
{
std::string retval; std::string retval;
if (skinSlots == 0) if (skinSlots == 0) {
{ retval =
retval = "cbuffer HECLVertUniform : register(b0)\n" "cbuffer HECLVertUniform : register(b0)\n"
"{\n" "{\n"
" float4x4 mv;\n" " float4x4 mv;\n"
" float4x4 mvInv;\n" " float4x4 mvInv;\n"
" float4x4 proj;\n" " float4x4 proj;\n"
"};\n"; "};\n";
} } else {
else retval = hecl::Format(
{ "cbuffer HECLVertUniform : register(b0)\n"
retval = hecl::Format("cbuffer HECLVertUniform : register(b0)\n"
"{\n" "{\n"
" float4x4 objs[%u];\n" " float4x4 objs[%u];\n"
" float4x4 objsInv[%u];\n" " float4x4 objsInv[%u];\n"
@ -104,7 +98,8 @@ std::string HLSL::GenerateVertUniformStruct(unsigned skinSlots, bool reflectionC
"};\n", "};\n",
skinSlots, skinSlots); skinSlots, skinSlots);
} }
retval += "struct TCGMtx\n" retval +=
"struct TCGMtx\n"
"{\n" "{\n"
" float4x4 mtx;\n" " float4x4 mtx;\n"
" float4x4 postMtx;\n" " float4x4 postMtx;\n"
@ -115,7 +110,8 @@ std::string HLSL::GenerateVertUniformStruct(unsigned skinSlots, bool reflectionC
"};\n"; "};\n";
if (reflectionCoords) if (reflectionCoords)
retval += "cbuffer HECLReflectMtx : register(b3)\n" retval +=
"cbuffer HECLReflectMtx : register(b3)\n"
"{\n" "{\n"
" float4x4 indMtx;\n" " float4x4 indMtx;\n"
" float4x4 reflectMtx;\n" " float4x4 reflectMtx;\n"
@ -126,18 +122,15 @@ std::string HLSL::GenerateVertUniformStruct(unsigned skinSlots, bool reflectionC
return retval; return retval;
} }
std::string HLSL::GenerateAlphaTest() const std::string HLSL::GenerateAlphaTest() const {
{
return " if (colorOut.a < 0.01)\n" return " if (colorOut.a < 0.01)\n"
" {\n" " {\n"
" discard;\n" " discard;\n"
" }\n"; " }\n";
} }
std::string HLSL::GenerateReflectionExpr(ReflectionType type) const std::string HLSL::GenerateReflectionExpr(ReflectionType type) const {
{ switch (type) {
switch (type)
{
case ReflectionType::None: case ReflectionType::None:
default: default:
return "float3(0.0, 0.0, 0.0)"; return "float3(0.0, 0.0, 0.0)";
@ -149,43 +142,41 @@ std::string HLSL::GenerateReflectionExpr(ReflectionType type) const
} }
} }
void HLSL::reset(const IR& ir, Diagnostics& diag) void HLSL::reset(const IR& ir, Diagnostics& diag) {
{
/* Common programmable interpretation */ /* Common programmable interpretation */
ProgrammableCommon::reset(ir, diag, "HLSL"); ProgrammableCommon::reset(ir, diag, "HLSL");
} }
std::string HLSL::makeVert(unsigned col, unsigned uv, unsigned w, std::string HLSL::makeVert(unsigned col, unsigned uv, unsigned w, unsigned s, size_t extTexCount,
unsigned s, size_t extTexCount, const TextureInfo* extTexs, ReflectionType reflectionType) const {
const TextureInfo* extTexs, ReflectionType reflectionType) const std::string retval = GenerateVertInStruct(col, uv, w) + "\n" +
{
std::string retval =
GenerateVertInStruct(col, uv, w) + "\n" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" + GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" +
GenerateVertUniformStruct(s, reflectionType != ReflectionType::None) + "\n" + GenerateVertUniformStruct(s, reflectionType != ReflectionType::None) + "\n" +
"VertToFrag main(in VertData v)\n" "VertToFrag main(in VertData v)\n"
"{\n" "{\n"
" VertToFrag vtf;\n"; " VertToFrag vtf;\n";
if (s) if (s) {
{
/* skinned */ /* skinned */
retval += " float4 objPos = float4(0.0,0.0,0.0,0.0);\n" retval +=
" float4 objPos = float4(0.0,0.0,0.0,0.0);\n"
" float4 objNorm = float4(0.0,0.0,0.0,0.0);\n"; " float4 objNorm = float4(0.0,0.0,0.0,0.0);\n";
for (size_t i=0 ; i<s ; ++i) for (size_t i = 0; i < s; ++i)
retval += hecl::Format(" objPos += mul(mv[%" PRISize "], float4(v.posIn, 1.0)) * v.weightIn[%" PRISize "][%" PRISize "];\n" retval += hecl::Format(
" objPos += mul(mv[%" PRISize "], float4(v.posIn, 1.0)) * v.weightIn[%" PRISize "][%" PRISize
"];\n"
" objNorm += mul(mvInv[%" PRISize "], float4(v.normIn, 1.0)) * v.weightIn[%" PRISize "][%" PRISize "];\n", " objNorm += mul(mvInv[%" PRISize "], float4(v.normIn, 1.0)) * v.weightIn[%" PRISize "][%" PRISize "];\n",
i, i/4, i%4, i, i/4, i%4); i, i / 4, i % 4, i, i / 4, i % 4);
retval += " objPos[3] = 1.0;\n" retval +=
" objPos[3] = 1.0;\n"
" objNorm = float4(normalize(objNorm.xyz), 0.0);\n" " objNorm = float4(normalize(objNorm.xyz), 0.0);\n"
" vtf.mvPos = mul(mv, objPos);\n" " vtf.mvPos = mul(mv, objPos);\n"
" vtf.mvNorm = float4(normalize(mul(mvInv, objNorm).xyz), 0.0);\n" " vtf.mvNorm = float4(normalize(mul(mvInv, objNorm).xyz), 0.0);\n"
" vtf.mvpPos = mul(proj, vtf.mvPos);\n"; " vtf.mvpPos = mul(proj, vtf.mvPos);\n";
} } else {
else
{
/* non-skinned */ /* non-skinned */
retval += " float4 objPos = float4(posIn, 1.0);\n" retval +=
" float4 objPos = float4(posIn, 1.0);\n"
" float4 objNorm = float4(normIn, 0.0);\n" " float4 objNorm = float4(normIn, 0.0);\n"
" vtf.mvPos = mul(mv, objPos);\n" " vtf.mvPos = mul(mv, objPos);\n"
" vtf.mvNorm = mul(mvInv, objNorm);\n" " vtf.mvNorm = mul(mvInv, objNorm);\n"
@ -195,51 +186,50 @@ std::string HLSL::makeVert(unsigned col, unsigned uv, unsigned w,
retval += " float4 tmpProj;\n"; retval += " float4 tmpProj;\n";
int tcgIdx = 0; int tcgIdx = 0;
for (const TexCoordGen& tcg : m_tcgs) for (const TexCoordGen& tcg : m_tcgs) {
{
if (tcg.m_mtx < 0) if (tcg.m_mtx < 0)
retval += hecl::Format(" vtf.tcgs[%u] = %s;\n", tcgIdx, retval += hecl::Format(" vtf.tcgs[%u] = %s;\n", tcgIdx, EmitTexGenSource2(tcg.m_src, tcg.m_uvIdx).c_str());
EmitTexGenSource2(tcg.m_src, tcg.m_uvIdx).c_str());
else else
retval += hecl::Format(" tmpProj = mul(texMtxs[%u].postMtx, float4(%s(mul(texMtxs[%u].mtx, %s).xyz), 1.0));\n" retval += hecl::Format(
" vtf.tcgs[%u] = (tmpProj / tmpProj.w).xy;\n", tcg.m_mtx, " tmpProj = mul(texMtxs[%u].postMtx, float4(%s(mul(texMtxs[%u].mtx, %s).xyz), 1.0));\n"
tcg.m_norm ? "normalize" : "", tcg.m_mtx, " vtf.tcgs[%u] = (tmpProj / tmpProj.w).xy;\n",
EmitTexGenSource4(tcg.m_src, tcg.m_uvIdx).c_str(), tcgIdx); tcg.m_mtx, tcg.m_norm ? "normalize" : "", tcg.m_mtx, EmitTexGenSource4(tcg.m_src, tcg.m_uvIdx).c_str(),
tcgIdx);
++tcgIdx; ++tcgIdx;
} }
for (int i=0 ; i<extTexCount ; ++i) for (int i = 0; i < extTexCount; ++i) {
{
const TextureInfo& extTex = extTexs[i]; const TextureInfo& extTex = extTexs[i];
if (extTex.mtxIdx < 0) if (extTex.mtxIdx < 0)
retval += hecl::Format(" vtf.extTcgs[%u] = %s;\n", i, retval += hecl::Format(" vtf.extTcgs[%u] = %s;\n", i, EmitTexGenSource2(extTex.src, extTex.uvIdx).c_str());
EmitTexGenSource2(extTex.src, extTex.uvIdx).c_str());
else else
retval += hecl::Format(" tmpProj = mul(texMtxs[%u].postMtx, float4(%s(mul(texMtxs[%u].mtx, %s).xyz), 1.0));\n" retval += hecl::Format(
" tmpProj = mul(texMtxs[%u].postMtx, float4(%s(mul(texMtxs[%u].mtx, %s).xyz), 1.0));\n"
" vtf.extTcgs[%u] = (tmpProj / tmpProj.w).xy;\n", " vtf.extTcgs[%u] = (tmpProj / tmpProj.w).xy;\n",
extTex.mtxIdx, extTex.normalize ? "normalize" : "", extTex.mtxIdx, extTex.mtxIdx, extTex.normalize ? "normalize" : "", extTex.mtxIdx,
EmitTexGenSource4(extTex.src, extTex.uvIdx).c_str(), i); EmitTexGenSource4(extTex.src, extTex.uvIdx).c_str(), i);
} }
if (reflectionType != ReflectionType::None) if (reflectionType != ReflectionType::None)
retval += " vtf.reflectTcgs[0] = normalize(mul(indMtx, float4(v.posIn, 1.0)).xz) * float2(0.5, 0.5) + float2(0.5, 0.5);\n" retval +=
" vtf.reflectTcgs[0] = normalize(mul(indMtx, float4(v.posIn, 1.0)).xz) * float2(0.5, 0.5) + float2(0.5, "
"0.5);\n"
" vtf.reflectTcgs[1] = mul(reflectMtx, float4(v.posIn, 1.0)).xy;\n" " vtf.reflectTcgs[1] = mul(reflectMtx, float4(v.posIn, 1.0)).xy;\n"
" vtf.reflectAlpha = reflectAlpha;\n"; " vtf.reflectAlpha = reflectAlpha;\n";
return retval + " return vtf;\n" return retval +
" return vtf;\n"
"}\n"; "}\n";
} }
std::string HLSL::makeFrag(size_t blockCount, const char** blockNames, std::string HLSL::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
bool alphaTest, ReflectionType reflectionType, BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting) const {
BlendFactor srcFactor, BlendFactor dstFactor,
const Function& lighting) const
{
std::string lightingSrc; std::string lightingSrc;
if (!lighting.m_source.empty()) if (!lighting.m_source.empty())
lightingSrc = lighting.m_source; lightingSrc = lighting.m_source;
else else
lightingSrc = "static const float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n" lightingSrc =
"static const float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 colorReg1 = float4(1.0, 1.0, 1.0, 1.0);\n" "static const float4 colorReg1 = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 colorReg2 = float4(1.0, 1.0, 1.0, 1.0);\n" "static const float4 colorReg2 = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n"; "static const float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n";
@ -248,27 +238,22 @@ std::string HLSL::makeFrag(size_t blockCount, const char** blockNames,
if (m_texMapEnd) if (m_texMapEnd)
texMapDecl = hecl::Format("Texture2D texs[%u] : register(t0);\n", m_texMapEnd); texMapDecl = hecl::Format("Texture2D texs[%u] : register(t0);\n", m_texMapEnd);
if (reflectionType == ReflectionType::Indirect) if (reflectionType == ReflectionType::Indirect)
texMapDecl += hecl::Format("Texture2D reflectionIndTex : register(t%u);\n" texMapDecl += hecl::Format(
"Texture2D reflectionIndTex : register(t%u);\n"
"Texture2D reflectionTex : register(t%u);\n", "Texture2D reflectionTex : register(t%u);\n",
m_texMapEnd, m_texMapEnd+1); m_texMapEnd, m_texMapEnd + 1);
else if (reflectionType == ReflectionType::Simple) else if (reflectionType == ReflectionType::Simple)
texMapDecl += hecl::Format("Texture2D reflectionTex : register(t%u);\n", texMapDecl += hecl::Format("Texture2D reflectionTex : register(t%u);\n", m_texMapEnd);
m_texMapEnd); std::string retval = std::string("#define BLEND_SRC_") + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" +
std::string retval =
std::string("#define BLEND_SRC_") + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" +
"#define BLEND_DST_" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" + "#define BLEND_DST_" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
"SamplerState samp : register(s0);\n" "SamplerState samp : register(s0);\n"
"SamplerState clampSamp : register(s1);\n" "SamplerState clampSamp : register(s1);\n"
"SamplerState reflectSamp : register(s2);\n" + "SamplerState reflectSamp : register(s2);\n" +
GenerateVertToFragStruct(0, reflectionType != ReflectionType::None) + GenerateVertToFragStruct(0, reflectionType != ReflectionType::None) + texMapDecl + "\n" +
texMapDecl + "\n" + lightingSrc + "\n" + (!alphaTest ? "\n[earlydepthstencil]\n" : "\n") +
lightingSrc + "\n" +
(!alphaTest ? "\n[earlydepthstencil]\n" : "\n") +
"float4 main(in VertToFrag vtf) : SV_Target0\n{\n"; "float4 main(in VertToFrag vtf) : SV_Target0\n{\n";
if (m_lighting) {
if (m_lighting)
{
if (!lighting.m_entry.empty()) if (!lighting.m_entry.empty())
retval += hecl::Format(" float4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n", retval += hecl::Format(" float4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n",
lighting.m_entry.data()); lighting.m_entry.data());
@ -278,8 +263,8 @@ std::string HLSL::makeFrag(size_t blockCount, const char** blockNames,
unsigned sampIdx = 0; unsigned sampIdx = 0;
for (const TexSampling& sampling : m_texSamplings) for (const TexSampling& sampling : m_texSamplings)
retval += hecl::Format(" float4 sampling%u = texs[%u].Sample(samp, vtf.tcgs[%u]);\n", retval += hecl::Format(" float4 sampling%u = texs[%u].Sample(samp, vtf.tcgs[%u]);\n", sampIdx++, sampling.mapIdx,
sampIdx++, sampling.mapIdx, sampling.tcgIdx); sampling.tcgIdx);
std::string reflectionExpr = GenerateReflectionExpr(reflectionType); std::string reflectionExpr = GenerateReflectionExpr(reflectionType);
@ -292,18 +277,15 @@ std::string HLSL::makeFrag(size_t blockCount, const char** blockNames,
return retval + (alphaTest ? GenerateAlphaTest() : "") + " return colorOut;\n}\n"; return retval + (alphaTest ? GenerateAlphaTest() : "") + " return colorOut;\n}\n";
} }
std::string HLSL::makeFrag(size_t blockCount, const char** blockNames, std::string HLSL::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
bool alphaTest, ReflectionType reflectionType, BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting, const Function& post,
BlendFactor srcFactor, BlendFactor dstFactor, size_t extTexCount, const TextureInfo* extTexs) const {
const Function& lighting,
const Function& post, size_t extTexCount,
const TextureInfo* extTexs) const
{
std::string lightingSrc; std::string lightingSrc;
if (!lighting.m_source.empty()) if (!lighting.m_source.empty())
lightingSrc = lighting.m_source; lightingSrc = lighting.m_source;
else else
lightingSrc = "static const float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n" lightingSrc =
"static const float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 colorReg1 = float4(1.0, 1.0, 1.0, 1.0);\n" "static const float4 colorReg1 = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 colorReg2 = float4(1.0, 1.0, 1.0, 1.0);\n" "static const float4 colorReg2 = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n"; "static const float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n";
@ -320,41 +302,32 @@ std::string HLSL::makeFrag(size_t blockCount, const char** blockNames,
if (m_texMapEnd) if (m_texMapEnd)
texMapDecl = hecl::Format("Texture2D texs[%u] : register(t0);\n", m_texMapEnd); texMapDecl = hecl::Format("Texture2D texs[%u] : register(t0);\n", m_texMapEnd);
if (reflectionType == ReflectionType::Indirect) if (reflectionType == ReflectionType::Indirect)
texMapDecl += hecl::Format("Texture2D reflectionIndTex : register(t%u);\n" texMapDecl += hecl::Format(
"Texture2D reflectionIndTex : register(t%u);\n"
"Texture2D reflectionTex : register(t%u);\n", "Texture2D reflectionTex : register(t%u);\n",
m_texMapEnd, m_texMapEnd+1); m_texMapEnd, m_texMapEnd + 1);
else if (reflectionType == ReflectionType::Simple) else if (reflectionType == ReflectionType::Simple)
texMapDecl += hecl::Format("Texture2D reflectionTex : register(t%u);\n", texMapDecl += hecl::Format("Texture2D reflectionTex : register(t%u);\n", m_texMapEnd);
m_texMapEnd);
uint32_t extTexBits = 0; uint32_t extTexBits = 0;
for (int i=0 ; i<extTexCount ; ++i) for (int i = 0; i < extTexCount; ++i) {
{
const TextureInfo& extTex = extTexs[i]; const TextureInfo& extTex = extTexs[i];
if (!(extTexBits & (1 << extTex.mapIdx))) if (!(extTexBits & (1 << extTex.mapIdx))) {
{ texMapDecl += hecl::Format("Texture2D extTex%u : register(t%u);\n", extTex.mapIdx, extTex.mapIdx);
texMapDecl += hecl::Format("Texture2D extTex%u : register(t%u);\n",
extTex.mapIdx, extTex.mapIdx);
extTexBits |= (1 << extTex.mapIdx); extTexBits |= (1 << extTex.mapIdx);
} }
} }
std::string retval = std::string retval = std::string("#define BLEND_SRC_") + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" +
std::string("#define BLEND_SRC_") + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" +
"#define BLEND_DST_" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" + "#define BLEND_DST_" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
"SamplerState samp : register(s0);\n" "SamplerState samp : register(s0);\n"
"SamplerState clampSamp : register(s1);\n" "SamplerState clampSamp : register(s1);\n"
"SamplerState reflectSamp : register(s2);\n" + "SamplerState reflectSamp : register(s2);\n" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + texMapDecl +
texMapDecl + "\n" + "\n" + lightingSrc + "\n" + postSrc + (!alphaTest ? "\n[earlydepthstencil]\n" : "\n") +
lightingSrc + "\n" +
postSrc +
(!alphaTest ? "\n[earlydepthstencil]\n" : "\n") +
"float4 main(in VertToFrag vtf) : SV_Target0\n{\n"; "float4 main(in VertToFrag vtf) : SV_Target0\n{\n";
if (m_lighting) {
if (m_lighting)
{
if (!lighting.m_entry.empty()) if (!lighting.m_entry.empty())
retval += hecl::Format(" float4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n", retval += hecl::Format(" float4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n",
lighting.m_entry.data()); lighting.m_entry.data());
@ -364,18 +337,20 @@ std::string HLSL::makeFrag(size_t blockCount, const char** blockNames,
unsigned sampIdx = 0; unsigned sampIdx = 0;
for (const TexSampling& sampling : m_texSamplings) for (const TexSampling& sampling : m_texSamplings)
retval += hecl::Format(" float4 sampling%u = texs[%u].Sample(samp, vtf.tcgs[%u]);\n", retval += hecl::Format(" float4 sampling%u = texs[%u].Sample(samp, vtf.tcgs[%u]);\n", sampIdx++, sampling.mapIdx,
sampIdx++, sampling.mapIdx, sampling.tcgIdx); sampling.tcgIdx);
std::string reflectionExpr = GenerateReflectionExpr(reflectionType); std::string reflectionExpr = GenerateReflectionExpr(reflectionType);
retval += " float4 colorOut;\n"; retval += " float4 colorOut;\n";
if (m_alphaExpr.size()) if (m_alphaExpr.size())
retval += " colorOut = " + postEntry + "(" + (postEntry.size() ? "vtf, " : "") + "float4(" + m_colorExpr + " + " + reflectionExpr + ", " + m_alphaExpr + ")) * mulColor;\n"; retval += " colorOut = " + postEntry + "(" + (postEntry.size() ? "vtf, " : "") + "float4(" + m_colorExpr +
" + " + reflectionExpr + ", " + m_alphaExpr + ")) * mulColor;\n";
else else
retval += " colorOut = " + postEntry + "(" + (postEntry.size() ? "vtf, " : "") + "float4(" + m_colorExpr + " + " + reflectionExpr + ", 1.0)) * mulColor;\n"; retval += " colorOut = " + postEntry + "(" + (postEntry.size() ? "vtf, " : "") + "float4(" + m_colorExpr +
" + " + reflectionExpr + ", 1.0)) * mulColor;\n";
return retval + (alphaTest ? GenerateAlphaTest() : "") + " return colorOut;\n}\n"; return retval + (alphaTest ? GenerateAlphaTest() : "") + " return colorOut;\n}\n";
} }
} } // namespace hecl::Backend

View File

@ -5,41 +5,37 @@
static logvisor::Module Log("hecl::Backend::Metal"); static logvisor::Module Log("hecl::Backend::Metal");
namespace hecl::Backend namespace hecl::Backend {
{
std::string Metal::EmitTexGenSource2(TexGenSrc src, int uvIdx) const std::string Metal::EmitTexGenSource2(TexGenSrc src, int uvIdx) const {
{ switch (src) {
switch (src)
{
case TexGenSrc::Position: case TexGenSrc::Position:
return "objPos.xy\n"; return "objPos.xy\n";
case TexGenSrc::Normal: case TexGenSrc::Normal:
return "objNorm.xy\n"; return "objNorm.xy\n";
case TexGenSrc::UV: case TexGenSrc::UV:
return hecl::Format("v.uvIn%u", uvIdx); return hecl::Format("v.uvIn%u", uvIdx);
default: break; default:
break;
} }
return std::string(); return std::string();
} }
std::string Metal::EmitTexGenSource4(TexGenSrc src, int uvIdx) const std::string Metal::EmitTexGenSource4(TexGenSrc src, int uvIdx) const {
{ switch (src) {
switch (src)
{
case TexGenSrc::Position: case TexGenSrc::Position:
return "float4(objPos.xyz, 1.0)\n"; return "float4(objPos.xyz, 1.0)\n";
case TexGenSrc::Normal: case TexGenSrc::Normal:
return "float4(objNorm.xyz, 1.0)\n"; return "float4(objNorm.xyz, 1.0)\n";
case TexGenSrc::UV: case TexGenSrc::UV:
return hecl::Format("float4(v.uvIn%u, 0.0, 1.0)", uvIdx); return hecl::Format("float4(v.uvIn%u, 0.0, 1.0)", uvIdx);
default: break; default:
break;
} }
return std::string(); return std::string();
} }
std::string Metal::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const std::string Metal::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const {
{
std::string retval = std::string retval =
"struct VertData\n" "struct VertData\n"
"{\n" "{\n"
@ -47,29 +43,25 @@ std::string Metal::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) c
" float3 normIn [[ attribute(1) ]];\n"; " float3 normIn [[ attribute(1) ]];\n";
unsigned idx = 2; unsigned idx = 2;
if (col) if (col) {
{ for (unsigned i = 0; i < col; ++i, ++idx)
for (unsigned i=0 ; i<col ; ++i, ++idx)
retval += hecl::Format(" float4 colIn%u [[ attribute(%u) ]];\n", i, idx); retval += hecl::Format(" float4 colIn%u [[ attribute(%u) ]];\n", i, idx);
} }
if (uv) if (uv) {
{ for (unsigned i = 0; i < uv; ++i, ++idx)
for (unsigned i=0 ; i<uv ; ++i, ++idx)
retval += hecl::Format(" float2 uvIn%u [[ attribute(%u) ]];\n", i, idx); retval += hecl::Format(" float2 uvIn%u [[ attribute(%u) ]];\n", i, idx);
} }
if (w) if (w) {
{ for (unsigned i = 0; i < w; ++i, ++idx)
for (unsigned i=0 ; i<w ; ++i, ++idx)
retval += hecl::Format(" float4 weightIn%u [[ attribute(%u) ]];\n", i, idx); retval += hecl::Format(" float4 weightIn%u [[ attribute(%u) ]];\n", i, idx);
} }
return retval + "};\n"; return retval + "};\n";
} }
std::string Metal::GenerateVertToFragStruct(size_t extTexCount, bool reflectionCoords) const std::string Metal::GenerateVertToFragStruct(size_t extTexCount, bool reflectionCoords) const {
{
std::string retval = std::string retval =
"struct VertToFrag\n" "struct VertToFrag\n"
"{\n" "{\n"
@ -78,26 +70,26 @@ std::string Metal::GenerateVertToFragStruct(size_t extTexCount, bool reflectionC
" float4 mvNorm;\n"; " float4 mvNorm;\n";
if (m_tcgs.size()) if (m_tcgs.size())
for (size_t i=0 ; i<m_tcgs.size() ; ++i) for (size_t i = 0; i < m_tcgs.size(); ++i)
retval += hecl::Format(" float2 tcgs%" PRISize ";\n", i); retval += hecl::Format(" float2 tcgs%" PRISize ";\n", i);
if (extTexCount) if (extTexCount)
for (size_t i=0 ; i<extTexCount ; ++i) for (size_t i = 0; i < extTexCount; ++i)
retval += hecl::Format(" float2 extTcgs%" PRISize ";\n", i); retval += hecl::Format(" float2 extTcgs%" PRISize ";\n", i);
if (reflectionCoords) if (reflectionCoords)
retval += " float2 reflectTcgs0;\n" retval +=
" float2 reflectTcgs0;\n"
" float2 reflectTcgs1;\n" " float2 reflectTcgs1;\n"
" float reflectAlpha;\n"; " float reflectAlpha;\n";
return retval + "};\n"; return retval + "};\n";
} }
std::string Metal::GenerateVertUniformStruct(unsigned skinSlots) const std::string Metal::GenerateVertUniformStruct(unsigned skinSlots) const {
{
std::string retval; std::string retval;
if (skinSlots == 0) if (skinSlots == 0) {
{ retval =
retval = "struct HECLVertUniform\n" "struct HECLVertUniform\n"
"{\n" "{\n"
" float4x4 mv;\n" " float4x4 mv;\n"
" float4x4 mvInv;\n" " float4x4 mvInv;\n"
@ -105,10 +97,9 @@ std::string Metal::GenerateVertUniformStruct(unsigned skinSlots) const
"};\n" "};\n"
"struct TexMtxs {float4x4 mtx; float4x4 postMtx;};\n" "struct TexMtxs {float4x4 mtx; float4x4 postMtx;};\n"
"struct ReflectTexMtxs {float4x4 indMtx; float4x4 reflectMtx; float reflectAlpha;};\n"; "struct ReflectTexMtxs {float4x4 indMtx; float4x4 reflectMtx; float reflectAlpha;};\n";
} } else {
else retval = hecl::Format(
{ "struct HECLVertUniform\n"
retval = hecl::Format("struct HECLVertUniform\n"
"{\n" "{\n"
" float4x4 objs[%u];\n" " float4x4 objs[%u];\n"
" float4x4 objsInv[%u];\n" " float4x4 objsInv[%u];\n"
@ -123,8 +114,7 @@ std::string Metal::GenerateVertUniformStruct(unsigned skinSlots) const
return retval; return retval;
} }
std::string Metal::GenerateFragOutStruct() const std::string Metal::GenerateFragOutStruct() const {
{
return "struct FragOut\n" return "struct FragOut\n"
"{\n" "{\n"
" float4 color [[ color(0) ]];\n" " float4 color [[ color(0) ]];\n"
@ -132,18 +122,15 @@ std::string Metal::GenerateFragOutStruct() const
"};\n"; "};\n";
} }
std::string Metal::GenerateAlphaTest() const std::string Metal::GenerateAlphaTest() const {
{
return " if (out.color.a < 0.01)\n" return " if (out.color.a < 0.01)\n"
" {\n" " {\n"
" discard_fragment();\n" " discard_fragment();\n"
" }\n"; " }\n";
} }
std::string Metal::GenerateReflectionExpr(ReflectionType type) const std::string Metal::GenerateReflectionExpr(ReflectionType type) const {
{ switch (type) {
switch (type)
{
case ReflectionType::None: case ReflectionType::None:
default: default:
return "float3(0.0, 0.0, 0.0)"; return "float3(0.0, 0.0, 0.0)";
@ -155,47 +142,47 @@ std::string Metal::GenerateReflectionExpr(ReflectionType type) const
} }
} }
void Metal::reset(const IR& ir, Diagnostics& diag) void Metal::reset(const IR& ir, Diagnostics& diag) {
{
/* Common programmable interpretation */ /* Common programmable interpretation */
ProgrammableCommon::reset(ir, diag, "Metal"); ProgrammableCommon::reset(ir, diag, "Metal");
} }
std::string Metal::makeVert(unsigned col, unsigned uv, unsigned w, std::string Metal::makeVert(unsigned col, unsigned uv, unsigned w, unsigned s, size_t extTexCount,
unsigned s, size_t extTexCount, const TextureInfo* extTexs, ReflectionType reflectionType) const {
const TextureInfo* extTexs, ReflectionType reflectionType) const
{
std::string tmStr = ",\nconstant TexMtxs* texMtxs [[ buffer(3) ]]"; std::string tmStr = ",\nconstant TexMtxs* texMtxs [[ buffer(3) ]]";
if (reflectionType != ReflectionType::None) if (reflectionType != ReflectionType::None)
tmStr += ",\nconstant ReflectTexMtxs& reflectMtxs [[ buffer(5) ]]"; tmStr += ",\nconstant ReflectTexMtxs& reflectMtxs [[ buffer(5) ]]";
std::string retval = "#include <metal_stdlib>\nusing namespace metal;\n" + std::string retval = "#include <metal_stdlib>\nusing namespace metal;\n" + GenerateVertInStruct(col, uv, w) + "\n" +
GenerateVertInStruct(col, uv, w) + "\n" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" + GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" +
GenerateVertUniformStruct(s) + GenerateVertUniformStruct(s) +
"\nvertex VertToFrag vmain(VertData v [[ stage_in ]],\n" "\nvertex VertToFrag vmain(VertData v [[ stage_in ]],\n"
" constant HECLVertUniform& vu [[ buffer(2) ]]" + tmStr + ")\n" " constant HECLVertUniform& vu [[ buffer(2) ]]" +
tmStr +
")\n"
"{\n" "{\n"
" VertToFrag vtf;\n"; " VertToFrag vtf;\n";
if (s) if (s) {
{
/* skinned */ /* skinned */
retval += " float4 objPos = float4(0.0,0.0,0.0,0.0);\n" retval +=
" float4 objPos = float4(0.0,0.0,0.0,0.0);\n"
" float4 objNorm = float4(0.0,0.0,0.0,0.0);\n"; " float4 objNorm = float4(0.0,0.0,0.0,0.0);\n";
for (size_t i=0 ; i<s ; ++i) for (size_t i = 0; i < s; ++i)
retval += hecl::Format(" objPos += (vu.objs[%" PRISize "] * float4(v.posIn, 1.0)) * v.weightIn%" PRISize "[%" PRISize "];\n" retval += hecl::Format(
" objPos += (vu.objs[%" PRISize "] * float4(v.posIn, 1.0)) * v.weightIn%" PRISize "[%" PRISize
"];\n"
" objNorm += (vu.objsInv[%" PRISize "] * float4(v.normIn, 1.0)) * v.weightIn%" PRISize "[%" PRISize "];\n", " objNorm += (vu.objsInv[%" PRISize "] * float4(v.normIn, 1.0)) * v.weightIn%" PRISize "[%" PRISize "];\n",
i, i/4, i%4, i, i/4, i%4); i, i / 4, i % 4, i, i / 4, i % 4);
retval += " objPos[3] = 1.0;\n" retval +=
" objPos[3] = 1.0;\n"
" objNorm = float4(normalize(objNorm.xyz), 0.0);\n" " objNorm = float4(normalize(objNorm.xyz), 0.0);\n"
" vtf.mvPos = vu.mv * objPos;\n" " vtf.mvPos = vu.mv * objPos;\n"
" vtf.mvNorm = float4(normalize((vu.mvInv * objNorm).xyz), 0.0);\n" " vtf.mvNorm = float4(normalize((vu.mvInv * objNorm).xyz), 0.0);\n"
" vtf.mvpPos = vu.proj * vtf.mvPos;\n"; " vtf.mvpPos = vu.proj * vtf.mvPos;\n";
} } else {
else
{
/* non-skinned */ /* non-skinned */
retval += " float4 objPos = float4(v.posIn, 1.0);\n" retval +=
" float4 objPos = float4(v.posIn, 1.0);\n"
" float4 objNorm = float4(v.normIn, 0.0);\n" " float4 objNorm = float4(v.normIn, 0.0);\n"
" vtf.mvPos = vu.mv * objPos;\n" " vtf.mvPos = vu.mv * objPos;\n"
" vtf.mvNorm = vu.mvInv * objNorm;\n" " vtf.mvNorm = vu.mvInv * objNorm;\n"
@ -205,98 +192,94 @@ std::string Metal::makeVert(unsigned col, unsigned uv, unsigned w,
retval += " float4 tmpProj;\n"; retval += " float4 tmpProj;\n";
int tcgIdx = 0; int tcgIdx = 0;
for (const TexCoordGen& tcg : m_tcgs) for (const TexCoordGen& tcg : m_tcgs) {
{
if (tcg.m_mtx < 0) if (tcg.m_mtx < 0)
retval += hecl::Format(" vtf.tcgs%u = %s;\n", tcgIdx, retval += hecl::Format(" vtf.tcgs%u = %s;\n", tcgIdx, EmitTexGenSource2(tcg.m_src, tcg.m_uvIdx).c_str());
EmitTexGenSource2(tcg.m_src, tcg.m_uvIdx).c_str());
else else
retval += hecl::Format(" tmpProj = texMtxs[%u].postMtx * float4(%s((texMtxs[%u].mtx * %s).xyz), 1.0);\n" retval += hecl::Format(
" vtf.tcgs%u = (tmpProj / tmpProj.w).xy;\n", tcg.m_mtx, " tmpProj = texMtxs[%u].postMtx * float4(%s((texMtxs[%u].mtx * %s).xyz), 1.0);\n"
tcg.m_norm ? "normalize" : "", tcg.m_mtx, " vtf.tcgs%u = (tmpProj / tmpProj.w).xy;\n",
EmitTexGenSource4(tcg.m_src, tcg.m_uvIdx).c_str(), tcgIdx); tcg.m_mtx, tcg.m_norm ? "normalize" : "", tcg.m_mtx, EmitTexGenSource4(tcg.m_src, tcg.m_uvIdx).c_str(),
tcgIdx);
++tcgIdx; ++tcgIdx;
} }
for (int i=0 ; i<extTexCount ; ++i) for (int i = 0; i < extTexCount; ++i) {
{
const TextureInfo& extTex = extTexs[i]; const TextureInfo& extTex = extTexs[i];
if (extTex.mtxIdx < 0) if (extTex.mtxIdx < 0)
retval += hecl::Format(" vtf.extTcgs%u = %s;\n", i, retval += hecl::Format(" vtf.extTcgs%u = %s;\n", i, EmitTexGenSource2(extTex.src, extTex.uvIdx).c_str());
EmitTexGenSource2(extTex.src, extTex.uvIdx).c_str());
else else
retval += hecl::Format(" tmpProj = texMtxs[%u].postMtx * float4(%s((texMtxs[%u].mtx * %s).xyz), 1.0);\n" retval += hecl::Format(
" vtf.extTcgs%u = (tmpProj / tmpProj.w).xy;\n", extTex.mtxIdx, " tmpProj = texMtxs[%u].postMtx * float4(%s((texMtxs[%u].mtx * %s).xyz), 1.0);\n"
extTex.normalize ? "normalize" : "", extTex.mtxIdx, " vtf.extTcgs%u = (tmpProj / tmpProj.w).xy;\n",
extTex.mtxIdx, extTex.normalize ? "normalize" : "", extTex.mtxIdx,
EmitTexGenSource4(extTex.src, extTex.uvIdx).c_str(), i); EmitTexGenSource4(extTex.src, extTex.uvIdx).c_str(), i);
} }
if (reflectionType != ReflectionType::None) if (reflectionType != ReflectionType::None)
retval += " vtf.reflectTcgs0 = normalize((reflectMtxs.indMtx * float4(v.posIn, 1.0)).xz) * float2(0.5, 0.5) + float2(0.5, 0.5);\n" retval +=
" vtf.reflectTcgs0 = normalize((reflectMtxs.indMtx * float4(v.posIn, 1.0)).xz) * float2(0.5, 0.5) + "
"float2(0.5, 0.5);\n"
" vtf.reflectTcgs1 = (reflectMtxs.reflectMtx * float4(v.posIn, 1.0)).xy;\n" " vtf.reflectTcgs1 = (reflectMtxs.reflectMtx * float4(v.posIn, 1.0)).xy;\n"
" vtf.reflectAlpha = reflectMtxs.reflectAlpha;\n"; " vtf.reflectAlpha = reflectMtxs.reflectAlpha;\n";
return retval + " return vtf;\n}\n"; return retval + " return vtf;\n}\n";
} }
std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
ReflectionType reflectionType, BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting) const {
BlendFactor srcFactor, BlendFactor dstFactor,
const Function& lighting) const
{
std::string lightingSrc; std::string lightingSrc;
if (!lighting.m_source.empty()) if (!lighting.m_source.empty())
lightingSrc = lighting.m_source; lightingSrc = lighting.m_source;
std::string texMapDecl; std::string texMapDecl;
if (m_texMapEnd) if (m_texMapEnd)
for (int i=0 ; i<m_texMapEnd ; ++i) for (int i = 0; i < m_texMapEnd; ++i)
texMapDecl += hecl::Format(",\ntexture2d<float> tex%u [[ texture(%u) ]]", i, i); texMapDecl += hecl::Format(",\ntexture2d<float> tex%u [[ texture(%u) ]]", i, i);
if (reflectionType == ReflectionType::Indirect) if (reflectionType == ReflectionType::Indirect)
texMapDecl += hecl::Format(",\ntexture2d<float> reflectionIndTex [[ texture(%u) ]]\n" texMapDecl += hecl::Format(
",\ntexture2d<float> reflectionIndTex [[ texture(%u) ]]\n"
",\ntexture2d<float> reflectionTex [[ texture(%u) ]]\n", ",\ntexture2d<float> reflectionTex [[ texture(%u) ]]\n",
m_texMapEnd, m_texMapEnd+1); m_texMapEnd, m_texMapEnd + 1);
else if (reflectionType == ReflectionType::Simple) else if (reflectionType == ReflectionType::Simple)
texMapDecl += hecl::Format(",\ntexture2d<float> reflectionTex [[ texture(%u) ]]\n", texMapDecl += hecl::Format(",\ntexture2d<float> reflectionTex [[ texture(%u) ]]\n", m_texMapEnd);
m_texMapEnd);
std::string blockCall; std::string blockCall;
for (size_t i=0 ; i<blockCount ; ++i) for (size_t i = 0; i < blockCount; ++i) {
{
texMapDecl += hecl::Format(",\nconstant %s& block%" PRISize " [[ buffer(%" PRISize ") ]]", blockNames[i], i, i + 4); texMapDecl += hecl::Format(",\nconstant %s& block%" PRISize " [[ buffer(%" PRISize ") ]]", blockNames[i], i, i + 4);
if (blockCall.size()) if (blockCall.size())
blockCall += ", "; blockCall += ", ";
blockCall += hecl::Format("block%" PRISize, i); blockCall += hecl::Format("block%" PRISize, i);
} }
std::string retval = std::string("#include <metal_stdlib>\nusing namespace metal;\n") + std::string retval =
"#define BLEND_SRC_" + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" + std::string("#include <metal_stdlib>\nusing namespace metal;\n") + "#define BLEND_SRC_" +
"#define BLEND_DST_" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" + "#define BLEND_DST_" +
GenerateVertToFragStruct(0, reflectionType != ReflectionType::None) + "\n" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
GenerateFragOutStruct() + "\n" + GenerateVertToFragStruct(0, reflectionType != ReflectionType::None) + "\n" + GenerateFragOutStruct() + "\n" +
lightingSrc + "\n" + lightingSrc + "\n" +
"fragment FragOut fmain(VertToFrag vtf [[ stage_in ]],\n" "fragment FragOut fmain(VertToFrag vtf [[ stage_in ]],\n"
"sampler samp [[ sampler(0) ]], sampler clampSamp [[ sampler(1) ]], sampler reflectSamp [[ sampler(2) ]]" + texMapDecl + ")\n" "sampler samp [[ sampler(0) ]], sampler clampSamp [[ sampler(1) ]], sampler reflectSamp [[ sampler(2) ]]" +
texMapDecl +
")\n"
"{\n" "{\n"
" FragOut out;\n"; " FragOut out;\n";
if (!lighting.m_source.empty()) if (!lighting.m_source.empty()) {
{ retval +=
retval += " float4 colorReg0 = block0.colorReg0;\n" " float4 colorReg0 = block0.colorReg0;\n"
" float4 colorReg1 = block0.colorReg1;\n" " float4 colorReg1 = block0.colorReg1;\n"
" float4 colorReg2 = block0.colorReg2;\n" " float4 colorReg2 = block0.colorReg2;\n"
" float4 mulColor = block0.mulColor;\n"; " float4 mulColor = block0.mulColor;\n";
} } else {
else retval +=
{ " float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n"
retval += " float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 colorReg1 = float4(1.0, 1.0, 1.0, 1.0);\n" " float4 colorReg1 = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 colorReg2 = float4(1.0, 1.0, 1.0, 1.0);\n" " float4 colorReg2 = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n"; " float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n";
} }
if (m_lighting) if (m_lighting) {
{
if (!lighting.m_entry.empty()) if (!lighting.m_entry.empty())
retval += hecl::Format(" float4 lighting = %s(%s, vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n", retval += hecl::Format(" float4 lighting = %s(%s, vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n",
lighting.m_entry.data(), blockCall.c_str()); lighting.m_entry.data(), blockCall.c_str());
@ -306,8 +289,8 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp
unsigned sampIdx = 0; unsigned sampIdx = 0;
for (const TexSampling& sampling : m_texSamplings) for (const TexSampling& sampling : m_texSamplings)
retval += hecl::Format(" float4 sampling%u = tex%u.sample(samp, vtf.tcgs%u);\n", retval += hecl::Format(" float4 sampling%u = tex%u.sample(samp, vtf.tcgs%u);\n", sampIdx++, sampling.mapIdx,
sampIdx++, sampling.mapIdx, sampling.tcgIdx); sampling.tcgIdx);
std::string reflectionExpr = GenerateReflectionExpr(reflectionType); std::string reflectionExpr = GenerateReflectionExpr(reflectionType);
@ -322,13 +305,9 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp
"}\n"; "}\n";
} }
std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
ReflectionType reflectionType, BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting,
BlendFactor srcFactor, BlendFactor dstFactor, const Function& post, size_t extTexCount, const TextureInfo* extTexs) const {
const Function& lighting,
const Function& post, size_t extTexCount,
const TextureInfo* extTexs) const
{
std::string lightingSrc; std::string lightingSrc;
if (!lighting.m_source.empty()) if (!lighting.m_source.empty())
lightingSrc = lighting.m_source; lightingSrc = lighting.m_source;
@ -346,32 +325,29 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp
postEntry = post.m_entry; postEntry = post.m_entry;
int extTexBits = 0; int extTexBits = 0;
for (int i=0 ; i<extTexCount ; ++i) for (int i = 0; i < extTexCount; ++i) {
{
const TextureInfo& extTex = extTexs[i]; const TextureInfo& extTex = extTexs[i];
extTexBits |= 1 << extTex.mapIdx; extTexBits |= 1 << extTex.mapIdx;
} }
std::string texMapDecl; std::string texMapDecl;
if (m_texMapEnd) if (m_texMapEnd)
for (int i=0 ; i<m_texMapEnd ; ++i) for (int i = 0; i < m_texMapEnd; ++i)
if (!(extTexBits & (1 << i))) if (!(extTexBits & (1 << i)))
texMapDecl += hecl::Format(",\ntexture2d<float> tex%u [[ texture(%u) ]]", i, i); texMapDecl += hecl::Format(",\ntexture2d<float> tex%u [[ texture(%u) ]]", i, i);
if (reflectionType == ReflectionType::Indirect) if (reflectionType == ReflectionType::Indirect)
texMapDecl += hecl::Format(",\ntexture2d<float> reflectionIndTex [[ texture(%u) ]]\n" texMapDecl += hecl::Format(
",\ntexture2d<float> reflectionIndTex [[ texture(%u) ]]\n"
",\ntexture2d<float> reflectionTex [[ texture(%u) ]]\n", ",\ntexture2d<float> reflectionTex [[ texture(%u) ]]\n",
m_texMapEnd, m_texMapEnd+1); m_texMapEnd, m_texMapEnd + 1);
else if (reflectionType == ReflectionType::Simple) else if (reflectionType == ReflectionType::Simple)
texMapDecl += hecl::Format(",\ntexture2d<float> reflectionTex [[ texture(%u) ]]\n", texMapDecl += hecl::Format(",\ntexture2d<float> reflectionTex [[ texture(%u) ]]\n", m_texMapEnd);
m_texMapEnd);
std::string extTexCall; std::string extTexCall;
int extTexBits2 = 0; int extTexBits2 = 0;
for (int i=0 ; i<extTexCount ; ++i) for (int i = 0; i < extTexCount; ++i) {
{
const TextureInfo& extTex = extTexs[i]; const TextureInfo& extTex = extTexs[i];
if (!(extTexBits2 & (1 << extTex.mapIdx))) if (!(extTexBits2 & (1 << extTex.mapIdx))) {
{
if (extTexCall.size()) if (extTexCall.size())
extTexCall += ", "; extTexCall += ", ";
extTexCall += hecl::Format("tex%u", extTex.mapIdx); extTexCall += hecl::Format("tex%u", extTex.mapIdx);
@ -381,71 +357,74 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp
} }
std::string blockCall; std::string blockCall;
for (size_t i=0 ; i<blockCount ; ++i) for (size_t i = 0; i < blockCount; ++i) {
{
texMapDecl += hecl::Format(",\nconstant %s& block%" PRISize " [[ buffer(%" PRISize ") ]]", blockNames[i], i, i + 4); texMapDecl += hecl::Format(",\nconstant %s& block%" PRISize " [[ buffer(%" PRISize ") ]]", blockNames[i], i, i + 4);
if (blockCall.size()) if (blockCall.size())
blockCall += ", "; blockCall += ", ";
blockCall += hecl::Format("block%" PRISize, i); blockCall += hecl::Format("block%" PRISize, i);
} }
std::string retval = std::string("#include <metal_stdlib>\nusing namespace metal;\n") + std::string retval =
"#define BLEND_SRC_" + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" + std::string("#include <metal_stdlib>\nusing namespace metal;\n") + "#define BLEND_SRC_" +
"#define BLEND_DST_" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" + "#define BLEND_DST_" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
GenerateFragOutStruct() + "\n" + GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" + GenerateFragOutStruct() +
lightingSrc + "\n" + "\n" + lightingSrc + "\n" + postSrc + "\n" +
postSrc + "\n" +
"fragment FragOut fmain(VertToFrag vtf [[ stage_in ]],\n" "fragment FragOut fmain(VertToFrag vtf [[ stage_in ]],\n"
"sampler samp [[ sampler(0) ]], sampler clampSamp [[ sampler(1) ]], sampler reflectSamp [[ sampler(2) ]]" + texMapDecl + ")\n" "sampler samp [[ sampler(0) ]], sampler clampSamp [[ sampler(1) ]], sampler reflectSamp [[ sampler(2) ]]" +
texMapDecl +
")\n"
"{\n" "{\n"
" FragOut out;\n"; " FragOut out;\n";
if (!lighting.m_source.empty()) if (!lighting.m_source.empty()) {
{ retval +=
retval += " float4 colorReg0 = block0.colorReg0;\n" " float4 colorReg0 = block0.colorReg0;\n"
" float4 colorReg1 = block0.colorReg1;\n" " float4 colorReg1 = block0.colorReg1;\n"
" float4 colorReg2 = block0.colorReg2;\n" " float4 colorReg2 = block0.colorReg2;\n"
" float4 mulColor = block0.mulColor;\n"; " float4 mulColor = block0.mulColor;\n";
} } else {
else retval +=
{ " float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n"
retval += " float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 colorReg1 = float4(1.0, 1.0, 1.0, 1.0);\n" " float4 colorReg1 = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 colorReg2 = float4(1.0, 1.0, 1.0, 1.0);\n" " float4 colorReg2 = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n"; " float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n";
} }
if (m_lighting) if (m_lighting) {
{ if (!lighting.m_entry.empty()) {
if (!lighting.m_entry.empty()) retval +=
{ " float4 lighting = " + lightingEntry + "(" + blockCall +
retval += " float4 lighting = " + lightingEntry + "(" + blockCall + ", vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf" + ", vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf" +
(!strncmp(lighting.m_entry.data(), "EXT", 3) ? (extTexCall.size() ? (", samp, clampSamp," + extTexCall) : "") : "") + ");\n"; (!strncmp(lighting.m_entry.data(), "EXT", 3) ? (extTexCall.size() ? (", samp, clampSamp," + extTexCall) : "")
} : "") +
else ");\n";
} else
retval += " float4 lighting = float4(1.0,1.0,1.0,1.0);\n"; retval += " float4 lighting = float4(1.0,1.0,1.0,1.0);\n";
} }
unsigned sampIdx = 0; unsigned sampIdx = 0;
for (const TexSampling& sampling : m_texSamplings) for (const TexSampling& sampling : m_texSamplings)
retval += hecl::Format(" float4 sampling%u = tex%u.sample(samp, vtf.tcgs%u);\n", retval += hecl::Format(" float4 sampling%u = tex%u.sample(samp, vtf.tcgs%u);\n", sampIdx++, sampling.mapIdx,
sampIdx++, sampling.mapIdx, sampling.tcgIdx); sampling.tcgIdx);
std::string reflectionExpr = GenerateReflectionExpr(reflectionType); std::string reflectionExpr = GenerateReflectionExpr(reflectionType);
if (m_alphaExpr.size()) if (m_alphaExpr.size()) {
{
retval += " out.color = " + postEntry + "(" + retval += " out.color = " + postEntry + "(" +
(postEntry.size() ? ("vtf, " + (blockCall.size() ? (blockCall + ", ") : "") + (postEntry.size() ? ("vtf, " + (blockCall.size() ? (blockCall + ", ") : "") +
(!strncmp(post.m_entry.data(), "EXT", 3) ? (extTexCall.size() ? ("samp, clampSamp," + extTexCall + ", ") : "") : "")) : "") + (!strncmp(post.m_entry.data(), "EXT", 3)
? (extTexCall.size() ? ("samp, clampSamp," + extTexCall + ", ") : "")
: ""))
: "") +
"float4(" + m_colorExpr + " + " + reflectionExpr + ", " + m_alphaExpr + ")) * mulColor;\n"; "float4(" + m_colorExpr + " + " + reflectionExpr + ", " + m_alphaExpr + ")) * mulColor;\n";
} } else {
else
{
retval += " out.color = " + postEntry + "(" + retval += " out.color = " + postEntry + "(" +
(postEntry.size() ? ("vtf, " + (blockCall.size() ? (blockCall + ", ") : "") + (postEntry.size() ? ("vtf, " + (blockCall.size() ? (blockCall + ", ") : "") +
(!strncmp(post.m_entry.data(), "EXT", 3) ? (extTexCall.size() ? ("samp, clampSamp," + extTexCall + ", ") : "") : "")) : "") + (!strncmp(post.m_entry.data(), "EXT", 3)
? (extTexCall.size() ? ("samp, clampSamp," + extTexCall + ", ") : "")
: ""))
: "") +
"float4(" + m_colorExpr + " + " + reflectionExpr + ", 1.0)) * mulColor;\n"; "float4(" + m_colorExpr + " + " + reflectionExpr + ", 1.0)) * mulColor;\n";
} }
@ -455,5 +434,4 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp
"}\n"; "}\n";
} }
} } // namespace hecl::Backend

View File

@ -1,13 +1,10 @@
#include "hecl/Backend/ProgrammableCommon.hpp" #include "hecl/Backend/ProgrammableCommon.hpp"
#include <map> #include <map>
namespace hecl::Backend namespace hecl::Backend {
{
const char* ProgrammableCommon::BlendFactorToDefine(BlendFactor factor, BlendFactor defaultFactor) const char* ProgrammableCommon::BlendFactorToDefine(BlendFactor factor, BlendFactor defaultFactor) {
{ switch (factor) {
switch (factor)
{
case BlendFactor::Zero: case BlendFactor::Zero:
return "ZERO"; return "ZERO";
case BlendFactor::One: case BlendFactor::One:
@ -37,10 +34,8 @@ const char* ProgrammableCommon::BlendFactorToDefine(BlendFactor factor, BlendFac
} }
} }
unsigned ProgrammableCommon::addTexCoordGen(TexGenSrc src, int uvIdx, int mtx, bool normalize) unsigned ProgrammableCommon::addTexCoordGen(TexGenSrc src, int uvIdx, int mtx, bool normalize) {
{ for (unsigned i = 0; i < m_tcgs.size(); ++i) {
for (unsigned i=0 ; i<m_tcgs.size() ; ++i)
{
TexCoordGen& tcg = m_tcgs[i]; TexCoordGen& tcg = m_tcgs[i];
if (tcg.m_src == src && tcg.m_uvIdx == uvIdx && tcg.m_mtx == mtx && tcg.m_norm == normalize) if (tcg.m_src == src && tcg.m_uvIdx == uvIdx && tcg.m_mtx == mtx && tcg.m_norm == normalize)
return i; return i;
@ -54,10 +49,8 @@ unsigned ProgrammableCommon::addTexCoordGen(TexGenSrc src, int uvIdx, int mtx, b
return m_tcgs.size() - 1; return m_tcgs.size() - 1;
} }
unsigned ProgrammableCommon::addTexSampling(unsigned mapIdx, unsigned tcgIdx) unsigned ProgrammableCommon::addTexSampling(unsigned mapIdx, unsigned tcgIdx) {
{ for (unsigned i = 0; i < m_texSamplings.size(); ++i) {
for (unsigned i=0 ; i<m_texSamplings.size() ; ++i)
{
TexSampling& samp = m_texSamplings[i]; TexSampling& samp = m_texSamplings[i];
if (samp.mapIdx == mapIdx && samp.tcgIdx == tcgIdx) if (samp.mapIdx == mapIdx && samp.tcgIdx == tcgIdx)
return i; return i;
@ -71,53 +64,44 @@ unsigned ProgrammableCommon::addTexSampling(unsigned mapIdx, unsigned tcgIdx)
return m_texSamplings.size() - 1; return m_texSamplings.size() - 1;
} }
unsigned ProgrammableCommon::RecursiveTraceTexGen(const IR& ir, Diagnostics& diag, unsigned ProgrammableCommon::RecursiveTraceTexGen(const IR& ir, Diagnostics& diag, const IR::Instruction& inst, int mtx,
const IR::Instruction& inst, int mtx, bool normalize) bool normalize) {
{
if (inst.m_op != IR::OpType::Call) if (inst.m_op != IR::OpType::Call)
diag.reportBackendErr(inst.m_loc, "TexCoordGen resolution requires function"); diag.reportBackendErr(inst.m_loc, "TexCoordGen resolution requires function");
const std::string& tcgName = inst.m_call.m_name; const std::string& tcgName = inst.m_call.m_name;
if (!tcgName.compare("UV")) if (!tcgName.compare("UV")) {
{
if (inst.getChildCount() < 1) if (inst.getChildCount() < 1)
diag.reportBackendErr(inst.m_loc, "TexCoordGen UV(layerIdx) requires one argument"); diag.reportBackendErr(inst.m_loc, "TexCoordGen UV(layerIdx) requires one argument");
const IR::Instruction& idxInst = inst.getChildInst(ir, 0); const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
auto& idxImm = idxInst.getImmVec(); auto& idxImm = idxInst.getImmVec();
return addTexCoordGen(TexGenSrc::UV, int(idxImm.simd[0]), mtx, normalize); return addTexCoordGen(TexGenSrc::UV, int(idxImm.simd[0]), mtx, normalize);
} } else if (!tcgName.compare("Normal"))
else if (!tcgName.compare("Normal"))
return addTexCoordGen(TexGenSrc::Normal, -1, mtx, normalize); return addTexCoordGen(TexGenSrc::Normal, -1, mtx, normalize);
else if (!tcgName.compare("View")) else if (!tcgName.compare("View"))
return addTexCoordGen(TexGenSrc::Position, -1, mtx, normalize); return addTexCoordGen(TexGenSrc::Position, -1, mtx, normalize);
/* Otherwise treat as game-specific function */ /* Otherwise treat as game-specific function */
const IR::Instruction& tcgSrcInst = inst.getChildInst(ir, 0); const IR::Instruction& tcgSrcInst = inst.getChildInst(ir, 0);
unsigned idx = RecursiveTraceTexGen(ir, diag, tcgSrcInst, m_texMtxRefs.size(), unsigned idx = RecursiveTraceTexGen(ir, diag, tcgSrcInst, m_texMtxRefs.size(), normalize || tcgName.back() == 'N');
normalize || tcgName.back() == 'N');
TexCoordGen& tcg = m_tcgs[idx]; TexCoordGen& tcg = m_tcgs[idx];
m_texMtxRefs.push_back(idx); m_texMtxRefs.push_back(idx);
tcg.m_gameFunction = tcgName; tcg.m_gameFunction = tcgName;
tcg.m_gameArgs.clear(); tcg.m_gameArgs.clear();
for (int i=1 ; i<inst.getChildCount() ; ++i) for (int i = 1; i < inst.getChildCount(); ++i) {
{
const IR::Instruction& ci = inst.getChildInst(ir, i); const IR::Instruction& ci = inst.getChildInst(ir, i);
tcg.m_gameArgs.push_back(ci.getImmVec()); tcg.m_gameArgs.push_back(ci.getImmVec());
} }
return idx; return idx;
} }
std::string ProgrammableCommon::RecursiveTraceColor(const IR& ir, Diagnostics& diag, std::string ProgrammableCommon::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const IR::Instruction& inst,
const IR::Instruction& inst, bool toSwizzle) bool toSwizzle) {
{ switch (inst.m_op) {
switch (inst.m_op) case IR::OpType::Call: {
{
case IR::OpType::Call:
{
const std::string& name = inst.m_call.m_name; const std::string& name = inst.m_call.m_name;
bool normalize = false; bool normalize = false;
if (!name.compare("Texture") || (normalize = true && !name.compare("TextureN"))) if (!name.compare("Texture") || (normalize = true && !name.compare("TextureN"))) {
{
if (inst.getChildCount() < 2) if (inst.getChildCount() < 2)
diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments"); diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments");
@ -128,72 +112,56 @@ std::string ProgrammableCommon::RecursiveTraceColor(const IR& ir, Diagnostics& d
const IR::Instruction& tcgInst = inst.getChildInst(ir, 1); const IR::Instruction& tcgInst = inst.getChildInst(ir, 1);
unsigned texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, -1, normalize); unsigned texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, -1, normalize);
return toSwizzle ? EmitSamplingUseRaw(addTexSampling(mapIdx, texGenIdx)) : return toSwizzle ? EmitSamplingUseRaw(addTexSampling(mapIdx, texGenIdx))
EmitSamplingUseRGB(addTexSampling(mapIdx, texGenIdx)); : EmitSamplingUseRGB(addTexSampling(mapIdx, texGenIdx));
} } else if (!name.compare("ColorReg")) {
else if (!name.compare("ColorReg"))
{
const IR::Instruction& idxInst = inst.getChildInst(ir, 0); const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
unsigned idx = unsigned(idxInst.getImmVec().simd[0]); unsigned idx = unsigned(idxInst.getImmVec().simd[0]);
return toSwizzle ? EmitColorRegUseRaw(idx) : EmitColorRegUseRGB(idx); return toSwizzle ? EmitColorRegUseRaw(idx) : EmitColorRegUseRGB(idx);
} } else if (!name.compare("Lighting")) {
else if (!name.compare("Lighting"))
{
m_lighting = true; m_lighting = true;
return toSwizzle ? EmitLightingRaw() : EmitLightingRGB(); return toSwizzle ? EmitLightingRaw() : EmitLightingRGB();
} } else if (!name.compare("vec3")) {
else if (!name.compare("vec3"))
{
if (inst.getChildCount() < 3) if (inst.getChildCount() < 3)
diag.reportBackendErr(inst.m_loc, "vec3(r,g,b) requires 3 arguments"); diag.reportBackendErr(inst.m_loc, "vec3(r,g,b) requires 3 arguments");
const IR::Instruction& aInst = inst.getChildInst(ir, 0); const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1); const IR::Instruction& bInst = inst.getChildInst(ir, 1);
const IR::Instruction& cInst = inst.getChildInst(ir, 2); const IR::Instruction& cInst = inst.getChildInst(ir, 2);
return EmitVec3(RecursiveTraceAlpha(ir, diag, aInst, false), return EmitVec3(RecursiveTraceAlpha(ir, diag, aInst, false), RecursiveTraceAlpha(ir, diag, bInst, false),
RecursiveTraceAlpha(ir, diag, bInst, false),
RecursiveTraceAlpha(ir, diag, cInst, false)); RecursiveTraceAlpha(ir, diag, cInst, false));
} } else
else
diag.reportBackendErr(inst.m_loc, "unable to interpret '%s'", name.c_str()); diag.reportBackendErr(inst.m_loc, "unable to interpret '%s'", name.c_str());
break; break;
} }
case IR::OpType::LoadImm: case IR::OpType::LoadImm: {
{
const atVec4f& vec = inst.m_loadImm.m_immVec; const atVec4f& vec = inst.m_loadImm.m_immVec;
return EmitVec3(vec); return EmitVec3(vec);
} }
case IR::OpType::Arithmetic: case IR::OpType::Arithmetic: {
{
ArithmeticOp op = inst.m_arithmetic.m_op; ArithmeticOp op = inst.m_arithmetic.m_op;
const IR::Instruction& aInst = inst.getChildInst(ir, 0); const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1); const IR::Instruction& bInst = inst.getChildInst(ir, 1);
std::string aTrace = RecursiveTraceColor(ir, diag, aInst, false); std::string aTrace = RecursiveTraceColor(ir, diag, aInst, false);
std::string bTrace = RecursiveTraceColor(ir, diag, bInst, false); std::string bTrace = RecursiveTraceColor(ir, diag, bInst, false);
switch (op) switch (op) {
{ case ArithmeticOp::Add: {
case ArithmeticOp::Add:
{
return EmitAdd(aTrace, bTrace); return EmitAdd(aTrace, bTrace);
} }
case ArithmeticOp::Subtract: case ArithmeticOp::Subtract: {
{
return EmitSub(aTrace, bTrace); return EmitSub(aTrace, bTrace);
} }
case ArithmeticOp::Multiply: case ArithmeticOp::Multiply: {
{
return EmitMult(aTrace, bTrace); return EmitMult(aTrace, bTrace);
} }
case ArithmeticOp::Divide: case ArithmeticOp::Divide: {
{
return EmitDiv(aTrace, bTrace); return EmitDiv(aTrace, bTrace);
} }
default: default:
diag.reportBackendErr(inst.m_loc, "invalid arithmetic op"); diag.reportBackendErr(inst.m_loc, "invalid arithmetic op");
} }
} }
case IR::OpType::Swizzle: case IR::OpType::Swizzle: {
{
const IR::Instruction& aInst = inst.getChildInst(ir, 0); const IR::Instruction& aInst = inst.getChildInst(ir, 0);
std::string aTrace = RecursiveTraceColor(ir, diag, aInst, true); std::string aTrace = RecursiveTraceColor(ir, diag, aInst, true);
return EmitSwizzle3(diag, inst.m_loc, aTrace, inst.m_swizzle.m_idxs); return EmitSwizzle3(diag, inst.m_loc, aTrace, inst.m_swizzle.m_idxs);
@ -205,17 +173,13 @@ std::string ProgrammableCommon::RecursiveTraceColor(const IR& ir, Diagnostics& d
return std::string(); return std::string();
} }
std::string ProgrammableCommon::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, std::string ProgrammableCommon::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const IR::Instruction& inst,
const IR::Instruction& inst, bool toSwizzle) bool toSwizzle) {
{ switch (inst.m_op) {
switch (inst.m_op) case IR::OpType::Call: {
{
case IR::OpType::Call:
{
const std::string& name = inst.m_call.m_name; const std::string& name = inst.m_call.m_name;
bool normalize = false; bool normalize = false;
if (!name.compare("Texture") || (normalize = true && !name.compare("TextureN"))) if (!name.compare("Texture") || (normalize = true && !name.compare("TextureN"))) {
{
if (inst.getChildCount() < 2) if (inst.getChildCount() < 2)
diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments"); diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments");
@ -226,61 +190,48 @@ std::string ProgrammableCommon::RecursiveTraceAlpha(const IR& ir, Diagnostics& d
const IR::Instruction& tcgInst = inst.getChildInst(ir, 1); const IR::Instruction& tcgInst = inst.getChildInst(ir, 1);
unsigned texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, -1, normalize); unsigned texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, -1, normalize);
return toSwizzle ? EmitSamplingUseRaw(addTexSampling(mapIdx, texGenIdx)) : return toSwizzle ? EmitSamplingUseRaw(addTexSampling(mapIdx, texGenIdx))
EmitSamplingUseAlpha(addTexSampling(mapIdx, texGenIdx)); : EmitSamplingUseAlpha(addTexSampling(mapIdx, texGenIdx));
} } else if (!name.compare("ColorReg")) {
else if (!name.compare("ColorReg"))
{
const IR::Instruction& idxInst = inst.getChildInst(ir, 0); const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
unsigned idx = unsigned(idxInst.getImmVec().simd[0]); unsigned idx = unsigned(idxInst.getImmVec().simd[0]);
return toSwizzle ? EmitColorRegUseRaw(idx) : EmitColorRegUseAlpha(idx); return toSwizzle ? EmitColorRegUseRaw(idx) : EmitColorRegUseAlpha(idx);
} } else if (!name.compare("Lighting")) {
else if (!name.compare("Lighting"))
{
m_lighting = true; m_lighting = true;
return toSwizzle ? EmitLightingRaw() : EmitLightingAlpha(); return toSwizzle ? EmitLightingRaw() : EmitLightingAlpha();
} } else
else
diag.reportBackendErr(inst.m_loc, "unable to interpret '%s'", name.c_str()); diag.reportBackendErr(inst.m_loc, "unable to interpret '%s'", name.c_str());
break; break;
} }
case IR::OpType::LoadImm: case IR::OpType::LoadImm: {
{
const atVec4f& vec = inst.m_loadImm.m_immVec; const atVec4f& vec = inst.m_loadImm.m_immVec;
return EmitVal(vec.simd[0]); return EmitVal(vec.simd[0]);
} }
case IR::OpType::Arithmetic: case IR::OpType::Arithmetic: {
{
ArithmeticOp op = inst.m_arithmetic.m_op; ArithmeticOp op = inst.m_arithmetic.m_op;
const IR::Instruction& aInst = inst.getChildInst(ir, 0); const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1); const IR::Instruction& bInst = inst.getChildInst(ir, 1);
std::string aTrace = RecursiveTraceAlpha(ir, diag, aInst, false); std::string aTrace = RecursiveTraceAlpha(ir, diag, aInst, false);
std::string bTrace = RecursiveTraceAlpha(ir, diag, bInst, false); std::string bTrace = RecursiveTraceAlpha(ir, diag, bInst, false);
switch (op) switch (op) {
{ case ArithmeticOp::Add: {
case ArithmeticOp::Add:
{
return EmitAdd(aTrace, bTrace); return EmitAdd(aTrace, bTrace);
} }
case ArithmeticOp::Subtract: case ArithmeticOp::Subtract: {
{
return EmitSub(aTrace, bTrace); return EmitSub(aTrace, bTrace);
} }
case ArithmeticOp::Multiply: case ArithmeticOp::Multiply: {
{
return EmitMult(aTrace, bTrace); return EmitMult(aTrace, bTrace);
} }
case ArithmeticOp::Divide: case ArithmeticOp::Divide: {
{
return EmitDiv(aTrace, bTrace); return EmitDiv(aTrace, bTrace);
} }
default: default:
diag.reportBackendErr(inst.m_loc, "invalid arithmetic op"); diag.reportBackendErr(inst.m_loc, "invalid arithmetic op");
} }
} }
case IR::OpType::Swizzle: case IR::OpType::Swizzle: {
{
const IR::Instruction& aInst = inst.getChildInst(ir, 0); const IR::Instruction& aInst = inst.getChildInst(ir, 0);
std::string aTrace = RecursiveTraceAlpha(ir, diag, aInst, true); std::string aTrace = RecursiveTraceAlpha(ir, diag, aInst, true);
return EmitSwizzle1(diag, inst.m_loc, aTrace, inst.m_swizzle.m_idxs); return EmitSwizzle1(diag, inst.m_loc, aTrace, inst.m_swizzle.m_idxs);
@ -292,8 +243,7 @@ std::string ProgrammableCommon::RecursiveTraceAlpha(const IR& ir, Diagnostics& d
return std::string(); return std::string();
} }
void ProgrammableCommon::reset(const IR& ir, Diagnostics& diag, const char* backendName) void ProgrammableCommon::reset(const IR& ir, Diagnostics& diag, const char* backendName) {
{
m_lighting = false; m_lighting = false;
m_texSamplings.clear(); m_texSamplings.clear();
m_texMapEnd = 0; m_texMapEnd = 0;
@ -306,50 +256,38 @@ void ProgrammableCommon::reset(const IR& ir, Diagnostics& diag, const char* back
/* Final instruction is the root call by hecl convention */ /* Final instruction is the root call by hecl convention */
const IR::Instruction& rootCall = ir.m_instructions.back(); const IR::Instruction& rootCall = ir.m_instructions.back();
if (!rootCall.m_call.m_name.compare("HECLOpaque")) if (!rootCall.m_call.m_name.compare("HECLOpaque")) {
{
m_blendSrc = BlendFactor::One; m_blendSrc = BlendFactor::One;
m_blendDst = BlendFactor::Zero; m_blendDst = BlendFactor::Zero;
} } else if (!rootCall.m_call.m_name.compare("HECLAlpha")) {
else if (!rootCall.m_call.m_name.compare("HECLAlpha"))
{
m_blendSrc = BlendFactor::SrcAlpha; m_blendSrc = BlendFactor::SrcAlpha;
m_blendDst = BlendFactor::InvSrcAlpha; m_blendDst = BlendFactor::InvSrcAlpha;
} } else if (!rootCall.m_call.m_name.compare("HECLAdditive")) {
else if (!rootCall.m_call.m_name.compare("HECLAdditive"))
{
m_blendSrc = BlendFactor::SrcAlpha; m_blendSrc = BlendFactor::SrcAlpha;
m_blendDst = BlendFactor::One; m_blendDst = BlendFactor::One;
} } else {
else diag.reportBackendErr(rootCall.m_loc, "%s backend doesn't handle '%s' root", backendName,
{ rootCall.m_call.m_name.c_str());
diag.reportBackendErr(rootCall.m_loc, "%s backend doesn't handle '%s' root",
backendName, rootCall.m_call.m_name.c_str());
return; return;
} }
/* Follow Color Chain */ /* Follow Color Chain */
const IR::Instruction& colorRoot = const IR::Instruction& colorRoot = ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(0));
ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(0));
m_colorExpr = RecursiveTraceColor(ir, diag, colorRoot, false); m_colorExpr = RecursiveTraceColor(ir, diag, colorRoot, false);
/* Follow Alpha Chain */ /* Follow Alpha Chain */
if (rootCall.m_call.m_argInstIdxs.size() > 1) if (rootCall.m_call.m_argInstIdxs.size() > 1) {
{ const IR::Instruction& alphaRoot = ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(1));
const IR::Instruction& alphaRoot =
ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(1));
m_alphaExpr = RecursiveTraceAlpha(ir, diag, alphaRoot, false); m_alphaExpr = RecursiveTraceAlpha(ir, diag, alphaRoot, false);
} }
} }
static const char SWIZZLE_CHARS[] = "rgba"; static const char SWIZZLE_CHARS[] = "rgba";
std::string ProgrammableCommon::EmitSwizzle3(Diagnostics& diag, const SourceLocation& loc, std::string ProgrammableCommon::EmitSwizzle3(Diagnostics& diag, const SourceLocation& loc, const std::string& a,
const std::string& a, const atInt8 swiz[4]) const const atInt8 swiz[4]) const {
{
std::string retval = a + '.'; std::string retval = a + '.';
for (int i=0 ; i<3 ; ++i) for (int i = 0; i < 3; ++i) {
{
if (swiz[i] < 0 || swiz[i] > 3) if (swiz[i] < 0 || swiz[i] > 3)
diag.reportBackendErr(loc, "unable to use swizzle as RGB value"); diag.reportBackendErr(loc, "unable to use swizzle as RGB value");
retval += SWIZZLE_CHARS[swiz[i]]; retval += SWIZZLE_CHARS[swiz[i]];
@ -357,9 +295,8 @@ std::string ProgrammableCommon::EmitSwizzle3(Diagnostics& diag, const SourceLoca
return retval; return retval;
} }
std::string ProgrammableCommon::EmitSwizzle1(Diagnostics& diag, const SourceLocation& loc, std::string ProgrammableCommon::EmitSwizzle1(Diagnostics& diag, const SourceLocation& loc, const std::string& a,
const std::string& a, const atInt8 swiz[4]) const const atInt8 swiz[4]) const {
{
std::string retval = a + '.'; std::string retval = a + '.';
if (swiz[0] < 0 || swiz[0] > 3) if (swiz[0] < 0 || swiz[0] > 3)
diag.reportBackendErr(loc, "unable to use swizzle as Alpha value"); diag.reportBackendErr(loc, "unable to use swizzle as Alpha value");
@ -367,4 +304,4 @@ std::string ProgrammableCommon::EmitSwizzle1(Diagnostics& diag, const SourceLoca
return retval; return retval;
} }
} } // namespace hecl::Backend

File diff suppressed because it is too large Load Diff

View File

@ -5,11 +5,9 @@
#undef min #undef min
#undef max #undef max
namespace hecl::blender namespace hecl::blender {
{
atVec3f MtxVecMul4RM(const Matrix4f& mtx, const Vector3f& vec) atVec3f MtxVecMul4RM(const Matrix4f& mtx, const Vector3f& vec) {
{
atVec3f res; atVec3f res;
athena::simd_floats resf; athena::simd_floats resf;
athena::simd_floats mtxf[3]; athena::simd_floats mtxf[3];
@ -23,8 +21,7 @@ atVec3f MtxVecMul4RM(const Matrix4f& mtx, const Vector3f& vec)
return res; return res;
} }
atVec3f MtxVecMul3RM(const Matrix4f& mtx, const Vector3f& vec) atVec3f MtxVecMul3RM(const Matrix4f& mtx, const Vector3f& vec) {
{
atVec3f res; atVec3f res;
athena::simd_floats resf; athena::simd_floats resf;
athena::simd_floats mtxf[3]; athena::simd_floats mtxf[3];
@ -38,8 +35,7 @@ atVec3f MtxVecMul3RM(const Matrix4f& mtx, const Vector3f& vec)
return res; return res;
} }
HMDLBuffers Mesh::getHMDLBuffers(bool absoluteCoords, PoolSkinIndex& poolSkinIndex) const HMDLBuffers Mesh::getHMDLBuffers(bool absoluteCoords, PoolSkinIndex& poolSkinIndex) const {
{
/* If skinned, compute max weight vec count */ /* If skinned, compute max weight vec count */
size_t weightCount = 0; size_t weightCount = 0;
for (const SkinBanks::Bank& bank : skinBanks.banks) for (const SkinBanks::Bank& bank : skinBanks.banks)
@ -74,31 +70,25 @@ HMDLBuffers Mesh::getHMDLBuffers(bool absoluteCoords, PoolSkinIndex& poolSkinInd
std::vector<atUint32> iboData; std::vector<atUint32> iboData;
iboData.reserve(boundVerts); iboData.reserve(boundVerts);
for (const Surface& surf : surfaces) for (const Surface& surf : surfaces) {
{
size_t iboStart = iboData.size(); size_t iboStart = iboData.size();
for (const Surface::Vert& v : surf.verts) for (const Surface::Vert& v : surf.verts) {
{ if (v.iPos == 0xffffffff) {
if (v.iPos == 0xffffffff)
{
iboData.push_back(0xffffffff); iboData.push_back(0xffffffff);
continue; continue;
} }
size_t ti = 0; size_t ti = 0;
bool found = false; bool found = false;
for (const std::pair<const Surface*, const Surface::Vert*>& tv : vertPool) for (const std::pair<const Surface*, const Surface::Vert*>& tv : vertPool) {
{ if (v == *tv.second && surf.skinBankIdx == tv.first->skinBankIdx) {
if (v == *tv.second && surf.skinBankIdx == tv.first->skinBankIdx)
{
iboData.push_back(ti); iboData.push_back(ti);
found = true; found = true;
break; break;
} }
++ti; ++ti;
} }
if (!found) if (!found) {
{
iboData.push_back(vertPool.size()); iboData.push_back(vertPool.size());
vertPool.emplace_back(&surf, &v); vertPool.emplace_back(&surf, &v);
} }
@ -114,13 +104,11 @@ HMDLBuffers Mesh::getHMDLBuffers(bool absoluteCoords, PoolSkinIndex& poolSkinInd
HMDLBuffers ret(std::move(metaOut), vboSz, iboData, std::move(outSurfaces), skinBanks); HMDLBuffers ret(std::move(metaOut), vboSz, iboData, std::move(outSurfaces), skinBanks);
athena::io::MemoryWriter vboW(ret.m_vboData.get(), vboSz); athena::io::MemoryWriter vboW(ret.m_vboData.get(), vboSz);
uint32_t curPoolIdx = 0; uint32_t curPoolIdx = 0;
for (const std::pair<const Surface*, const Surface::Vert*>& sv : vertPool) for (const std::pair<const Surface*, const Surface::Vert*>& sv : vertPool) {
{
const Surface& s = *sv.first; const Surface& s = *sv.first;
const Surface::Vert& v = *sv.second; const Surface::Vert& v = *sv.second;
if (absoluteCoords) if (absoluteCoords) {
{
atVec3f preXfPos = MtxVecMul4RM(sceneXf, pos[v.iPos]); atVec3f preXfPos = MtxVecMul4RM(sceneXf, pos[v.iPos]);
vboW.writeVec3fLittle(preXfPos); vboW.writeVec3fLittle(preXfPos);
@ -131,15 +119,12 @@ HMDLBuffers Mesh::getHMDLBuffers(bool absoluteCoords, PoolSkinIndex& poolSkinInd
mag = 1.f / std::sqrt(mag); mag = 1.f / std::sqrt(mag);
preXfNorm.simd *= mag; preXfNorm.simd *= mag;
vboW.writeVec3fLittle(preXfNorm); vboW.writeVec3fLittle(preXfNorm);
} } else {
else
{
vboW.writeVec3fLittle(pos[v.iPos]); vboW.writeVec3fLittle(pos[v.iPos]);
vboW.writeVec3fLittle(norm[v.iNorm]); vboW.writeVec3fLittle(norm[v.iNorm]);
} }
for (size_t i=0 ; i<colorLayerCount ; ++i) for (size_t i = 0; i < colorLayerCount; ++i) {
{
const Vector3f& c = color[v.iColor[i]]; const Vector3f& c = color[v.iColor[i]];
athena::simd_floats f(c.val.simd); athena::simd_floats f(c.val.simd);
vboW.writeUByte(std::max(0, std::min(255, int(f[0] * 255)))); vboW.writeUByte(std::max(0, std::min(255, int(f[0] * 255))));
@ -148,25 +133,21 @@ HMDLBuffers Mesh::getHMDLBuffers(bool absoluteCoords, PoolSkinIndex& poolSkinInd
vboW.writeUByte(255); vboW.writeUByte(255);
} }
for (size_t i=0 ; i<uvLayerCount ; ++i) for (size_t i = 0; i < uvLayerCount; ++i)
vboW.writeVec2fLittle(uv[v.iUv[i]]); vboW.writeVec2fLittle(uv[v.iUv[i]]);
if (weightVecCount) if (weightVecCount) {
{
const SkinBanks::Bank& bank = skinBanks.banks[s.skinBankIdx]; const SkinBanks::Bank& bank = skinBanks.banks[s.skinBankIdx];
const std::vector<SkinBind>& binds = skins[v.iSkin]; const std::vector<SkinBind>& binds = skins[v.iSkin];
auto it = bank.m_boneIdxs.cbegin(); auto it = bank.m_boneIdxs.cbegin();
for (size_t i=0 ; i<weightVecCount ; ++i) for (size_t i = 0; i < weightVecCount; ++i) {
{
atVec4f vec = {}; atVec4f vec = {};
for (size_t j=0 ; j<4 ; ++j) for (size_t j = 0; j < 4; ++j) {
{
if (it == bank.m_boneIdxs.cend()) if (it == bank.m_boneIdxs.cend())
break; break;
for (const SkinBind& bind : binds) for (const SkinBind& bind : binds)
if (bind.boneIdx == *it) if (bind.boneIdx == *it) {
{
vec.simd[j] = bind.weight; vec.simd[j] = bind.weight;
break; break;
} }
@ -184,4 +165,4 @@ HMDLBuffers Mesh::getHMDLBuffers(bool absoluteCoords, PoolSkinIndex& poolSkinInd
return ret; return ret;
} }
} } // namespace hecl::blender

View File

@ -2,22 +2,16 @@
#include "athena/FileReader.hpp" #include "athena/FileReader.hpp"
#include <zlib.h> #include <zlib.h>
namespace hecl::blender namespace hecl::blender {
{
void SDNABlock::SDNAStruct::computeOffsets(const SDNABlock& block) void SDNABlock::SDNAStruct::computeOffsets(const SDNABlock& block) {
{
atUint32 offset = 0; atUint32 offset = 0;
for (SDNAField& f : fields) for (SDNAField& f : fields) {
{
const auto& name = block.names[f.name]; const auto& name = block.names[f.name];
f.offset = offset; f.offset = offset;
if (name.front() == '*') if (name.front() == '*') {
{
offset += 8; offset += 8;
} } else {
else
{
atUint32 length = block.tlens[f.type]; atUint32 length = block.tlens[f.type];
auto bracket = name.find('['); auto bracket = name.find('[');
if (bracket != std::string::npos) if (bracket != std::string::npos)
@ -27,28 +21,23 @@ void SDNABlock::SDNAStruct::computeOffsets(const SDNABlock& block)
} }
} }
const SDNABlock::SDNAStruct::SDNAField* SDNABlock::SDNAStruct::lookupField(const SDNABlock& block, const char* n) const const SDNABlock::SDNAStruct::SDNAField* SDNABlock::SDNAStruct::lookupField(const SDNABlock& block,
{ const char* n) const {
for (const SDNAField& field : fields) for (const SDNAField& field : fields) {
{
const auto& name = block.names[field.name]; const auto& name = block.names[field.name];
auto bracket = name.find('['); auto bracket = name.find('[');
if (bracket != std::string::npos) if (bracket != std::string::npos) {
{
if (!name.compare(0, bracket, n)) if (!name.compare(0, bracket, n))
return &field; return &field;
} } else if (!name.compare(n))
else if (!name.compare(n))
return &field; return &field;
} }
return nullptr; return nullptr;
} }
const SDNABlock::SDNAStruct* SDNABlock::lookupStruct(const char* n, int& idx) const const SDNABlock::SDNAStruct* SDNABlock::lookupStruct(const char* n, int& idx) const {
{
idx = 0; idx = 0;
for (const SDNAStruct& strc : strcs) for (const SDNAStruct& strc : strcs) {
{
const auto& name = types[strc.type]; const auto& name = types[strc.type];
if (!name.compare(n)) if (!name.compare(n))
return &strc; return &strc;
@ -57,12 +46,10 @@ const SDNABlock::SDNAStruct* SDNABlock::lookupStruct(const char* n, int& idx) co
return nullptr; return nullptr;
} }
void SDNARead::enumerate(const std::function<bool(const FileBlock& block, athena::io::MemoryReader& r)>& func) const void SDNARead::enumerate(const std::function<bool(const FileBlock& block, athena::io::MemoryReader& r)>& func) const {
{
athena::io::MemoryReader r(m_data.data(), m_data.size()); athena::io::MemoryReader r(m_data.data(), m_data.size());
r.seek(12); r.seek(12);
while (r.position() < r.length()) while (r.position() < r.length()) {
{
FileBlock block; FileBlock block;
block.read(r); block.read(r);
if (block.type == FOURCC('ENDB')) if (block.type == FOURCC('ENDB'))
@ -74,8 +61,7 @@ void SDNARead::enumerate(const std::function<bool(const FileBlock& block, athena
} }
} }
SDNARead::SDNARead(SystemStringView path) SDNARead::SDNARead(SystemStringView path) {
{
athena::io::FileReader r(path); athena::io::FileReader r(path);
if (r.hasError()) if (r.hasError())
return; return;
@ -84,8 +70,7 @@ SDNARead::SDNARead(SystemStringView path)
char magicBuf[7]; char magicBuf[7];
r.readUBytesToBuf(magicBuf, 7); r.readUBytesToBuf(magicBuf, 7);
r.seek(0, athena::Begin); r.seek(0, athena::Begin);
if (strncmp(magicBuf, "BLENDER", 7)) if (strncmp(magicBuf, "BLENDER", 7)) {
{
/* Try gzip decompression */ /* Try gzip decompression */
std::unique_ptr<uint8_t[]> compBuf(new uint8_t[4096]); std::unique_ptr<uint8_t[]> compBuf(new uint8_t[4096]);
m_data.resize((length * 2 + 4095) & ~4095); m_data.resize((length * 2 + 4095) & ~4095);
@ -96,15 +81,12 @@ SDNARead::SDNARead(SystemStringView path)
zstrm.total_out = 0; zstrm.total_out = 0;
atUint64 rs; atUint64 rs;
while ((rs = r.readUBytesToBuf(compBuf.get(), 4096))) while ((rs = r.readUBytesToBuf(compBuf.get(), 4096))) {
{
int inflateRet; int inflateRet;
zstrm.next_in = compBuf.get(); zstrm.next_in = compBuf.get();
zstrm.avail_in = rs; zstrm.avail_in = rs;
while (zstrm.avail_in) while (zstrm.avail_in) {
{ if (!zstrm.avail_out) {
if (!zstrm.avail_out)
{
zstrm.avail_out = m_data.size(); zstrm.avail_out = m_data.size();
m_data.resize(zstrm.avail_out * 2); m_data.resize(zstrm.avail_out * 2);
zstrm.next_out = (Bytef*)m_data.data() + zstrm.avail_out; zstrm.next_out = (Bytef*)m_data.data() + zstrm.avail_out;
@ -112,8 +94,7 @@ SDNARead::SDNARead(SystemStringView path)
inflateRet = inflate(&zstrm, Z_NO_FLUSH); inflateRet = inflate(&zstrm, Z_NO_FLUSH);
if (inflateRet == Z_STREAM_END) if (inflateRet == Z_STREAM_END)
break; break;
if (inflateRet != Z_OK) if (inflateRet != Z_OK) {
{
inflateEnd(&zstrm); inflateEnd(&zstrm);
m_data = std::vector<uint8_t>(); m_data = std::vector<uint8_t>();
return; return;
@ -125,22 +106,17 @@ SDNARead::SDNARead(SystemStringView path)
inflateEnd(&zstrm); inflateEnd(&zstrm);
if (strncmp((char*)m_data.data(), "BLENDER", 7)) if (strncmp((char*)m_data.data(), "BLENDER", 7)) {
{
m_data = std::vector<uint8_t>(); m_data = std::vector<uint8_t>();
return; return;
} }
} } else {
else
{
m_data.resize(length); m_data.resize(length);
r.readUBytesToBuf(m_data.data(), length); r.readUBytesToBuf(m_data.data(), length);
} }
enumerate([this](const FileBlock& block, athena::io::MemoryReader& r) enumerate([this](const FileBlock& block, athena::io::MemoryReader& r) {
{ if (block.type == FOURCC('DNA1')) {
if (block.type == FOURCC('DNA1'))
{
m_sdnaBlock.read(r); m_sdnaBlock.read(r);
for (SDNABlock::SDNAStruct& s : m_sdnaBlock.strcs) for (SDNABlock::SDNAStruct& s : m_sdnaBlock.strcs)
s.computeOffsets(m_sdnaBlock); s.computeOffsets(m_sdnaBlock);
@ -150,8 +126,7 @@ SDNARead::SDNARead(SystemStringView path)
}); });
} }
BlendType GetBlendType(SystemStringView path) BlendType GetBlendType(SystemStringView path) {
{
SDNARead r(path); SDNARead r(path);
if (!r) if (!r)
return BlendType::None; return BlendType::None;
@ -183,10 +158,9 @@ BlendType GetBlendType(SystemStringView path)
atUint32 valOffset = dataOffset + valField->offset; atUint32 valOffset = dataOffset + valField->offset;
BlendType ret = BlendType::None; BlendType ret = BlendType::None;
r.enumerate([idPropIdx, typeOffset, nameOffset, valOffset, &ret](const FileBlock& block, athena::io::MemoryReader& r) r.enumerate(
{ [idPropIdx, typeOffset, nameOffset, valOffset, &ret](const FileBlock& block, athena::io::MemoryReader& r) {
if (block.type == FOURCC('DATA') && block.sdnaIdx == idPropIdx) if (block.type == FOURCC('DATA') && block.sdnaIdx == idPropIdx) {
{
r.seek(typeOffset, athena::Begin); r.seek(typeOffset, athena::Begin);
if (r.readUByte() != 1) if (r.readUByte() != 1)
return true; return true;
@ -205,4 +179,4 @@ BlendType GetBlendType(SystemStringView path)
return ret; return ret;
} }
} } // namespace hecl::blender

162
hecl/lib/CVar.cpp Executable file → Normal file
View File

@ -6,16 +6,15 @@
#include <algorithm> #include <algorithm>
#include <sstream> #include <sstream>
namespace hecl namespace hecl {
{
extern CVar* com_developer; extern CVar* com_developer;
extern CVar* com_enableCheats; extern CVar* com_enableCheats;
using namespace std::literals; using namespace std::literals;
CVar::CVar(std::string_view name, std::string_view value, std::string_view help, EType type, EFlags flags, CVarManager& parent) CVar::CVar(std::string_view name, std::string_view value, std::string_view help, EType type, EFlags flags,
: m_mgr(parent) CVarManager& parent)
{ : m_mgr(parent) {
m_name = std::string(name); m_name = std::string(name);
m_value = std::string(value); m_value = std::string(value);
m_defaultValue = std::string(value); m_defaultValue = std::string(value);
@ -24,9 +23,9 @@ CVar::CVar(std::string_view name, std::string_view value, std::string_view help,
m_flags = flags; m_flags = flags;
} }
CVar::CVar(std::string_view name, std::string_view value, std::string_view help, CVar::EFlags flags, CVarManager& parent) CVar::CVar(std::string_view name, std::string_view value, std::string_view help, CVar::EFlags flags,
: m_mgr(parent) CVarManager& parent)
{ : m_mgr(parent) {
m_flags = flags; m_flags = flags;
m_name = std::string(name); m_name = std::string(name);
m_help = help; m_help = help;
@ -45,8 +44,7 @@ CVar::CVar(std::string_view name, std::string_view value, std::string_view help,
} }
CVar::CVar(std::string_view name, const atVec4f& value, std::string_view help, EFlags flags, CVarManager& parent) CVar::CVar(std::string_view name, const atVec4f& value, std::string_view help, EFlags flags, CVarManager& parent)
: m_mgr(parent) : m_mgr(parent) {
{
m_name = std::string(name); m_name = std::string(name);
m_help = help; m_help = help;
m_type = EType::Vec4f; m_type = EType::Vec4f;
@ -65,8 +63,7 @@ CVar::CVar(std::string_view name, const atVec4f& value, std::string_view help, E
} }
CVar::CVar(std::string_view name, float value, std::string_view help, EFlags flags, CVarManager& parent) CVar::CVar(std::string_view name, float value, std::string_view help, EFlags flags, CVarManager& parent)
: m_mgr(parent) : m_mgr(parent) {
{
m_name = std::string(name); m_name = std::string(name);
m_help = help; m_help = help;
m_type = EType::Float; m_type = EType::Float;
@ -85,8 +82,7 @@ CVar::CVar(std::string_view name, float value, std::string_view help, EFlags fla
} }
CVar::CVar(std::string_view name, bool value, std::string_view help, CVar::EFlags flags, CVarManager& parent) CVar::CVar(std::string_view name, bool value, std::string_view help, CVar::EFlags flags, CVarManager& parent)
: m_mgr(parent) : m_mgr(parent) {
{
m_name = std::string(name); m_name = std::string(name);
m_help = help; m_help = help;
m_type = EType::Boolean; m_type = EType::Boolean;
@ -105,8 +101,7 @@ CVar::CVar(std::string_view name, bool value, std::string_view help, CVar::EFlag
} }
CVar::CVar(std::string_view name, int value, std::string_view help, CVar::EFlags flags, CVarManager& parent) CVar::CVar(std::string_view name, int value, std::string_view help, CVar::EFlags flags, CVarManager& parent)
: m_mgr(parent) : m_mgr(parent) {
{
m_name = std::string(name); m_name = std::string(name);
m_help = help; m_help = help;
m_type = EType::Integer; m_type = EType::Integer;
@ -124,16 +119,13 @@ CVar::CVar(std::string_view name, int value, std::string_view help, CVar::EFlags
m_flags = flags; m_flags = flags;
} }
std::string CVar::help() const std::string CVar::help() const {
{
return std::string(m_help + (m_defaultValue != std::string() ? "\ndefault: " + m_defaultValue : "") + return std::string(m_help + (m_defaultValue != std::string() ? "\ndefault: " + m_defaultValue : "") +
(isReadOnly() ? " [ReadOnly]" : "")); (isReadOnly() ? " [ReadOnly]" : ""));
} }
atVec4f CVar::toVec4f(bool* isValid) const atVec4f CVar::toVec4f(bool* isValid) const {
{ if (m_type != EType::Vec4f) {
if (m_type != EType::Vec4f)
{
if (isValid != nullptr) if (isValid != nullptr)
*isValid = false; *isValid = false;
@ -151,10 +143,8 @@ atVec4f CVar::toVec4f(bool* isValid) const
return vec; return vec;
} }
float CVar::toFloat(bool* isValid) const float CVar::toFloat(bool* isValid) const {
{ if (m_type != EType::Float) {
if (m_type != EType::Float)
{
if (isValid) if (isValid)
*isValid = false; *isValid = false;
return 0.0f; return 0.0f;
@ -163,10 +153,8 @@ float CVar::toFloat(bool* isValid) const
return strtof(m_value.c_str(), nullptr); return strtof(m_value.c_str(), nullptr);
} }
bool CVar::toBoolean(bool* isValid) const bool CVar::toBoolean(bool* isValid) const {
{ if (m_type != EType::Boolean) {
if (m_type != EType::Boolean)
{
if (isValid) if (isValid)
*isValid = false; *isValid = false;
@ -177,14 +165,11 @@ bool CVar::toBoolean(bool* isValid) const
std::string tmp = m_value; std::string tmp = m_value;
athena::utility::tolower(tmp); athena::utility::tolower(tmp);
if (!tmp.compare("yes") || !tmp.compare("true") || !tmp.compare("1")) if (!tmp.compare("yes") || !tmp.compare("true") || !tmp.compare("1")) {
{
if (isValid) if (isValid)
*isValid = true; *isValid = true;
return true; return true;
} } else if (!tmp.compare("no") || !tmp.compare("false") || !tmp.compare("0")) {
else if (!tmp.compare("no") || !tmp.compare("false") || !tmp.compare("0"))
{
if (isValid) if (isValid)
*isValid = true; *isValid = true;
return false; return false;
@ -196,10 +181,8 @@ bool CVar::toBoolean(bool* isValid) const
return false; return false;
} }
int CVar::toInteger(bool* isValid) const int CVar::toInteger(bool* isValid) const {
{ if (m_type != EType::Integer) {
if (m_type != EType::Integer)
{
if (isValid) if (isValid)
*isValid = false; *isValid = false;
return 0; return 0;
@ -208,36 +191,29 @@ int CVar::toInteger(bool* isValid) const
return strtol(m_value.c_str(), nullptr, 0); return strtol(m_value.c_str(), nullptr, 0);
} }
const std::string CVar::toLiteral(bool* isValid) const const std::string CVar::toLiteral(bool* isValid) const {
{ if (m_type != EType::Literal && (com_developer && com_developer->toBoolean())) {
if (m_type != EType::Literal && (com_developer && com_developer->toBoolean()))
{
if (isValid != nullptr) if (isValid != nullptr)
*isValid = false; *isValid = false;
} } else if (isValid != nullptr)
else if (isValid != nullptr)
*isValid = true; *isValid = true;
// Even if it's not a literal, it's still safe to return // Even if it's not a literal, it's still safe to return
return m_value; return m_value;
} }
const std::wstring CVar::toWideLiteral(bool* isValid) const const std::wstring CVar::toWideLiteral(bool* isValid) const {
{ if (m_type != EType::Literal && (com_developer && com_developer->toBoolean())) {
if (m_type != EType::Literal && (com_developer && com_developer->toBoolean()))
{
if (isValid != nullptr) if (isValid != nullptr)
*isValid = false; *isValid = false;
} } else if (isValid != nullptr)
else if (isValid != nullptr)
*isValid = true; *isValid = true;
// Even if it's not a literal, it's still safe to return // Even if it's not a literal, it's still safe to return
return hecl::UTF8ToWide(m_value); return hecl::UTF8ToWide(m_value);
} }
bool CVar::fromVec4f(const atVec4f& val) bool CVar::fromVec4f(const atVec4f& val) {
{
if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean()))
return false; return false;
else if (isCheat()) else if (isCheat())
@ -255,8 +231,7 @@ bool CVar::fromVec4f(const atVec4f& val)
return true; return true;
} }
bool CVar::fromFloat(float val) bool CVar::fromFloat(float val) {
{
if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean()))
return false; return false;
else if (isCheat()) else if (isCheat())
@ -273,8 +248,7 @@ bool CVar::fromFloat(float val)
return true; return true;
} }
bool CVar::fromBoolean(bool val) bool CVar::fromBoolean(bool val) {
{
if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean()))
return false; return false;
else if (isCheat()) else if (isCheat())
@ -295,8 +269,7 @@ bool CVar::fromBoolean(bool val)
return true; return true;
} }
bool CVar::fromInteger(int val) bool CVar::fromInteger(int val) {
{
if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean()))
return false; return false;
else if (isCheat()) else if (isCheat())
@ -313,8 +286,7 @@ bool CVar::fromInteger(int val)
return true; return true;
} }
bool CVar::fromLiteral(std::string_view val) bool CVar::fromLiteral(std::string_view val) {
{
if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean()))
return false; return false;
else if (isCheat()) else if (isCheat())
@ -331,8 +303,7 @@ bool CVar::fromLiteral(std::string_view val)
return true; return true;
} }
bool CVar::fromLiteral(std::wstring_view val) bool CVar::fromLiteral(std::wstring_view val) {
{
if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean()))
return false; return false;
else if (isCheat()) else if (isCheat())
@ -349,37 +320,32 @@ bool CVar::fromLiteral(std::wstring_view val)
return true; return true;
} }
bool CVar::fromLiteralToType(std::string_view val, bool setDefault) bool CVar::fromLiteralToType(std::string_view val, bool setDefault) {
{ switch (m_type) {
switch (m_type) case EType::Literal:
{ return fromLiteral(val);
case EType::Literal: return fromLiteral(val); case EType::Boolean: {
case EType::Boolean:
{
std::stringstream ss; std::stringstream ss;
ss << std::boolalpha << val; ss << std::boolalpha << val;
bool v; bool v;
ss >> v; ss >> v;
return fromBoolean(v); return fromBoolean(v);
} }
case EType::Float: case EType::Float: {
{
std::stringstream ss; std::stringstream ss;
ss << val; ss << val;
float v; float v;
ss >> v; ss >> v;
return fromFloat(v); return fromFloat(v);
} }
case EType::Integer: case EType::Integer: {
{
std::stringstream ss; std::stringstream ss;
ss << val; ss << val;
int v; int v;
ss >> v; ss >> v;
return fromInteger(v); return fromInteger(v);
} }
case EType::Vec4f: case EType::Vec4f: {
{
atVec4f vec; atVec4f vec;
athena::simd_floats f; athena::simd_floats f;
std::sscanf(val.data(), "%f %f %f %f", &f[0], &f[1], &f[2], &f[3]); std::sscanf(val.data(), "%f %f %f %f", &f[0], &f[1], &f[2], &f[3]);
@ -392,37 +358,32 @@ bool CVar::fromLiteralToType(std::string_view val, bool setDefault)
return false; return false;
} }
bool CVar::fromLiteralToType(std::wstring_view val, bool setDefault) bool CVar::fromLiteralToType(std::wstring_view val, bool setDefault) {
{ switch (m_type) {
switch (m_type) case EType::Literal:
{ return fromLiteral(val);
case EType::Literal: return fromLiteral(val); case EType::Boolean: {
case EType::Boolean:
{
std::wstringstream ss; std::wstringstream ss;
ss << std::boolalpha << val; ss << std::boolalpha << val;
bool v; bool v;
ss >> v; ss >> v;
return fromBoolean(v); return fromBoolean(v);
} }
case EType::Float: case EType::Float: {
{
std::wstringstream ss; std::wstringstream ss;
ss << val; ss << val;
float v; float v;
ss >> v; ss >> v;
return fromFloat(v); return fromFloat(v);
} }
case EType::Integer: case EType::Integer: {
{
std::wstringstream ss; std::wstringstream ss;
ss << val; ss << val;
int v; int v;
ss >> v; ss >> v;
return fromInteger(v); return fromInteger(v);
} }
case EType::Vec4f: case EType::Vec4f: {
{
atVec4f vec; atVec4f vec;
athena::simd_floats f; athena::simd_floats f;
std::swscanf(val.data(), L"%f %f %f %f", &f[0], &f[1], &f[2], &f[3]); std::swscanf(val.data(), L"%f %f %f %f", &f[0], &f[1], &f[2], &f[3]);
@ -435,7 +396,7 @@ bool CVar::fromLiteralToType(std::wstring_view val, bool setDefault)
return false; return false;
} }
bool CVar::isModified() const { return int(m_flags & EFlags::Modified) != 0;} bool CVar::isModified() const { return int(m_flags & EFlags::Modified) != 0; }
bool CVar::modificationRequiresRestart() const { return int(m_flags & EFlags::ModifyRestart) != 0; } bool CVar::modificationRequiresRestart() const { return int(m_flags & EFlags::ModifyRestart) != 0; }
bool CVar::isReadOnly() const { return int(m_flags & EFlags::ReadOnly) != 0; } bool CVar::isReadOnly() const { return int(m_flags & EFlags::ReadOnly) != 0; }
@ -452,37 +413,30 @@ bool CVar::wasDeserialized() const { return m_wasDeserialized; }
bool CVar::hasDefaultValue() const { return m_defaultValue == m_value; } bool CVar::hasDefaultValue() const { return m_defaultValue == m_value; }
void CVar::clearModified() void CVar::clearModified() {
{
if (!modificationRequiresRestart()) if (!modificationRequiresRestart())
m_flags &= ~EFlags::Modified; m_flags &= ~EFlags::Modified;
} }
void CVar::setModified() { m_flags |= EFlags::Modified; } void CVar::setModified() { m_flags |= EFlags::Modified; }
void CVar::unlock() void CVar::unlock() {
{ if (isReadOnly() && !m_unlocked) {
if (isReadOnly() && !m_unlocked)
{
m_oldFlags = m_flags; m_oldFlags = m_flags;
m_flags &= ~EFlags::ReadOnly; m_flags &= ~EFlags::ReadOnly;
m_unlocked = true; m_unlocked = true;
} }
} }
void CVar::lock() void CVar::lock() {
{ if (!isReadOnly() && m_unlocked) {
if (!isReadOnly() && m_unlocked)
{
m_flags = m_oldFlags; m_flags = m_oldFlags;
m_unlocked = false; m_unlocked = false;
} }
} }
void CVar::dispatch() void CVar::dispatch() {
{
for (const ListenerFunc& listen : m_listeners) for (const ListenerFunc& listen : m_listeners)
listen(this); listen(this);
} }
} } // namespace hecl

165
hecl/lib/CVarManager.cpp Executable file → Normal file
View File

@ -7,8 +7,7 @@
#include <memory> #include <memory>
#include <regex> #include <regex>
namespace hecl namespace hecl {
{
CVar* com_developer = nullptr; CVar* com_developer = nullptr;
CVar* com_configfile = nullptr; CVar* com_configfile = nullptr;
@ -19,21 +18,18 @@ CVarManager* CVarManager::m_instance = nullptr;
static logvisor::Module CVarLog("CVarManager"); static logvisor::Module CVarLog("CVarManager");
CVarManager::CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary) CVarManager::CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary)
: m_store(store), : m_store(store), m_useBinary(useBinary) {
m_useBinary(useBinary)
{
m_instance = this; m_instance = this;
com_configfile = newCVar("config", "File to store configuration", std::string("config"), CVar::EFlags::System); com_configfile = newCVar("config", "File to store configuration", std::string("config"), CVar::EFlags::System);
com_developer = newCVar("developer", "Enables developer mode", false, (CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable)); com_developer = newCVar("developer", "Enables developer mode", false,
com_enableCheats = newCVar("cheats", "Enable cheats", false, (CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::Hidden)); (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));
} }
CVarManager::~CVarManager() CVarManager::~CVarManager() {}
{
}
CVar* CVarManager::registerCVar(std::unique_ptr<CVar>&& cvar) CVar* CVarManager::registerCVar(std::unique_ptr<CVar>&& cvar) {
{
std::string tmp(cvar->name()); std::string tmp(cvar->name());
athena::utility::tolower(tmp); athena::utility::tolower(tmp);
if (m_cvars.find(tmp) != m_cvars.end()) if (m_cvars.find(tmp) != m_cvars.end())
@ -44,8 +40,7 @@ CVar* CVarManager::registerCVar(std::unique_ptr<CVar>&& cvar)
return ret; return ret;
} }
CVar* CVarManager::findCVar(std::string_view name) CVar* CVarManager::findCVar(std::string_view name) {
{
std::string lower(name); std::string lower(name);
athena::utility::tolower(lower); athena::utility::tolower(lower);
auto search = m_cvars.find(lower); auto search = m_cvars.find(lower);
@ -55,8 +50,7 @@ CVar* CVarManager::findCVar(std::string_view name)
return search->second.get(); return search->second.get();
} }
std::vector<CVar*> CVarManager::archivedCVars() const std::vector<CVar*> CVarManager::archivedCVars() const {
{
std::vector<CVar*> ret; std::vector<CVar*> ret;
for (const auto& pair : m_cvars) for (const auto& pair : m_cvars)
if (pair.second->isArchive()) if (pair.second->isArchive())
@ -65,8 +59,7 @@ std::vector<CVar*> CVarManager::archivedCVars() const
return ret; return ret;
} }
std::vector<CVar*> CVarManager::cvars(CVar::EFlags filter) const std::vector<CVar*> CVarManager::cvars(CVar::EFlags filter) const {
{
std::vector<CVar*> ret; std::vector<CVar*> ret;
for (const auto& pair : m_cvars) for (const auto& pair : m_cvars)
if (filter == CVar::EFlags::None || (pair.second->flags() & filter) != 0) if (filter == CVar::EFlags::None || (pair.second->flags() & filter) != 0)
@ -75,16 +68,14 @@ std::vector<CVar*> CVarManager::cvars(CVar::EFlags filter) const
return ret; return ret;
} }
void CVarManager::deserialize(CVar* cvar) void CVarManager::deserialize(CVar* cvar) {
{
if (!cvar) if (!cvar)
return; return;
/* First let's check for a deferred value */ /* First let's check for a deferred value */
std::string lowName = cvar->name().data(); std::string lowName = cvar->name().data();
athena::utility::tolower(lowName); athena::utility::tolower(lowName);
if (m_deferedCVars.find(lowName) != m_deferedCVars.end()) if (m_deferedCVars.find(lowName) != m_deferedCVars.end()) {
{
std::string val = m_deferedCVars[lowName]; std::string val = m_deferedCVars[lowName];
m_deferedCVars.erase(lowName); m_deferedCVars.erase(lowName);
if (cvar->fromLiteralToType(val)) if (cvar->fromLiteralToType(val))
@ -96,14 +87,15 @@ void CVarManager::deserialize(CVar* cvar)
return; return;
#if _WIN32 #if _WIN32
hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral(); hecl::SystemString filename =
hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral();
#else #else
hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toLiteral(); hecl::SystemString filename =
hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toLiteral();
#endif #endif
hecl::Sstat st; hecl::Sstat st;
if (m_useBinary) if (m_useBinary) {
{
CVarContainer container; CVarContainer container;
filename += _SYS_STR(".bin"); filename += _SYS_STR(".bin");
if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode)) if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
@ -112,18 +104,14 @@ void CVarManager::deserialize(CVar* cvar)
if (reader.isOpen()) if (reader.isOpen())
container.read(reader); container.read(reader);
if (container.cvars.size() > 0) if (container.cvars.size() > 0) {
{ auto serialized = std::find_if(container.cvars.begin(), container.cvars.end(),
auto serialized = std::find_if(container.cvars.begin(),
container.cvars.end(),
[&cvar](const DNACVAR::CVar& c) { return c.m_name == cvar->name(); }); [&cvar](const DNACVAR::CVar& c) { return c.m_name == cvar->name(); });
if (serialized != container.cvars.end()) if (serialized != container.cvars.end()) {
{
DNACVAR::CVar& tmp = *serialized; DNACVAR::CVar& tmp = *serialized;
if (cvar->m_value != tmp.m_value) if (cvar->m_value != tmp.m_value) {
{
cvar->unlock(); cvar->unlock();
cvar->fromLiteralToType(tmp.m_value, true); cvar->fromLiteralToType(tmp.m_value, true);
cvar->m_wasDeserialized = true; cvar->m_wasDeserialized = true;
@ -131,29 +119,22 @@ void CVarManager::deserialize(CVar* cvar)
} }
} }
} }
} } else {
else
{
filename += _SYS_STR(".yaml"); filename += _SYS_STR(".yaml");
if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode)) if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
return; return;
athena::io::FileReader reader(filename); athena::io::FileReader reader(filename);
if (reader.isOpen()) if (reader.isOpen()) {
{
athena::io::YAMLDocReader docReader; athena::io::YAMLDocReader docReader;
if (docReader.parse(&reader)) if (docReader.parse(&reader)) {
{
std::unique_ptr<athena::io::YAMLNode> root = docReader.releaseRootNode(); std::unique_ptr<athena::io::YAMLNode> root = docReader.releaseRootNode();
auto serialized = std::find_if(root->m_mapChildren.begin(), auto serialized = std::find_if(root->m_mapChildren.begin(), root->m_mapChildren.end(),
root->m_mapChildren.end(),
[&cvar](const auto& c) { return c.first == cvar->name(); }); [&cvar](const auto& c) { return c.first == cvar->name(); });
if (serialized != root->m_mapChildren.end()) if (serialized != root->m_mapChildren.end()) {
{
const std::unique_ptr<athena::io::YAMLNode>& tmp = serialized->second; const std::unique_ptr<athena::io::YAMLNode>& tmp = serialized->second;
if (cvar->m_value != tmp->m_scalarString) if (cvar->m_value != tmp->m_scalarString) {
{
cvar->unlock(); cvar->unlock();
cvar->fromLiteralToType(tmp->m_scalarString, true); cvar->fromLiteralToType(tmp->m_scalarString, true);
cvar->m_wasDeserialized = true; cvar->m_wasDeserialized = true;
@ -165,20 +146,20 @@ void CVarManager::deserialize(CVar* cvar)
} }
} }
void CVarManager::serialize() void CVarManager::serialize() {
{
#if _WIN32 #if _WIN32
hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral(); hecl::SystemString filename =
hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral();
#else #else
hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toLiteral(); hecl::SystemString filename =
hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toLiteral();
#endif #endif
if (m_useBinary) if (m_useBinary) {
{
CVarContainer container; CVarContainer container;
for (const auto& pair : m_cvars) for (const auto& pair : m_cvars)
if (pair.second->isArchive() || (pair.second->isInternalArchivable() && if (pair.second->isArchive() ||
pair.second->wasDeserialized() && !pair.second->hasDefaultValue())) (pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue()))
container.cvars.push_back(*pair.second); container.cvars.push_back(*pair.second);
container.cvarCount = atUint32(container.cvars.size()); container.cvarCount = atUint32(container.cvars.size());
@ -186,9 +167,7 @@ void CVarManager::serialize()
athena::io::FileWriter writer(filename); athena::io::FileWriter writer(filename);
if (writer.isOpen()) if (writer.isOpen())
container.write(writer); container.write(writer);
} } else {
else
{
filename += _SYS_STR(".yaml"); filename += _SYS_STR(".yaml");
athena::io::FileReader r(filename); athena::io::FileReader r(filename);
@ -197,8 +176,8 @@ void CVarManager::serialize()
docWriter.setStyle(athena::io::YAMLNodeStyle::Block); docWriter.setStyle(athena::io::YAMLNodeStyle::Block);
for (const auto& pair : m_cvars) for (const auto& pair : m_cvars)
if (pair.second->isArchive() || (pair.second->isInternalArchivable() && if (pair.second->isArchive() ||
pair.second->wasDeserialized() && !pair.second->hasDefaultValue())) (pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue()))
docWriter.writeString(pair.second->name().data(), pair.second->toLiteral()); docWriter.writeString(pair.second->name().data(), pair.second->toLiteral());
athena::io::FileWriter w(filename); athena::io::FileWriter w(filename);
@ -207,32 +186,24 @@ void CVarManager::serialize()
} }
} }
CVarManager* CVarManager::instance() CVarManager* CVarManager::instance() { return m_instance; }
{
return m_instance;
}
void CVarManager::list(Console* con, const std::vector<std::string>& /*args*/) void CVarManager::list(Console* con, const std::vector<std::string>& /*args*/) {
{ for (const auto& cvar : m_cvars) {
for (const auto& cvar : m_cvars)
{
if (!cvar.second->isHidden()) if (!cvar.second->isHidden())
con->report(Console::Level::Info, "%s: %s", cvar.second->name().data(), cvar.second->help().c_str()); con->report(Console::Level::Info, "%s: %s", cvar.second->name().data(), cvar.second->help().c_str());
} }
} }
void CVarManager::setCVar(Console* con, const std::vector<std::string> &args) void CVarManager::setCVar(Console* con, const std::vector<std::string>& args) {
{ if (args.size() < 2) {
if (args.size() < 2)
{
con->report(Console::Level::Info, "Usage setCvar <cvar> <value>"); con->report(Console::Level::Info, "Usage setCvar <cvar> <value>");
return; return;
} }
std::string cvName = args[0]; std::string cvName = args[0];
athena::utility::tolower(cvName); athena::utility::tolower(cvName);
if (m_cvars.find(cvName) == m_cvars.end()) if (m_cvars.find(cvName) == m_cvars.end()) {
{
con->report(Console::Level::Error, "CVar '%s' does not exist", args[0].c_str()); con->report(Console::Level::Error, "CVar '%s' does not exist", args[0].c_str());
return; return;
} }
@ -254,18 +225,15 @@ void CVarManager::setCVar(Console* con, const std::vector<std::string> &args)
con->report(Console::Level::Info, "Set '%s' from '%s' to '%s'", cv->name().data(), oldVal.c_str(), value.c_str()); con->report(Console::Level::Info, "Set '%s' from '%s' to '%s'", cv->name().data(), oldVal.c_str(), value.c_str());
} }
void CVarManager::getCVar(Console* con, const std::vector<std::string> &args) void CVarManager::getCVar(Console* con, const std::vector<std::string>& args) {
{ if (args.empty()) {
if (args.empty())
{
con->report(Console::Level::Info, "Usage getCVar <cvar>"); con->report(Console::Level::Info, "Usage getCVar <cvar>");
return; return;
} }
std::string cvName = args[0]; std::string cvName = args[0];
athena::utility::tolower(cvName); athena::utility::tolower(cvName);
if (m_cvars.find(cvName) == m_cvars.end()) if (m_cvars.find(cvName) == m_cvars.end()) {
{
con->report(Console::Level::Error, "CVar '%s' does not exist", args[0].c_str()); con->report(Console::Level::Error, "CVar '%s' does not exist", args[0].c_str());
return; return;
} }
@ -274,21 +242,17 @@ void CVarManager::getCVar(Console* con, const std::vector<std::string> &args)
con->report(Console::Level::Info, "'%s' = '%s'", cv->name().data(), cv->value().c_str()); con->report(Console::Level::Info, "'%s' = '%s'", cv->name().data(), cv->value().c_str());
} }
void CVarManager::setDeveloperMode(bool v, bool setDeserialized) void CVarManager::setDeveloperMode(bool v, bool setDeserialized) {
{
com_developer->unlock(); com_developer->unlock();
com_developer->fromBoolean(v); com_developer->fromBoolean(v);
if (setDeserialized) if (setDeserialized)
com_developer->m_wasDeserialized = true; com_developer->m_wasDeserialized = true;
com_developer->lock(); com_developer->lock();
com_developer->setModified(); com_developer->setModified();
} }
bool CVarManager::restartRequired() const bool CVarManager::restartRequired() const {
{ for (const auto& cv : m_cvars) {
for (const auto& cv : m_cvars)
{
if (cv.second->isModified() && cv.second->modificationRequiresRestart()) if (cv.second->isModified() && cv.second->modificationRequiresRestart())
return true; return true;
} }
@ -296,32 +260,25 @@ bool CVarManager::restartRequired() const
return false; return false;
} }
void CVarManager::parseCommandLine(const std::vector<SystemString>& args) void CVarManager::parseCommandLine(const std::vector<SystemString>& args) {
{
bool oldDeveloper = suppressDeveloper(); bool oldDeveloper = suppressDeveloper();
std::string developerName = com_developer->name().data(); std::string developerName = com_developer->name().data();
athena::utility::tolower(developerName); athena::utility::tolower(developerName);
for (const SystemString& arg : args) for (const SystemString& arg : args) {
{ if (arg[0] == _SYS_STR('+')) {
if (arg[0] == _SYS_STR('+'))
{
std::string tmp = SystemUTF8Conv(arg).c_str(); std::string tmp = SystemUTF8Conv(arg).c_str();
std::smatch matches; std::smatch matches;
if (std::regex_match(tmp, matches, cmdLineRegex)) if (std::regex_match(tmp, matches, cmdLineRegex)) {
{
std::string cvarName = matches[1].str(); std::string cvarName = matches[1].str();
std::string cvarValue = matches[2].str(); std::string cvarValue = matches[2].str();
if (CVar* cv = findCVar(cvarName)) if (CVar* cv = findCVar(cvarName)) {
{
cv->fromLiteralToType(cvarValue); cv->fromLiteralToType(cvarValue);
athena::utility::tolower(cvarName); athena::utility::tolower(cvarName);
if (developerName == cvarName) if (developerName == cvarName)
/* Make sure we're not overriding developer mode when we restore */ /* Make sure we're not overriding developer mode when we restore */
oldDeveloper = com_developer->toBoolean(); oldDeveloper = com_developer->toBoolean();
} } else {
else
{
/* Unable to find an existing CVar, let's defer for the time being 8 */ /* Unable to find an existing CVar, let's defer for the time being 8 */
athena::utility::tolower(cvarName); athena::utility::tolower(cvarName);
m_deferedCVars[cvarName] = cvarValue; m_deferedCVars[cvarName] = cvarValue;
@ -333,8 +290,7 @@ void CVarManager::parseCommandLine(const std::vector<SystemString>& args)
restoreDeveloper(oldDeveloper); restoreDeveloper(oldDeveloper);
} }
bool CVarManager::suppressDeveloper() bool CVarManager::suppressDeveloper() {
{
bool oldDeveloper = com_developer->toBoolean(); bool oldDeveloper = com_developer->toBoolean();
CVarUnlocker unlock(com_developer); CVarUnlocker unlock(com_developer);
com_developer->fromBoolean(true); com_developer->fromBoolean(true);
@ -342,10 +298,9 @@ bool CVarManager::suppressDeveloper()
return oldDeveloper; return oldDeveloper;
} }
void CVarManager::restoreDeveloper(bool oldDeveloper) void CVarManager::restoreDeveloper(bool oldDeveloper) {
{
CVarUnlocker unlock(com_developer); CVarUnlocker unlock(com_developer);
com_developer->fromBoolean(oldDeveloper); com_developer->fromBoolean(oldDeveloper);
} }
} } // namespace hecl

View File

@ -13,14 +13,12 @@
#define HECL_MULTIPROCESSOR 1 #define HECL_MULTIPROCESSOR 1
namespace hecl namespace hecl {
{
static logvisor::Module CP_Log("hecl::ClientProcess"); static logvisor::Module CP_Log("hecl::ClientProcess");
ThreadLocalPtr<ClientProcess::Worker> ClientProcess::ThreadWorker; ThreadLocalPtr<ClientProcess::Worker> ClientProcess::ThreadWorker;
static int GetCPUCount() static int GetCPUCount() {
{
#if _WIN32 #if _WIN32
SYSTEM_INFO sysinfo; SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo); GetSystemInfo(&sysinfo);
@ -30,13 +28,10 @@ static int GetCPUCount()
#endif #endif
} }
void ClientProcess::BufferTransaction::run(blender::Token& btok) void ClientProcess::BufferTransaction::run(blender::Token& btok) {
{
athena::io::FileReader r(m_path.getAbsolutePath(), 32 * 1024, false); athena::io::FileReader r(m_path.getAbsolutePath(), 32 * 1024, false);
if (r.hasError()) if (r.hasError()) {
{ CP_Log.report(logvisor::Fatal, _SYS_STR("unable to background-buffer '%s'"), m_path.getAbsolutePath().data());
CP_Log.report(logvisor::Fatal, _SYS_STR("unable to background-buffer '%s'"),
m_path.getAbsolutePath().data());
return; return;
} }
if (m_offset) if (m_offset)
@ -45,8 +40,7 @@ void ClientProcess::BufferTransaction::run(blender::Token& btok)
m_complete = true; m_complete = true;
} }
void ClientProcess::CookTransaction::run(blender::Token& btok) void ClientProcess::CookTransaction::run(blender::Token& btok) {
{
m_dataSpec->setThreadProject(); m_dataSpec->setThreadProject();
m_returnResult = m_parent.syncCook(m_path, m_dataSpec, btok, m_force, m_fast); m_returnResult = m_parent.syncCook(m_path, m_dataSpec, btok, m_force, m_fast);
std::unique_lock<std::mutex> lk(m_parent.m_mutex); std::unique_lock<std::mutex> lk(m_parent.m_mutex);
@ -55,20 +49,16 @@ void ClientProcess::CookTransaction::run(blender::Token& btok)
m_complete = true; m_complete = true;
} }
void ClientProcess::LambdaTransaction::run(blender::Token& btok) void ClientProcess::LambdaTransaction::run(blender::Token& btok) {
{
m_func(btok); m_func(btok);
m_complete = true; m_complete = true;
} }
ClientProcess::Worker::Worker(ClientProcess& proc, int idx) ClientProcess::Worker::Worker(ClientProcess& proc, int idx) : m_proc(proc), m_idx(idx) {
: m_proc(proc), m_idx(idx)
{
m_thr = std::thread(std::bind(&Worker::proc, this)); m_thr = std::thread(std::bind(&Worker::proc, this));
} }
void ClientProcess::Worker::proc() void ClientProcess::Worker::proc() {
{
ClientProcess::ThreadWorker.reset(this); ClientProcess::ThreadWorker.reset(this);
char thrName[64]; char thrName[64];
@ -76,15 +66,12 @@ void ClientProcess::Worker::proc()
logvisor::RegisterThreadName(thrName); logvisor::RegisterThreadName(thrName);
std::unique_lock<std::mutex> lk(m_proc.m_mutex); std::unique_lock<std::mutex> lk(m_proc.m_mutex);
while (m_proc.m_running) while (m_proc.m_running) {
{ if (!m_didInit) {
if (!m_didInit)
{
m_proc.m_initCv.notify_one(); m_proc.m_initCv.notify_one();
m_didInit = true; m_didInit = true;
} }
while (m_proc.m_running && m_proc.m_pendingQueue.size()) while (m_proc.m_running && m_proc.m_pendingQueue.size()) {
{
std::shared_ptr<Transaction> trans = std::move(m_proc.m_pendingQueue.front()); std::shared_ptr<Transaction> trans = std::move(m_proc.m_pendingQueue.front());
++m_proc.m_inProgress; ++m_proc.m_inProgress;
m_proc.m_pendingQueue.pop_front(); m_proc.m_pendingQueue.pop_front();
@ -103,27 +90,23 @@ void ClientProcess::Worker::proc()
m_blendTok.shutdown(); m_blendTok.shutdown();
} }
ClientProcess::ClientProcess(const MultiProgressPrinter* progPrinter) ClientProcess::ClientProcess(const MultiProgressPrinter* progPrinter) : m_progPrinter(progPrinter) {
: m_progPrinter(progPrinter)
{
#if HECL_MULTIPROCESSOR #if HECL_MULTIPROCESSOR
const int cpuCount = GetCPUCount(); const int cpuCount = GetCPUCount();
#else #else
constexpr int cpuCount = 1; constexpr int cpuCount = 1;
#endif #endif
m_workers.reserve(cpuCount); m_workers.reserve(cpuCount);
for (int i=0 ; i<cpuCount ; ++i) for (int i = 0; i < cpuCount; ++i) {
{
std::unique_lock<std::mutex> lk(m_mutex); std::unique_lock<std::mutex> lk(m_mutex);
m_workers.emplace_back(*this, m_workers.size()); m_workers.emplace_back(*this, m_workers.size());
m_initCv.wait(lk); m_initCv.wait(lk);
} }
} }
std::shared_ptr<const ClientProcess::BufferTransaction> std::shared_ptr<const ClientProcess::BufferTransaction> ClientProcess::addBufferTransaction(const ProjectPath& path,
ClientProcess::addBufferTransaction(const ProjectPath& path, void* target, void* target, size_t maxLen,
size_t maxLen, size_t offset) size_t offset) {
{
std::unique_lock<std::mutex> lk(m_mutex); std::unique_lock<std::mutex> lk(m_mutex);
auto ret = std::make_shared<BufferTransaction>(*this, path, target, maxLen, offset); auto ret = std::make_shared<BufferTransaction>(*this, path, target, maxLen, offset);
m_pendingQueue.emplace_back(ret); m_pendingQueue.emplace_back(ret);
@ -131,10 +114,9 @@ ClientProcess::addBufferTransaction(const ProjectPath& path, void* target,
return ret; return ret;
} }
std::shared_ptr<const ClientProcess::CookTransaction> std::shared_ptr<const ClientProcess::CookTransaction> ClientProcess::addCookTransaction(const hecl::ProjectPath& path,
ClientProcess::addCookTransaction(const hecl::ProjectPath& path, bool force, bool force, bool fast,
bool fast, Database::IDataSpec* spec) Database::IDataSpec* spec) {
{
std::unique_lock<std::mutex> lk(m_mutex); std::unique_lock<std::mutex> lk(m_mutex);
auto ret = std::make_shared<CookTransaction>(*this, path, force, fast, spec); auto ret = std::make_shared<CookTransaction>(*this, path, force, fast, spec);
m_pendingQueue.emplace_back(ret); m_pendingQueue.emplace_back(ret);
@ -145,8 +127,7 @@ ClientProcess::addCookTransaction(const hecl::ProjectPath& path, bool force,
} }
std::shared_ptr<const ClientProcess::LambdaTransaction> std::shared_ptr<const ClientProcess::LambdaTransaction>
ClientProcess::addLambdaTransaction(std::function<void(blender::Token&)>&& func) ClientProcess::addLambdaTransaction(std::function<void(blender::Token&)>&& func) {
{
std::unique_lock<std::mutex> lk(m_mutex); std::unique_lock<std::mutex> lk(m_mutex);
auto ret = std::make_shared<LambdaTransaction>(*this, std::move(func)); auto ret = std::make_shared<LambdaTransaction>(*this, std::move(func));
m_pendingQueue.emplace_back(ret); m_pendingQueue.emplace_back(ret);
@ -154,23 +135,17 @@ ClientProcess::addLambdaTransaction(std::function<void(blender::Token&)>&& func)
return ret; return ret;
} }
bool ClientProcess::syncCook(const hecl::ProjectPath& path, Database::IDataSpec* spec, blender::Token& btok, bool ClientProcess::syncCook(const hecl::ProjectPath& path, Database::IDataSpec* spec, blender::Token& btok, bool force,
bool force, bool fast) bool fast) {
{ if (spec->canCook(path, btok)) {
if (spec->canCook(path, btok))
{
const Database::DataSpecEntry* specEnt = spec->overrideDataSpec(path, spec->getDataSpecEntry(), btok); const Database::DataSpecEntry* specEnt = spec->overrideDataSpec(path, spec->getDataSpecEntry(), btok);
if (specEnt) if (specEnt) {
{
hecl::ProjectPath cooked = path.getCookedPath(*specEnt); hecl::ProjectPath cooked = path.getCookedPath(*specEnt);
if (fast) if (fast)
cooked = cooked.getWithExtension(_SYS_STR(".fast")); cooked = cooked.getWithExtension(_SYS_STR(".fast"));
cooked.makeDirChain(false); cooked.makeDirChain(false);
if (force || cooked.getPathType() == ProjectPath::Type::None || if (force || cooked.getPathType() == ProjectPath::Type::None || path.getModtime() > cooked.getModtime()) {
path.getModtime() > cooked.getModtime()) if (m_progPrinter) {
{
if (m_progPrinter)
{
hecl::SystemString str; hecl::SystemString str;
if (path.getAuxInfo().empty()) if (path.getAuxInfo().empty())
str = hecl::SysFormat(_SYS_STR("Cooking %s"), path.getRelativePath().data()); str = hecl::SysFormat(_SYS_STR("Cooking %s"), path.getRelativePath().data());
@ -178,20 +153,15 @@ bool ClientProcess::syncCook(const hecl::ProjectPath& path, Database::IDataSpec*
str = hecl::SysFormat(_SYS_STR("Cooking %s|%s"), path.getRelativePath().data(), path.getAuxInfo().data()); str = hecl::SysFormat(_SYS_STR("Cooking %s|%s"), path.getRelativePath().data(), path.getAuxInfo().data());
m_progPrinter->print(str.c_str(), nullptr, -1.f, hecl::ClientProcess::GetThreadWorkerIdx()); m_progPrinter->print(str.c_str(), nullptr, -1.f, hecl::ClientProcess::GetThreadWorkerIdx());
m_progPrinter->flush(); m_progPrinter->flush();
} } else {
else
{
if (path.getAuxInfo().empty()) if (path.getAuxInfo().empty())
LogModule.report(logvisor::Info, _SYS_STR("Cooking %s"), LogModule.report(logvisor::Info, _SYS_STR("Cooking %s"), path.getRelativePath().data());
path.getRelativePath().data());
else else
LogModule.report(logvisor::Info, _SYS_STR("Cooking %s|%s"), LogModule.report(logvisor::Info, _SYS_STR("Cooking %s|%s"), path.getRelativePath().data(),
path.getRelativePath().data(),
path.getAuxInfo().data()); path.getAuxInfo().data());
} }
spec->doCook(path, cooked, false, btok, [](const SystemChar*) {}); spec->doCook(path, cooked, false, btok, [](const SystemChar*) {});
if (m_progPrinter) if (m_progPrinter) {
{
hecl::SystemString str; hecl::SystemString str;
if (path.getAuxInfo().empty()) if (path.getAuxInfo().empty())
str = hecl::SysFormat(_SYS_STR("Cooked %s"), path.getRelativePath().data()); str = hecl::SysFormat(_SYS_STR("Cooked %s"), path.getRelativePath().data());
@ -207,21 +177,18 @@ bool ClientProcess::syncCook(const hecl::ProjectPath& path, Database::IDataSpec*
return false; return false;
} }
void ClientProcess::swapCompletedQueue(std::list<std::shared_ptr<Transaction>>& queue) void ClientProcess::swapCompletedQueue(std::list<std::shared_ptr<Transaction>>& queue) {
{
std::unique_lock<std::mutex> lk(m_mutex); std::unique_lock<std::mutex> lk(m_mutex);
queue.swap(m_completedQueue); queue.swap(m_completedQueue);
} }
void ClientProcess::waitUntilComplete() void ClientProcess::waitUntilComplete() {
{
std::unique_lock<std::mutex> lk(m_mutex); std::unique_lock<std::mutex> lk(m_mutex);
while (isBusy()) while (isBusy())
m_waitCv.wait(lk); m_waitCv.wait(lk);
} }
void ClientProcess::shutdown() void ClientProcess::shutdown() {
{
if (!m_running) if (!m_running)
return; return;
std::unique_lock<std::mutex> lk(m_mutex); std::unique_lock<std::mutex> lk(m_mutex);
@ -234,4 +201,4 @@ void ClientProcess::shutdown()
worker.m_thr.join(); worker.m_thr.join();
} }
} } // namespace hecl

View File

@ -14,36 +14,33 @@ extern pD3DCompile D3DCompilePROC;
#include <memory> #include <memory>
#endif #endif
namespace hecl namespace hecl {
{
logvisor::Module Log("hecl::Compilers"); logvisor::Module Log("hecl::Compilers");
namespace PlatformType namespace PlatformType {
{
const char* OpenGL::Name = "OpenGL"; const char* OpenGL::Name = "OpenGL";
const char* Vulkan::Name = "Vulkan"; const char* Vulkan::Name = "Vulkan";
const char* D3D11::Name = "D3D11"; const char* D3D11::Name = "D3D11";
const char* Metal::Name = "Metal"; const char* Metal::Name = "Metal";
const char* NX::Name = "NX"; const char* NX::Name = "NX";
} } // namespace PlatformType
namespace PipelineStage namespace PipelineStage {
{
const char* Null::Name = "Null"; const char* Null::Name = "Null";
const char* Vertex::Name = "Vertex"; const char* Vertex::Name = "Vertex";
const char* Fragment::Name = "Fragment"; const char* Fragment::Name = "Fragment";
const char* Geometry::Name = "Geometry"; const char* Geometry::Name = "Geometry";
const char* Control::Name = "Control"; const char* Control::Name = "Control";
const char* Evaluation::Name = "Evaluation"; const char* Evaluation::Name = "Evaluation";
} } // namespace PipelineStage
template<typename P> struct ShaderCompiler {}; template <typename P>
struct ShaderCompiler {};
template<> struct ShaderCompiler<PlatformType::OpenGL> template <>
{ struct ShaderCompiler<PlatformType::OpenGL> {
template<typename S> template <typename S>
static std::pair<StageBinaryData, size_t> Compile(std::string_view text) static std::pair<StageBinaryData, size_t> Compile(std::string_view text) {
{
std::string str = "#version 330\n"; std::string str = "#version 330\n";
str += BOO_GLSL_BINDING_HEAD; str += BOO_GLSL_BINDING_HEAD;
str += text; str += text;
@ -53,28 +50,20 @@ template<> struct ShaderCompiler<PlatformType::OpenGL>
} }
}; };
template<> struct ShaderCompiler<PlatformType::Vulkan> template <>
{ struct ShaderCompiler<PlatformType::Vulkan> {
static constexpr EShLanguage ShaderTypes[] = static constexpr EShLanguage ShaderTypes[] = {EShLangVertex, /* Invalid */
{ EShLangVertex, EShLangFragment, EShLangGeometry,
EShLangVertex, /* Invalid */ EShLangTessControl, EShLangTessEvaluation};
EShLangVertex,
EShLangFragment,
EShLangGeometry,
EShLangTessControl,
EShLangTessEvaluation
};
template<typename S> template <typename S>
static std::pair<StageBinaryData, size_t> Compile(std::string_view text) static std::pair<StageBinaryData, size_t> Compile(std::string_view text) {
{
EShLanguage lang = ShaderTypes[int(S::Enum)]; EShLanguage lang = ShaderTypes[int(S::Enum)];
const EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules); const EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules);
glslang::TShader shader(lang); glslang::TShader shader(lang);
const char* strings[] = { "#version 330\n", BOO_GLSL_BINDING_HEAD, text.data() }; const char* strings[] = {"#version 330\n", BOO_GLSL_BINDING_HEAD, text.data()};
shader.setStrings(strings, 3); shader.setStrings(strings, 3);
if (!shader.parse(&glslang::DefaultTBuiltInResource, 110, false, messages)) if (!shader.parse(&glslang::DefaultTBuiltInResource, 110, false, messages)) {
{
printf("%s\n", text.data()); printf("%s\n", text.data());
Log.report(logvisor::Fatal, "unable to compile shader\n%s", shader.getInfoLog()); Log.report(logvisor::Fatal, "unable to compile shader\n%s", shader.getInfoLog());
return {}; return {};
@ -82,8 +71,7 @@ template<> struct ShaderCompiler<PlatformType::Vulkan>
glslang::TProgram prog; glslang::TProgram prog;
prog.addShader(&shader); prog.addShader(&shader);
if (!prog.link(messages)) if (!prog.link(messages)) {
{
Log.report(logvisor::Fatal, "unable to link shader program\n%s", prog.getInfoLog()); Log.report(logvisor::Fatal, "unable to link shader program\n%s", prog.getInfoLog());
return {}; return {};
} }
@ -97,36 +85,25 @@ template<> struct ShaderCompiler<PlatformType::Vulkan>
}; };
#if _WIN32 #if _WIN32
static const char* D3DShaderTypes[] = static const char* D3DShaderTypes[] = {nullptr, "vs_5_0", "ps_5_0", "gs_5_0", "hs_5_0", "ds_5_0"};
{ template <>
nullptr, struct ShaderCompiler<PlatformType::D3D11> {
"vs_5_0",
"ps_5_0",
"gs_5_0",
"hs_5_0",
"ds_5_0"
};
template<> struct ShaderCompiler<PlatformType::D3D11>
{
#if _DEBUG && 0 #if _DEBUG && 0
#define BOO_D3DCOMPILE_FLAG D3DCOMPILE_DEBUG | D3DCOMPILE_OPTIMIZATION_LEVEL0 #define BOO_D3DCOMPILE_FLAG D3DCOMPILE_DEBUG | D3DCOMPILE_OPTIMIZATION_LEVEL0
#else #else
#define BOO_D3DCOMPILE_FLAG D3DCOMPILE_OPTIMIZATION_LEVEL3 #define BOO_D3DCOMPILE_FLAG D3DCOMPILE_OPTIMIZATION_LEVEL3
#endif #endif
template<typename S> template <typename S>
static std::pair<StageBinaryData, size_t> Compile(std::string_view text) static std::pair<StageBinaryData, size_t> Compile(std::string_view text) {
{
ComPtr<ID3DBlob> errBlob; ComPtr<ID3DBlob> errBlob;
ComPtr<ID3DBlob> blobOut; ComPtr<ID3DBlob> blobOut;
if (FAILED(D3DCompilePROC(text.data(), text.size(), "Boo HLSL Source", nullptr, nullptr, "main", if (FAILED(D3DCompilePROC(text.data(), text.size(), "Boo HLSL Source", nullptr, nullptr, "main",
D3DShaderTypes[int(S::Enum)], BOO_D3DCOMPILE_FLAG, 0, &blobOut, &errBlob))) D3DShaderTypes[int(S::Enum)], BOO_D3DCOMPILE_FLAG, 0, &blobOut, &errBlob))) {
{
printf("%s\n", text.data()); printf("%s\n", text.data());
Log.report(logvisor::Fatal, "error compiling shader: %s", errBlob->GetBufferPointer()); Log.report(logvisor::Fatal, "error compiling shader: %s", errBlob->GetBufferPointer());
return {}; return {};
} }
std::pair<StageBinaryData, size_t> ret(MakeStageBinaryData(blobOut->GetBufferSize()), std::pair<StageBinaryData, size_t> ret(MakeStageBinaryData(blobOut->GetBufferSize()), blobOut->GetBufferSize());
blobOut->GetBufferSize());
memcpy(ret.first.get(), blobOut->GetBufferPointer(), blobOut->GetBufferSize()); memcpy(ret.first.get(), blobOut->GetBufferPointer(), blobOut->GetBufferSize());
return ret; return ret;
} }
@ -134,21 +111,19 @@ template<> struct ShaderCompiler<PlatformType::D3D11>
#endif #endif
#if __APPLE__ #if __APPLE__
template<> struct ShaderCompiler<PlatformType::Metal> template <>
{ struct ShaderCompiler<PlatformType::Metal> {
static bool m_didCompilerSearch; static bool m_didCompilerSearch;
static bool m_hasCompiler; static bool m_hasCompiler;
static bool SearchForCompiler() static bool SearchForCompiler() {
{
m_didCompilerSearch = true; m_didCompilerSearch = true;
const char* no_metal_compiler = getenv("HECL_NO_METAL_COMPILER"); const char* no_metal_compiler = getenv("HECL_NO_METAL_COMPILER");
if (no_metal_compiler && atoi(no_metal_compiler)) if (no_metal_compiler && atoi(no_metal_compiler))
return false; return false;
pid_t pid = fork(); pid_t pid = fork();
if (!pid) if (!pid) {
{
execlp("xcrun", "xcrun", "-sdk", "macosx", "metal", NULL); execlp("xcrun", "xcrun", "-sdk", "macosx", "metal", NULL);
/* xcrun returns 72 if metal command not found; /* xcrun returns 72 if metal command not found;
* emulate that if xcrun not found */ * emulate that if xcrun not found */
@ -162,27 +137,24 @@ template<> struct ShaderCompiler<PlatformType::Metal>
return WEXITSTATUS(status) == 1; return WEXITSTATUS(status) == 1;
} }
template<typename S> template <typename S>
static std::pair<StageBinaryData, size_t> Compile(std::string_view text) static std::pair<StageBinaryData, size_t> Compile(std::string_view text) {
{
if (!m_didCompilerSearch) if (!m_didCompilerSearch)
m_hasCompiler = SearchForCompiler(); m_hasCompiler = SearchForCompiler();
std::string str = "#include <metal_stdlib>\n" std::string str =
"#include <metal_stdlib>\n"
"using namespace metal;\n"; "using namespace metal;\n";
str += text; str += text;
std::pair<StageBinaryData, size_t> ret; std::pair<StageBinaryData, size_t> ret;
if (!m_hasCompiler) if (!m_hasCompiler) {
{
/* First byte unset to indicate source data */ /* First byte unset to indicate source data */
ret.first = MakeStageBinaryData(str.size() + 2); ret.first = MakeStageBinaryData(str.size() + 2);
ret.first.get()[0] = 0; ret.first.get()[0] = 0;
ret.second = str.size() + 2; ret.second = str.size() + 2;
memcpy(&ret.first.get()[1], str.data(), str.size() + 1); memcpy(&ret.first.get()[1], str.data(), str.size() + 1);
} } else {
else
{
int compilerOut[2]; int compilerOut[2];
int compilerIn[2]; int compilerIn[2];
pipe(compilerOut); pipe(compilerOut);
@ -195,8 +167,7 @@ template<> struct ShaderCompiler<PlatformType::Metal>
/* Pipe source write to compiler */ /* Pipe source write to compiler */
pid_t compilerPid = fork(); pid_t compilerPid = fork();
if (!compilerPid) if (!compilerPid) {
{
dup2(compilerIn[0], STDIN_FILENO); dup2(compilerIn[0], STDIN_FILENO);
dup2(compilerOut[1], STDOUT_FILENO); dup2(compilerOut[1], STDOUT_FILENO);
@ -215,8 +186,7 @@ template<> struct ShaderCompiler<PlatformType::Metal>
/* Pipe compiler to linker */ /* Pipe compiler to linker */
pid_t linkerPid = fork(); pid_t linkerPid = fork();
if (!linkerPid) if (!linkerPid) {
{
dup2(compilerOut[0], STDIN_FILENO); dup2(compilerOut[0], STDIN_FILENO);
close(compilerOut[0]); close(compilerOut[0]);
@ -232,11 +202,9 @@ template<> struct ShaderCompiler<PlatformType::Metal>
/* Stream in source */ /* Stream in source */
const char* inPtr = str.data(); const char* inPtr = str.data();
size_t inRem = str.size(); size_t inRem = str.size();
while (inRem) while (inRem) {
{
ssize_t writeRes = write(compilerIn[1], inPtr, inRem); ssize_t writeRes = write(compilerIn[1], inPtr, inRem);
if (writeRes < 0) if (writeRes < 0) {
{
fprintf(stderr, "write fail %s\n", strerror(errno)); fprintf(stderr, "write fail %s\n", strerror(errno));
break; break;
} }
@ -247,30 +215,26 @@ template<> struct ShaderCompiler<PlatformType::Metal>
/* Wait for completion */ /* Wait for completion */
int compilerStat, linkerStat; int compilerStat, linkerStat;
while (waitpid(compilerPid, &compilerStat, 0) < 0) while (waitpid(compilerPid, &compilerStat, 0) < 0) {
{
if (errno == EINTR) if (errno == EINTR)
continue; continue;
Log.report(logvisor::Fatal, "waitpid fail %s", strerror(errno)); Log.report(logvisor::Fatal, "waitpid fail %s", strerror(errno));
return {}; return {};
} }
if (WEXITSTATUS(compilerStat)) if (WEXITSTATUS(compilerStat)) {
{
Log.report(logvisor::Fatal, "compile fail"); Log.report(logvisor::Fatal, "compile fail");
return {}; return {};
} }
while (waitpid(linkerPid, &linkerStat, 0) < 0) while (waitpid(linkerPid, &linkerStat, 0) < 0) {
{
if (errno == EINTR) if (errno == EINTR)
continue; continue;
Log.report(logvisor::Fatal, "waitpid fail %s", strerror(errno)); Log.report(logvisor::Fatal, "waitpid fail %s", strerror(errno));
return {}; return {};
} }
if (WEXITSTATUS(linkerStat)) if (WEXITSTATUS(linkerStat)) {
{
Log.report(logvisor::Fatal, "link fail"); Log.report(logvisor::Fatal, "link fail");
return {}; return {};
} }
@ -296,11 +260,10 @@ bool ShaderCompiler<PlatformType::Metal>::m_hasCompiler = false;
#endif #endif
#if HECL_NOUVEAU_NX #if HECL_NOUVEAU_NX
template<> struct ShaderCompiler<PlatformType::NX> template <>
{ struct ShaderCompiler<PlatformType::NX> {
template<typename S> template <typename S>
static std::pair<std::shared_ptr<uint8_t[]>, size_t> Compile(std::string_view text) static std::pair<std::shared_ptr<uint8_t[]>, size_t> Compile(std::string_view text) {
{
std::string str = "#version 330\n"; std::string str = "#version 330\n";
str += BOO_GLSL_BINDING_HEAD; str += BOO_GLSL_BINDING_HEAD;
str += text; str += text;
@ -311,17 +274,16 @@ template<> struct ShaderCompiler<PlatformType::NX>
}; };
#endif #endif
template<typename P, typename S> template <typename P, typename S>
std::pair<StageBinaryData, size_t> CompileShader(std::string_view text) std::pair<StageBinaryData, size_t> CompileShader(std::string_view text) {
{
return ShaderCompiler<P>::template Compile<S>(text); return ShaderCompiler<P>::template Compile<S>(text);
} }
#define SPECIALIZE_COMPILE_SHADER(P) \ #define SPECIALIZE_COMPILE_SHADER(P) \
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Vertex>(std::string_view text); \ template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Vertex>(std::string_view text); \
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Fragment>(std::string_view text); \ template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Fragment>(std::string_view text); \
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Geometry>(std::string_view text); \ template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Geometry>(std::string_view text); \
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Control>(std::string_view text); \ template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Control>(std::string_view text); \
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Evaluation>(std::string_view text); template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Evaluation>(std::string_view text);
SPECIALIZE_COMPILE_SHADER(PlatformType::OpenGL) SPECIALIZE_COMPILE_SHADER(PlatformType::OpenGL)
SPECIALIZE_COMPILE_SHADER(PlatformType::Vulkan) SPECIALIZE_COMPILE_SHADER(PlatformType::Vulkan)
#if _WIN32 #if _WIN32
@ -334,4 +296,4 @@ SPECIALIZE_COMPILE_SHADER(PlatformType::Metal)
SPECIALIZE_COMPILE_SHADER(PlatformType::NX) SPECIALIZE_COMPILE_SHADER(PlatformType::NX)
#endif #endif
} } // namespace hecl

View File

@ -4,45 +4,46 @@
#include "hecl/hecl.hpp" #include "hecl/hecl.hpp"
#include "athena/Utility.hpp" #include "athena/Utility.hpp"
namespace hecl namespace hecl {
{
Console* Console::m_instance = nullptr; Console* Console::m_instance = nullptr;
Console::Console(CVarManager* cvarMgr) Console::Console(CVarManager* cvarMgr) : m_cvarMgr(cvarMgr), m_overwrite(false), m_cursorAtEnd(false) {
: m_cvarMgr(cvarMgr)
, m_overwrite(false)
, m_cursorAtEnd(false)
{
m_instance = this; m_instance = this;
registerCommand("help", "Prints information about a given function", "<command>", std::bind(&Console::help, this, std::placeholders::_1, std::placeholders::_2)); registerCommand("help", "Prints information about a given function", "<command>",
registerCommand("listCommands", "Prints a list of all available Commands", "", std::bind(&Console::listCommands, this, std::placeholders::_1, std::placeholders::_2)); std::bind(&Console::help, this, std::placeholders::_1, std::placeholders::_2));
registerCommand("listCVars", "Lists all available CVars", "", std::bind(&CVarManager::list, m_cvarMgr, std::placeholders::_1, std::placeholders::_2)); registerCommand("listCommands", "Prints a list of all available Commands", "",
registerCommand("setCVar", "Sets a given Console Variable to the specified value", "<cvar> <value>", std::bind(&CVarManager::setCVar, m_cvarMgr, std::placeholders::_1, std::placeholders::_2)); std::bind(&Console::listCommands, this, std::placeholders::_1, std::placeholders::_2));
registerCommand("getCVar", "Prints the value stored in the specified Console Variable", "<cvar>", std::bind(&CVarManager::getCVar, m_cvarMgr, std::placeholders::_1, std::placeholders::_2)); registerCommand("listCVars", "Lists all available CVars", "",
m_conSpeed = cvarMgr->findOrMakeCVar("con_speed", "Speed at which the console opens and closes, calculated as pixels per second", 1.f, std::bind(&CVarManager::list, m_cvarMgr, std::placeholders::_1, std::placeholders::_2));
hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive); registerCommand("setCVar", "Sets a given Console Variable to the specified value", "<cvar> <value>",
m_conHeight = cvarMgr->findOrMakeCVar("con_height", "Maximum absolute height of the console, height is calculated from the top of the window, expects values ranged from [0.f,1.f]", 0.5f, std::bind(&CVarManager::setCVar, m_cvarMgr, std::placeholders::_1, std::placeholders::_2));
hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive); registerCommand("getCVar", "Prints the value stored in the specified Console Variable", "<cvar>",
std::bind(&CVarManager::getCVar, m_cvarMgr, std::placeholders::_1, std::placeholders::_2));
m_conSpeed = cvarMgr->findOrMakeCVar("con_speed",
"Speed at which the console opens and closes, calculated as pixels per second",
1.f, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive);
m_conHeight = cvarMgr->findOrMakeCVar("con_height",
"Maximum absolute height of the console, height is calculated from the top of "
"the window, expects values ranged from [0.f,1.f]",
0.5f, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive);
} }
void Console::registerCommand(std::string_view name, std::string_view helpText, std::string_view usage, const std::function<void(Console*, const std::vector<std::string> &)>&& func, SConsoleCommand::ECommandFlags cmdFlags) void Console::registerCommand(std::string_view name, std::string_view helpText, std::string_view usage,
{ const std::function<void(Console*, const std::vector<std::string>&)>&& func,
SConsoleCommand::ECommandFlags cmdFlags) {
std::string lowName = name.data(); std::string lowName = name.data();
athena::utility::tolower(lowName); athena::utility::tolower(lowName);
if (m_commands.find(lowName) == m_commands.end()) if (m_commands.find(lowName) == m_commands.end())
m_commands[lowName] = SConsoleCommand{name.data(), helpText.data(), usage.data(), std::move(func), cmdFlags}; m_commands[lowName] = SConsoleCommand{name.data(), helpText.data(), usage.data(), std::move(func), cmdFlags};
} }
void Console::unregisterCommand(std::string_view name) void Console::unregisterCommand(std::string_view name) {
{
std::string lowName = name.data(); std::string lowName = name.data();
athena::utility::tolower(lowName); athena::utility::tolower(lowName);
if (m_commands.find(lowName) != m_commands.end()) if (m_commands.find(lowName) != m_commands.end())
m_commands.erase(m_commands.find(lowName)); m_commands.erase(m_commands.find(lowName));
} }
void Console::executeString(const std::string& str) void Console::executeString(const std::string& str) {
{
if (str.empty()) if (str.empty())
return; return;
@ -52,8 +53,7 @@ void Console::executeString(const std::string& str)
if (commands.empty()) if (commands.empty())
return; return;
for (std::string command : commands) for (std::string command : commands) {
{
command = athena::utility::trim(command); command = athena::utility::trim(command);
std::vector<std::string> tmpArgs = athena::utility::split(command, ' '); std::vector<std::string> tmpArgs = athena::utility::split(command, ' ');
if (tmpArgs.empty()) if (tmpArgs.empty())
@ -64,36 +64,28 @@ void Console::executeString(const std::string& str)
bool isInLiteral = false; bool isInLiteral = false;
std::string curLiteral; std::string curLiteral;
int depth = 0; int depth = 0;
for (std::string arg : tmpArgs) for (std::string arg : tmpArgs) {
{ if ((arg.front() == '\'' || arg.front() == '"')) {
if ((arg.front() == '\'' || arg.front() == '"'))
{
++depth; ++depth;
isInLiteral = true; isInLiteral = true;
curLiteral += arg; curLiteral += arg;
} } else if ((arg.back() == '\'' || arg.back() == '"') && isInLiteral) {
else if ((arg.back() == '\'' || arg.back() == '"') && isInLiteral)
{
--depth; --depth;
curLiteral += arg; curLiteral += arg;
args.push_back(curLiteral); args.push_back(curLiteral);
if (depth <= 0) if (depth <= 0) {
{
depth = 0; depth = 0;
isInLiteral = false; isInLiteral = false;
curLiteral.clear(); curLiteral.clear();
} }
} } else if (isInLiteral)
else if (isInLiteral)
curLiteral += arg; curLiteral += arg;
else else
args.push_back(arg); args.push_back(arg);
} }
if (isInLiteral) if (isInLiteral) {
{ if ((curLiteral.back() != '\'' && curLiteral.back() != '"') || depth > 1) {
if ((curLiteral.back() != '\'' && curLiteral.back() != '"') || depth > 1)
{
report(Level::Warning, "Unterminated string literal"); report(Level::Warning, "Unterminated string literal");
return; return;
} }
@ -105,47 +97,38 @@ void Console::executeString(const std::string& str)
std::string lowComName = commandName; std::string lowComName = commandName;
athena::utility::tolower(lowComName); athena::utility::tolower(lowComName);
if (m_commands.find(lowComName) != m_commands.end()) if (m_commands.find(lowComName) != m_commands.end()) {
{
const SConsoleCommand& cmd = m_commands[lowComName]; const SConsoleCommand& cmd = m_commands[lowComName];
if (bool(cmd.m_flags & SConsoleCommand::ECommandFlags::Developer) && !com_developer->toBoolean()) if (bool(cmd.m_flags & SConsoleCommand::ECommandFlags::Developer) && !com_developer->toBoolean()) {
{
report(Level::Error, "This command can only be executed in developer mode", commandName.c_str()); report(Level::Error, "This command can only be executed in developer mode", commandName.c_str());
return; return;
} }
if (bool(cmd.m_flags & SConsoleCommand::ECommandFlags::Cheat) && !com_enableCheats->toBoolean()) if (bool(cmd.m_flags & SConsoleCommand::ECommandFlags::Cheat) && !com_enableCheats->toBoolean()) {
{
report(Level::Error, "This command can only be executed with cheats enabled", commandName.c_str()); report(Level::Error, "This command can only be executed with cheats enabled", commandName.c_str());
return; return;
} }
m_commands[lowComName].m_func(this, args); m_commands[lowComName].m_func(this, args);
} } else if (const CVar* cv = m_cvarMgr->findCVar(commandName)) {
else if (const CVar* cv = m_cvarMgr->findCVar(commandName))
{
args.insert(args.begin(), commandName); args.insert(args.begin(), commandName);
if (args.size() > 1) if (args.size() > 1)
m_cvarMgr->setCVar(this, args); m_cvarMgr->setCVar(this, args);
else else
m_cvarMgr->getCVar(this, args); m_cvarMgr->getCVar(this, args);
} } else
else
report(Level::Error, "Command '%s' is not valid!", commandName.c_str()); report(Level::Error, "Command '%s' is not valid!", commandName.c_str());
} }
} }
void Console::help(Console* /*con*/, const std::vector<std::string>& args) void Console::help(Console* /*con*/, const std::vector<std::string>& args) {
{ if (args.empty()) {
if (args.empty())
{
report(Level::Info, "Expected usage: help <command>"); report(Level::Info, "Expected usage: help <command>");
return; return;
} }
std::string cmd = args.front(); std::string cmd = args.front();
athena::utility::tolower(cmd); athena::utility::tolower(cmd);
auto it = m_commands.find(cmd); auto it = m_commands.find(cmd);
if (it == m_commands.end()) if (it == m_commands.end()) {
{
report(Level::Error, "No such command '%s'", args.front().c_str()); report(Level::Error, "No such command '%s'", args.front().c_str());
return; return;
} }
@ -155,66 +138,55 @@ void Console::help(Console* /*con*/, const std::vector<std::string>& args)
report(Level::Info, "Usage: %s %s", it->second.m_displayName.c_str(), it->second.m_usage.c_str()); report(Level::Info, "Usage: %s %s", it->second.m_displayName.c_str(), it->second.m_usage.c_str());
} }
void Console::listCommands(Console* /*con*/, const std::vector<std::string>& /*args*/) void Console::listCommands(Console* /*con*/, const std::vector<std::string>& /*args*/) {
{
for (const auto& comPair : m_commands) for (const auto& comPair : m_commands)
report(Level::Info, "'%s': %s", comPair.second.m_displayName.c_str(), comPair.second.m_helpString.c_str()); report(Level::Info, "'%s': %s", comPair.second.m_displayName.c_str(), comPair.second.m_helpString.c_str());
} }
bool Console::commandExists(std::string_view cmd) bool Console::commandExists(std::string_view cmd) {
{
std::string cmdName = cmd.data(); std::string cmdName = cmd.data();
athena::utility::tolower(cmdName); athena::utility::tolower(cmdName);
return m_commands.find(cmdName) != m_commands.end(); return m_commands.find(cmdName) != m_commands.end();
} }
void Console::report(Level level, const char* fmt, va_list list) void Console::report(Level level, const char* fmt, va_list list) {
{
char tmp[2048]; char tmp[2048];
vsnprintf(tmp, 2048, fmt, list); vsnprintf(tmp, 2048, fmt, list);
std::vector<std::string> lines = athena::utility::split(tmp, '\n'); std::vector<std::string> lines = athena::utility::split(tmp, '\n');
for (const std::string& line : lines) for (const std::string& line : lines) {
{
std::string v = athena::utility::sprintf("%s", line.c_str()); std::string v = athena::utility::sprintf("%s", line.c_str());
m_log.emplace_back(v, level); m_log.emplace_back(v, level);
} }
printf("%s\n", tmp); printf("%s\n", tmp);
} }
void Console::report(Level level, const char* fmt, ...) void Console::report(Level level, const char* fmt, ...) {
{
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
report(level, fmt, ap); report(level, fmt, ap);
va_end(ap); va_end(ap);
} }
void Console::proc() void Console::proc() {
{ if (m_conHeight->isModified()) {
if (m_conHeight->isModified())
{
m_cachedConHeight = m_conHeight->toFloat(); m_cachedConHeight = m_conHeight->toFloat();
m_conHeight->clearModified(); m_conHeight->clearModified();
} }
if (m_conSpeed->isModified()) if (m_conSpeed->isModified()) {
{
m_cachedConSpeed = m_conSpeed->toFloat(); m_cachedConSpeed = m_conSpeed->toFloat();
m_conSpeed->clearModified(); m_conSpeed->clearModified();
} }
if (m_state == State::Opened) if (m_state == State::Opened) {
{
printf("\r%s ", m_commandString.c_str()); printf("\r%s ", m_commandString.c_str());
fflush(stdout); fflush(stdout);
} } else if (m_state == State::Opening)
else if (m_state == State::Opening)
m_state = State::Opened; m_state = State::Opened;
else if (m_state == State::Closing) else if (m_state == State::Closing)
m_state = State::Closed; m_state = State::Closed;
if (m_cursorPosition > int(m_commandString.size() - 1)) if (m_cursorPosition > int(m_commandString.size() - 1))
m_cursorPosition = int(m_commandString.size() - 1); m_cursorPosition = int(m_commandString.size() - 1);
if (m_cursorPosition < -1) if (m_cursorPosition < -1)
@ -226,61 +198,46 @@ void Console::proc()
m_logOffset = 0; m_logOffset = 0;
} }
void Console::draw(boo::IGraphicsCommandQueue* /*gfxQ*/) void Console::draw(boo::IGraphicsCommandQueue* /*gfxQ*/) {}
{
}
void Console::handleCharCode(unsigned long chr, boo::EModifierKey /*mod*/, bool /*repeat*/) void Console::handleCharCode(unsigned long chr, boo::EModifierKey /*mod*/, bool /*repeat*/) {
{ if (chr == U'`' || chr == U'~') {
if (chr == U'`' || chr == U'~')
{
if (m_state == State::Closed || m_state == State::Closing) if (m_state == State::Closed || m_state == State::Closing)
m_state = State::Opening; m_state = State::Opening;
else else
m_state = State::Closing; m_state = State::Closing;
} }
if (m_state == State::Opened) if (m_state == State::Opened) {
{ if (!m_commandString.empty() && m_cursorPosition + 1 < int(m_commandString.size())) {
if (!m_commandString.empty() && m_cursorPosition + 1 < int(m_commandString.size()))
{
if (m_overwrite) if (m_overwrite)
m_commandString[unsigned(m_cursorPosition + 1)] = char(chr); m_commandString[unsigned(m_cursorPosition + 1)] = char(chr);
else else
m_commandString.insert(m_commandString.begin() + m_cursorPosition + 1, char(chr)); m_commandString.insert(m_commandString.begin() + m_cursorPosition + 1, char(chr));
} } else
else
m_commandString += char(chr); m_commandString += char(chr);
++m_cursorPosition; ++m_cursorPosition;
} }
} }
void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, bool /*repeat*/) void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, bool /*repeat*/) {
{
if (m_state != Opened) if (m_state != Opened)
return; return;
switch (sp) switch (sp) {
{
case boo::ESpecialKey::Insert: case boo::ESpecialKey::Insert:
m_overwrite ^= 1; m_overwrite ^= 1;
break; break;
case boo::ESpecialKey::Backspace: case boo::ESpecialKey::Backspace: {
{ if (!m_commandString.empty()) {
if (!m_commandString.empty()) if (int(mod & boo::EModifierKey::Ctrl) != 0) {
{
if (int(mod & boo::EModifierKey::Ctrl) != 0)
{
size_t index = m_commandString.rfind(' ', size_t(m_cursorPosition - 1)); size_t index = m_commandString.rfind(' ', size_t(m_cursorPosition - 1));
if (index == std::string::npos) if (index == std::string::npos) {
{
m_commandString.clear(); m_commandString.clear();
m_cursorPosition = -1; m_cursorPosition = -1;
} } else {
else
{
m_commandString.erase(index, (index - m_commandString.size())); m_commandString.erase(index, (index - m_commandString.size()));
m_cursorPosition = int(index); m_cursorPosition = int(index);
} }
@ -294,16 +251,13 @@ void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, b
} }
break; break;
} }
case boo::ESpecialKey::Delete: case boo::ESpecialKey::Delete: {
{ if (!m_commandString.empty()) {
if (!m_commandString.empty())
{
// Don't try to delete if the cursor is at the end of the line // Don't try to delete if the cursor is at the end of the line
if ((m_cursorPosition + 1) >= int(m_commandString.size())) if ((m_cursorPosition + 1) >= int(m_commandString.size()))
break; break;
if (int(mod & boo::EModifierKey::Ctrl) != 0) if (int(mod & boo::EModifierKey::Ctrl) != 0) {
{
size_t index = m_commandString.find_first_of(' ', size_t(m_cursorPosition + 1)); size_t index = m_commandString.find_first_of(' ', size_t(m_cursorPosition + 1));
if (index != std::string::npos) if (index != std::string::npos)
m_commandString.erase(size_t(m_cursorPosition + 1), index + 1); m_commandString.erase(size_t(m_cursorPosition + 1), index + 1);
@ -315,20 +269,17 @@ void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, b
} }
break; break;
} }
case boo::ESpecialKey::PgUp: case boo::ESpecialKey::PgUp: {
{
if (m_logOffset < int(m_log.size() - m_maxLines) - 1) if (m_logOffset < int(m_log.size() - m_maxLines) - 1)
m_logOffset++; m_logOffset++;
break; break;
} }
case boo::ESpecialKey::PgDown: case boo::ESpecialKey::PgDown: {
{
if (m_logOffset > 0) if (m_logOffset > 0)
m_logOffset--; m_logOffset--;
break; break;
} }
case boo::ESpecialKey::Enter: case boo::ESpecialKey::Enter: {
{
printf("\n"); printf("\n");
executeString(m_commandString); executeString(m_commandString);
m_cursorPosition = -1; m_cursorPosition = -1;
@ -338,8 +289,7 @@ void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, b
m_cursorTime = 0.f; m_cursorTime = 0.f;
break; break;
} }
case boo::ESpecialKey::Left: case boo::ESpecialKey::Left: {
{
if (m_cursorPosition < 0) if (m_cursorPosition < 0)
break; break;
@ -352,13 +302,11 @@ void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, b
m_cursorTime = 0.f; m_cursorTime = 0.f;
break; break;
} }
case boo::ESpecialKey::Right: case boo::ESpecialKey::Right: {
{
if (m_cursorPosition >= int(m_commandString.size() - 1)) if (m_cursorPosition >= int(m_commandString.size() - 1))
break; break;
if (int(mod & boo::EModifierKey::Ctrl) != 0) if (int(mod & boo::EModifierKey::Ctrl) != 0) {
{
if (m_commandString[size_t(m_cursorPosition)] == ' ') if (m_commandString[size_t(m_cursorPosition)] == ' ')
m_cursorPosition++; m_cursorPosition++;
@ -367,8 +315,7 @@ void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, b
m_cursorPosition = int(m_commandString.size() - 1); m_cursorPosition = int(m_commandString.size() - 1);
else else
m_cursorPosition = int(tmpPos); m_cursorPosition = int(tmpPos);
} } else
else
m_cursorPosition++; m_cursorPosition++;
m_showCursor = true; m_showCursor = true;
@ -376,8 +323,7 @@ void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, b
break; break;
} }
case boo::ESpecialKey::Up: case boo::ESpecialKey::Up: {
{
if (m_commandHistory.size() == 0) if (m_commandHistory.size() == 0)
break; break;
@ -390,17 +336,13 @@ void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, b
m_cursorPosition = int(m_commandString.size() - 1); m_cursorPosition = int(m_commandString.size() - 1);
break; break;
} }
case boo::ESpecialKey::Down: case boo::ESpecialKey::Down: {
{
if (m_commandHistory.empty()) if (m_commandHistory.empty())
break; break;
m_currentCommand--; m_currentCommand--;
if (m_currentCommand >= 0) if (m_currentCommand >= 0) {
{
m_commandString = m_commandHistory[size_t(m_currentCommand)]; m_commandString = m_commandHistory[size_t(m_currentCommand)];
} } else if (m_currentCommand <= -1) {
else if (m_currentCommand <= -1)
{
m_currentCommand = -1; m_currentCommand = -1;
m_commandString.clear(); m_commandString.clear();
} }
@ -418,60 +360,51 @@ void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, b
} }
} }
void Console::handleSpecialKeyUp(boo::ESpecialKey /*sp*/, boo::EModifierKey /*mod*/) void Console::handleSpecialKeyUp(boo::ESpecialKey /*sp*/, boo::EModifierKey /*mod*/) {}
{
}
void Console::LogVisorAdapter::report(const char* modName, logvisor::Level severity, const char *format, va_list ap) void Console::LogVisorAdapter::report(const char* modName, logvisor::Level severity, const char* format, va_list ap) {
{
char tmp[2048]; char tmp[2048];
vsnprintf(tmp, 2048, format, ap); vsnprintf(tmp, 2048, format, ap);
std::vector<std::string> lines = athena::utility::split(tmp, '\n'); std::vector<std::string> lines = athena::utility::split(tmp, '\n');
for (const std::string& line : lines) for (const std::string& line : lines) {
{
std::string v = athena::utility::sprintf("[%s] %s", modName, line.c_str()); std::string v = athena::utility::sprintf("[%s] %s", modName, line.c_str());
m_con->m_log.emplace_back(v, Console::Level(severity)); m_con->m_log.emplace_back(v, Console::Level(severity));
} }
} }
void Console::LogVisorAdapter::report(const char* modName, logvisor::Level severity, const wchar_t* format, va_list ap) void Console::LogVisorAdapter::report(const char* modName, logvisor::Level severity, const wchar_t* format,
{ va_list ap) {
wchar_t tmp[2048]; wchar_t tmp[2048];
vswprintf(tmp, 2048, format, ap); vswprintf(tmp, 2048, format, ap);
std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n'); std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n');
for (const std::string& line : lines) for (const std::string& line : lines) {
{
std::string v = athena::utility::sprintf("[%s] %s", modName, line.c_str()); std::string v = athena::utility::sprintf("[%s] %s", modName, line.c_str());
m_con->m_log.emplace_back(v, Console::Level(severity)); m_con->m_log.emplace_back(v, Console::Level(severity));
} }
} }
void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file, unsigned linenum, const char* format, va_list ap) void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file,
{ unsigned linenum, const char* format, va_list ap) {
char tmp[2048]; char tmp[2048];
vsnprintf(tmp, 2048, format, ap); vsnprintf(tmp, 2048, format, ap);
std::string v = athena::utility::sprintf("[%s] %s %s:%i", modName, tmp, file, linenum); std::string v = athena::utility::sprintf("[%s] %s %s:%i", modName, tmp, file, linenum);
m_con->m_log.emplace_back(v, Console::Level(severity)); m_con->m_log.emplace_back(v, Console::Level(severity));
} }
void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file, unsigned linenum, const wchar_t* format, va_list ap) void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file,
{ unsigned linenum, const wchar_t* format, va_list ap) {
wchar_t tmp[2048]; wchar_t tmp[2048];
vswprintf(tmp, 2048, format, ap); vswprintf(tmp, 2048, format, ap);
std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n'); std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n');
for (const std::string& line : lines) for (const std::string& line : lines) {
{
std::string v = athena::utility::sprintf("[%s] %s %s:%i", modName, line.c_str(), file, linenum); std::string v = athena::utility::sprintf("[%s] %s %s:%i", modName, line.c_str(), file, linenum);
m_con->m_log.emplace_back(v, Console::Level(severity)); m_con->m_log.emplace_back(v, Console::Level(severity));
} }
} }
void Console::dumpLog() void Console::dumpLog() {
{ for (const auto& l : m_log) {
for (const auto& l : m_log) switch (l.second) {
{
switch(l.second)
{
case Level::Info: case Level::Info:
printf("%s\n", l.first.c_str()); printf("%s\n", l.first.c_str());
break; break;
@ -488,13 +421,7 @@ void Console::dumpLog()
} }
} }
void Console::RegisterLogger(Console* con) void Console::RegisterLogger(Console* con) { logvisor::MainLoggers.emplace_back(new LogVisorAdapter(con)); }
{
logvisor::MainLoggers.emplace_back(new LogVisorAdapter(con));
}
Console* Console::instance() Console* Console::instance() { return m_instance; }
{ } // namespace hecl
return m_instance;
}
}

View File

@ -12,14 +12,11 @@
#define BOLD "\x1b[1m" #define BOLD "\x1b[1m"
#define NORMAL "\x1b[0m" #define NORMAL "\x1b[0m"
namespace hecl::Frontend namespace hecl::Frontend {
{
std::string Diagnostics::sourceDiagString(const SourceLocation& l, bool ansi) const std::string Diagnostics::sourceDiagString(const SourceLocation& l, bool ansi) const {
{
std::string::const_iterator it = m_source.begin(); std::string::const_iterator it = m_source.begin();
for (int i=1 ; i<l.line ; ++i) for (int i = 1; i < l.line; ++i) {
{
while (*it != '\n' && it != m_source.end()) while (*it != '\n' && it != m_source.end())
++it; ++it;
if (*it == '\n') if (*it == '\n')
@ -32,7 +29,7 @@ std::string Diagnostics::sourceDiagString(const SourceLocation& l, bool ansi) co
std::string retval(begin, end); std::string retval(begin, end);
retval += '\n'; retval += '\n';
for (int i=1 ; i<l.col ; ++i) for (int i = 1; i < l.col; ++i)
retval += ' '; retval += ' ';
if (ansi) if (ansi)
retval += GREEN "^" NORMAL; retval += GREEN "^" NORMAL;
@ -41,8 +38,7 @@ std::string Diagnostics::sourceDiagString(const SourceLocation& l, bool ansi) co
return retval; return retval;
} }
void Diagnostics::reportScannerErr(const SourceLocation& l, const char* fmt, ...) void Diagnostics::reportScannerErr(const SourceLocation& l, const char* fmt, ...) {
{
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
char* result = nullptr; char* result = nullptr;
@ -55,56 +51,54 @@ void Diagnostics::reportScannerErr(const SourceLocation& l, const char* fmt, ...
#endif #endif
va_end(ap); va_end(ap);
if (logvisor::XtermColor) if (logvisor::XtermColor)
LogModule.report(logvisor::Fatal, CYAN "[Scanner]" NORMAL " %s " YELLOW "@%d:%d " NORMAL "\n%s\n%s", LogModule.report(logvisor::Fatal, CYAN "[Scanner]" NORMAL " %s " YELLOW "@%d:%d " NORMAL "\n%s\n%s", m_name.c_str(),
l.line, l.col, result, sourceDiagString(l, true).c_str());
else
LogModule.report(logvisor::Fatal, "[Scanner] %s @%d:%d\n%s\n%s", m_name.c_str(), l.line, l.col, result,
sourceDiagString(l, false).c_str());
free(result);
}
void Diagnostics::reportParserErr(const SourceLocation& l, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
char* result = nullptr;
#ifdef _WIN32
int length = _vscprintf(fmt, ap);
result = (char*)malloc(length);
vsnprintf(result, length, fmt, ap);
#else
vasprintf(&result, fmt, ap);
#endif
va_end(ap);
if (logvisor::XtermColor)
LogModule.report(logvisor::Fatal, CYAN "[Parser]" NORMAL " %s " YELLOW "@%d:%d " NORMAL "\n%s\n%s", m_name.c_str(),
l.line, l.col, result, sourceDiagString(l, true).c_str());
else
LogModule.report(logvisor::Fatal, "[Parser] %s @%d:%d\n%s\n%s", m_name.c_str(), l.line, l.col, result,
sourceDiagString(l, false).c_str());
free(result);
}
void Diagnostics::reportBackendErr(const SourceLocation& l, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
char* result = nullptr;
#ifdef _WIN32
int length = _vscprintf(fmt, ap);
result = (char*)malloc(length);
vsnprintf(result, length, fmt, ap);
#else
vasprintf(&result, fmt, ap);
#endif
va_end(ap);
if (logvisor::XtermColor)
LogModule.report(logvisor::Fatal, CYAN "[%s]" NORMAL " %s " YELLOW "@%d:%d " NORMAL "\n%s\n%s", m_backend.c_str(),
m_name.c_str(), l.line, l.col, result, sourceDiagString(l, true).c_str()); m_name.c_str(), l.line, l.col, result, sourceDiagString(l, true).c_str());
else else
LogModule.report(logvisor::Fatal, "[Scanner] %s @%d:%d\n%s\n%s", LogModule.report(logvisor::Fatal, "[%s] %s @%d:%d\n%s\n%s", m_backend.c_str(), m_name.c_str(), l.line, l.col,
m_name.c_str(), l.line, l.col, result, sourceDiagString(l, false).c_str()); result, sourceDiagString(l, false).c_str());
free(result); free(result);
} }
void Diagnostics::reportParserErr(const SourceLocation& l, const char* fmt, ...) } // namespace hecl::Frontend
{
va_list ap;
va_start(ap, fmt);
char* result = nullptr;
#ifdef _WIN32
int length = _vscprintf(fmt, ap);
result = (char*)malloc(length);
vsnprintf(result, length, fmt, ap);
#else
vasprintf(&result, fmt, ap);
#endif
va_end(ap);
if (logvisor::XtermColor)
LogModule.report(logvisor::Fatal, CYAN "[Parser]" NORMAL " %s " YELLOW "@%d:%d " NORMAL "\n%s\n%s",
m_name.c_str(), l.line, l.col, result, sourceDiagString(l, true).c_str());
else
LogModule.report(logvisor::Fatal, "[Parser] %s @%d:%d\n%s\n%s",
m_name.c_str(), l.line, l.col, result, sourceDiagString(l, false).c_str());
free(result);
}
void Diagnostics::reportBackendErr(const SourceLocation& l, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
char* result = nullptr;
#ifdef _WIN32
int length = _vscprintf(fmt, ap);
result = (char*)malloc(length);
vsnprintf(result, length, fmt, ap);
#else
vasprintf(&result, fmt, ap);
#endif
va_end(ap);
if (logvisor::XtermColor)
LogModule.report(logvisor::Fatal, CYAN "[%s]" NORMAL " %s " YELLOW "@%d:%d " NORMAL "\n%s\n%s",
m_backend.c_str(), m_name.c_str(), l.line, l.col, result, sourceDiagString(l, true).c_str());
else
LogModule.report(logvisor::Fatal, "[%s] %s @%d:%d\n%s\n%s",
m_backend.c_str(), m_name.c_str(), l.line, l.col, result, sourceDiagString(l, false).c_str());
free(result);
}
}

View File

@ -1,12 +1,9 @@
#include "hecl/Frontend.hpp" #include "hecl/Frontend.hpp"
namespace hecl::Frontend namespace hecl::Frontend {
{
int IR::Instruction::getChildCount() const int IR::Instruction::getChildCount() const {
{ switch (m_op) {
switch (m_op)
{
case OpType::Call: case OpType::Call:
return m_call.m_argInstIdxs.size(); return m_call.m_argInstIdxs.size();
case OpType::Arithmetic: case OpType::Arithmetic:
@ -19,10 +16,8 @@ int IR::Instruction::getChildCount() const
return -1; return -1;
} }
const IR::Instruction& IR::Instruction::getChildInst(const IR& ir, size_t idx) const const IR::Instruction& IR::Instruction::getChildInst(const IR& ir, size_t idx) const {
{ switch (m_op) {
switch (m_op)
{
case OpType::Call: case OpType::Call:
return ir.m_instructions.at(m_call.m_argInstIdxs.at(idx)); return ir.m_instructions.at(m_call.m_argInstIdxs.at(idx));
case OpType::Arithmetic: case OpType::Arithmetic:
@ -39,21 +34,19 @@ const IR::Instruction& IR::Instruction::getChildInst(const IR& ir, size_t idx) c
return *this; return *this;
} }
const atVec4f& IR::Instruction::getImmVec() const const atVec4f& IR::Instruction::getImmVec() const {
{
if (m_op != OpType::LoadImm) if (m_op != OpType::LoadImm)
LogModule.report(logvisor::Fatal, "invalid op type"); LogModule.report(logvisor::Fatal, "invalid op type");
return m_loadImm.m_immVec; return m_loadImm.m_immVec;
} }
template <class Op> template <class Op>
void IR::Instruction::Enumerate(typename Op::StreamT& s) void IR::Instruction::Enumerate(typename Op::StreamT& s) {
{
Do<Op>({"op"}, m_op, s); Do<Op>({"op"}, m_op, s);
Do<Op>({"target"}, m_target, s); Do<Op>({"target"}, m_target, s);
switch (m_op) switch (m_op) {
{ default:
default: break; break;
case OpType::Call: case OpType::Call:
Do<Op>({"call"}, m_call, s); Do<Op>({"call"}, m_call, s);
break; break;
@ -69,10 +62,8 @@ void IR::Instruction::Enumerate(typename Op::StreamT& s)
} }
} }
atInt8 IR::swizzleCompIdx(char aChar) atInt8 IR::swizzleCompIdx(char aChar) {
{ switch (aChar) {
switch (aChar)
{
case 'x': case 'x':
case 'r': case 'r':
return 0; return 0;
@ -91,50 +82,40 @@ atInt8 IR::swizzleCompIdx(char aChar)
return -1; return -1;
} }
int IR::addInstruction(const IRNode& n, IR::RegID target) int IR::addInstruction(const IRNode& n, IR::RegID target) {
{
if (n.kind == IRNode::Kind::None) if (n.kind == IRNode::Kind::None)
return -1; return -1;
switch (n.kind) switch (n.kind) {
{ case IRNode::Kind::Call: {
case IRNode::Kind::Call: if (!n.str.compare("vec3") && n.children.size() >= 3) {
{
if (!n.str.compare("vec3") && n.children.size() >= 3)
{
atVec4f vec = {}; atVec4f vec = {};
auto it = n.children.cbegin(); auto it = n.children.cbegin();
int i; int i;
athena::simd_floats f; athena::simd_floats f;
for (i=0 ; i<3 ; ++i, ++it) for (i = 0; i < 3; ++i, ++it) {
{
if (it->kind != IRNode::Kind::Imm) if (it->kind != IRNode::Kind::Imm)
break; break;
f[i] = it->val; f[i] = it->val;
} }
vec.simd.copy_from(f); vec.simd.copy_from(f);
if (i == 3) if (i == 3) {
{
m_instructions.emplace_back(OpType::LoadImm, target, n.loc); m_instructions.emplace_back(OpType::LoadImm, target, n.loc);
Instruction::LoadImm& inst = m_instructions.back().m_loadImm; Instruction::LoadImm& inst = m_instructions.back().m_loadImm;
inst.m_immVec = vec; inst.m_immVec = vec;
return m_instructions.size() - 1; return m_instructions.size() - 1;
} }
} } else if (!n.str.compare("vec4") && n.children.size() >= 4) {
else if (!n.str.compare("vec4") && n.children.size() >= 4)
{
atVec4f vec = {}; atVec4f vec = {};
auto it = n.children.cbegin(); auto it = n.children.cbegin();
int i; int i;
athena::simd_floats f; athena::simd_floats f;
for (i=0 ; i<4 ; ++i, ++it) for (i = 0; i < 4; ++i, ++it) {
{
if (it->kind != IRNode::Kind::Imm) if (it->kind != IRNode::Kind::Imm)
break; break;
f[i] = it->val; f[i] = it->val;
} }
vec.simd.copy_from(f); vec.simd.copy_from(f);
if (i == 4) if (i == 4) {
{
m_instructions.emplace_back(OpType::LoadImm, target, n.loc); m_instructions.emplace_back(OpType::LoadImm, target, n.loc);
Instruction::LoadImm& inst = m_instructions.back().m_loadImm; Instruction::LoadImm& inst = m_instructions.back().m_loadImm;
inst.m_immVec = vec; inst.m_immVec = vec;
@ -154,15 +135,13 @@ int IR::addInstruction(const IRNode& n, IR::RegID target)
inst.m_argInstIdxs = argInstIdxs; inst.m_argInstIdxs = argInstIdxs;
return m_instructions.size() - 1; return m_instructions.size() - 1;
} }
case IRNode::Kind::Imm: case IRNode::Kind::Imm: {
{
m_instructions.emplace_back(OpType::LoadImm, target, n.loc); m_instructions.emplace_back(OpType::LoadImm, target, n.loc);
Instruction::LoadImm& inst = m_instructions.back().m_loadImm; Instruction::LoadImm& inst = m_instructions.back().m_loadImm;
inst.m_immVec.simd = athena::simd<float>(n.val); inst.m_immVec.simd = athena::simd<float>(n.val);
return m_instructions.size() - 1; return m_instructions.size() - 1;
} }
case IRNode::Kind::Binop: case IRNode::Kind::Binop: {
{
atUint16 left = addInstruction(*n.left, target); atUint16 left = addInstruction(*n.left, target);
atUint16 right = addInstruction(*n.right, target + 1); atUint16 right = addInstruction(*n.right, target + 1);
m_instructions.emplace_back(OpType::Arithmetic, target, n.loc); m_instructions.emplace_back(OpType::Arithmetic, target, n.loc);
@ -172,12 +151,11 @@ int IR::addInstruction(const IRNode& n, IR::RegID target)
inst.m_instIdxs[1] = right; inst.m_instIdxs[1] = right;
return m_instructions.size() - 1; return m_instructions.size() - 1;
} }
case IRNode::Kind::Swizzle: case IRNode::Kind::Swizzle: {
{
atUint16 left = addInstruction(*n.left, target); atUint16 left = addInstruction(*n.left, target);
m_instructions.emplace_back(OpType::Swizzle, target, n.loc); m_instructions.emplace_back(OpType::Swizzle, target, n.loc);
Instruction::Swizzle& inst = m_instructions.back().m_swizzle; Instruction::Swizzle& inst = m_instructions.back().m_swizzle;
for (int i=0 ; i<n.str.size() && i<4 ; ++i) for (int i = 0; i < n.str.size() && i < 4; ++i)
inst.m_idxs[i] = swizzleCompIdx(n.str[i]); inst.m_idxs[i] = swizzleCompIdx(n.str[i]);
inst.m_instIdx = left; inst.m_instIdx = left;
return m_instructions.size() - 1; return m_instructions.size() - 1;
@ -188,32 +166,26 @@ int IR::addInstruction(const IRNode& n, IR::RegID target)
} }
template <> template <>
void IR::Enumerate<BigDNA::Read>(typename Read::StreamT& reader) void IR::Enumerate<BigDNA::Read>(typename Read::StreamT& reader) {
{
m_hash = reader.readUint64Big(); m_hash = reader.readUint64Big();
m_regCount = reader.readUint16Big(); m_regCount = reader.readUint16Big();
atUint16 instCount = reader.readUint16Big(); atUint16 instCount = reader.readUint16Big();
m_instructions.clear(); m_instructions.clear();
m_instructions.reserve(instCount); m_instructions.reserve(instCount);
for (atUint16 i=0 ; i<instCount ; ++i) for (atUint16 i = 0; i < instCount; ++i)
m_instructions.emplace_back(reader); m_instructions.emplace_back(reader);
/* Pre-resolve blending mode */ /* Pre-resolve blending mode */
const IR::Instruction& rootCall = m_instructions.back(); const IR::Instruction& rootCall = m_instructions.back();
m_doAlpha = false; m_doAlpha = false;
if (!rootCall.m_call.m_name.compare("HECLOpaque")) if (!rootCall.m_call.m_name.compare("HECLOpaque")) {
{
m_blendSrc = boo::BlendFactor::One; m_blendSrc = boo::BlendFactor::One;
m_blendDst = boo::BlendFactor::Zero; m_blendDst = boo::BlendFactor::Zero;
} } else if (!rootCall.m_call.m_name.compare("HECLAlpha")) {
else if (!rootCall.m_call.m_name.compare("HECLAlpha"))
{
m_blendSrc = boo::BlendFactor::SrcAlpha; m_blendSrc = boo::BlendFactor::SrcAlpha;
m_blendDst = boo::BlendFactor::InvSrcAlpha; m_blendDst = boo::BlendFactor::InvSrcAlpha;
m_doAlpha = true; m_doAlpha = true;
} } else if (!rootCall.m_call.m_name.compare("HECLAdditive")) {
else if (!rootCall.m_call.m_name.compare("HECLAdditive"))
{
m_blendSrc = boo::BlendFactor::SrcAlpha; m_blendSrc = boo::BlendFactor::SrcAlpha;
m_blendDst = boo::BlendFactor::One; m_blendDst = boo::BlendFactor::One;
m_doAlpha = true; m_doAlpha = true;
@ -221,8 +193,7 @@ void IR::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
} }
template <> template <>
void IR::Enumerate<BigDNA::Write>(typename Write::StreamT& writer) void IR::Enumerate<BigDNA::Write>(typename Write::StreamT& writer) {
{
writer.writeUint64Big(m_hash); writer.writeUint64Big(m_hash);
writer.writeUint16Big(m_regCount); writer.writeUint16Big(m_regCount);
writer.writeUint16Big(m_instructions.size()); writer.writeUint16Big(m_instructions.size());
@ -231,15 +202,13 @@ void IR::Enumerate<BigDNA::Write>(typename Write::StreamT& writer)
} }
template <> template <>
void IR::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& sz) void IR::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& sz) {
{
sz += 12; sz += 12;
for (const Instruction& inst : m_instructions) for (const Instruction& inst : m_instructions)
inst.binarySize(sz); inst.binarySize(sz);
} }
IR Frontend::compileSource(std::string_view source, std::string_view diagName) IR Frontend::compileSource(std::string_view source, std::string_view diagName) {
{
m_diag.reset(diagName, source); m_diag.reset(diagName, source);
m_parser.reset(source); m_parser.reset(source);
auto insts = m_parser.parse(); auto insts = m_parser.parse();
@ -253,4 +222,4 @@ IR Frontend::compileSource(std::string_view source, std::string_view diagName)
return ir; return ir;
} }
} } // namespace hecl::Frontend

View File

@ -3,8 +3,7 @@
/* Syntatical token parsing system */ /* Syntatical token parsing system */
namespace hecl::Frontend namespace hecl::Frontend {
{
/* /*
* hecl = { lf } call { lf { lf } call } { lf } . * hecl = { lf } call { lf { lf } call } { lf } .
@ -15,10 +14,9 @@ namespace hecl::Frontend
* value = ( call [ "." ident ] ) * value = ( call [ "." ident ] )
* | [ "-" ] number * | [ "-" ] number
* . * .
*/ */
std::string IRNode::rep(int n, std::string_view s) std::string IRNode::rep(int n, std::string_view s) {
{
std::string buf; std::string buf;
buf.reserve(n * s.size()); buf.reserve(n * s.size());
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
@ -26,24 +24,19 @@ std::string IRNode::rep(int n, std::string_view s)
return buf; return buf;
} }
std::string IRNode::fmt(int level, bool stripUVAnims) const std::string IRNode::fmt(int level, bool stripUVAnims) const {
{
std::string buf; std::string buf;
auto indent = rep(level, "\t"sv); auto indent = rep(level, "\t"sv);
switch (kind) switch (kind) {
{
case Kind::Call: case Kind::Call:
if (stripUVAnims && (str == "Texture" || str == "TextureN") && children.size() >= 2) if (stripUVAnims && (str == "Texture" || str == "TextureN") && children.size() >= 2) {
{
auto it = children.begin(); auto it = children.begin();
IRNode& uvNode = const_cast<IRNode&>(*++it); IRNode& uvNode = const_cast<IRNode&>(*++it);
if (uvNode.str != "UV" && uvNode.str != "Normal" && uvNode.str != "View") if (uvNode.str != "UV" && uvNode.str != "Normal" && uvNode.str != "View") {
{
std::string replacementName(str); std::string replacementName(str);
if (uvNode.str.back() == 'N' && replacementName.back() != 'N') if (uvNode.str.back() == 'N' && replacementName.back() != 'N')
replacementName += 'N'; replacementName += 'N';
IRNode replacementNode(Kind::Call, std::move(replacementName), IRNode replacementNode(Kind::Call, std::move(replacementName), std::move(uvNode.children), loc);
std::move(uvNode.children), loc);
auto ret = replacementNode.fmt(level, false); auto ret = replacementNode.fmt(level, false);
uvNode.children = std::move(replacementNode.children); uvNode.children = std::move(replacementNode.children);
return ret; return ret;
@ -51,11 +44,9 @@ std::string IRNode::fmt(int level, bool stripUVAnims) const
} }
buf.append(indent); buf.append(indent);
buf.append("Call "sv).append(str); buf.append("Call "sv).append(str);
if (!children.empty()) if (!children.empty()) {
{
buf.append(" {\n"sv); buf.append(" {\n"sv);
for (const IRNode& n : children) for (const IRNode& n : children) {
{
buf.append(n.fmt(level + 1, stripUVAnims)); buf.append(n.fmt(level + 1, stripUVAnims));
buf.append("\n"sv); buf.append("\n"sv);
} }
@ -87,26 +78,21 @@ std::string IRNode::fmt(int level, bool stripUVAnims) const
return buf; return buf;
} }
std::string IRNode::describe() const {
std::string IRNode::describe() const
{
std::vector<std::string> l; std::vector<std::string> l;
l.push_back("kind="s + KindToStr(kind).data()); l.push_back("kind="s + KindToStr(kind).data());
if (!str.empty()) if (!str.empty())
l.push_back("str="s + str); l.push_back("str="s + str);
if (kind == Kind::Binop) if (kind == Kind::Binop) {
{
l.push_back("op="s + OpToStr(op).data()); l.push_back("op="s + OpToStr(op).data());
l.push_back("left="s + left->toString()); l.push_back("left="s + left->toString());
l.push_back("right="s + right->toString()); l.push_back("right="s + right->toString());
} }
if (kind == Kind::Swizzle) if (kind == Kind::Swizzle)
l.push_back("node="s + left->toString()); l.push_back("node="s + left->toString());
if (kind == Kind::Call) if (kind == Kind::Call) {
{
std::string str = "children=["s; std::string str = "children=["s;
for (auto it = children.begin(); it != children.end(); ++it) for (auto it = children.begin(); it != children.end(); ++it) {
{
str += it->toString(); str += it->toString();
if (&*it != &children.back()) if (&*it != &children.back())
str += ';'; str += ';';
@ -116,8 +102,7 @@ std::string IRNode::describe() const
} }
std::string str = "IRNode["s; std::string str = "IRNode["s;
for (auto it = l.begin(); it != l.end(); ++it) for (auto it = l.begin(); it != l.end(); ++it) {
{
str += *it; str += *it;
if (&*it != &l.back()) if (&*it != &l.back())
str += ';'; str += ';';
@ -126,28 +111,24 @@ std::string IRNode::describe() const
return str; return str;
} }
void Parser::check(Token::Kind expected) void Parser::check(Token::Kind expected) {
{
if (sym == expected) if (sym == expected)
scan(); scan();
else else
error("expected %s, was %s", Token::KindToStr(expected).data(), Token::KindToStr(sym).data()); error("expected %s, was %s", Token::KindToStr(expected).data(), Token::KindToStr(sym).data());
} }
IRNode Parser::call() IRNode Parser::call() {
{
check(Token::Kind::Ident); check(Token::Kind::Ident);
std::string name = t.str; std::string name = t.str;
std::list<IRNode> args; std::list<IRNode> args;
check(Token::Kind::Lpar); check(Token::Kind::Lpar);
if (sym == Token::Kind::Lpar || sym == Token::Kind::Ident || if (sym == Token::Kind::Lpar || sym == Token::Kind::Ident || sym == Token::Kind::Number ||
sym == Token::Kind::Number || sym == Token::Kind::Minus) sym == Token::Kind::Minus) {
{
args.push_back(expr()); args.push_back(expr());
while (sym == Token::Kind::Comma) while (sym == Token::Kind::Comma) {
{
scan(); scan();
args.push_back(expr()); args.push_back(expr());
} }
@ -160,21 +141,17 @@ IRNode Parser::call()
return IRNode(IRNode::Kind::Call, std::move(name), std::move(args), t.loc); return IRNode(IRNode::Kind::Call, std::move(name), std::move(args), t.loc);
} }
bool Parser::imm(const IRNode& a, const IRNode& b) bool Parser::imm(const IRNode& a, const IRNode& b) {
{
return a.kind == IRNode::Kind::Imm && b.kind == IRNode::Kind::Imm; return a.kind == IRNode::Kind::Imm && b.kind == IRNode::Kind::Imm;
} }
IRNode Parser::expr() IRNode Parser::expr() {
{
IRNode node = sum(); IRNode node = sum();
while (sym == Token::Kind::Plus || sym == Token::Kind::Minus) while (sym == Token::Kind::Plus || sym == Token::Kind::Minus) {
{
scan(); scan();
Token::Kind op = t.kind; Token::Kind op = t.kind;
IRNode right = sum(); IRNode right = sum();
switch (op) switch (op) {
{
case Token::Kind::Plus: case Token::Kind::Plus:
if (imm(node, right)) // constant folding if (imm(node, right)) // constant folding
return IRNode(IRNode::Kind::Imm, node.val + right.val, t.loc); return IRNode(IRNode::Kind::Imm, node.val + right.val, t.loc);
@ -194,16 +171,13 @@ IRNode Parser::expr()
return node; return node;
} }
IRNode Parser::sum() IRNode Parser::sum() {
{
IRNode node = factor(); IRNode node = factor();
while (sym == Token::Kind::Times || sym == Token::Kind::Div) while (sym == Token::Kind::Times || sym == Token::Kind::Div) {
{
scan(); scan();
Token::Kind op = t.kind; Token::Kind op = t.kind;
IRNode right = factor(); IRNode right = factor();
switch (op) switch (op) {
{
case Token::Kind::Times: case Token::Kind::Times:
if (imm(node, right)) // constant folding if (imm(node, right)) // constant folding
node = IRNode(IRNode::Kind::Imm, node.val * right.val, t.loc); node = IRNode(IRNode::Kind::Imm, node.val * right.val, t.loc);
@ -223,10 +197,8 @@ IRNode Parser::sum()
return node; return node;
} }
IRNode Parser::factor() IRNode Parser::factor() {
{ if (sym == Token::Kind::Lpar) {
if (sym == Token::Kind::Lpar)
{
scan(); scan();
IRNode node = expr(); IRNode node = expr();
check(Token::Kind::Rpar); check(Token::Kind::Rpar);
@ -235,47 +207,37 @@ IRNode Parser::factor()
return value(); return value();
} }
IRNode Parser::value() IRNode Parser::value() {
{ if (sym == Token::Kind::Number || sym == Token::Kind::Minus) {
if (sym == Token::Kind::Number || sym == Token::Kind::Minus)
{
scan(); scan();
bool neg = false; bool neg = false;
if (t.kind == Token::Kind::Minus) if (t.kind == Token::Kind::Minus) {
{
neg = true; neg = true;
check(Token::Kind::Number); check(Token::Kind::Number);
} }
float val = strtof(((neg ? "-"s : ""s) + t.str).c_str(), nullptr); float val = strtof(((neg ? "-"s : ""s) + t.str).c_str(), nullptr);
return IRNode(IRNode::Kind::Imm, val, t.loc); return IRNode(IRNode::Kind::Imm, val, t.loc);
} } else if (sym == Token::Kind::Ident) {
else if (sym == Token::Kind::Ident)
{
IRNode call = Parser::call(); IRNode call = Parser::call();
if (sym == Token::Kind::Period) if (sym == Token::Kind::Period) {
{
scan(); scan();
check(Token::Kind::Ident); check(Token::Kind::Ident);
return IRNode(IRNode::Kind::Swizzle, std::string(t.str), std::move(call), t.loc); return IRNode(IRNode::Kind::Swizzle, std::string(t.str), std::move(call), t.loc);
} }
return call; return call;
} } else {
else
{
error("expected number|call, was %s", Token::KindToStr(sym).data()); error("expected number|call, was %s", Token::KindToStr(sym).data());
return IRNode(); return IRNode();
} }
} }
std::list<IRNode> Parser::parse() std::list<IRNode> Parser::parse() {
{
std::list<IRNode> result; std::list<IRNode> result;
scan(); scan();
while (sym == Token::Kind::Lf) while (sym == Token::Kind::Lf)
scan(); scan();
result.push_back(call()); result.push_back(call());
while (sym == Token::Kind::Lf) while (sym == Token::Kind::Lf) {
{
while (sym == Token::Kind::Lf) while (sym == Token::Kind::Lf)
scan(); scan();
if (sym != Token::Kind::Eof) if (sym != Token::Kind::Eof)
@ -292,4 +254,4 @@ std::list<IRNode> Parser::parse()
return result; return result;
} }
} } // namespace hecl::Frontend

View File

@ -1,42 +1,34 @@
#include "hecl/Frontend.hpp" #include "hecl/Frontend.hpp"
namespace hecl::Frontend namespace hecl::Frontend {
{
int Scanner::_read() int Scanner::_read() {
{
if (m_sourceIt == m_source.end()) if (m_sourceIt == m_source.end())
return -1; return -1;
return *m_sourceIt++; return *m_sourceIt++;
} }
bool Scanner::read() bool Scanner::read() {
{
if (ch == EOF) if (ch == EOF)
return false; return false;
if (ch == LF) if (ch == LF) {
{
lastLine = std::move(currentLine); lastLine = std::move(currentLine);
currentLine = std::string(); currentLine = std::string();
} }
int c = _read(); int c = _read();
ch = char(c); ch = char(c);
if (ch == LF) if (ch == LF) {
{
loc.line++; loc.line++;
lfcol = loc.col; lfcol = loc.col;
loc.col = 0; loc.col = 0;
} } else if (c != EOF) {
else if (c != EOF)
{
currentLine += ch; currentLine += ch;
loc.col++; loc.col++;
} }
return c != EOF; return c != EOF;
} }
Token Scanner::next() Token Scanner::next() {
{
if (ch == EOF) if (ch == EOF)
return Token(Token::Kind::Eof, loc); return Token(Token::Kind::Eof, loc);
@ -47,12 +39,9 @@ Token Scanner::next()
read(); read();
// skip comments and newlines // skip comments and newlines
while (c != EOF && (c == COMMENT || isspace(c))) while (c != EOF && (c == COMMENT || isspace(c))) {
{ if (c == COMMENT) {
if (c == COMMENT) while (c != LF && c != EOF) {
{
while (c != LF && c != EOF)
{
tline = loc.line; tline = loc.line;
tcol = loc.col; tcol = loc.col;
tlfcol = lfcol; tlfcol = lfcol;
@ -60,8 +49,7 @@ Token Scanner::next()
read(); read();
} }
} }
while (c != EOF && isspace(c)) while (c != EOF && isspace(c)) {
{
if (c == LF) if (c == LF)
return Token(Token::Kind::Lf, {tline - 1, tlfcol + 1}); return Token(Token::Kind::Lf, {tline - 1, tlfcol + 1});
tline = loc.line; tline = loc.line;
@ -80,21 +68,17 @@ Token Scanner::next()
return Token(Token::Kind::Eof, {tline, tcol}); return Token(Token::Kind::Eof, {tline, tcol});
// ident or number // ident or number
if (isDigit(c)) if (isDigit(c)) {
{
std::string buf; std::string buf;
buf += c; buf += c;
while (isDigit(ch)) while (isDigit(ch)) {
{
buf += ch; buf += ch;
read(); read();
} }
if (ch == '.') if (ch == '.') { // float
{ // float
buf += ch; buf += ch;
read(); read();
while (isDigit(ch)) while (isDigit(ch)) {
{
buf += ch; buf += ch;
read(); read();
} }
@ -102,12 +86,10 @@ Token Scanner::next()
return Token(Token::Kind::Number, std::move(buf), {tline, tcol}); return Token(Token::Kind::Number, std::move(buf), {tline, tcol});
} }
if (isStartIdent(c)) if (isStartIdent(c)) {
{
std::string buf; std::string buf;
buf += c; buf += c;
while (isMidIdent(ch)) while (isMidIdent(ch)) {
{
buf += ch; buf += ch;
read(); read();
} }
@ -119,4 +101,4 @@ Token Scanner::next()
return Token(Token::Kind::None, {tline, tcol}); return Token(Token::Kind::None, {tline, tcol});
} }
} } // namespace hecl::Frontend

View File

@ -32,14 +32,12 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
namespace hecl namespace hecl {
{
static logvisor::Module Log("hecl::HumanizeNumber"); static logvisor::Module Log("hecl::HumanizeNumber");
static const int maxscale = 7; static const int maxscale = 7;
std::string HumanizeNumber(int64_t quotient, size_t len, const char* suffix, int scale, HNFlags flags) std::string HumanizeNumber(int64_t quotient, size_t len, const char* suffix, int scale, HNFlags flags) {
{
const char *prefixes, *sep; const char *prefixes, *sep;
int i, r, remainder, s1, s2, sign; int i, r, remainder, s1, s2, sign;
int divisordeccut; int divisordeccut;
@ -91,7 +89,7 @@ std::string HumanizeNumber(int64_t quotient, size_t len, const char* suffix, int
} }
} }
#define SCALE2PREFIX(scale) (&prefixes[(scale) * 3]) #define SCALE2PREFIX(scale) (&prefixes[(scale)*3])
if (quotient < 0) { if (quotient < 0) {
sign = -1; sign = -1;
@ -111,9 +109,7 @@ std::string HumanizeNumber(int64_t quotient, size_t len, const char* suffix, int
/* Check if enough room for `x y' + suffix */ /* Check if enough room for `x y' + suffix */
if (len < baselen) if (len < baselen)
Log.report(logvisor::Fatal, Log.report(logvisor::Fatal, "buffer size %" PRISize "insufficient for minimum size %" PRISize, len, baselen);
"buffer size %" PRISize "insufficient for minimum size %" PRISize,
len, baselen);
std::string ret(len, '\0'); std::string ret(len, '\0');
len += 1; len += 1;
@ -127,9 +123,7 @@ std::string HumanizeNumber(int64_t quotient, size_t len, const char* suffix, int
* If there will be an overflow by the rounding below, * If there will be an overflow by the rounding below,
* divide once more. * divide once more.
*/ */
for (i = 0; for (i = 0; (quotient >= max || (quotient == max - 1 && remainder >= divisordeccut)) && i < maxscale; i++) {
(quotient >= max || (quotient == max - 1 &&
remainder >= divisordeccut)) && i < maxscale; i++) {
remainder = quotient % divisor; remainder = quotient % divisor;
quotient /= divisor; quotient /= divisor;
} }
@ -145,20 +139,17 @@ std::string HumanizeNumber(int64_t quotient, size_t len, const char* suffix, int
* XXX - should we make sure there is enough space for the decimal * XXX - should we make sure there is enough space for the decimal
* place and if not, don't do HN_DECIMAL? * place and if not, don't do HN_DECIMAL?
*/ */
if (((quotient == 9 && remainder < divisordeccut) || quotient < 9) && if (((quotient == 9 && remainder < divisordeccut) || quotient < 9) && i > 0 &&
i > 0 && (flags & HNFlags::Decimal) != HNFlags::None) { (flags & HNFlags::Decimal) != HNFlags::None) {
s1 = (int)quotient + ((remainder * 10 + divisor / 2) / s1 = (int)quotient + ((remainder * 10 + divisor / 2) / divisor / 10);
divisor / 10);
s2 = ((remainder * 10 + divisor / 2) / divisor) % 10; s2 = ((remainder * 10 + divisor / 2) / divisor) % 10;
r = snprintf(&ret[0], len, "%d%s%d%s%s%s", r = snprintf(&ret[0], len, "%d%s%d%s%s%s", sign * s1, localeconv()->decimal_point, s2, sep, SCALE2PREFIX(i),
sign * s1, localeconv()->decimal_point, s2, suffix);
sep, SCALE2PREFIX(i), suffix);
} else } else
r = snprintf(&ret[0], len, "%" PRId64 "%s%s%s", r = snprintf(&ret[0], len, "%" PRId64 "%s%s%s", sign * (quotient + (remainder + divisor / 2) / divisor), sep,
sign * (quotient + (remainder + divisor / 2) / divisor), SCALE2PREFIX(i), suffix);
sep, SCALE2PREFIX(i), suffix);
return ret; return ret;
} }
} } // namespace hecl

View File

@ -7,14 +7,12 @@
#define SHOW_CURSOR "\033[?25h" #define SHOW_CURSOR "\033[?25h"
#if _WIN32 #if _WIN32
#define FOREGROUND_WHITE FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE #define FOREGROUND_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
#endif #endif
namespace hecl namespace hecl {
{
void MultiProgressPrinter::ThreadStat::print(const TermInfo& tinfo) const void MultiProgressPrinter::ThreadStat::print(const TermInfo& tinfo) const {
{
bool blocks = m_factor >= 0.f; bool blocks = m_factor >= 0.f;
float factor = std::max(0.f, std::min(1.f, m_factor)); float factor = std::max(0.f, std::min(1.f, m_factor));
int iFactor = factor * 100.f; int iFactor = factor * 100.f;
@ -30,58 +28,49 @@ void MultiProgressPrinter::ThreadStat::print(const TermInfo& tinfo) const
else else
half = messageLen; half = messageLen;
if (half - messageLen < submessageLen-2) if (half - messageLen < submessageLen - 2)
submessageLen = 0; submessageLen = 0;
if (submessageLen) if (submessageLen) {
{ if (messageLen > half - submessageLen - 1)
if (messageLen > half-submessageLen-1) hecl::Printf(_SYS_STR(" %.*s... %s "), half - submessageLen - 4, m_message.c_str(), m_submessage.c_str());
hecl::Printf(_SYS_STR(" %.*s... %s "), half-submessageLen-4, m_message.c_str(), m_submessage.c_str()); else {
else
{
hecl::Printf(_SYS_STR(" %s"), m_message.c_str()); hecl::Printf(_SYS_STR(" %s"), m_message.c_str());
for (int i=half-messageLen-submessageLen-1 ; i>=0 ; --i) for (int i = half - messageLen - submessageLen - 1; i >= 0; --i)
hecl::Printf(_SYS_STR(" ")); hecl::Printf(_SYS_STR(" "));
hecl::Printf(_SYS_STR("%s "), m_submessage.c_str()); hecl::Printf(_SYS_STR("%s "), m_submessage.c_str());
} }
} } else {
else
{
if (messageLen > half) if (messageLen > half)
hecl::Printf(_SYS_STR(" %.*s... "), half-3, m_message.c_str()); hecl::Printf(_SYS_STR(" %.*s... "), half - 3, m_message.c_str());
else else {
{
hecl::Printf(_SYS_STR(" %s"), m_message.c_str()); hecl::Printf(_SYS_STR(" %s"), m_message.c_str());
for (int i=half-messageLen ; i>=0 ; --i) for (int i = half - messageLen; i >= 0; --i)
hecl::Printf(_SYS_STR(" ")); hecl::Printf(_SYS_STR(" "));
} }
} }
if (blocks) if (blocks) {
{
int rightHalf = tinfo.width - half - 4; int rightHalf = tinfo.width - half - 4;
int blocks = rightHalf - 7; int blocks = rightHalf - 7;
int filled = blocks * factor; int filled = blocks * factor;
int rem = blocks - filled; int rem = blocks - filled;
if (tinfo.xtermColor) if (tinfo.xtermColor) {
{
hecl::Printf(_SYS_STR("" BOLD "%3d%% ["), iFactor); hecl::Printf(_SYS_STR("" BOLD "%3d%% ["), iFactor);
for (int b=0 ; b<filled ; ++b) for (int b = 0; b < filled; ++b)
hecl::Printf(_SYS_STR("#")); hecl::Printf(_SYS_STR("#"));
for (int b=0 ; b<rem ; ++b) for (int b = 0; b < rem; ++b)
hecl::Printf(_SYS_STR("-")); hecl::Printf(_SYS_STR("-"));
hecl::Printf(_SYS_STR("]" NORMAL "")); hecl::Printf(_SYS_STR("]" NORMAL ""));
} } else {
else
{
#if _WIN32 #if _WIN32
SetConsoleTextAttribute(tinfo.console, FOREGROUND_INTENSITY | FOREGROUND_WHITE); SetConsoleTextAttribute(tinfo.console, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
#endif #endif
hecl::Printf(_SYS_STR("%3d%% ["), iFactor); hecl::Printf(_SYS_STR("%3d%% ["), iFactor);
for (int b=0 ; b<filled ; ++b) for (int b = 0; b < filled; ++b)
hecl::Printf(_SYS_STR("#")); hecl::Printf(_SYS_STR("#"));
for (int b=0 ; b<rem ; ++b) for (int b = 0; b < rem; ++b)
hecl::Printf(_SYS_STR("-")); hecl::Printf(_SYS_STR("-"));
hecl::Printf(_SYS_STR("]")); hecl::Printf(_SYS_STR("]"));
#if _WIN32 #if _WIN32
@ -91,8 +80,7 @@ void MultiProgressPrinter::ThreadStat::print(const TermInfo& tinfo) const
} }
} }
void MultiProgressPrinter::DrawIndeterminateBar() void MultiProgressPrinter::DrawIndeterminateBar() {
{
int half = m_termInfo.width - 2; int half = m_termInfo.width - 2;
int blocks = half - 2; int blocks = half - 2;
@ -106,26 +94,23 @@ void MultiProgressPrinter::DrawIndeterminateBar()
int pre = absCounter; int pre = absCounter;
int rem = blocks - pre - 1; int rem = blocks - pre - 1;
if (m_termInfo.xtermColor) if (m_termInfo.xtermColor) {
{
hecl::Printf(_SYS_STR("" BOLD " [")); hecl::Printf(_SYS_STR("" BOLD " ["));
for (int b=0 ; b<pre ; ++b) for (int b = 0; b < pre; ++b)
hecl::Printf(_SYS_STR("-")); hecl::Printf(_SYS_STR("-"));
hecl::Printf(_SYS_STR("#")); hecl::Printf(_SYS_STR("#"));
for (int b=0 ; b<rem ; ++b) for (int b = 0; b < rem; ++b)
hecl::Printf(_SYS_STR("-")); hecl::Printf(_SYS_STR("-"));
hecl::Printf(_SYS_STR("]" NORMAL "")); hecl::Printf(_SYS_STR("]" NORMAL ""));
} } else {
else
{
#if _WIN32 #if _WIN32
SetConsoleTextAttribute(m_termInfo.console, FOREGROUND_INTENSITY | FOREGROUND_WHITE); SetConsoleTextAttribute(m_termInfo.console, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
#endif #endif
hecl::Printf(_SYS_STR(" [")); hecl::Printf(_SYS_STR(" ["));
for (int b=0 ; b<pre ; ++b) for (int b = 0; b < pre; ++b)
hecl::Printf(_SYS_STR("-")); hecl::Printf(_SYS_STR("-"));
hecl::Printf(_SYS_STR("#")); hecl::Printf(_SYS_STR("#"));
for (int b=0 ; b<rem ; ++b) for (int b = 0; b < rem; ++b)
hecl::Printf(_SYS_STR("-")); hecl::Printf(_SYS_STR("-"));
hecl::Printf(_SYS_STR("]")); hecl::Printf(_SYS_STR("]"));
#if _WIN32 #if _WIN32
@ -134,17 +119,13 @@ void MultiProgressPrinter::DrawIndeterminateBar()
} }
} }
void MultiProgressPrinter::MoveCursorUp(int n) void MultiProgressPrinter::MoveCursorUp(int n) {
{ if (n) {
if (n) if (m_termInfo.xtermColor) {
{
if (m_termInfo.xtermColor)
{
hecl::Printf(_SYS_STR("" PREV_LINE ""), n); hecl::Printf(_SYS_STR("" PREV_LINE ""), n);
} }
#if _WIN32 #if _WIN32
else else {
{
CONSOLE_SCREEN_BUFFER_INFO consoleInfo; CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
GetConsoleScreenBufferInfo(m_termInfo.console, &consoleInfo); GetConsoleScreenBufferInfo(m_termInfo.console, &consoleInfo);
consoleInfo.dwCursorPosition.X = 0; consoleInfo.dwCursorPosition.X = 0;
@ -152,19 +133,15 @@ void MultiProgressPrinter::MoveCursorUp(int n)
SetConsoleCursorPosition(m_termInfo.console, consoleInfo.dwCursorPosition); SetConsoleCursorPosition(m_termInfo.console, consoleInfo.dwCursorPosition);
} }
#endif #endif
} } else {
else
{
hecl::Printf(_SYS_STR("\r")); hecl::Printf(_SYS_STR("\r"));
} }
} }
void MultiProgressPrinter::DoPrint() void MultiProgressPrinter::DoPrint() {
{
auto logLk = logvisor::LockLog(); auto logLk = logvisor::LockLog();
uint64_t logCounter = logvisor::GetLogCounter(); uint64_t logCounter = logvisor::GetLogCounter();
if (logCounter != m_lastLogCounter) if (logCounter != m_lastLogCounter) {
{
m_curThreadLines = 0; m_curThreadLines = 0;
m_lastLogCounter = logCounter; m_lastLogCounter = logCounter;
} }
@ -177,18 +154,14 @@ void MultiProgressPrinter::DoPrint()
if (m_termInfo.xtermColor) if (m_termInfo.xtermColor)
hecl::Printf(_SYS_STR("" HIDE_CURSOR "")); hecl::Printf(_SYS_STR("" HIDE_CURSOR ""));
if (m_dirty) if (m_dirty) {
{
m_termInfo.width = (hecl::GuiMode ? 120 : std::max(80, hecl::ConsoleWidth(&m_termInfo.truncate))); m_termInfo.width = (hecl::GuiMode ? 120 : std::max(80, hecl::ConsoleWidth(&m_termInfo.truncate)));
MoveCursorUp(m_curThreadLines + m_curProgLines); MoveCursorUp(m_curThreadLines + m_curProgLines);
m_curThreadLines = m_curProgLines = 0; m_curThreadLines = m_curProgLines = 0;
if (m_newLineAfter) if (m_newLineAfter) {
{ for (const ThreadStat& stat : m_threadStats) {
for (const ThreadStat& stat : m_threadStats) if (stat.m_active) {
{
if (stat.m_active)
{
stat.print(m_termInfo); stat.print(m_termInfo);
hecl::Printf(_SYS_STR("\n")); hecl::Printf(_SYS_STR("\n"));
++m_curThreadLines; ++m_curThreadLines;
@ -199,14 +172,11 @@ void MultiProgressPrinter::DoPrint()
#ifndef _WIN32 #ifndef _WIN32
&& m_termInfo.xtermColor && m_termInfo.xtermColor
#endif #endif
) ) {
{
DrawIndeterminateBar(); DrawIndeterminateBar();
hecl::Printf(_SYS_STR("\n")); hecl::Printf(_SYS_STR("\n"));
++m_curProgLines; ++m_curProgLines;
} } else if (m_mainFactor >= 0.f) {
else if (m_mainFactor >= 0.f)
{
float factor = std::max(0.0f, std::min(1.0f, m_mainFactor)); float factor = std::max(0.0f, std::min(1.0f, m_mainFactor));
int iFactor = factor * 100.0; int iFactor = factor * 100.0;
int half = m_termInfo.width - 2; int half = m_termInfo.width - 2;
@ -215,24 +185,21 @@ void MultiProgressPrinter::DoPrint()
int filled = blocks * factor; int filled = blocks * factor;
int rem = blocks - filled; int rem = blocks - filled;
if (m_termInfo.xtermColor) if (m_termInfo.xtermColor) {
{
hecl::Printf(_SYS_STR("" BOLD " %3d%% ["), iFactor); hecl::Printf(_SYS_STR("" BOLD " %3d%% ["), iFactor);
for (int b=0 ; b<filled ; ++b) for (int b = 0; b < filled; ++b)
hecl::Printf(_SYS_STR("#")); hecl::Printf(_SYS_STR("#"));
for (int b=0 ; b<rem ; ++b) for (int b = 0; b < rem; ++b)
hecl::Printf(_SYS_STR("-")); hecl::Printf(_SYS_STR("-"));
hecl::Printf(_SYS_STR("]" NORMAL "")); hecl::Printf(_SYS_STR("]" NORMAL ""));
} } else {
else
{
#if _WIN32 #if _WIN32
SetConsoleTextAttribute(m_termInfo.console, FOREGROUND_INTENSITY | FOREGROUND_WHITE); SetConsoleTextAttribute(m_termInfo.console, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
#endif #endif
hecl::Printf(_SYS_STR(" %3d%% ["), iFactor); hecl::Printf(_SYS_STR(" %3d%% ["), iFactor);
for (int b=0 ; b<filled ; ++b) for (int b = 0; b < filled; ++b)
hecl::Printf(_SYS_STR("#")); hecl::Printf(_SYS_STR("#"));
for (int b=0 ; b<rem ; ++b) for (int b = 0; b < rem; ++b)
hecl::Printf(_SYS_STR("-")); hecl::Printf(_SYS_STR("-"));
hecl::Printf(_SYS_STR("]")); hecl::Printf(_SYS_STR("]"));
#if _WIN32 #if _WIN32
@ -243,21 +210,17 @@ void MultiProgressPrinter::DoPrint()
hecl::Printf(_SYS_STR("\n")); hecl::Printf(_SYS_STR("\n"));
++m_curProgLines; ++m_curProgLines;
} }
} } else if (m_latestThread != -1) {
else if (m_latestThread != -1)
{
const ThreadStat& stat = m_threadStats[m_latestThread]; const ThreadStat& stat = m_threadStats[m_latestThread];
stat.print(m_termInfo); stat.print(m_termInfo);
hecl::Printf(_SYS_STR("\r")); hecl::Printf(_SYS_STR("\r"));
} }
m_dirty = false; m_dirty = false;
} } else if (m_mainIndeterminate
else if (m_mainIndeterminate
#ifndef _WIN32 #ifndef _WIN32
&& m_termInfo.xtermColor && m_termInfo.xtermColor
#endif #endif
) ) {
{
m_termInfo.width = (hecl::GuiMode ? 120 : std::max(80, hecl::ConsoleWidth())); m_termInfo.width = (hecl::GuiMode ? 120 : std::max(80, hecl::ConsoleWidth()));
MoveCursorUp(m_curProgLines); MoveCursorUp(m_curProgLines);
m_curProgLines = 0; m_curProgLines = 0;
@ -276,10 +239,8 @@ void MultiProgressPrinter::DoPrint()
#endif #endif
} }
void MultiProgressPrinter::LogProc() void MultiProgressPrinter::LogProc() {
{ while (m_running) {
while (m_running)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (!m_dirty && !m_mainIndeterminate) if (!m_dirty && !m_mainIndeterminate)
continue; continue;
@ -288,10 +249,8 @@ void MultiProgressPrinter::LogProc()
} }
} }
MultiProgressPrinter::MultiProgressPrinter(bool activate) MultiProgressPrinter::MultiProgressPrinter(bool activate) {
{ if (activate) {
if (activate)
{
/* Xterm check */ /* Xterm check */
#if _WIN32 #if _WIN32
m_newLineAfter = true; m_newLineAfter = true;
@ -302,8 +261,7 @@ MultiProgressPrinter::MultiProgressPrinter(bool activate)
#else #else
m_newLineAfter = false; m_newLineAfter = false;
const char* term = getenv("TERM"); const char* term = getenv("TERM");
if (term && !strncmp(term, "xterm", 5)) if (term && !strncmp(term, "xterm", 5)) {
{
m_termInfo.xtermColor = true; m_termInfo.xtermColor = true;
m_newLineAfter = true; m_newLineAfter = true;
} }
@ -314,17 +272,14 @@ MultiProgressPrinter::MultiProgressPrinter(bool activate)
} }
} }
MultiProgressPrinter::~MultiProgressPrinter() MultiProgressPrinter::~MultiProgressPrinter() {
{
m_running = false; m_running = false;
if (m_logThread.joinable()) if (m_logThread.joinable())
m_logThread.join(); m_logThread.join();
} }
void MultiProgressPrinter::print(const hecl::SystemChar* message, void MultiProgressPrinter::print(const hecl::SystemChar* message, const hecl::SystemChar* submessage, float factor,
const hecl::SystemChar* submessage, int threadIdx) const {
float factor, int threadIdx) const
{
if (!m_running) if (!m_running)
return; return;
std::lock_guard<std::mutex> lk(m_logLock); std::lock_guard<std::mutex> lk(m_logLock);
@ -347,8 +302,7 @@ void MultiProgressPrinter::print(const hecl::SystemChar* message,
m_dirty = true; m_dirty = true;
} }
void MultiProgressPrinter::setMainFactor(float factor) const void MultiProgressPrinter::setMainFactor(float factor) const {
{
if (!m_running) if (!m_running)
return; return;
std::lock_guard<std::mutex> lk(m_logLock); std::lock_guard<std::mutex> lk(m_logLock);
@ -357,20 +311,17 @@ void MultiProgressPrinter::setMainFactor(float factor) const
m_mainFactor = factor; m_mainFactor = factor;
} }
void MultiProgressPrinter::setMainIndeterminate(bool indeterminate) const void MultiProgressPrinter::setMainIndeterminate(bool indeterminate) const {
{
if (!m_running) if (!m_running)
return; return;
std::lock_guard<std::mutex> lk(m_logLock); std::lock_guard<std::mutex> lk(m_logLock);
if (m_mainIndeterminate != indeterminate) if (m_mainIndeterminate != indeterminate) {
{
m_mainIndeterminate = indeterminate; m_mainIndeterminate = indeterminate;
m_dirty = true; m_dirty = true;
} }
} }
void MultiProgressPrinter::startNewLine() const void MultiProgressPrinter::startNewLine() const {
{
if (!m_running) if (!m_running)
return; return;
std::lock_guard<std::mutex> lk(m_logLock); std::lock_guard<std::mutex> lk(m_logLock);
@ -383,10 +334,9 @@ void MultiProgressPrinter::startNewLine() const
hecl::Printf(_SYS_STR("\n")); hecl::Printf(_SYS_STR("\n"));
} }
void MultiProgressPrinter::flush() const void MultiProgressPrinter::flush() const {
{
std::lock_guard<std::mutex> lk(m_logLock); std::lock_guard<std::mutex> lk(m_logLock);
const_cast<MultiProgressPrinter&>(*this).DoPrint(); const_cast<MultiProgressPrinter&>(*this).DoPrint();
} }
} } // namespace hecl

View File

@ -2,22 +2,19 @@
#include "athena/FileReader.hpp" #include "athena/FileReader.hpp"
#include <zlib.h> #include <zlib.h>
namespace hecl namespace hecl {
{
#if HECL_RUNTIME #if HECL_RUNTIME
PipelineConverterBase* conv = nullptr; PipelineConverterBase* conv = nullptr;
class ShaderCacheZipStream : public athena::io::IStreamReader class ShaderCacheZipStream : public athena::io::IStreamReader {
{
std::unique_ptr<uint8_t[]> m_compBuf; std::unique_ptr<uint8_t[]> m_compBuf;
athena::io::FileReader m_reader; athena::io::FileReader m_reader;
z_stream m_zstrm = {}; z_stream m_zstrm = {};
public: public:
explicit ShaderCacheZipStream(const hecl::SystemChar* path) explicit ShaderCacheZipStream(const hecl::SystemChar* path) : m_reader(path) {
: m_reader(path)
{
if (m_reader.hasError()) if (m_reader.hasError())
return; return;
if (m_reader.readUint32Big() != SBIG('SHAD')) if (m_reader.readUint32Big() != SBIG('SHAD'))
@ -27,20 +24,14 @@ public:
m_zstrm.avail_in = 0; m_zstrm.avail_in = 0;
inflateInit(&m_zstrm); inflateInit(&m_zstrm);
} }
~ShaderCacheZipStream() ~ShaderCacheZipStream() { inflateEnd(&m_zstrm); }
{
inflateEnd(&m_zstrm);
}
operator bool() const { return m_compBuf.operator bool(); } operator bool() const { return m_compBuf.operator bool(); }
atUint64 readUBytesToBuf(void *buf, atUint64 len) atUint64 readUBytesToBuf(void* buf, atUint64 len) {
{
m_zstrm.next_out = (Bytef*)buf; m_zstrm.next_out = (Bytef*)buf;
m_zstrm.avail_out = len; m_zstrm.avail_out = len;
m_zstrm.total_out = 0; m_zstrm.total_out = 0;
while (m_zstrm.avail_out != 0) while (m_zstrm.avail_out != 0) {
{ if (m_zstrm.avail_in == 0) {
if (m_zstrm.avail_in == 0)
{
atUint64 readSz = m_reader.readUBytesToBuf(m_compBuf.get(), 4096); atUint64 readSz = m_reader.readUBytesToBuf(m_compBuf.get(), 4096);
m_zstrm.avail_in = readSz; m_zstrm.avail_in = readSz;
m_zstrm.next_in = m_compBuf.get(); m_zstrm.next_in = m_compBuf.get();
@ -52,27 +43,23 @@ public:
return m_zstrm.total_out; return m_zstrm.total_out;
} }
void seek(atInt64, athena::SeekOrigin) {} void seek(atInt64, athena::SeekOrigin) {}
atUint64 position() const {return 0;} atUint64 position() const { return 0; }
atUint64 length() const {return 0;} atUint64 length() const { return 0; }
}; };
template<typename P, typename S> template <typename P, typename S>
void StageConverter<P, S>::loadFromStream(FactoryCtx& ctx, ShaderCacheZipStream& r) void StageConverter<P, S>::loadFromStream(FactoryCtx& ctx, ShaderCacheZipStream& r) {
{
uint32_t count = r.readUint32Big(); uint32_t count = r.readUint32Big();
for (uint32_t i = 0; i < count; ++i) for (uint32_t i = 0; i < count; ++i) {
{
uint64_t hash = r.readUint64Big(); uint64_t hash = r.readUint64Big();
uint32_t size = r.readUint32Big(); uint32_t size = r.readUint32Big();
StageBinaryData data = MakeStageBinaryData(size); StageBinaryData data = MakeStageBinaryData(size);
r.readUBytesToBuf(data.get(), size); r.readUBytesToBuf(data.get(), size);
m_stageCache.insert(std::make_pair(hash, m_stageCache.insert(std::make_pair(hash, Do<StageTargetTp>(ctx, StageBinary<P, S>(data, size))));
Do<StageTargetTp>(ctx, StageBinary<P, S>(data, size))));
} }
} }
static boo::AdditionalPipelineInfo ReadAdditionalInfo(ShaderCacheZipStream& r) static boo::AdditionalPipelineInfo ReadAdditionalInfo(ShaderCacheZipStream& r) {
{
boo::AdditionalPipelineInfo additionalInfo; boo::AdditionalPipelineInfo additionalInfo;
additionalInfo.srcFac = boo::BlendFactor(r.readUint32Big()); additionalInfo.srcFac = boo::BlendFactor(r.readUint32Big());
additionalInfo.dstFac = boo::BlendFactor(r.readUint32Big()); additionalInfo.dstFac = boo::BlendFactor(r.readUint32Big());
@ -88,14 +75,12 @@ static boo::AdditionalPipelineInfo ReadAdditionalInfo(ShaderCacheZipStream& r)
return additionalInfo; return additionalInfo;
} }
static std::vector<boo::VertexElementDescriptor> ReadVertexFormat(ShaderCacheZipStream& r) static std::vector<boo::VertexElementDescriptor> ReadVertexFormat(ShaderCacheZipStream& r) {
{
std::vector<boo::VertexElementDescriptor> ret; std::vector<boo::VertexElementDescriptor> ret;
uint32_t count = r.readUint32Big(); uint32_t count = r.readUint32Big();
ret.reserve(count); ret.reserve(count);
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i) {
{
ret.emplace_back(); ret.emplace_back();
ret.back().semantic = boo::VertexSemantic(r.readUint32Big()); ret.back().semantic = boo::VertexSemantic(r.readUint32Big());
ret.back().semanticIdx = int(r.readUint32Big()); ret.back().semanticIdx = int(r.readUint32Big());
@ -104,9 +89,8 @@ static std::vector<boo::VertexElementDescriptor> ReadVertexFormat(ShaderCacheZip
return ret; return ret;
} }
template<typename P> template <typename P>
bool PipelineConverter<P>::loadFromFile(FactoryCtx& ctx, const hecl::SystemChar* path) bool PipelineConverter<P>::loadFromFile(FactoryCtx& ctx, const hecl::SystemChar* path) {
{
ShaderCacheZipStream r(path); ShaderCacheZipStream r(path);
if (!r) if (!r)
return false; return false;
@ -118,8 +102,7 @@ bool PipelineConverter<P>::loadFromFile(FactoryCtx& ctx, const hecl::SystemChar*
m_evaluationConverter.loadFromStream(ctx, r); m_evaluationConverter.loadFromStream(ctx, r);
uint32_t count = r.readUint32Big(); uint32_t count = r.readUint32Big();
for (uint32_t i = 0; i < count; ++i) for (uint32_t i = 0; i < count; ++i) {
{
uint64_t hash = r.readUint64Big(); uint64_t hash = r.readUint64Big();
StageRuntimeObject<P, PipelineStage::Vertex> vertex; StageRuntimeObject<P, PipelineStage::Vertex> vertex;
StageRuntimeObject<P, PipelineStage::Fragment> fragment; StageRuntimeObject<P, PipelineStage::Fragment> fragment;
@ -140,9 +123,10 @@ bool PipelineConverter<P>::loadFromFile(FactoryCtx& ctx, const hecl::SystemChar*
boo::AdditionalPipelineInfo additionalInfo = ReadAdditionalInfo(r); boo::AdditionalPipelineInfo additionalInfo = ReadAdditionalInfo(r);
std::vector<boo::VertexElementDescriptor> vtxFmt = ReadVertexFormat(r); std::vector<boo::VertexElementDescriptor> vtxFmt = ReadVertexFormat(r);
m_pipelineCache.insert(std::make_pair(hash, FinalPipeline<P>(*this, ctx, m_pipelineCache.insert(
StageCollection<StageRuntimeObject<P, PipelineStage::Null>> std::make_pair(hash, FinalPipeline<P>(*this, ctx,
(vertex, fragment, geometry, control, evaluation, additionalInfo, StageCollection<StageRuntimeObject<P, PipelineStage::Null>>(
vertex, fragment, geometry, control, evaluation, additionalInfo,
boo::VertexFormatInfo(vtxFmt.size(), vtxFmt.data()))))); boo::VertexFormatInfo(vtxFmt.size(), vtxFmt.data())))));
} }
@ -150,11 +134,11 @@ bool PipelineConverter<P>::loadFromFile(FactoryCtx& ctx, const hecl::SystemChar*
} }
#define SPECIALIZE_STAGE_CONVERTER(P) \ #define SPECIALIZE_STAGE_CONVERTER(P) \
template class StageConverter<P, PipelineStage::Vertex>; \ template class StageConverter<P, PipelineStage::Vertex>; \
template class StageConverter<P, PipelineStage::Fragment>; \ template class StageConverter<P, PipelineStage::Fragment>; \
template class StageConverter<P, PipelineStage::Geometry>; \ template class StageConverter<P, PipelineStage::Geometry>; \
template class StageConverter<P, PipelineStage::Control>; \ template class StageConverter<P, PipelineStage::Control>; \
template class StageConverter<P, PipelineStage::Evaluation>; template class StageConverter<P, PipelineStage::Evaluation>;
#if BOO_HAS_GL #if BOO_HAS_GL
template class PipelineConverter<PlatformType::OpenGL>; template class PipelineConverter<PlatformType::OpenGL>;
@ -179,4 +163,4 @@ SPECIALIZE_STAGE_CONVERTER(PlatformType::NX)
#endif #endif
} } // namespace hecl

View File

@ -14,8 +14,7 @@
#include "hecl/ClientProcess.hpp" #include "hecl/ClientProcess.hpp"
#include "hecl/MultiProgressPrinter.hpp" #include "hecl/MultiProgressPrinter.hpp"
namespace hecl::Database namespace hecl::Database {
{
logvisor::Module LogModule("hecl::Database"); logvisor::Module LogModule("hecl::Database");
static const hecl::FourCC HECLfcc("HECL"); static const hecl::FourCC HECLfcc("HECL");
@ -24,17 +23,12 @@ static const hecl::FourCC HECLfcc("HECL");
* Project::ConfigFile * Project::ConfigFile
**********************************************/ **********************************************/
static inline bool CheckNewLineAdvance(std::string::const_iterator& it) static inline bool CheckNewLineAdvance(std::string::const_iterator& it) {
{ if (*it == '\n') {
if (*it == '\n')
{
it += 1; it += 1;
return true; return true;
} } else if (*it == '\r') {
else if (*it == '\r') if (*(it + 1) == '\n') {
{
if (*(it+1) == '\n')
{
it += 2; it += 2;
return true; return true;
} }
@ -44,14 +38,11 @@ static inline bool CheckNewLineAdvance(std::string::const_iterator& it)
return false; return false;
} }
Project::ConfigFile::ConfigFile(const Project& project, SystemStringView name, Project::ConfigFile::ConfigFile(const Project& project, SystemStringView name, SystemStringView subdir) {
SystemStringView subdir)
{
m_filepath = SystemString(project.m_rootPath.getAbsolutePath()) + subdir.data() + name.data(); m_filepath = SystemString(project.m_rootPath.getAbsolutePath()) + subdir.data() + name.data();
} }
std::vector<std::string>& Project::ConfigFile::lockAndRead() std::vector<std::string>& Project::ConfigFile::lockAndRead() {
{
if (m_lockedFile) if (m_lockedFile)
return m_lines; return m_lines;
@ -68,13 +59,11 @@ std::vector<std::string>& Project::ConfigFile::lockAndRead()
std::string::const_iterator end = mainString.begin(); std::string::const_iterator end = mainString.begin();
m_lines.clear(); m_lines.clear();
while (end != mainString.end()) while (end != mainString.end()) {
{
std::string::const_iterator origEnd = end; std::string::const_iterator origEnd = end;
if (*end == '\0') if (*end == '\0')
break; break;
else if (CheckNewLineAdvance(end)) else if (CheckNewLineAdvance(end)) {
{
if (begin != origEnd) if (begin != origEnd)
m_lines.push_back(std::string(begin, origEnd)); m_lines.push_back(std::string(begin, origEnd));
begin = end; begin = end;
@ -88,26 +77,19 @@ std::vector<std::string>& Project::ConfigFile::lockAndRead()
return m_lines; return m_lines;
} }
void Project::ConfigFile::addLine(std::string_view line) void Project::ConfigFile::addLine(std::string_view line) {
{
if (!checkForLine(line)) if (!checkForLine(line))
m_lines.emplace_back(line); m_lines.emplace_back(line);
} }
void Project::ConfigFile::removeLine(std::string_view refLine) void Project::ConfigFile::removeLine(std::string_view refLine) {
{ if (!m_lockedFile) {
if (!m_lockedFile) LogModule.reportSource(logvisor::Fatal, __FILE__, __LINE__, "Project::ConfigFile::lockAndRead not yet called");
{
LogModule.reportSource(logvisor::Fatal, __FILE__, __LINE__,
"Project::ConfigFile::lockAndRead not yet called");
return; return;
} }
for (auto it = m_lines.begin(); for (auto it = m_lines.begin(); it != m_lines.end();) {
it != m_lines.end();) if (!(*it).compare(refLine)) {
{
if (!(*it).compare(refLine))
{
it = m_lines.erase(it); it = m_lines.erase(it);
continue; continue;
} }
@ -115,12 +97,9 @@ void Project::ConfigFile::removeLine(std::string_view refLine)
} }
} }
bool Project::ConfigFile::checkForLine(std::string_view refLine) bool Project::ConfigFile::checkForLine(std::string_view refLine) {
{ if (!m_lockedFile) {
if (!m_lockedFile) LogModule.reportSource(logvisor::Fatal, __FILE__, __LINE__, "Project::ConfigFile::lockAndRead not yet called");
{
LogModule.reportSource(logvisor::Fatal, __FILE__, __LINE__,
"Project::ConfigFile::lockAndRead not yet called");
return false; return false;
} }
@ -130,12 +109,9 @@ bool Project::ConfigFile::checkForLine(std::string_view refLine)
return false; return false;
} }
void Project::ConfigFile::unlockAndDiscard() void Project::ConfigFile::unlockAndDiscard() {
{ if (!m_lockedFile) {
if (!m_lockedFile) LogModule.reportSource(logvisor::Fatal, __FILE__, __LINE__, "Project::ConfigFile::lockAndRead not yet called");
{
LogModule.reportSource(logvisor::Fatal, __FILE__, __LINE__,
"Project::ConfigFile::lockAndRead not yet called");
return; return;
} }
@ -144,27 +120,21 @@ void Project::ConfigFile::unlockAndDiscard()
m_lockedFile = NULL; m_lockedFile = NULL;
} }
bool Project::ConfigFile::unlockAndCommit() bool Project::ConfigFile::unlockAndCommit() {
{ if (!m_lockedFile) {
if (!m_lockedFile) LogModule.reportSource(logvisor::Fatal, __FILE__, __LINE__, "Project::ConfigFile::lockAndRead not yet called");
{
LogModule.reportSource(logvisor::Fatal, __FILE__, __LINE__,
"Project::ConfigFile::lockAndRead not yet called");
return false; return false;
} }
SystemString newPath = m_filepath + _SYS_STR(".part"); SystemString newPath = m_filepath + _SYS_STR(".part");
FILE* newFile = hecl::Fopen(newPath.c_str(), _SYS_STR("w"), FileLockType::Write); FILE* newFile = hecl::Fopen(newPath.c_str(), _SYS_STR("w"), FileLockType::Write);
bool fail = false; bool fail = false;
for (const std::string& line : m_lines) for (const std::string& line : m_lines) {
{ if (fwrite(line.c_str(), 1, line.size(), newFile) != line.size()) {
if (fwrite(line.c_str(), 1, line.size(), newFile) != line.size())
{
fail = true; fail = true;
break; break;
} }
if (fwrite("\n", 1, 1, newFile) != 1) if (fwrite("\n", 1, 1, newFile) != 1) {
{
fail = true; fail = true;
break; break;
} }
@ -173,17 +143,14 @@ bool Project::ConfigFile::unlockAndCommit()
fclose(newFile); fclose(newFile);
fclose(m_lockedFile); fclose(m_lockedFile);
m_lockedFile = NULL; m_lockedFile = NULL;
if (fail) if (fail) {
{
#if HECL_UCS2 #if HECL_UCS2
_wunlink(newPath.c_str()); _wunlink(newPath.c_str());
#else #else
unlink(newPath.c_str()); unlink(newPath.c_str());
#endif #endif
return false; return false;
} } else {
else
{
#if HECL_UCS2 #if HECL_UCS2
//_wrename(newPath.c_str(), m_filepath.c_str()); //_wrename(newPath.c_str(), m_filepath.c_str());
MoveFileExW(newPath.c_str(), m_filepath.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH); MoveFileExW(newPath.c_str(), m_filepath.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
@ -199,24 +166,21 @@ bool Project::ConfigFile::unlockAndCommit()
**********************************************/ **********************************************/
Project::Project(const ProjectRootPath& rootPath) Project::Project(const ProjectRootPath& rootPath)
: m_rootPath(rootPath), : m_rootPath(rootPath)
m_workRoot(*this, _SYS_STR("")), , m_workRoot(*this, _SYS_STR(""))
m_dotPath(m_workRoot, _SYS_STR(".hecl")), , m_dotPath(m_workRoot, _SYS_STR(".hecl"))
m_cookedRoot(m_dotPath, _SYS_STR("cooked")), , m_cookedRoot(m_dotPath, _SYS_STR("cooked"))
m_specs(*this, _SYS_STR("specs")), , m_specs(*this, _SYS_STR("specs"))
m_paths(*this, _SYS_STR("paths")), , m_paths(*this, _SYS_STR("paths"))
m_groups(*this, _SYS_STR("groups")) , m_groups(*this, _SYS_STR("groups")) {
{
/* Stat for existing project directory (must already exist) */ /* Stat for existing project directory (must already exist) */
Sstat myStat; Sstat myStat;
if (hecl::Stat(m_rootPath.getAbsolutePath().data(), &myStat)) if (hecl::Stat(m_rootPath.getAbsolutePath().data(), &myStat)) {
{
LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s"), m_rootPath.getAbsolutePath().data()); LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s"), m_rootPath.getAbsolutePath().data());
return; return;
} }
if (!S_ISDIR(myStat.st_mode)) if (!S_ISDIR(myStat.st_mode)) {
{
LogModule.report(logvisor::Error, _SYS_STR("provided path must be a directory; '%s' isn't"), LogModule.report(logvisor::Error, _SYS_STR("provided path must be a directory; '%s' isn't"),
m_rootPath.getAbsolutePath().data()); m_rootPath.getAbsolutePath().data());
return; return;
@ -229,23 +193,19 @@ Project::Project(const ProjectRootPath& rootPath)
/* Ensure beacon is valid or created */ /* Ensure beacon is valid or created */
ProjectPath beaconPath(m_dotPath, _SYS_STR("beacon")); ProjectPath beaconPath(m_dotPath, _SYS_STR("beacon"));
FILE* bf = hecl::Fopen(beaconPath.getAbsolutePath().data(), _SYS_STR("a+b")); FILE* bf = hecl::Fopen(beaconPath.getAbsolutePath().data(), _SYS_STR("a+b"));
struct BeaconStruct struct BeaconStruct {
{
hecl::FourCC magic; hecl::FourCC magic;
uint32_t version; uint32_t version;
} beacon; } beacon;
#define DATA_VERSION 1 #define DATA_VERSION 1
if (fread(&beacon, 1, sizeof(beacon), bf) != sizeof(beacon)) if (fread(&beacon, 1, sizeof(beacon), bf) != sizeof(beacon)) {
{
fseek(bf, 0, SEEK_SET); fseek(bf, 0, SEEK_SET);
beacon.magic = HECLfcc; beacon.magic = HECLfcc;
beacon.version = SBig(DATA_VERSION); beacon.version = SBig(DATA_VERSION);
fwrite(&beacon, 1, sizeof(beacon), bf); fwrite(&beacon, 1, sizeof(beacon), bf);
} }
fclose(bf); fclose(bf);
if (beacon.magic != HECLfcc || if (beacon.magic != HECLfcc || SBig(beacon.version) != DATA_VERSION) {
SBig(beacon.version) != DATA_VERSION)
{
LogModule.report(logvisor::Fatal, "incompatible project version"); LogModule.report(logvisor::Fatal, "incompatible project version");
return; return;
} }
@ -255,8 +215,7 @@ Project::Project(const ProjectRootPath& rootPath)
m_valid = true; m_valid = true;
} }
const ProjectPath& Project::getProjectCookedPath(const DataSpecEntry& spec) const const ProjectPath& Project::getProjectCookedPath(const DataSpecEntry& spec) const {
{
for (const ProjectDataSpec& sp : m_compiledSpecs) for (const ProjectDataSpec& sp : m_compiledSpecs)
if (&sp.spec == &spec) if (&sp.spec == &spec)
return sp.cookedPath; return sp.cookedPath;
@ -264,60 +223,48 @@ const ProjectPath& Project::getProjectCookedPath(const DataSpecEntry& spec) cons
return m_cookedRoot; return m_cookedRoot;
} }
bool Project::addPaths(const std::vector<ProjectPath>& paths) bool Project::addPaths(const std::vector<ProjectPath>& paths) {
{
m_paths.lockAndRead(); m_paths.lockAndRead();
for (const ProjectPath& path : paths) for (const ProjectPath& path : paths)
m_paths.addLine(path.getRelativePathUTF8()); m_paths.addLine(path.getRelativePathUTF8());
return m_paths.unlockAndCommit(); return m_paths.unlockAndCommit();
} }
bool Project::removePaths(const std::vector<ProjectPath>& paths, bool recursive) bool Project::removePaths(const std::vector<ProjectPath>& paths, bool recursive) {
{
std::vector<std::string>& existingPaths = m_paths.lockAndRead(); std::vector<std::string>& existingPaths = m_paths.lockAndRead();
if (recursive) if (recursive) {
{ for (const ProjectPath& path : paths) {
for (const ProjectPath& path : paths)
{
auto recursiveBase = path.getRelativePathUTF8(); auto recursiveBase = path.getRelativePathUTF8();
for (auto it = existingPaths.begin(); for (auto it = existingPaths.begin(); it != existingPaths.end();) {
it != existingPaths.end();) if (!(*it).compare(0, recursiveBase.size(), recursiveBase)) {
{
if (!(*it).compare(0, recursiveBase.size(), recursiveBase))
{
it = existingPaths.erase(it); it = existingPaths.erase(it);
continue; continue;
} }
++it; ++it;
} }
} }
} } else
else
for (const ProjectPath& path : paths) for (const ProjectPath& path : paths)
m_paths.removeLine(path.getRelativePathUTF8()); m_paths.removeLine(path.getRelativePathUTF8());
return m_paths.unlockAndCommit(); return m_paths.unlockAndCommit();
} }
bool Project::addGroup(const hecl::ProjectPath& path) bool Project::addGroup(const hecl::ProjectPath& path) {
{
m_groups.lockAndRead(); m_groups.lockAndRead();
m_groups.addLine(path.getRelativePathUTF8()); m_groups.addLine(path.getRelativePathUTF8());
return m_groups.unlockAndCommit(); return m_groups.unlockAndCommit();
} }
bool Project::removeGroup(const ProjectPath& path) bool Project::removeGroup(const ProjectPath& path) {
{
m_groups.lockAndRead(); m_groups.lockAndRead();
m_groups.removeLine(path.getRelativePathUTF8()); m_groups.removeLine(path.getRelativePathUTF8());
return m_groups.unlockAndCommit(); return m_groups.unlockAndCommit();
} }
void Project::rescanDataSpecs() void Project::rescanDataSpecs() {
{
m_compiledSpecs.clear(); m_compiledSpecs.clear();
m_specs.lockAndRead(); m_specs.lockAndRead();
for (const DataSpecEntry* spec : DATA_SPEC_REGISTRY) for (const DataSpecEntry* spec : DATA_SPEC_REGISTRY) {
{
hecl::SystemString specStr(spec->m_name); hecl::SystemString specStr(spec->m_name);
SystemUTF8Conv specUTF8(specStr); SystemUTF8Conv specUTF8(specStr);
m_compiledSpecs.push_back({*spec, ProjectPath(m_cookedRoot, hecl::SystemString(spec->m_name) + _SYS_STR(".spec")), m_compiledSpecs.push_back({*spec, ProjectPath(m_cookedRoot, hecl::SystemString(spec->m_name) + _SYS_STR(".spec")),
@ -326,11 +273,9 @@ void Project::rescanDataSpecs()
m_specs.unlockAndDiscard(); m_specs.unlockAndDiscard();
} }
bool Project::enableDataSpecs(const std::vector<SystemString>& specs) bool Project::enableDataSpecs(const std::vector<SystemString>& specs) {
{
m_specs.lockAndRead(); m_specs.lockAndRead();
for (const SystemString& spec : specs) for (const SystemString& spec : specs) {
{
SystemUTF8Conv specView(spec); SystemUTF8Conv specView(spec);
m_specs.addLine(specView.str()); m_specs.addLine(specView.str());
} }
@ -339,11 +284,9 @@ bool Project::enableDataSpecs(const std::vector<SystemString>& specs)
return result; return result;
} }
bool Project::disableDataSpecs(const std::vector<SystemString>& specs) bool Project::disableDataSpecs(const std::vector<SystemString>& specs) {
{
m_specs.lockAndRead(); m_specs.lockAndRead();
for (const SystemString& spec : specs) for (const SystemString& spec : specs) {
{
SystemUTF8Conv specView(spec); SystemUTF8Conv specView(spec);
m_specs.removeLine(specView.str()); m_specs.removeLine(specView.str());
} }
@ -352,26 +295,30 @@ bool Project::disableDataSpecs(const std::vector<SystemString>& specs)
return result; return result;
} }
class CookProgress class CookProgress {
{
const hecl::MultiProgressPrinter& m_progPrinter; const hecl::MultiProgressPrinter& m_progPrinter;
const SystemChar* m_dir = nullptr; const SystemChar* m_dir = nullptr;
const SystemChar* m_file = nullptr; const SystemChar* m_file = nullptr;
float m_prog = 0.f; float m_prog = 0.f;
public: public:
CookProgress(const hecl::MultiProgressPrinter& progPrinter) : m_progPrinter(progPrinter) {} CookProgress(const hecl::MultiProgressPrinter& progPrinter) : m_progPrinter(progPrinter) {}
void changeDir(const SystemChar* dir) {m_dir = dir; m_progPrinter.startNewLine();} void changeDir(const SystemChar* dir) {
void changeFile(const SystemChar* file, float prog) {m_file = file; m_prog = prog;} m_dir = dir;
void reportFile(const DataSpecEntry* specEnt) m_progPrinter.startNewLine();
{ }
void changeFile(const SystemChar* file, float prog) {
m_file = file;
m_prog = prog;
}
void reportFile(const DataSpecEntry* specEnt) {
SystemString submsg(m_file); SystemString submsg(m_file);
submsg += _SYS_STR(" ("); submsg += _SYS_STR(" (");
submsg += specEnt->m_name.data(); submsg += specEnt->m_name.data();
submsg += _SYS_STR(')'); submsg += _SYS_STR(')');
m_progPrinter.print(m_dir, submsg.c_str(), m_prog); m_progPrinter.print(m_dir, submsg.c_str(), m_prog);
} }
void reportFile(const DataSpecEntry* specEnt, const SystemChar* extra) void reportFile(const DataSpecEntry* specEnt, const SystemChar* extra) {
{
SystemString submsg(m_file); SystemString submsg(m_file);
submsg += _SYS_STR(" ("); submsg += _SYS_STR(" (");
submsg += specEnt->m_name.data(); submsg += specEnt->m_name.data();
@ -380,59 +327,42 @@ public:
submsg += _SYS_STR(')'); submsg += _SYS_STR(')');
m_progPrinter.print(m_dir, submsg.c_str(), m_prog); m_progPrinter.print(m_dir, submsg.c_str(), m_prog);
} }
void reportDirComplete() void reportDirComplete() { m_progPrinter.print(m_dir, nullptr, 1.f); }
{
m_progPrinter.print(m_dir, nullptr, 1.f);
}
}; };
static void VisitFile(const ProjectPath& path, bool force, bool fast, static void VisitFile(const ProjectPath& path, bool force, bool fast,
std::vector<std::unique_ptr<IDataSpec>>& specInsts, std::vector<std::unique_ptr<IDataSpec>>& specInsts, CookProgress& progress, ClientProcess* cp,
CookProgress& progress, ClientProcess* cp, int cookPass) int cookPass) {
{ for (auto& spec : specInsts) {
for (auto& spec : specInsts) if (spec->canCook(path, hecl::blender::SharedBlenderToken, cookPass)) {
{ if (cp) {
if (spec->canCook(path, hecl::blender::SharedBlenderToken, cookPass))
{
if (cp)
{
cp->addCookTransaction(path, force, fast, spec.get()); cp->addCookTransaction(path, force, fast, spec.get());
} } else {
else const DataSpecEntry* override =
{ spec->overrideDataSpec(path, spec->getDataSpecEntry(), hecl::blender::SharedBlenderToken);
const DataSpecEntry* override = spec->overrideDataSpec(path, spec->getDataSpecEntry(),
hecl::blender::SharedBlenderToken);
if (!override) if (!override)
continue; continue;
ProjectPath cooked = path.getCookedPath(*override); ProjectPath cooked = path.getCookedPath(*override);
if (fast) if (fast)
cooked = cooked.getWithExtension(_SYS_STR(".fast")); cooked = cooked.getWithExtension(_SYS_STR(".fast"));
if (force || cooked.getPathType() == ProjectPath::Type::None || if (force || cooked.getPathType() == ProjectPath::Type::None || path.getModtime() > cooked.getModtime()) {
path.getModtime() > cooked.getModtime())
{
progress.reportFile(override); progress.reportFile(override);
spec->doCook(path, cooked, fast, hecl::blender::SharedBlenderToken, spec->doCook(path, cooked, fast, hecl::blender::SharedBlenderToken,
[&](const SystemChar* extra) [&](const SystemChar* extra) { progress.reportFile(override, extra); });
{
progress.reportFile(override, extra);
});
} }
} }
} }
} }
} }
static void VisitDirectory(const ProjectPath& dir, static void VisitDirectory(const ProjectPath& dir, bool recursive, bool force, bool fast,
bool recursive, bool force, bool fast, std::vector<std::unique_ptr<IDataSpec>>& specInsts, CookProgress& progress,
std::vector<std::unique_ptr<IDataSpec>>& specInsts, ClientProcess* cp, int cookPass) {
CookProgress& progress, ClientProcess* cp, int cookPass)
{
if (dir.getLastComponent().size() > 1 && dir.getLastComponent()[0] == _SYS_STR('.')) if (dir.getLastComponent().size() > 1 && dir.getLastComponent()[0] == _SYS_STR('.'))
return; return;
if (hecl::ProjectPath(dir, _SYS_STR("!project.yaml")).isFile() && if (hecl::ProjectPath(dir, _SYS_STR("!project.yaml")).isFile() &&
hecl::ProjectPath(dir, _SYS_STR("!pool.yaml")).isFile()) hecl::ProjectPath(dir, _SYS_STR("!pool.yaml")).isFile()) {
{
/* Handle AudioGroup case */ /* Handle AudioGroup case */
VisitFile(dir, force, fast, specInsts, progress, cp, cookPass); VisitFile(dir, force, fast, specInsts, progress, cp, cookPass);
return; return;
@ -451,50 +381,39 @@ static void VisitDirectory(const ProjectPath& dir,
int progNum = 0; int progNum = 0;
float progDenom = childFileCount; float progDenom = childFileCount;
progress.changeDir(dir.getLastComponent().data()); progress.changeDir(dir.getLastComponent().data());
for (auto& child : children) for (auto& child : children) {
{ if (child.second.getPathType() == ProjectPath::Type::File) {
if (child.second.getPathType() == ProjectPath::Type::File) progress.changeFile(child.first.c_str(), progNum++ / progDenom);
{
progress.changeFile(child.first.c_str(), progNum++/progDenom);
VisitFile(child.second, force, fast, specInsts, progress, cp, cookPass); VisitFile(child.second, force, fast, specInsts, progress, cp, cookPass);
} }
} }
progress.reportDirComplete(); progress.reportDirComplete();
/* Pass 3: child directories */ /* Pass 3: child directories */
if (recursive) if (recursive) {
{ for (auto& child : children) {
for (auto& child : children) switch (child.second.getPathType()) {
{ case ProjectPath::Type::Directory: {
switch (child.second.getPathType())
{
case ProjectPath::Type::Directory:
{
VisitDirectory(child.second, recursive, force, fast, specInsts, progress, cp, cookPass); VisitDirectory(child.second, recursive, force, fast, specInsts, progress, cp, cookPass);
break; break;
} }
default: break; default:
break;
} }
} }
} }
} }
bool Project::cookPath(const ProjectPath& path, const hecl::MultiProgressPrinter& progress, bool Project::cookPath(const ProjectPath& path, const hecl::MultiProgressPrinter& progress, bool recursive, bool force,
bool recursive, bool force, bool fast, const DataSpecEntry* spec, bool fast, const DataSpecEntry* spec, ClientProcess* cp, int cookPass) {
ClientProcess* cp, int cookPass)
{
/* Construct DataSpec instances for cooking */ /* Construct DataSpec instances for cooking */
if (spec) if (spec) {
{ if (m_cookSpecs.size() != 1 || m_cookSpecs[0]->getDataSpecEntry() != spec) {
if (m_cookSpecs.size() != 1 || m_cookSpecs[0]->getDataSpecEntry() != spec)
{
m_cookSpecs.clear(); m_cookSpecs.clear();
if (spec->m_factory) if (spec->m_factory)
m_cookSpecs.push_back(spec->m_factory(*this, DataSpecTool::Cook)); m_cookSpecs.push_back(spec->m_factory(*this, DataSpecTool::Cook));
} }
} } else if (m_cookSpecs.empty()) {
else if (m_cookSpecs.empty())
{
m_cookSpecs.reserve(m_compiledSpecs.size()); m_cookSpecs.reserve(m_compiledSpecs.size());
for (const ProjectDataSpec& spec : m_compiledSpecs) for (const ProjectDataSpec& spec : m_compiledSpecs)
if (spec.active && spec.spec.m_factory) if (spec.active && spec.spec.m_factory)
@ -503,50 +422,39 @@ bool Project::cookPath(const ProjectPath& path, const hecl::MultiProgressPrinter
/* Iterate complete directory/file/glob list */ /* Iterate complete directory/file/glob list */
CookProgress cookProg(progress); CookProgress cookProg(progress);
switch (path.getPathType()) switch (path.getPathType()) {
{
case ProjectPath::Type::File: case ProjectPath::Type::File:
case ProjectPath::Type::Glob: case ProjectPath::Type::Glob: {
{
cookProg.changeFile(path.getLastComponent().data(), 0.f); cookProg.changeFile(path.getLastComponent().data(), 0.f);
VisitFile(path, force, fast, m_cookSpecs, cookProg, cp, cookPass); VisitFile(path, force, fast, m_cookSpecs, cookProg, cp, cookPass);
break; break;
} }
case ProjectPath::Type::Directory: case ProjectPath::Type::Directory: {
{
VisitDirectory(path, recursive, force, fast, m_cookSpecs, cookProg, cp, cookPass); VisitDirectory(path, recursive, force, fast, m_cookSpecs, cookProg, cp, cookPass);
break; break;
} }
default: break; default:
break;
} }
return true; return true;
} }
bool Project::packagePath(const ProjectPath& path, const hecl::MultiProgressPrinter& progress, bool Project::packagePath(const ProjectPath& path, const hecl::MultiProgressPrinter& progress, bool fast,
bool fast, const DataSpecEntry* spec, ClientProcess* cp) const DataSpecEntry* spec, ClientProcess* cp) {
{
/* Construct DataSpec instance for packaging */ /* Construct DataSpec instance for packaging */
const DataSpecEntry* specEntry = nullptr; const DataSpecEntry* specEntry = nullptr;
if (spec) if (spec) {
{
if (spec->m_factory) if (spec->m_factory)
specEntry = spec; specEntry = spec;
} } else {
else
{
bool foundPC = false; bool foundPC = false;
for (const ProjectDataSpec& spec : m_compiledSpecs) for (const ProjectDataSpec& spec : m_compiledSpecs) {
{ if (spec.active && spec.spec.m_factory) {
if (spec.active && spec.spec.m_factory) if (hecl::StringUtils::EndsWith(spec.spec.m_name, _SYS_STR("-PC"))) {
{
if (hecl::StringUtils::EndsWith(spec.spec.m_name, _SYS_STR("-PC")))
{
foundPC = true; foundPC = true;
specEntry = &spec.spec; specEntry = &spec.spec;
} } else if (!foundPC) {
else if (!foundPC)
{
specEntry = &spec.spec; specEntry = &spec.spec;
} }
} }
@ -559,8 +467,7 @@ bool Project::packagePath(const ProjectPath& path, const hecl::MultiProgressPrin
if (!m_lastPackageSpec || m_lastPackageSpec->getDataSpecEntry() != specEntry) if (!m_lastPackageSpec || m_lastPackageSpec->getDataSpecEntry() != specEntry)
m_lastPackageSpec = specEntry->m_factory(*this, DataSpecTool::Package); m_lastPackageSpec = specEntry->m_factory(*this, DataSpecTool::Package);
if (m_lastPackageSpec->canPackage(path)) if (m_lastPackageSpec->canPackage(path)) {
{
m_lastPackageSpec->doPackage(path, specEntry, fast, hecl::blender::SharedBlenderToken, progress, cp); m_lastPackageSpec->doPackage(path, specEntry, fast, hecl::blender::SharedBlenderToken, progress, cp);
return true; return true;
} }
@ -568,38 +475,24 @@ bool Project::packagePath(const ProjectPath& path, const hecl::MultiProgressPrin
return false; return false;
} }
void Project::interruptCook() void Project::interruptCook() {
{
if (m_lastPackageSpec) if (m_lastPackageSpec)
m_lastPackageSpec->interruptCook(); m_lastPackageSpec->interruptCook();
} }
bool Project::cleanPath(const ProjectPath& path, bool recursive) bool Project::cleanPath(const ProjectPath& path, bool recursive) { return false; }
{
return false;
}
PackageDepsgraph Project::buildPackageDepsgraph(const ProjectPath& path) PackageDepsgraph Project::buildPackageDepsgraph(const ProjectPath& path) { return PackageDepsgraph(); }
{
return PackageDepsgraph();
}
void Project::addBridgePathToCache(uint64_t id, const ProjectPath& path) void Project::addBridgePathToCache(uint64_t id, const ProjectPath& path) { m_bridgePathCache[id] = path; }
{
m_bridgePathCache[id] = path;
}
void Project::clearBridgePathCache() void Project::clearBridgePathCache() { m_bridgePathCache.clear(); }
{
m_bridgePathCache.clear();
}
const ProjectPath* Project::lookupBridgePath(uint64_t id) const const ProjectPath* Project::lookupBridgePath(uint64_t id) const {
{
auto search = m_bridgePathCache.find(id); auto search = m_bridgePathCache.find(id);
if (search == m_bridgePathCache.cend()) if (search == m_bridgePathCache.cend())
return nullptr; return nullptr;
return &search->second; return &search->second;
} }
} } // namespace hecl::Database

View File

@ -2,27 +2,22 @@
#include "hecl/Database.hpp" #include "hecl/Database.hpp"
#include <regex> #include <regex>
namespace hecl namespace hecl {
{ static const SystemRegex regPATHCOMP(_SYS_STR("[/\\\\]*([^/\\\\]+)"), SystemRegex::ECMAScript | SystemRegex::optimize);
static const SystemRegex regPATHCOMP(_SYS_STR("[/\\\\]*([^/\\\\]+)"), SystemRegex::ECMAScript|SystemRegex::optimize); static const SystemRegex regDRIVELETTER(_SYS_STR("^([^/]*)/"), SystemRegex::ECMAScript | SystemRegex::optimize);
static const SystemRegex regDRIVELETTER(_SYS_STR("^([^/]*)/"), SystemRegex::ECMAScript|SystemRegex::optimize);
static SystemString CanonRelPath(SystemStringView path) static SystemString CanonRelPath(SystemStringView path) {
{
/* Tokenize Path */ /* Tokenize Path */
std::vector<SystemString> comps; std::vector<SystemString> comps;
hecl::SystemRegexMatch matches; hecl::SystemRegexMatch matches;
SystemString in(path); SystemString in(path);
SanitizePath(in); SanitizePath(in);
for (; std::regex_search(in, matches, regPATHCOMP) ; in = matches.suffix().str()) for (; std::regex_search(in, matches, regPATHCOMP); in = matches.suffix().str()) {
{
hecl::SystemRegexMatch::const_reference match = matches[1]; hecl::SystemRegexMatch::const_reference match = matches[1];
if (!match.compare(_SYS_STR("."))) if (!match.compare(_SYS_STR(".")))
continue; continue;
else if (!match.compare(_SYS_STR(".."))) else if (!match.compare(_SYS_STR(".."))) {
{ if (comps.empty()) {
if (comps.empty())
{
/* Unable to resolve outside project */ /* Unable to resolve outside project */
LogModule.report(logvisor::Fatal, _SYS_STR("Unable to resolve outside project root in %s"), path.data()); LogModule.report(logvisor::Fatal, _SYS_STR("Unable to resolve outside project root in %s"), path.data());
return _SYS_STR("."); return _SYS_STR(".");
@ -34,14 +29,11 @@ static SystemString CanonRelPath(SystemStringView path)
} }
/* Emit relative path */ /* Emit relative path */
if (comps.size()) if (comps.size()) {
{
auto it = comps.begin(); auto it = comps.begin();
SystemString retval = *it; SystemString retval = *it;
for (++it ; it != comps.end() ; ++it) for (++it; it != comps.end(); ++it) {
{ if ((*it).size()) {
if ((*it).size())
{
retval += _SYS_STR('/'); retval += _SYS_STR('/');
retval += *it; retval += *it;
} }
@ -51,26 +43,22 @@ static SystemString CanonRelPath(SystemStringView path)
return _SYS_STR("."); return _SYS_STR(".");
} }
static SystemString CanonRelPath(SystemStringView path, const ProjectRootPath& projectRoot) static SystemString CanonRelPath(SystemStringView path, const ProjectRootPath& projectRoot) {
{
/* Absolute paths not allowed; attempt to make project-relative */ /* Absolute paths not allowed; attempt to make project-relative */
if (IsAbsolute(path)) if (IsAbsolute(path))
return CanonRelPath(projectRoot.getProjectRelativeFromAbsolute(path)); return CanonRelPath(projectRoot.getProjectRelativeFromAbsolute(path));
return CanonRelPath(path); return CanonRelPath(path);
} }
void ProjectPath::assign(Database::Project& project, SystemStringView path) void ProjectPath::assign(Database::Project& project, SystemStringView path) {
{
m_proj = &project; m_proj = &project;
SystemString usePath; SystemString usePath;
size_t pipeFind = path.rfind(_SYS_STR('|')); size_t pipeFind = path.rfind(_SYS_STR('|'));
if (pipeFind != SystemString::npos) if (pipeFind != SystemString::npos) {
{
m_auxInfo.assign(path.cbegin() + pipeFind + 1, path.cend()); m_auxInfo.assign(path.cbegin() + pipeFind + 1, path.cend());
usePath.assign(path.cbegin(), path.cbegin() + pipeFind); usePath.assign(path.cbegin(), path.cbegin() + pipeFind);
} } else
else
usePath = path; usePath = path;
m_relPath = CanonRelPath(usePath, project.getProjectRootPath()); m_relPath = CanonRelPath(usePath, project.getProjectRootPath());
@ -82,25 +70,21 @@ void ProjectPath::assign(Database::Project& project, SystemStringView path)
} }
#if HECL_UCS2 #if HECL_UCS2
void ProjectPath::assign(Database::Project& project, std::string_view path) void ProjectPath::assign(Database::Project& project, std::string_view path) {
{
std::wstring wpath = UTF8ToWide(path); std::wstring wpath = UTF8ToWide(path);
assign(project, wpath); assign(project, wpath);
} }
#endif #endif
void ProjectPath::assign(const ProjectPath& parentPath, SystemStringView path) void ProjectPath::assign(const ProjectPath& parentPath, SystemStringView path) {
{
m_proj = parentPath.m_proj; m_proj = parentPath.m_proj;
SystemString usePath; SystemString usePath;
size_t pipeFind = path.rfind(_SYS_STR('|')); size_t pipeFind = path.rfind(_SYS_STR('|'));
if (pipeFind != SystemString::npos) if (pipeFind != SystemString::npos) {
{
m_auxInfo.assign(path.cbegin() + pipeFind + 1, path.cend()); m_auxInfo.assign(path.cbegin() + pipeFind + 1, path.cend());
usePath.assign(path.cbegin(), path.cbegin() + pipeFind); usePath.assign(path.cbegin(), path.cbegin() + pipeFind);
} } else
else
usePath = path; usePath = path;
m_relPath = CanonRelPath(parentPath.m_relPath + _SYS_STR('/') + usePath); m_relPath = CanonRelPath(parentPath.m_relPath + _SYS_STR('/') + usePath);
@ -112,37 +96,31 @@ void ProjectPath::assign(const ProjectPath& parentPath, SystemStringView path)
} }
#if HECL_UCS2 #if HECL_UCS2
void ProjectPath::assign(const ProjectPath& parentPath, std::string_view path) void ProjectPath::assign(const ProjectPath& parentPath, std::string_view path) {
{
std::wstring wpath = UTF8ToWide(path); std::wstring wpath = UTF8ToWide(path);
assign(parentPath, wpath); assign(parentPath, wpath);
} }
#endif #endif
ProjectPath ProjectPath::getWithExtension(const SystemChar* ext, bool replace) const ProjectPath ProjectPath::getWithExtension(const SystemChar* ext, bool replace) const {
{
ProjectPath pp(*this); ProjectPath pp(*this);
if (replace) if (replace) {
{
auto relIt = pp.m_relPath.end(); auto relIt = pp.m_relPath.end();
if (relIt != pp.m_relPath.begin()) if (relIt != pp.m_relPath.begin())
--relIt; --relIt;
auto absIt = pp.m_absPath.end(); auto absIt = pp.m_absPath.end();
if (absIt != pp.m_absPath.begin()) if (absIt != pp.m_absPath.begin())
--absIt; --absIt;
while (relIt != pp.m_relPath.begin() && *relIt != _SYS_STR('.') && *relIt != _SYS_STR('/')) while (relIt != pp.m_relPath.begin() && *relIt != _SYS_STR('.') && *relIt != _SYS_STR('/')) {
{
--relIt; --relIt;
--absIt; --absIt;
} }
if (*relIt == _SYS_STR('.') && relIt != pp.m_relPath.begin()) if (*relIt == _SYS_STR('.') && relIt != pp.m_relPath.begin()) {
{
pp.m_relPath.resize(relIt - pp.m_relPath.begin()); pp.m_relPath.resize(relIt - pp.m_relPath.begin());
pp.m_absPath.resize(absIt - pp.m_absPath.begin()); pp.m_absPath.resize(absIt - pp.m_absPath.begin());
} }
} }
if (ext) if (ext) {
{
pp.m_relPath += ext; pp.m_relPath += ext;
pp.m_absPath += ext; pp.m_absPath += ext;
} }
@ -151,8 +129,7 @@ ProjectPath ProjectPath::getWithExtension(const SystemChar* ext, bool replace) c
return pp; return pp;
} }
ProjectPath ProjectPath::getCookedPath(const Database::DataSpecEntry& spec) const ProjectPath ProjectPath::getCookedPath(const Database::DataSpecEntry& spec) const {
{
ProjectPath woExt = getWithExtension(nullptr, true); ProjectPath woExt = getWithExtension(nullptr, true);
ProjectPath ret(m_proj->getProjectCookedPath(spec), woExt.getRelativePath()); ProjectPath ret(m_proj->getProjectCookedPath(spec), woExt.getRelativePath());
@ -162,8 +139,7 @@ ProjectPath ProjectPath::getCookedPath(const Database::DataSpecEntry& spec) cons
return ret; return ret;
} }
ProjectPath::Type ProjectPath::getPathType() const ProjectPath::Type ProjectPath::getPathType() const {
{
if (m_absPath.find(_SYS_STR('*')) != SystemString::npos) if (m_absPath.find(_SYS_STR('*')) != SystemString::npos)
return Type::Glob; return Type::Glob;
Sstat theStat; Sstat theStat;
@ -176,38 +152,27 @@ ProjectPath::Type ProjectPath::getPathType() const
return Type::None; return Type::None;
} }
Time ProjectPath::getModtime() const Time ProjectPath::getModtime() const {
{
Sstat theStat; Sstat theStat;
time_t latestTime = 0; time_t latestTime = 0;
if (m_absPath.find(_SYS_STR('*')) != SystemString::npos) if (m_absPath.find(_SYS_STR('*')) != SystemString::npos) {
{
std::vector<ProjectPath> globResults; std::vector<ProjectPath> globResults;
getGlobResults(globResults); getGlobResults(globResults);
for (ProjectPath& path : globResults) for (ProjectPath& path : globResults) {
{ if (!hecl::Stat(path.getAbsolutePath().data(), &theStat)) {
if (!hecl::Stat(path.getAbsolutePath().data(), &theStat))
{
if (S_ISREG(theStat.st_mode) && theStat.st_mtime > latestTime) if (S_ISREG(theStat.st_mode) && theStat.st_mtime > latestTime)
latestTime = theStat.st_mtime; latestTime = theStat.st_mtime;
} }
} }
return Time(latestTime); return Time(latestTime);
} }
if (!hecl::Stat(m_absPath.c_str(), &theStat)) if (!hecl::Stat(m_absPath.c_str(), &theStat)) {
{ if (S_ISREG(theStat.st_mode)) {
if (S_ISREG(theStat.st_mode))
{
return Time(theStat.st_mtime); return Time(theStat.st_mtime);
} } else if (S_ISDIR(theStat.st_mode)) {
else if (S_ISDIR(theStat.st_mode)) hecl::DirectoryEnumerator de(m_absPath, hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
{ for (const hecl::DirectoryEnumerator::Entry& ent : de) {
hecl::DirectoryEnumerator de(m_absPath, hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted, if (!hecl::Stat(ent.m_path.c_str(), &theStat)) {
false, false, true);
for (const hecl::DirectoryEnumerator::Entry& ent : de)
{
if (!hecl::Stat(ent.m_path.c_str(), &theStat))
{
if (S_ISREG(theStat.st_mode) && theStat.st_mtime > latestTime) if (S_ISREG(theStat.st_mode) && theStat.st_mtime > latestTime)
latestTime = theStat.st_mtime; latestTime = theStat.st_mtime;
} }
@ -219,19 +184,14 @@ Time ProjectPath::getModtime() const
return Time(); return Time();
} }
static void _recursiveGlob(Database::Project& proj, static void _recursiveGlob(Database::Project& proj, std::vector<ProjectPath>& outPaths, const SystemString& remPath,
std::vector<ProjectPath>& outPaths, const SystemString& itStr, bool needSlash) {
const SystemString& remPath,
const SystemString& itStr,
bool needSlash)
{
SystemRegexMatch matches; SystemRegexMatch matches;
if (!std::regex_search(remPath, matches, regPATHCOMP)) if (!std::regex_search(remPath, matches, regPATHCOMP))
return; return;
const SystemString& comp = matches[1]; const SystemString& comp = matches[1];
if (comp.find(_SYS_STR('*')) == SystemString::npos) if (comp.find(_SYS_STR('*')) == SystemString::npos) {
{
SystemString nextItStr = itStr; SystemString nextItStr = itStr;
if (needSlash) if (needSlash)
nextItStr += _SYS_STR('/'); nextItStr += _SYS_STR('/');
@ -251,12 +211,9 @@ static void _recursiveGlob(Database::Project& proj,
/* Compile component into regex */ /* Compile component into regex */
SystemRegex regComp(comp, SystemRegex::ECMAScript); SystemRegex regComp(comp, SystemRegex::ECMAScript);
hecl::DirectoryEnumerator de(itStr, hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted, hecl::DirectoryEnumerator de(itStr, hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
false, false, true); for (const hecl::DirectoryEnumerator::Entry& ent : de) {
for (const hecl::DirectoryEnumerator::Entry& ent : de) if (std::regex_match(ent.m_name, regComp)) {
{
if (std::regex_match(ent.m_name, regComp))
{
SystemString nextItStr = itStr; SystemString nextItStr = itStr;
if (needSlash) if (needSlash)
nextItStr += '/'; nextItStr += '/';
@ -274,40 +231,31 @@ static void _recursiveGlob(Database::Project& proj,
} }
} }
void ProjectPath::getDirChildren(std::map<SystemString, ProjectPath>& outPaths) const void ProjectPath::getDirChildren(std::map<SystemString, ProjectPath>& outPaths) const {
{ hecl::DirectoryEnumerator de(m_absPath, hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
hecl::DirectoryEnumerator de(m_absPath, hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted,
false, false, true);
for (const hecl::DirectoryEnumerator::Entry& ent : de) for (const hecl::DirectoryEnumerator::Entry& ent : de)
outPaths[ent.m_name] = ProjectPath(*this, ent.m_name); outPaths[ent.m_name] = ProjectPath(*this, ent.m_name);
} }
hecl::DirectoryEnumerator ProjectPath::enumerateDir() const hecl::DirectoryEnumerator ProjectPath::enumerateDir() const {
{ return hecl::DirectoryEnumerator(m_absPath, hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
return hecl::DirectoryEnumerator(m_absPath, hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted,
false, false, true);
} }
void ProjectPath::getGlobResults(std::vector<ProjectPath>& outPaths) const void ProjectPath::getGlobResults(std::vector<ProjectPath>& outPaths) const {
{
auto rootPath = m_proj->getProjectRootPath().getAbsolutePath(); auto rootPath = m_proj->getProjectRootPath().getAbsolutePath();
_recursiveGlob(*m_proj, outPaths, m_relPath, rootPath.data(), rootPath.back() != _SYS_STR('/')); _recursiveGlob(*m_proj, outPaths, m_relPath, rootPath.data(), rootPath.back() != _SYS_STR('/'));
} }
ProjectRootPath SearchForProject(SystemStringView path) ProjectRootPath SearchForProject(SystemStringView path) {
{
ProjectRootPath testRoot(path); ProjectRootPath testRoot(path);
auto begin = testRoot.getAbsolutePath().begin(); auto begin = testRoot.getAbsolutePath().begin();
auto end = testRoot.getAbsolutePath().end(); auto end = testRoot.getAbsolutePath().end();
while (begin != end) while (begin != end) {
{
SystemString testPath(begin, end); SystemString testPath(begin, end);
SystemString testIndexPath = testPath + _SYS_STR("/.hecl/beacon"); SystemString testIndexPath = testPath + _SYS_STR("/.hecl/beacon");
Sstat theStat; Sstat theStat;
if (!hecl::Stat(testIndexPath.c_str(), &theStat)) if (!hecl::Stat(testIndexPath.c_str(), &theStat)) {
{ if (S_ISREG(theStat.st_mode)) {
if (S_ISREG(theStat.st_mode))
{
FILE* fp = hecl::Fopen(testIndexPath.c_str(), _SYS_STR("rb")); FILE* fp = hecl::Fopen(testIndexPath.c_str(), _SYS_STR("rb"));
if (!fp) if (!fp)
continue; continue;
@ -323,7 +271,7 @@ ProjectRootPath SearchForProject(SystemStringView path)
} }
} }
while (begin != end && *(end-1) != _SYS_STR('/') && *(end-1) != _SYS_STR('\\')) while (begin != end && *(end - 1) != _SYS_STR('/') && *(end - 1) != _SYS_STR('\\'))
--end; --end;
if (begin != end) if (begin != end)
--end; --end;
@ -331,20 +279,16 @@ ProjectRootPath SearchForProject(SystemStringView path)
return ProjectRootPath(); return ProjectRootPath();
} }
ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut) ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut) {
{
ProjectRootPath testRoot(path); ProjectRootPath testRoot(path);
auto begin = testRoot.getAbsolutePath().begin(); auto begin = testRoot.getAbsolutePath().begin();
auto end = testRoot.getAbsolutePath().end(); auto end = testRoot.getAbsolutePath().end();
while (begin != end) while (begin != end) {
{
SystemString testPath(begin, end); SystemString testPath(begin, end);
SystemString testIndexPath = testPath + _SYS_STR("/.hecl/beacon"); SystemString testIndexPath = testPath + _SYS_STR("/.hecl/beacon");
Sstat theStat; Sstat theStat;
if (!hecl::Stat(testIndexPath.c_str(), &theStat)) if (!hecl::Stat(testIndexPath.c_str(), &theStat)) {
{ if (S_ISREG(theStat.st_mode)) {
if (S_ISREG(theStat.st_mode))
{
FILE* fp = hecl::Fopen(testIndexPath.c_str(), _SYS_STR("rb")); FILE* fp = hecl::Fopen(testIndexPath.c_str(), _SYS_STR("rb"));
if (!fp) if (!fp)
continue; continue;
@ -366,7 +310,7 @@ ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut
} }
} }
while (begin != end && *(end-1) != _SYS_STR('/') && *(end-1) != _SYS_STR('\\')) while (begin != end && *(end - 1) != _SYS_STR('/') && *(end - 1) != _SYS_STR('\\'))
--end; --end;
if (begin != end) if (begin != end)
--end; --end;
@ -374,4 +318,4 @@ ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut
return ProjectRootPath(); return ProjectRootPath();
} }
} } // namespace hecl

View File

@ -8,13 +8,10 @@
using namespace Windows::Storage; using namespace Windows::Storage;
#endif #endif
namespace hecl::Runtime namespace hecl::Runtime {
{
static logvisor::Module Log("FileStoreManager"); static logvisor::Module Log("FileStoreManager");
FileStoreManager::FileStoreManager(SystemStringView domain) FileStoreManager::FileStoreManager(SystemStringView domain) : m_domain(domain) {
: m_domain(domain)
{
#if _WIN32 #if _WIN32
#if !WINDOWS_STORE #if !WINDOWS_STORE
WCHAR home[MAX_PATH]; WCHAR home[MAX_PATH];
@ -23,7 +20,7 @@ FileStoreManager::FileStoreManager(SystemStringView domain)
SystemString path(home); SystemString path(home);
#else #else
StorageFolder^ cacheFolder = ApplicationData::Current->LocalCacheFolder; StorageFolder ^ cacheFolder = ApplicationData::Current->LocalCacheFolder;
SystemString path(cacheFolder->Path->Data()); SystemString path(cacheFolder->Path->Data());
#endif #endif
path += _SYS_STR("/.heclrun"); path += _SYS_STR("/.heclrun");
@ -50,4 +47,4 @@ FileStoreManager::FileStoreManager(SystemStringView domain)
#endif #endif
} }
} } // namespace hecl::Runtime

View File

@ -2,13 +2,10 @@
#include "hecl/Runtime.hpp" #include "hecl/Runtime.hpp"
#include <athena/MemoryReader.hpp> #include <athena/MemoryReader.hpp>
namespace hecl::Runtime namespace hecl::Runtime {
{
static logvisor::Module HMDL_Log("HMDL"); static logvisor::Module HMDL_Log("HMDL");
HMDLData::HMDLData(boo::IGraphicsDataFactory::Context& ctx, HMDLData::HMDLData(boo::IGraphicsDataFactory::Context& ctx, const void* metaData, const void* vbo, const void* ibo) {
const void* metaData, const void* vbo, const void* ibo)
{
HMDLMeta meta; HMDLMeta meta;
{ {
athena::io::MemoryReader r((atUint8*)metaData, HECL_HMDL_META_SZ); athena::io::MemoryReader r((atUint8*)metaData, HECL_HMDL_META_SZ);
@ -27,20 +24,17 @@ HMDLData::HMDLData(boo::IGraphicsDataFactory::Context& ctx,
m_vtxFmtData[1].semantic = boo::VertexSemantic::Normal3; m_vtxFmtData[1].semantic = boo::VertexSemantic::Normal3;
size_t e = 2; size_t e = 2;
for (size_t i=0 ; i<meta.colorCount ; ++i, ++e) for (size_t i = 0; i < meta.colorCount; ++i, ++e) {
{
m_vtxFmtData[e].semantic = boo::VertexSemantic::ColorUNorm; m_vtxFmtData[e].semantic = boo::VertexSemantic::ColorUNorm;
m_vtxFmtData[e].semanticIdx = i; m_vtxFmtData[e].semanticIdx = i;
} }
for (size_t i=0 ; i<meta.uvCount ; ++i, ++e) for (size_t i = 0; i < meta.uvCount; ++i, ++e) {
{
m_vtxFmtData[e].semantic = boo::VertexSemantic::UV2; m_vtxFmtData[e].semantic = boo::VertexSemantic::UV2;
m_vtxFmtData[e].semanticIdx = i; m_vtxFmtData[e].semanticIdx = i;
} }
for (size_t i=0 ; i<meta.weightCount ; ++i, ++e) for (size_t i = 0; i < meta.weightCount; ++i, ++e) {
{
m_vtxFmtData[e].semantic = boo::VertexSemantic::Weight; m_vtxFmtData[e].semantic = boo::VertexSemantic::Weight;
m_vtxFmtData[e].semanticIdx = i; m_vtxFmtData[e].semanticIdx = i;
} }
@ -48,4 +42,4 @@ HMDLData::HMDLData(boo::IGraphicsDataFactory::Context& ctx,
m_vtxFmt = boo::VertexFormatInfo(elemCount, m_vtxFmtData.get()); m_vtxFmt = boo::VertexFormatInfo(elemCount, m_vtxFmtData.get());
} }
} } // namespace hecl::Runtime

View File

@ -7,15 +7,12 @@
#define PATH_SEP '/' #define PATH_SEP '/'
#endif #endif
namespace hecl namespace hecl {
{
/* Used to extract alternate steam install directories from libraryfolders.vdf */ /* Used to extract alternate steam install directories from libraryfolders.vdf */
static const std::regex regSteamPath(R"(^\s+\"[0-9]+\"\s+\"(.*)\")", static const std::regex regSteamPath(R"(^\s+\"[0-9]+\"\s+\"(.*)\")", std::regex::ECMAScript | std::regex::optimize);
std::regex::ECMAScript|std::regex::optimize);
hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name) hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name) {
{
hecl::SystemString steamInstallDir; hecl::SystemString steamInstallDir;
hecl::Sstat theStat; hecl::Sstat theStat;
@ -23,17 +20,16 @@ hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name)
#if !WINDOWS_STORE #if !WINDOWS_STORE
HKEY hkey; HKEY hkey;
hecl::SystemChar _steamInstallDir[MAX_PATH] = {0}; hecl::SystemChar _steamInstallDir[MAX_PATH] = {0};
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _SYS_STR("Software\\Valve\\Steam"), if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _SYS_STR("Software\\Valve\\Steam"), 0, KEY_QUERY_VALUE, &hkey) !=
0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) ERROR_SUCCESS) {
{ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _SYS_STR("Software\\Valve\\Steam"), 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY,
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _SYS_STR("Software\\Valve\\Steam"), &hkey) != ERROR_SUCCESS)
0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hkey) != ERROR_SUCCESS)
return {}; return {};
} }
DWORD size = MAX_PATH; DWORD size = MAX_PATH;
if (RegQueryValueEx(hkey, _SYS_STR("InstallPath"), nullptr, nullptr, if (RegQueryValueEx(hkey, _SYS_STR("InstallPath"), nullptr, nullptr, (LPBYTE)_steamInstallDir, &size) ==
(LPBYTE)_steamInstallDir, &size) == ERROR_SUCCESS) ERROR_SUCCESS)
steamInstallDir = _steamInstallDir; steamInstallDir = _steamInstallDir;
RegCloseKey(hkey); RegCloseKey(hkey);
@ -52,8 +48,7 @@ hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name)
#else #else
steamInstallDir = getenv("HOME"); steamInstallDir = getenv("HOME");
steamInstallDir += "/.local/share/Steam"; steamInstallDir += "/.local/share/Steam";
if (hecl::Stat(steamInstallDir.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) if (hecl::Stat(steamInstallDir.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) {
{
steamInstallDir = getenv("HOME"); steamInstallDir = getenv("HOME");
steamInstallDir += "/.steam/steam"; steamInstallDir += "/.steam/steam";
if (hecl::Stat(steamInstallDir.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) if (hecl::Stat(steamInstallDir.c_str(), &theStat) || !S_ISDIR(theStat.st_mode))
@ -77,16 +72,14 @@ hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name)
return {}; return {};
hecl::FSeek(fp, 0, SEEK_END); hecl::FSeek(fp, 0, SEEK_END);
int64_t fileLen = hecl::FTell(fp); int64_t fileLen = hecl::FTell(fp);
if (fileLen <= 0) if (fileLen <= 0) {
{
fclose(fp); fclose(fp);
return {}; return {};
} }
hecl::FSeek(fp, 0, SEEK_SET); hecl::FSeek(fp, 0, SEEK_SET);
std::string fileBuf; std::string fileBuf;
fileBuf.resize(fileLen); fileBuf.resize(fileLen);
if (fread(&fileBuf[0], 1, fileLen, fp) != fileLen) if (fread(&fileBuf[0], 1, fileLen, fp) != fileLen) {
{
fclose(fp); fclose(fp);
return {}; return {};
} }
@ -95,12 +88,11 @@ hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name)
std::smatch dirMatch; std::smatch dirMatch;
auto begin = fileBuf.cbegin(); auto begin = fileBuf.cbegin();
auto end = fileBuf.cend(); auto end = fileBuf.cend();
while (std::regex_search(begin, end, dirMatch, regSteamPath)) while (std::regex_search(begin, end, dirMatch, regSteamPath)) {
{
std::string match = dirMatch[1].str(); std::string match = dirMatch[1].str();
hecl::SystemStringConv otherInstallDir(match); hecl::SystemStringConv otherInstallDir(match);
hecl::SystemString otherAppPath = hecl::SystemString(otherInstallDir.sys_str()) + PATH_SEP + hecl::SystemString otherAppPath =
_SYS_STR("steamapps") + PATH_SEP + appPath; hecl::SystemString(otherInstallDir.sys_str()) + PATH_SEP + _SYS_STR("steamapps") + PATH_SEP + appPath;
if (!hecl::Stat(otherAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) if (!hecl::Stat(otherAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode))
return otherAppPath; return otherAppPath;
begin = dirMatch.suffix().first; begin = dirMatch.suffix().first;
@ -109,4 +101,4 @@ hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name)
return {}; return {};
} }
} } // namespace hecl

View File

@ -1,20 +1,16 @@
#include <utf8proc.h> #include <utf8proc.h>
#include "hecl/hecl.hpp" #include "hecl/hecl.hpp"
namespace hecl namespace hecl {
{
static logvisor::Module Log("hecl-wsconv"); static logvisor::Module Log("hecl-wsconv");
std::string WideToUTF8(std::wstring_view src) std::string WideToUTF8(std::wstring_view src) {
{
std::string retval; std::string retval;
retval.reserve(src.length()); retval.reserve(src.length());
for (wchar_t ch : src) for (wchar_t ch : src) {
{
utf8proc_uint8_t mb[4]; utf8proc_uint8_t mb[4];
utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb); utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb);
if (c < 0) if (c < 0) {
{
Log.report(logvisor::Warning, "invalid UTF-8 character while encoding"); Log.report(logvisor::Warning, "invalid UTF-8 character while encoding");
return retval; return retval;
} }
@ -23,16 +19,13 @@ std::string WideToUTF8(std::wstring_view src)
return retval; return retval;
} }
std::string Char16ToUTF8(std::u16string_view src) std::string Char16ToUTF8(std::u16string_view src) {
{
std::string retval; std::string retval;
retval.reserve(src.length()); retval.reserve(src.length());
for (char16_t ch : src) for (char16_t ch : src) {
{
utf8proc_uint8_t mb[4]; utf8proc_uint8_t mb[4];
utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb); utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb);
if (c < 0) if (c < 0) {
{
Log.report(logvisor::Warning, "invalid UTF-8 character while encoding"); Log.report(logvisor::Warning, "invalid UTF-8 character while encoding");
return retval; return retval;
} }
@ -41,17 +34,14 @@ std::string Char16ToUTF8(std::u16string_view src)
return retval; return retval;
} }
std::wstring UTF8ToWide(std::string_view src) std::wstring UTF8ToWide(std::string_view src) {
{
std::wstring retval; std::wstring retval;
retval.reserve(src.length()); retval.reserve(src.length());
const utf8proc_uint8_t* buf = reinterpret_cast<const utf8proc_uint8_t*>(src.data()); const utf8proc_uint8_t* buf = reinterpret_cast<const utf8proc_uint8_t*>(src.data());
while (*buf) while (*buf) {
{
utf8proc_int32_t wc; utf8proc_int32_t wc;
utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc); utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc);
if (len < 0) if (len < 0) {
{
Log.report(logvisor::Warning, "invalid UTF-8 character while decoding"); Log.report(logvisor::Warning, "invalid UTF-8 character while decoding");
return retval; return retval;
} }
@ -61,17 +51,14 @@ std::wstring UTF8ToWide(std::string_view src)
return retval; return retval;
} }
std::u16string UTF8ToChar16(std::string_view src) std::u16string UTF8ToChar16(std::string_view src) {
{
std::u16string retval; std::u16string retval;
retval.reserve(src.length()); retval.reserve(src.length());
const utf8proc_uint8_t* buf = reinterpret_cast<const utf8proc_uint8_t*>(src.data()); const utf8proc_uint8_t* buf = reinterpret_cast<const utf8proc_uint8_t*>(src.data());
while (*buf) while (*buf) {
{
utf8proc_int32_t wc; utf8proc_int32_t wc;
utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc); utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc);
if (len < 0) if (len < 0) {
{
Log.report(logvisor::Warning, "invalid UTF-8 character while decoding"); Log.report(logvisor::Warning, "invalid UTF-8 character while decoding");
return retval; return retval;
} }
@ -81,4 +68,4 @@ std::u16string UTF8ToChar16(std::string_view src)
return retval; return retval;
} }
} } // namespace hecl

View File

@ -20,18 +20,17 @@
#include <sys/wait.h> #include <sys/wait.h>
#endif #endif
namespace hecl namespace hecl {
{
unsigned VerbosityLevel = 0; unsigned VerbosityLevel = 0;
bool GuiMode = false; bool GuiMode = false;
logvisor::Module LogModule("hecl"); logvisor::Module LogModule("hecl");
static const std::string Illegals {"<>?\"|"}; static const std::string Illegals{"<>?\"|"};
#if __GNUC__ #if __GNUC__
__attribute__((__format__ (__printf__, 1, 2))) __attribute__((__format__(__printf__, 1, 2)))
#endif #endif
SystemString SysFormat(const SystemChar* format, ...) SystemString
{ SysFormat(const SystemChar* format, ...) {
SystemChar resultBuf[FORMAT_BUF_SZ]; SystemChar resultBuf[FORMAT_BUF_SZ];
va_list va; va_list va;
va_start(va, format); va_start(va, format);
@ -45,10 +44,10 @@ SystemString SysFormat(const SystemChar* format, ...)
} }
#if __GNUC__ #if __GNUC__
__attribute__((__format__ (__printf__, 1, 2))) __attribute__((__format__(__printf__, 1, 2)))
#endif #endif
std::string Format(const char* format, ...) std::string
{ Format(const char* format, ...) {
char resultBuf[FORMAT_BUF_SZ]; char resultBuf[FORMAT_BUF_SZ];
va_list va; va_list va;
va_start(va, format); va_start(va, format);
@ -57,8 +56,7 @@ std::string Format(const char* format, ...)
return std::string(resultBuf, printSz); return std::string(resultBuf, printSz);
} }
std::wstring WideFormat(const wchar_t* format, ...) std::wstring WideFormat(const wchar_t* format, ...) {
{
wchar_t resultBuf[FORMAT_BUF_SZ]; wchar_t resultBuf[FORMAT_BUF_SZ];
va_list va; va_list va;
va_start(va, format); va_start(va, format);
@ -67,8 +65,7 @@ std::wstring WideFormat(const wchar_t* format, ...)
return std::wstring(resultBuf, printSz); return std::wstring(resultBuf, printSz);
} }
std::u16string Char16Format(const wchar_t* format, ...) std::u16string Char16Format(const wchar_t* format, ...) {
{
wchar_t resultBuf[FORMAT_BUF_SZ]; wchar_t resultBuf[FORMAT_BUF_SZ];
va_list va; va_list va;
va_start(va, format); va_start(va, format);
@ -76,13 +73,12 @@ std::u16string Char16Format(const wchar_t* format, ...)
va_end(va); va_end(va);
std::u16string res; std::u16string res;
res.reserve(printSz); res.reserve(printSz);
for (size_t i=0 ; i<printSz ; ++i) for (size_t i = 0; i < printSz; ++i)
res.push_back(resultBuf[i]); res.push_back(resultBuf[i]);
return res; return res;
} }
void SanitizePath(std::string& path) void SanitizePath(std::string& path) {
{
if (path.empty()) if (path.empty())
return; return;
path.erase(std::remove(path.begin(), path.end(), '\n'), path.end()); path.erase(std::remove(path.begin(), path.end(), '\n'), path.end());
@ -91,19 +87,16 @@ void SanitizePath(std::string& path)
bool ic = false; bool ic = false;
std::transform(path.begin(), path.end(), path.begin(), [&](const char a) -> char { std::transform(path.begin(), path.end(), path.begin(), [&](const char a) -> char {
++p1; ++p1;
if (Illegals.find_first_of(a) != std::string::npos) if (Illegals.find_first_of(a) != std::string::npos) {
{
ic = false; ic = false;
return '_'; return '_';
} }
if (ic) if (ic) {
{
ic = false; ic = false;
return a; return a;
} }
if (a == '\\' && (p1 == path.end() || *p1 != '\\')) if (a == '\\' && (p1 == path.end() || *p1 != '\\')) {
{
ic = true; ic = true;
return '/'; return '/';
} }
@ -113,10 +106,9 @@ void SanitizePath(std::string& path)
path.pop_back(); path.pop_back();
} }
static const std::wstring WIllegals {L"<>?\"|"}; static const std::wstring WIllegals{L"<>?\"|"};
void SanitizePath(std::wstring& path) void SanitizePath(std::wstring& path) {
{
if (path.empty()) if (path.empty())
return; return;
path.erase(std::remove(path.begin(), path.end(), L'\n'), path.end()); path.erase(std::remove(path.begin(), path.end(), L'\n'), path.end());
@ -125,19 +117,16 @@ void SanitizePath(std::wstring& path)
bool ic = false; bool ic = false;
std::transform(path.begin(), path.end(), path.begin(), [&](const wchar_t a) -> wchar_t { std::transform(path.begin(), path.end(), path.begin(), [&](const wchar_t a) -> wchar_t {
++p1; ++p1;
if (WIllegals.find_first_of(a) != std::wstring::npos) if (WIllegals.find_first_of(a) != std::wstring::npos) {
{
ic = false; ic = false;
return L'_'; return L'_';
} }
if (ic) if (ic) {
{
ic = false; ic = false;
return a; return a;
} }
if (a == L'\\' && (p1 == path.end() || *p1 != L'\\')) if (a == L'\\' && (p1 == path.end() || *p1 != L'\\')) {
{
ic = true; ic = true;
return L'/'; return L'/';
} }
@ -147,31 +136,27 @@ void SanitizePath(std::wstring& path)
path.pop_back(); path.pop_back();
} }
SystemString GetcwdStr() SystemString GetcwdStr() {
{
/* http://stackoverflow.com/a/2869667 */ /* http://stackoverflow.com/a/2869667 */
//const size_t ChunkSize=255; // const size_t ChunkSize=255;
//const int MaxChunks=10240; // 2550 KiBs of current path are more than enough // const int MaxChunks=10240; // 2550 KiBs of current path are more than enough
SystemChar stackBuffer[255]; // Stack buffer for the "normal" case SystemChar stackBuffer[255]; // Stack buffer for the "normal" case
if (Getcwd(stackBuffer, 255) != nullptr) if (Getcwd(stackBuffer, 255) != nullptr)
return SystemString(stackBuffer); return SystemString(stackBuffer);
if (errno != ERANGE) if (errno != ERANGE) {
{
// It's not ERANGE, so we don't know how to handle it // It's not ERANGE, so we don't know how to handle it
LogModule.report(logvisor::Fatal, "Cannot determine the current path."); LogModule.report(logvisor::Fatal, "Cannot determine the current path.");
// Of course you may choose a different error reporting method // Of course you may choose a different error reporting method
} }
// Ok, the stack buffer isn't long enough; fallback to heap allocation // Ok, the stack buffer isn't long enough; fallback to heap allocation
for (int chunks=2 ; chunks<10240 ; chunks++) for (int chunks = 2; chunks < 10240; chunks++) {
{
// With boost use scoped_ptr; in C++0x, use unique_ptr // With boost use scoped_ptr; in C++0x, use unique_ptr
// If you want to be less C++ but more efficient you may want to use realloc // If you want to be less C++ but more efficient you may want to use realloc
std::unique_ptr<SystemChar[]> cwd(new SystemChar[255*chunks]); std::unique_ptr<SystemChar[]> cwd(new SystemChar[255 * chunks]);
if (Getcwd(cwd.get(), 255*chunks) != nullptr) if (Getcwd(cwd.get(), 255 * chunks) != nullptr)
return SystemString(cwd.get()); return SystemString(cwd.get());
if (errno != ERANGE) if (errno != ERANGE) {
{
// It's not ERANGE, so we don't know how to handle it // It's not ERANGE, so we don't know how to handle it
LogModule.report(logvisor::Fatal, "Cannot determine the current path."); LogModule.report(logvisor::Fatal, "Cannot determine the current path.");
// Of course you may choose a different error reporting method // Of course you may choose a different error reporting method
@ -184,8 +169,7 @@ SystemString GetcwdStr()
static std::mutex PathsMutex; static std::mutex PathsMutex;
static std::unordered_map<std::thread::id, ProjectPath> PathsInProgress; static std::unordered_map<std::thread::id, ProjectPath> PathsInProgress;
bool ResourceLock::InProgress(const ProjectPath& path) bool ResourceLock::InProgress(const ProjectPath& path) {
{
std::unique_lock<std::mutex> lk(PathsMutex); std::unique_lock<std::mutex> lk(PathsMutex);
for (const auto& p : PathsInProgress) for (const auto& p : PathsInProgress)
if (p.second == path) if (p.second == path)
@ -193,8 +177,7 @@ bool ResourceLock::InProgress(const ProjectPath& path)
return false; return false;
} }
bool ResourceLock::SetThreadRes(const ProjectPath& path) bool ResourceLock::SetThreadRes(const ProjectPath& path) {
{
std::unique_lock<std::mutex> lk(PathsMutex); std::unique_lock<std::mutex> lk(PathsMutex);
if (PathsInProgress.find(std::this_thread::get_id()) != PathsInProgress.cend()) if (PathsInProgress.find(std::this_thread::get_id()) != PathsInProgress.cend())
LogModule.report(logvisor::Fatal, "multiple resource locks on thread"); LogModule.report(logvisor::Fatal, "multiple resource locks on thread");
@ -207,20 +190,17 @@ bool ResourceLock::SetThreadRes(const ProjectPath& path)
return true; return true;
} }
void ResourceLock::ClearThreadRes() void ResourceLock::ClearThreadRes() {
{
std::unique_lock<std::mutex> lk(PathsMutex); std::unique_lock<std::mutex> lk(PathsMutex);
PathsInProgress.erase(std::this_thread::get_id()); PathsInProgress.erase(std::this_thread::get_id());
} }
bool IsPathPNG(const hecl::ProjectPath& path) bool IsPathPNG(const hecl::ProjectPath& path) {
{
FILE* fp = hecl::Fopen(path.getAbsolutePath().data(), _SYS_STR("rb")); FILE* fp = hecl::Fopen(path.getAbsolutePath().data(), _SYS_STR("rb"));
if (!fp) if (!fp)
return false; return false;
uint32_t buf = 0; uint32_t buf = 0;
if (fread(&buf, 1, 4, fp) != 4) if (fread(&buf, 1, 4, fp) != 4) {
{
fclose(fp); fclose(fp);
return false; return false;
} }
@ -231,8 +211,7 @@ bool IsPathPNG(const hecl::ProjectPath& path)
return false; return false;
} }
bool IsPathBlend(const hecl::ProjectPath& path) bool IsPathBlend(const hecl::ProjectPath& path) {
{
auto lastCompExt = path.getLastComponentExt(); auto lastCompExt = path.getLastComponentExt();
if (lastCompExt.empty() || hecl::StrCmp(lastCompExt.data(), _SYS_STR("blend"))) if (lastCompExt.empty() || hecl::StrCmp(lastCompExt.data(), _SYS_STR("blend")))
return false; return false;
@ -240,8 +219,7 @@ bool IsPathBlend(const hecl::ProjectPath& path)
if (!fp) if (!fp)
return false; return false;
uint32_t buf = 0; uint32_t buf = 0;
if (fread(&buf, 1, 4, fp) != 4) if (fread(&buf, 1, 4, fp) != 4) {
{
fclose(fp); fclose(fp);
return false; return false;
} }
@ -252,22 +230,19 @@ bool IsPathBlend(const hecl::ProjectPath& path)
return false; return false;
} }
bool IsPathYAML(const hecl::ProjectPath& path) bool IsPathYAML(const hecl::ProjectPath& path) {
{
if (!hecl::StrCmp(path.getLastComponent().data(), _SYS_STR("!catalog.yaml"))) if (!hecl::StrCmp(path.getLastComponent().data(), _SYS_STR("!catalog.yaml")))
return false; /* !catalog.yaml is exempt from general use */ return false; /* !catalog.yaml is exempt from general use */
auto lastCompExt = path.getLastComponentExt(); auto lastCompExt = path.getLastComponentExt();
if (lastCompExt.empty()) if (lastCompExt.empty())
return false; return false;
if (!hecl::StrCmp(lastCompExt.data(), _SYS_STR("yaml")) || if (!hecl::StrCmp(lastCompExt.data(), _SYS_STR("yaml")) || !hecl::StrCmp(lastCompExt.data(), _SYS_STR("yml")))
!hecl::StrCmp(lastCompExt.data(), _SYS_STR("yml")))
return true; return true;
return false; return false;
} }
hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool sizeSort, bool reverse,
bool sizeSort, bool reverse, bool noHidden) bool noHidden) {
{
hecl::Sstat theStat; hecl::Sstat theStat;
if (hecl::Stat(path.data(), &theStat) || !S_ISDIR(theStat.st_mode)) if (hecl::Stat(path.data(), &theStat) || !S_ISDIR(theStat.st_mode))
return; return;
@ -279,11 +254,9 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
HANDLE dir = FindFirstFileW(wc.c_str(), &d); HANDLE dir = FindFirstFileW(wc.c_str(), &d);
if (dir == INVALID_HANDLE_VALUE) if (dir == INVALID_HANDLE_VALUE)
return; return;
switch (mode) switch (mode) {
{
case Mode::Native: case Mode::Native:
do do {
{
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR(".."))) if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
continue; continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
@ -308,17 +281,15 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
} while (FindNextFileW(dir, &d)); } while (FindNextFileW(dir, &d));
break; break;
case Mode::DirsThenFilesSorted: case Mode::DirsThenFilesSorted:
case Mode::DirsSorted: case Mode::DirsSorted: {
{
std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort; std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort;
do do {
{
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR(".."))) if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
continue; continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
continue; continue;
hecl::SystemString fp(path); hecl::SystemString fp(path);
fp +=_SYS_STR('/'); fp += _SYS_STR('/');
fp += d.cFileName; fp += d.cFileName;
hecl::Sstat st; hecl::Sstat st;
if (hecl::Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode)) if (hecl::Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
@ -327,7 +298,7 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
} while (FindNextFileW(dir, &d)); } while (FindNextFileW(dir, &d));
if (reverse) if (reverse)
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it) for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second)); m_entries.push_back(std::move(it->second));
else else
for (auto& e : sort) for (auto& e : sort)
@ -338,16 +309,13 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
FindClose(dir); FindClose(dir);
dir = FindFirstFileW(wc.c_str(), &d); dir = FindFirstFileW(wc.c_str(), &d);
} }
case Mode::FilesSorted: case Mode::FilesSorted: {
{
if (mode == Mode::FilesSorted) if (mode == Mode::FilesSorted)
m_entries.clear(); m_entries.clear();
if (sizeSort) if (sizeSort) {
{
std::multimap<size_t, Entry> sort; std::multimap<size_t, Entry> sort;
do do {
{
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR(".."))) if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
continue; continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
@ -362,17 +330,14 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
} while (FindNextFileW(dir, &d)); } while (FindNextFileW(dir, &d));
if (reverse) if (reverse)
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it) for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second)); m_entries.push_back(std::move(it->second));
else else
for (auto& e : sort) for (auto& e : sort)
m_entries.push_back(std::move(e.second)); m_entries.push_back(std::move(e.second));
} } else {
else
{
std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort; std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort;
do do {
{
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR(".."))) if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
continue; continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
@ -387,7 +352,7 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
} while (FindNextFileW(dir, &d)); } while (FindNextFileW(dir, &d));
if (reverse) if (reverse)
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it) for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second)); m_entries.push_back(std::move(it->second));
else else
for (auto& e : sort) for (auto& e : sort)
@ -405,11 +370,9 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
if (!dir) if (!dir)
return; return;
const dirent* d; const dirent* d;
switch (mode) switch (mode) {
{
case Mode::Native: case Mode::Native:
while ((d = readdir(dir))) while ((d = readdir(dir))) {
{
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue; continue;
if (noHidden && d->d_name[0] == '.') if (noHidden && d->d_name[0] == '.')
@ -434,11 +397,9 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
} }
break; break;
case Mode::DirsThenFilesSorted: case Mode::DirsThenFilesSorted:
case Mode::DirsSorted: case Mode::DirsSorted: {
{
std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort; std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort;
while ((d = readdir(dir))) while ((d = readdir(dir))) {
{
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue; continue;
if (noHidden && d->d_name[0] == '.') if (noHidden && d->d_name[0] == '.')
@ -453,7 +414,7 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
} }
if (reverse) if (reverse)
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it) for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second)); m_entries.push_back(std::move(it->second));
else else
for (auto& e : sort) for (auto& e : sort)
@ -463,16 +424,13 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
break; break;
rewinddir(dir); rewinddir(dir);
} }
case Mode::FilesSorted: case Mode::FilesSorted: {
{
if (mode == Mode::FilesSorted) if (mode == Mode::FilesSorted)
m_entries.clear(); m_entries.clear();
if (sizeSort) if (sizeSort) {
{
std::multimap<size_t, Entry> sort; std::multimap<size_t, Entry> sort;
while ((d = readdir(dir))) while ((d = readdir(dir))) {
{
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue; continue;
if (noHidden && d->d_name[0] == '.') if (noHidden && d->d_name[0] == '.')
@ -487,17 +445,14 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
} }
if (reverse) if (reverse)
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it) for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second)); m_entries.push_back(std::move(it->second));
else else
for (auto& e : sort) for (auto& e : sort)
m_entries.push_back(std::move(e.second)); m_entries.push_back(std::move(e.second));
} } else {
else
{
std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort; std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort;
while ((d = readdir(dir))) while ((d = readdir(dir))) {
{
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue; continue;
if (noHidden && d->d_name[0] == '.') if (noHidden && d->d_name[0] == '.')
@ -512,7 +467,7 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
} }
if (reverse) if (reverse)
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it) for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second)); m_entries.push_back(std::move(it->second));
else else
for (auto& e : sort) for (auto& e : sort)
@ -529,9 +484,7 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
#define FILE_MAXDIR 768 #define FILE_MAXDIR 768
static std::pair<hecl::SystemString, std::string> static std::pair<hecl::SystemString, std::string> NameFromPath(hecl::SystemStringView path) {
NameFromPath(hecl::SystemStringView path)
{
hecl::SystemUTF8Conv utf8(path); hecl::SystemUTF8Conv utf8(path);
if (utf8.str().size() == 1 && utf8.str()[0] == '/') if (utf8.str().size() == 1 && utf8.str()[0] == '/')
return {hecl::SystemString(path), "/"}; return {hecl::SystemString(path), "/"};
@ -542,8 +495,7 @@ NameFromPath(hecl::SystemStringView path)
return {hecl::SystemString(path), std::string(utf8.str())}; return {hecl::SystemString(path), std::string(utf8.str())};
} }
std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations() std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations() {
{
std::vector<std::pair<hecl::SystemString, std::string>> ret; std::vector<std::pair<hecl::SystemString, std::string>> ret;
#ifdef WIN32 #ifdef WIN32
#if !WINDOWS_STORE #if !WINDOWS_STORE
@ -556,10 +508,8 @@ std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations()
tmp = GetLogicalDrives(); tmp = GetLogicalDrives();
for (i = 0; i < 26; i++) for (i = 0; i < 26; i++) {
{ if ((tmp >> i) & 1) {
if ((tmp >> i) & 1)
{
wline[0] = L'A' + i; wline[0] = L'A' + i;
wline[1] = L':'; wline[1] = L':';
wline[2] = L'/'; wline[2] = L'/';
@ -567,11 +517,9 @@ std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations()
name = nullptr; name = nullptr;
/* Flee from horrible win querying hover floppy drives! */ /* Flee from horrible win querying hover floppy drives! */
if (i > 1) if (i > 1) {
{
/* Try to get volume label as well... */ /* Try to get volume label as well... */
if (GetVolumeInformationW(wline, wline + 4, FILE_MAXDIR - 4, nullptr, nullptr, nullptr, nullptr, 0)) if (GetVolumeInformationW(wline, wline + 4, FILE_MAXDIR - 4, nullptr, nullptr, nullptr, nullptr, 0)) {
{
size_t labelLen = wcslen(wline + 4); size_t labelLen = wcslen(wline + 4);
_snwprintf(wline + 4 + labelLen, FILE_MAXDIR - 4 - labelLen, L" (%.2s)", wline); _snwprintf(wline + 4 + labelLen, FILE_MAXDIR - 4 - labelLen, L" (%.2s)", wline);
name = wline + 4; name = wline + 4;
@ -604,8 +552,7 @@ std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations()
hecl::Sstat theStat; hecl::Sstat theStat;
const char* home = getenv("HOME"); const char* home = getenv("HOME");
if (home) if (home) {
{
ret.push_back(NameFromPath(home)); ret.push_back(NameFromPath(home));
std::string desktop(home); std::string desktop(home);
desktop += "/Desktop"; desktop += "/Desktop";
@ -621,15 +568,14 @@ std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations()
CFURLEnumeratorResult result = kCFURLEnumeratorSuccess; CFURLEnumeratorResult result = kCFURLEnumeratorSuccess;
CFURLEnumeratorRef volEnum = CFURLEnumeratorCreateForMountedVolumes(NULL, kCFURLEnumeratorSkipInvisibles, NULL); CFURLEnumeratorRef volEnum = CFURLEnumeratorCreateForMountedVolumes(NULL, kCFURLEnumeratorSkipInvisibles, NULL);
while (result != kCFURLEnumeratorEnd) while (result != kCFURLEnumeratorEnd) {
{
char defPath[1024]; char defPath[1024];
result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, NULL); result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, NULL);
if (result != kCFURLEnumeratorSuccess) if (result != kCFURLEnumeratorSuccess)
continue; continue;
CFURLGetFileSystemRepresentation(cfURL, false, (UInt8 *)defPath, 1024); CFURLGetFileSystemRepresentation(cfURL, false, (UInt8*)defPath, 1024);
ret.push_back(NameFromPath(defPath)); ret.push_back(NameFromPath(defPath));
} }
@ -641,8 +587,7 @@ std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations()
hecl::Sstat theStat; hecl::Sstat theStat;
const char* home = getenv("HOME"); const char* home = getenv("HOME");
if (home) if (home) {
{
ret.push_back(NameFromPath(home)); ret.push_back(NameFromPath(home));
std::string desktop(home); std::string desktop(home);
desktop += "/Desktop"; desktop += "/Desktop";
@ -654,13 +599,11 @@ std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations()
bool found = false; bool found = false;
#ifdef __linux__ #ifdef __linux__
/* Loop over mount points */ /* Loop over mount points */
struct mntent *mnt; struct mntent* mnt;
FILE* fp = setmntent(MOUNTED, "r"); FILE* fp = setmntent(MOUNTED, "r");
if (fp) if (fp) {
{ while ((mnt = getmntent(fp))) {
while ((mnt = getmntent(fp)))
{
if (strlen(mnt->mnt_fsname) < 4 || strncmp(mnt->mnt_fsname, "/dev", 4)) if (strlen(mnt->mnt_fsname) < 4 || strncmp(mnt->mnt_fsname, "/dev", 4))
continue; continue;
@ -684,16 +627,13 @@ std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations()
return ret; return ret;
} }
std::wstring Char16ToWide(std::u16string_view src) std::wstring Char16ToWide(std::u16string_view src) { return std::wstring(src.begin(), src.end()); }
{
return std::wstring(src.begin(), src.end());
}
/* recursive mkdir */ /* recursive mkdir */
#if _WIN32 #if _WIN32
int RecursiveMakeDir(const SystemChar* dir) { int RecursiveMakeDir(const SystemChar* dir) {
SystemChar tmp[1024]; SystemChar tmp[1024];
SystemChar *p = nullptr; SystemChar* p = nullptr;
Sstat sb; Sstat sb;
size_t len; size_t len;
@ -705,13 +645,13 @@ int RecursiveMakeDir(const SystemChar* dir) {
} }
/* remove trailing slash */ /* remove trailing slash */
if(tmp[len - 1] == '/' || tmp[len - 1] == '\\') { if (tmp[len - 1] == '/' || tmp[len - 1] == '\\') {
tmp[len - 1] = 0; tmp[len - 1] = 0;
} }
/* recursive mkdir */ /* recursive mkdir */
for(p = tmp + 1; *p; p++) { for (p = tmp + 1; *p; p++) {
if(*p == '/' || *p == '\\') { if (*p == '/' || *p == '\\') {
*p = 0; *p = 0;
/* test path */ /* test path */
if (Stat(tmp, &sb) != 0) { if (Stat(tmp, &sb) != 0) {
@ -741,7 +681,7 @@ int RecursiveMakeDir(const SystemChar* dir) {
#else #else
int RecursiveMakeDir(const SystemChar* dir) { int RecursiveMakeDir(const SystemChar* dir) {
SystemChar tmp[1024]; SystemChar tmp[1024];
SystemChar *p = nullptr; SystemChar* p = nullptr;
Sstat sb; Sstat sb;
size_t len; size_t len;
@ -753,13 +693,13 @@ int RecursiveMakeDir(const SystemChar* dir) {
} }
/* remove trailing slash */ /* remove trailing slash */
if(tmp[len - 1] == '/') { if (tmp[len - 1] == '/') {
tmp[len - 1] = 0; tmp[len - 1] = 0;
} }
/* recursive mkdir */ /* recursive mkdir */
for(p = tmp + 1; *p; p++) { for (p = tmp + 1; *p; p++) {
if(*p == '/') { if (*p == '/') {
*p = 0; *p = 0;
/* test path */ /* test path */
if (Stat(tmp, &sb) != 0) { if (Stat(tmp, &sb) != 0) {
@ -788,8 +728,7 @@ int RecursiveMakeDir(const SystemChar* dir) {
} }
#endif #endif
const SystemChar* GetTmpDir() const SystemChar* GetTmpDir() {
{
#ifdef _WIN32 #ifdef _WIN32
#if WINDOWS_STORE #if WINDOWS_STORE
wchar_t* TMPDIR = nullptr; wchar_t* TMPDIR = nullptr;
@ -807,33 +746,27 @@ const SystemChar* GetTmpDir()
} }
#if !WINDOWS_STORE #if !WINDOWS_STORE
int RunProcess(const SystemChar* path, const SystemChar* const args[]) int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
{
#ifdef _WIN32 #ifdef _WIN32
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
HANDLE consoleOutReadTmp, consoleOutWrite, consoleErrWrite, consoleOutRead; HANDLE consoleOutReadTmp, consoleOutWrite, consoleErrWrite, consoleOutRead;
if (!CreatePipe(&consoleOutReadTmp, &consoleOutWrite, &sattrs, 0)) if (!CreatePipe(&consoleOutReadTmp, &consoleOutWrite, &sattrs, 0)) {
{
LogModule.report(logvisor::Fatal, "Error with CreatePipe"); LogModule.report(logvisor::Fatal, "Error with CreatePipe");
return -1; return -1;
} }
if (!DuplicateHandle(GetCurrentProcess(), consoleOutWrite, if (!DuplicateHandle(GetCurrentProcess(), consoleOutWrite, GetCurrentProcess(), &consoleErrWrite, 0, TRUE,
GetCurrentProcess(), &consoleErrWrite, 0, DUPLICATE_SAME_ACCESS)) {
TRUE,DUPLICATE_SAME_ACCESS))
{
LogModule.report(logvisor::Fatal, "Error with DuplicateHandle"); LogModule.report(logvisor::Fatal, "Error with DuplicateHandle");
CloseHandle(consoleOutReadTmp); CloseHandle(consoleOutReadTmp);
CloseHandle(consoleOutWrite); CloseHandle(consoleOutWrite);
return -1; return -1;
} }
if (!DuplicateHandle(GetCurrentProcess(), consoleOutReadTmp, if (!DuplicateHandle(GetCurrentProcess(), consoleOutReadTmp, GetCurrentProcess(),
GetCurrentProcess(),
&consoleOutRead, // Address of new handle. &consoleOutRead, // Address of new handle.
0, FALSE, // Make it uninheritable. 0, FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS)) DUPLICATE_SAME_ACCESS)) {
{
LogModule.report(logvisor::Fatal, "Error with DupliateHandle"); LogModule.report(logvisor::Fatal, "Error with DupliateHandle");
CloseHandle(consoleOutReadTmp); CloseHandle(consoleOutReadTmp);
CloseHandle(consoleOutWrite); CloseHandle(consoleOutWrite);
@ -845,27 +778,26 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[])
hecl::SystemString cmdLine; hecl::SystemString cmdLine;
const SystemChar* const* arg = &args[1]; const SystemChar* const* arg = &args[1];
while (*arg) while (*arg) {
{
cmdLine += _SYS_STR(" \""); cmdLine += _SYS_STR(" \"");
cmdLine += *arg++; cmdLine += *arg++;
cmdLine += _SYS_STR('"'); cmdLine += _SYS_STR('"');
} }
STARTUPINFO sinfo = {sizeof(STARTUPINFO)}; STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
HANDLE nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, HANDLE nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sattrs, OPEN_EXISTING,
&sattrs, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); FILE_ATTRIBUTE_NORMAL, NULL);
sinfo.dwFlags = STARTF_USESTDHANDLES; sinfo.dwFlags = STARTF_USESTDHANDLES;
sinfo.hStdInput = nulHandle; sinfo.hStdInput = nulHandle;
sinfo.hStdError = consoleErrWrite; sinfo.hStdError = consoleErrWrite;
sinfo.hStdOutput = consoleOutWrite; sinfo.hStdOutput = consoleOutWrite;
PROCESS_INFORMATION pinfo = {}; PROCESS_INFORMATION pinfo = {};
if (!CreateProcessW(path, (LPWSTR)cmdLine.c_str(), NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &sinfo, &pinfo)) if (!CreateProcessW(path, (LPWSTR)cmdLine.c_str(), NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &sinfo,
{ &pinfo)) {
LPWSTR messageBuffer = nullptr; LPWSTR messageBuffer = nullptr;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL); GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
LogModule.report(logvisor::Error, L"unable to launch process from %s: %s", path, messageBuffer); LogModule.report(logvisor::Error, L"unable to launch process from %s: %s", path, messageBuffer);
LocalFree(messageBuffer); LocalFree(messageBuffer);
@ -881,17 +813,13 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[])
CloseHandle(consoleOutWrite); CloseHandle(consoleOutWrite);
bool consoleThreadRunning = true; bool consoleThreadRunning = true;
auto consoleThread = std::thread([=, &consoleThreadRunning]() auto consoleThread = std::thread([=, &consoleThreadRunning]() {
{
CHAR lpBuffer[256]; CHAR lpBuffer[256];
DWORD nBytesRead; DWORD nBytesRead;
DWORD nCharsWritten; DWORD nCharsWritten;
while (consoleThreadRunning) while (consoleThreadRunning) {
{ if (!ReadFile(consoleOutRead, lpBuffer, sizeof(lpBuffer), &nBytesRead, NULL) || !nBytesRead) {
if (!ReadFile(consoleOutRead, lpBuffer, sizeof(lpBuffer),
&nBytesRead, NULL) || !nBytesRead)
{
DWORD err = GetLastError(); DWORD err = GetLastError();
if (err == ERROR_BROKEN_PIPE) if (err == ERROR_BROKEN_PIPE)
break; // pipe done - normal exit path. break; // pipe done - normal exit path.
@ -901,10 +829,8 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[])
// Display the character read on the screen. // Display the character read on the screen.
auto lk = logvisor::LockLog(); auto lk = logvisor::LockLog();
if (!WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), lpBuffer, if (!WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), lpBuffer, nBytesRead, &nCharsWritten, NULL)) {
nBytesRead, &nCharsWritten, NULL)) // LogModule.report(logvisor::Error, "Error with WriteConsole: %08X", GetLastError());
{
//LogModule.report(logvisor::Error, "Error with WriteConsole: %08X", GetLastError());
} }
} }
@ -925,9 +851,8 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[])
return ret; return ret;
#else #else
pid_t pid = fork(); pid_t pid = fork();
if (!pid) if (!pid) {
{ execvp(path, (char* const*)args);
execvp(path, (char * const *)args);
exit(1); exit(1);
} }
int ret; int ret;
@ -940,4 +865,4 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[])
} }
#endif #endif
} } // namespace hecl

View File

@ -5,28 +5,26 @@
#include "hecl/winsupport.hpp" #include "hecl/winsupport.hpp"
/* /*
* The memmem() function finds the start of the first occurrence of the * The memmem() function finds the start of the first occurrence of the
* substring 'needle' of length 'nlen' in the memory area 'haystack' of * substring 'needle' of length 'nlen' in the memory area 'haystack' of
* length 'hlen'. * length 'hlen'.
* *
* The return value is a pointer to the beginning of the sub-string, or * The return value is a pointer to the beginning of the sub-string, or
* NULL if the substring is not found. * NULL if the substring is not found.
*/ */
void *memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen) void* memmem(const void* haystack, size_t hlen, const void* needle, size_t nlen) {
{
int needle_first; int needle_first;
const uint8_t *p = static_cast<const uint8_t*>(haystack); const uint8_t* p = static_cast<const uint8_t*>(haystack);
size_t plen = hlen; size_t plen = hlen;
if (!nlen) if (!nlen)
return NULL; return NULL;
needle_first = *(unsigned char *)needle; needle_first = *(unsigned char*)needle;
while (plen >= nlen && (p = static_cast<const uint8_t*>(memchr(p, needle_first, plen - nlen + 1)))) while (plen >= nlen && (p = static_cast<const uint8_t*>(memchr(p, needle_first, plen - nlen + 1)))) {
{
if (!memcmp(p, needle, nlen)) if (!memcmp(p, needle, nlen))
return (void *)p; return (void*)p;
p++; p++;
plen = hlen - (p - static_cast<const uint8_t*>(haystack)); plen = hlen - (p - static_cast<const uint8_t*>(haystack));
@ -35,8 +33,7 @@ void *memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen)
return NULL; return NULL;
} }
int asprintf(char** buf, const char* format, ...) int asprintf(char** buf, const char* format, ...) {
{
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
int len = vsnprintf(nullptr, 0, format, ap); int len = vsnprintf(nullptr, 0, format, ap);

View File

@ -11,27 +11,21 @@ static logvisor::Module Log("shaderc");
extern pD3DCompile D3DCompilePROC; extern pD3DCompile D3DCompilePROC;
pD3DCompile D3DCompilePROC = nullptr; pD3DCompile D3DCompilePROC = nullptr;
static bool FindBestD3DCompile() static bool FindBestD3DCompile() {
{
HMODULE d3dCompilelib = LoadLibraryW(L"D3DCompiler_47.dll"); HMODULE d3dCompilelib = LoadLibraryW(L"D3DCompiler_47.dll");
if (!d3dCompilelib) if (!d3dCompilelib) {
{
d3dCompilelib = LoadLibraryW(L"D3DCompiler_46.dll"); d3dCompilelib = LoadLibraryW(L"D3DCompiler_46.dll");
if (!d3dCompilelib) if (!d3dCompilelib) {
{
d3dCompilelib = LoadLibraryW(L"D3DCompiler_45.dll"); d3dCompilelib = LoadLibraryW(L"D3DCompiler_45.dll");
if (!d3dCompilelib) if (!d3dCompilelib) {
{
d3dCompilelib = LoadLibraryW(L"D3DCompiler_44.dll"); d3dCompilelib = LoadLibraryW(L"D3DCompiler_44.dll");
if (!d3dCompilelib) if (!d3dCompilelib) {
{
d3dCompilelib = LoadLibraryW(L"D3DCompiler_43.dll"); d3dCompilelib = LoadLibraryW(L"D3DCompiler_43.dll");
} }
} }
} }
} }
if (d3dCompilelib) if (d3dCompilelib) {
{
D3DCompilePROC = (pD3DCompile)GetProcAddress(d3dCompilelib, "D3DCompile"); D3DCompilePROC = (pD3DCompile)GetProcAddress(d3dCompilelib, "D3DCompile");
return D3DCompilePROC != nullptr; return D3DCompilePROC != nullptr;
} }
@ -47,56 +41,39 @@ int main(int argc, const hecl::SystemChar** argv)
logvisor::RegisterStandardExceptions(); logvisor::RegisterStandardExceptions();
#if _WIN32 #if _WIN32
if (!FindBestD3DCompile()) if (!FindBestD3DCompile()) {
{
Log.report(logvisor::Info, "Unable to find D3DCompiler dll"); Log.report(logvisor::Info, "Unable to find D3DCompiler dll");
return 1; return 1;
} }
#endif #endif
if (argc == 1) if (argc == 1) {
{
Log.report(logvisor::Info, "Usage: shaderc -o <out-base> [-D definevar=defineval]... <in-files>..."); Log.report(logvisor::Info, "Usage: shaderc -o <out-base> [-D definevar=defineval]... <in-files>...");
return 0; return 0;
} }
hecl::SystemString outPath; hecl::SystemString outPath;
hecl::shaderc::Compiler c; hecl::shaderc::Compiler c;
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i) {
{ if (argv[i][0] == '-') {
if (argv[i][0] == '-') if (argv[i][1] == 'o') {
{ if (argv[i][2]) {
if (argv[i][1] == 'o')
{
if (argv[i][2])
{
outPath = &argv[i][2]; outPath = &argv[i][2];
} } else if (i + 1 < argc) {
else if (i + 1 < argc)
{
++i; ++i;
outPath = argv[i]; outPath = argv[i];
} } else {
else
{
Log.report(logvisor::Error, "Invalid -o argument"); Log.report(logvisor::Error, "Invalid -o argument");
return 1; return 1;
} }
} } else if (argv[i][1] == 'D') {
else if (argv[i][1] == 'D')
{
const hecl::SystemChar* define; const hecl::SystemChar* define;
if (argv[i][2]) if (argv[i][2]) {
{
define = &argv[i][2]; define = &argv[i][2];
} } else if (i + 1 < argc) {
else if (i + 1 < argc)
{
++i; ++i;
define = argv[i]; define = argv[i];
} } else {
else
{
Log.report(logvisor::Error, "Invalid -D argument"); Log.report(logvisor::Error, "Invalid -D argument");
return 1; return 1;
} }
@ -106,21 +83,16 @@ int main(int argc, const hecl::SystemChar** argv)
c.addDefine(std::string(defineU8, equals - defineU8), equals + 1); c.addDefine(std::string(defineU8, equals - defineU8), equals + 1);
else else
c.addDefine(defineU8, ""); c.addDefine(defineU8, "");
} } else {
else
{
Log.report(logvisor::Error, "Unrecognized flag option '%c'", argv[i][1]); Log.report(logvisor::Error, "Unrecognized flag option '%c'", argv[i][1]);
return 1; return 1;
} }
} } else {
else
{
c.addInputFile(argv[i]); c.addInputFile(argv[i]);
} }
} }
if (outPath.empty()) if (outPath.empty()) {
{
Log.report(logvisor::Error, "-o option is required"); Log.report(logvisor::Error, "-o option is required");
return 1; return 1;
} }
@ -132,8 +104,7 @@ int main(int argc, const hecl::SystemChar** argv)
else else
baseName = outPath; baseName = outPath;
if (!glslang::InitializeProcess()) if (!glslang::InitializeProcess()) {
{
Log.report(logvisor::Error, "Unable to initialize glslang"); Log.report(logvisor::Error, "Unable to initialize glslang");
return 1; return 1;
} }
@ -146,8 +117,7 @@ int main(int argc, const hecl::SystemChar** argv)
{ {
hecl::SystemString headerPath = outPath + _SYS_STR(".hpp"); hecl::SystemString headerPath = outPath + _SYS_STR(".hpp");
athena::io::FileWriter w(headerPath); athena::io::FileWriter w(headerPath);
if (w.hasError()) if (w.hasError()) {
{
Log.report(logvisor::Error, _SYS_STR("Error opening '%s' for writing"), headerPath.c_str()); Log.report(logvisor::Error, _SYS_STR("Error opening '%s' for writing"), headerPath.c_str());
return 1; return 1;
} }
@ -157,8 +127,7 @@ int main(int argc, const hecl::SystemChar** argv)
{ {
hecl::SystemString impPath = outPath + _SYS_STR(".cpp"); hecl::SystemString impPath = outPath + _SYS_STR(".cpp");
athena::io::FileWriter w(impPath); athena::io::FileWriter w(impPath);
if (w.hasError()) if (w.hasError()) {
{
Log.report(logvisor::Error, _SYS_STR("Error opening '%s' for writing"), impPath.c_str()); Log.report(logvisor::Error, _SYS_STR("Error opening '%s' for writing"), impPath.c_str());
return 1; return 1;
} }

View File

@ -13,17 +13,16 @@
using namespace std::literals; using namespace std::literals;
namespace hecl::shaderc namespace hecl::shaderc {
{
static logvisor::Module Log("shaderc"); static logvisor::Module Log("shaderc");
static constexpr std::regex::flag_type RegexFlags = std::regex::ECMAScript|std::regex::optimize; static constexpr std::regex::flag_type RegexFlags = std::regex::ECMAScript | std::regex::optimize;
#if __GNUC__ #if __GNUC__
__attribute__((__format__ (__printf__, 1, 2))) __attribute__((__format__(__printf__, 1, 2)))
#endif #endif
static std::string Format(const char* format, ...) static std::string
{ Format(const char* format, ...) {
char resultBuf[FORMAT_BUF_SZ]; char resultBuf[FORMAT_BUF_SZ];
va_list va; va_list va;
va_start(va, format); va_start(va, format);
@ -32,11 +31,9 @@ static std::string Format(const char* format, ...)
return std::string(resultBuf, printSz); return std::string(resultBuf, printSz);
} }
const std::string* Compiler::getFileContents(SystemStringView path) const std::string* Compiler::getFileContents(SystemStringView path) {
{
auto search = m_fileContents.find(path.data()); auto search = m_fileContents.find(path.data());
if (search == m_fileContents.end()) if (search == m_fileContents.end()) {
{
athena::io::FileReader r(path); athena::io::FileReader r(path);
if (r.hasError()) if (r.hasError())
return nullptr; return nullptr;
@ -47,88 +44,76 @@ const std::string* Compiler::getFileContents(SystemStringView path)
return &search->second; return &search->second;
} }
void Compiler::addInputFile(SystemStringView file) void Compiler::addInputFile(SystemStringView file) {
{
if (std::find(m_inputFiles.begin(), m_inputFiles.end(), file) == m_inputFiles.end()) if (std::find(m_inputFiles.begin(), m_inputFiles.end(), file) == m_inputFiles.end())
m_inputFiles.emplace_back(file); m_inputFiles.emplace_back(file);
} }
void Compiler::addDefine(std::string_view var, std::string_view val) void Compiler::addDefine(std::string_view var, std::string_view val) { m_defines[var.data()] = val; }
{
m_defines[var.data()] = val;
}
static const char* ShaderHeaderTemplate = static const char* ShaderHeaderTemplate =
"class Shader_%s : public hecl::GeneralShader\n" "class Shader_%s : public hecl::GeneralShader\n"
"{\n" "{\n"
"public:\n" "public:\n"
" static const boo::VertexFormatInfo VtxFmt;\n" " static const boo::VertexFormatInfo VtxFmt;\n"
" static const boo::AdditionalPipelineInfo PipelineInfo;\n" " static const boo::AdditionalPipelineInfo PipelineInfo;\n"
" static constexpr bool HasHash = true;\n" " static constexpr bool HasHash = true;\n"
" static constexpr uint64_t Hash() { return 0x%016llX; }\n" " static constexpr uint64_t Hash() { return 0x%016llX; }\n"
"};\n\n"; "};\n\n";
static const char* StageObjectHeaderTemplate = static const char* StageObjectHeaderTemplate =
"template<typename P, typename S>\n" "template<typename P, typename S>\n"
"class StageObject_%s : public hecl::StageBinary<P, S>\n" "class StageObject_%s : public hecl::StageBinary<P, S>\n"
"{\n" "{\n"
" static const hecl::StageBinary<P, S> Prototype;\n" " static const hecl::StageBinary<P, S> Prototype;\n"
"public:\n" "public:\n"
" StageObject_%s(hecl::StageConverter<P, S>& conv, hecl::FactoryCtx& ctx, const Shader_%s& in)\n" " StageObject_%s(hecl::StageConverter<P, S>& conv, hecl::FactoryCtx& ctx, const Shader_%s& in)\n"
" : hecl::StageBinary<P, S>(Prototype) {}\n" " : hecl::StageBinary<P, S>(Prototype) {}\n"
"};\n" "};\n"
"STAGEOBJECT_PROTOTYPE_DECLARATIONS(StageObject_%s)\n\n"; "STAGEOBJECT_PROTOTYPE_DECLARATIONS(StageObject_%s)\n\n";
static const char* StageObjectImplTemplate = static const char* StageObjectImplTemplate =
"template<>\n" "template<>\n"
"const hecl::StageBinary<hecl::PlatformType::%s, hecl::PipelineStage::%s>\n" "const hecl::StageBinary<hecl::PlatformType::%s, hecl::PipelineStage::%s>\n"
"StageObject_%s<hecl::PlatformType::%s, hecl::PipelineStage::%s>::Prototype = \n" "StageObject_%s<hecl::PlatformType::%s, hecl::PipelineStage::%s>::Prototype = \n"
"{%s_%s_%s_data, sizeof(%s_%s_%s_data)};\n\n"; "{%s_%s_%s_data, sizeof(%s_%s_%s_data)};\n\n";
struct CompileSubStageAction struct CompileSubStageAction {
{ template <typename P, typename S>
template<typename P, typename S> static bool Do(const std::string& name, const std::string& basename, const std::string& stage, std::string& implOut) {
static bool Do(const std::string& name, const std::string& basename, const std::string& stage, std::string& implOut) implOut += Format(StageObjectImplTemplate, P::Name, S::Name, name.c_str(), P::Name, S::Name, basename.c_str(),
{ P::Name, S::Name, basename.c_str(), P::Name, S::Name);
implOut += Format(StageObjectImplTemplate, P::Name, S::Name, name.c_str(), P::Name, S::Name,
basename.c_str(), P::Name, S::Name, basename.c_str(), P::Name, S::Name);
return true; return true;
} }
}; };
struct CompileStageAction struct CompileStageAction {
{ template <typename P, typename S>
template<typename P, typename S> static bool Do(const std::string& name, const std::string& basename, const std::string& stage, std::string& implOut) {
static bool Do(const std::string& name, const std::string& basename, const std::string& stage, std::string& implOut)
{
std::pair<StageBinaryData, size_t> data = CompileShader<P, S>(stage); std::pair<StageBinaryData, size_t> data = CompileShader<P, S>(stage);
if (data.second == 0) if (data.second == 0)
return false; return false;
implOut += Format("static const uint8_t %s_%s_%s_data[] = {\n", name.c_str(), P::Name, S::Name); implOut += Format("static const uint8_t %s_%s_%s_data[] = {\n", name.c_str(), P::Name, S::Name);
for (size_t i = 0; i < data.second; ) for (size_t i = 0; i < data.second;) {
{
implOut += " "; implOut += " ";
for (int j = 0; j < 10 && i < data.second ; ++i, ++j) for (int j = 0; j < 10 && i < data.second; ++i, ++j)
implOut += Format("0x%02X, ", data.first.get()[i]); implOut += Format("0x%02X, ", data.first.get()[i]);
implOut += "\n"; implOut += "\n";
} }
implOut += "};\n\n"; implOut += "};\n\n";
implOut += Format(StageObjectImplTemplate, P::Name, S::Name, name.c_str(), P::Name, S::Name, implOut += Format(StageObjectImplTemplate, P::Name, S::Name, name.c_str(), P::Name, S::Name, name.c_str(), P::Name,
name.c_str(), P::Name, S::Name, name.c_str(), P::Name, S::Name); S::Name, name.c_str(), P::Name, S::Name);
return true; return true;
} }
}; };
template<typename Action, typename P> template <typename Action, typename P>
bool Compiler::StageAction(StageType type, bool Compiler::StageAction(StageType type, const std::string& name, const std::string& basename,
const std::string& name, const std::string& basename, const std::string& stage, const std::string& stage, std::string& implOut) {
std::string& implOut) switch (type) {
{
switch (type)
{
case StageType::Vertex: case StageType::Vertex:
return Action::template Do<P, PipelineStage::Vertex>(name, basename, stage, implOut); return Action::template Do<P, PipelineStage::Vertex>(name, basename, stage, implOut);
case StageType::Fragment: case StageType::Fragment:
@ -148,20 +133,16 @@ bool Compiler::StageAction(StageType type,
static const std::regex regWord(R"((\w+))", RegexFlags); static const std::regex regWord(R"((\w+))", RegexFlags);
template<typename Action> template <typename Action>
bool Compiler::StageAction(const std::string& platforms, StageType type, bool Compiler::StageAction(const std::string& platforms, StageType type, const std::string& name,
const std::string& name, const std::string& basename, const std::string& stage, const std::string& basename, const std::string& stage, std::string& implOut) {
std::string& implOut)
{
std::smatch match; std::smatch match;
auto begin = platforms.cbegin(); auto begin = platforms.cbegin();
auto end = platforms.cend(); auto end = platforms.cend();
while (std::regex_search(begin, end, match, regWord)) while (std::regex_search(begin, end, match, regWord)) {
{
std::string plat = match[1].str(); std::string plat = match[1].str();
std::transform(plat.begin(), plat.end(), plat.begin(), ::tolower); std::transform(plat.begin(), plat.end(), plat.begin(), ::tolower);
if (plat == "glsl") if (plat == "glsl") {
{
if (!StageAction<Action, PlatformType::OpenGL>(type, name, basename, stage, implOut) || if (!StageAction<Action, PlatformType::OpenGL>(type, name, basename, stage, implOut) ||
!StageAction<Action, PlatformType::Vulkan>(type, name, basename, stage, implOut) !StageAction<Action, PlatformType::Vulkan>(type, name, basename, stage, implOut)
#if HECL_NOUVEAU_NX #if HECL_NOUVEAU_NX
@ -169,40 +150,28 @@ bool Compiler::StageAction(const std::string& platforms, StageType type,
#endif #endif
) )
return false; return false;
} } else if (plat == "opengl") {
else if (plat == "opengl")
{
if (!StageAction<Action, PlatformType::OpenGL>(type, name, basename, stage, implOut)) if (!StageAction<Action, PlatformType::OpenGL>(type, name, basename, stage, implOut))
return false; return false;
} } else if (plat == "vulkan") {
else if (plat == "vulkan")
{
if (!StageAction<Action, PlatformType::Vulkan>(type, name, basename, stage, implOut)) if (!StageAction<Action, PlatformType::Vulkan>(type, name, basename, stage, implOut))
return false; return false;
} } else if (plat == "nx") {
else if (plat == "nx")
{
#if HECL_NOUVEAU_NX #if HECL_NOUVEAU_NX
if (!StageAction<Action, PlatformType::NX>(type, name, basename, stage, implOut)) if (!StageAction<Action, PlatformType::NX>(type, name, basename, stage, implOut))
return false; return false;
#endif #endif
} } else if (plat == "d3d11" || plat == "hlsl") {
else if (plat == "d3d11" || plat == "hlsl")
{
#if _WIN32 #if _WIN32
if (!StageAction<Action, PlatformType::D3D11>(type, name, basename, stage, implOut)) if (!StageAction<Action, PlatformType::D3D11>(type, name, basename, stage, implOut))
return false; return false;
#endif #endif
} } else if (plat == "metal") {
else if (plat == "metal")
{
#if __APPLE__ #if __APPLE__
if (!StageAction<Action, PlatformType::Metal>(type, name, basename, stage, implOut)) if (!StageAction<Action, PlatformType::Metal>(type, name, basename, stage, implOut))
return false; return false;
#endif #endif
} } else {
else
{
Log.report(logvisor::Error, "Unknown platform '%s'", plat.c_str()); Log.report(logvisor::Error, "Unknown platform '%s'", plat.c_str());
return false; return false;
} }
@ -237,17 +206,14 @@ static const std::regex regGeometry(R"(#\s*geometry\s+(.*))", RegexFlags);
static const std::regex regControl(R"(#\s*control\s+(.*))", RegexFlags); static const std::regex regControl(R"(#\s*control\s+(.*))", RegexFlags);
static const std::regex regEvaluation(R"(#\s*evaluation\s+(.*))", RegexFlags); static const std::regex regEvaluation(R"(#\s*evaluation\s+(.*))", RegexFlags);
bool Compiler::includeFile(SystemStringView file, std::string& out, int depth) bool Compiler::includeFile(SystemStringView file, std::string& out, int depth) {
{ if (depth > 32) {
if (depth > 32)
{
Log.report(logvisor::Error, _SYS_STR("Too many levels of includes (>32) at '%s'"), file.data()); Log.report(logvisor::Error, _SYS_STR("Too many levels of includes (>32) at '%s'"), file.data());
return false; return false;
} }
const std::string* data = getFileContents(file); const std::string* data = getFileContents(file);
if (!data) if (!data) {
{
Log.report(logvisor::Error, _SYS_STR("Unable to access '%s'"), file.data()); Log.report(logvisor::Error, _SYS_STR("Unable to access '%s'"), file.data());
return false; return false;
} }
@ -262,8 +228,7 @@ bool Compiler::includeFile(SystemStringView file, std::string& out, int depth)
auto begin = sdata.cbegin(); auto begin = sdata.cbegin();
auto end = sdata.cend(); auto end = sdata.cend();
while (begin != end) while (begin != end) {
{
std::string::const_iterator nextBegin; std::string::const_iterator nextBegin;
auto findPos = sdata.find('\n', begin - sdata.begin()); auto findPos = sdata.find('\n', begin - sdata.begin());
if (findPos == std::string::npos) if (findPos == std::string::npos)
@ -272,11 +237,9 @@ bool Compiler::includeFile(SystemStringView file, std::string& out, int depth)
nextBegin = sdata.begin() + findPos + 1; nextBegin = sdata.begin() + findPos + 1;
std::smatch subMatch; std::smatch subMatch;
if (std::regex_search(begin, nextBegin, subMatch, regInclude)) if (std::regex_search(begin, nextBegin, subMatch, regInclude)) {
{
std::string path = subMatch[1].str(); std::string path = subMatch[1].str();
if (path.empty()) if (path.empty()) {
{
Log.report(logvisor::Error, _SYS_STR("Empty path provided to include in '%s'"), file.data()); Log.report(logvisor::Error, _SYS_STR("Empty path provided to include in '%s'"), file.data());
return false; return false;
} }
@ -286,9 +249,7 @@ bool Compiler::includeFile(SystemStringView file, std::string& out, int depth)
pathStr = directory + _SYS_STR('/') + pathStr; pathStr = directory + _SYS_STR('/') + pathStr;
if (!includeFile(pathStr, out, depth + 1)) if (!includeFile(pathStr, out, depth + 1))
return false; return false;
} } else {
else
{
out.insert(out.end(), begin, nextBegin); out.insert(out.end(), begin, nextBegin);
} }
@ -297,10 +258,8 @@ bool Compiler::includeFile(SystemStringView file, std::string& out, int depth)
return true; return true;
} }
static std::string_view BlendFactorToStr(boo::BlendFactor fac) static std::string_view BlendFactorToStr(boo::BlendFactor fac) {
{ switch (fac) {
switch (fac)
{
case boo::BlendFactor::Zero: case boo::BlendFactor::Zero:
default: default:
return "boo::BlendFactor::Zero"sv; return "boo::BlendFactor::Zero"sv;
@ -331,8 +290,7 @@ static std::string_view BlendFactorToStr(boo::BlendFactor fac)
} }
} }
static bool StrToBlendFactor(std::string str, boo::BlendFactor& fac) static bool StrToBlendFactor(std::string str, boo::BlendFactor& fac) {
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower); std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (str == "zero") if (str == "zero")
fac = boo::BlendFactor::Zero; fac = boo::BlendFactor::Zero;
@ -360,18 +318,15 @@ static bool StrToBlendFactor(std::string str, boo::BlendFactor& fac)
fac = boo::BlendFactor::InvSrcColor1; fac = boo::BlendFactor::InvSrcColor1;
else if (str == "subtract") else if (str == "subtract")
fac = boo::BlendFactor::Subtract; fac = boo::BlendFactor::Subtract;
else else {
{
Log.report(logvisor::Error, "Unrecognized blend mode '%s'", str.c_str()); Log.report(logvisor::Error, "Unrecognized blend mode '%s'", str.c_str());
return false; return false;
} }
return true; return true;
} }
static std::string_view PrimitiveToStr(boo::Primitive prim) static std::string_view PrimitiveToStr(boo::Primitive prim) {
{ switch (prim) {
switch (prim)
{
case boo::Primitive::Triangles: case boo::Primitive::Triangles:
default: default:
return "boo::Primitive::Triangles"sv; return "boo::Primitive::Triangles"sv;
@ -382,8 +337,7 @@ static std::string_view PrimitiveToStr(boo::Primitive prim)
} }
} }
static bool StrToPrimitive(std::string str, boo::Primitive& prim) static bool StrToPrimitive(std::string str, boo::Primitive& prim) {
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower); std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (str == "triangles") if (str == "triangles")
prim = boo::Primitive::Triangles; prim = boo::Primitive::Triangles;
@ -391,18 +345,15 @@ static bool StrToPrimitive(std::string str, boo::Primitive& prim)
prim = boo::Primitive::TriStrips; prim = boo::Primitive::TriStrips;
else if (str == "patches") else if (str == "patches")
prim = boo::Primitive::Patches; prim = boo::Primitive::Patches;
else else {
{
Log.report(logvisor::Error, "Unrecognized primitive '%s'", str.c_str()); Log.report(logvisor::Error, "Unrecognized primitive '%s'", str.c_str());
return false; return false;
} }
return true; return true;
} }
static std::string_view ZTestToStr(boo::ZTest ztest) static std::string_view ZTestToStr(boo::ZTest ztest) {
{ switch (ztest) {
switch (ztest)
{
case boo::ZTest::None: case boo::ZTest::None:
default: default:
return "boo::ZTest::None"sv; return "boo::ZTest::None"sv;
@ -417,8 +368,7 @@ static std::string_view ZTestToStr(boo::ZTest ztest)
} }
} }
static bool StrToZTest(std::string str, boo::ZTest& ztest) static bool StrToZTest(std::string str, boo::ZTest& ztest) {
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower); std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (str == "none") if (str == "none")
ztest = boo::ZTest::None; ztest = boo::ZTest::None;
@ -430,18 +380,15 @@ static bool StrToZTest(std::string str, boo::ZTest& ztest)
ztest = boo::ZTest::GEqual; ztest = boo::ZTest::GEqual;
else if (str == "equal") else if (str == "equal")
ztest = boo::ZTest::Equal; ztest = boo::ZTest::Equal;
else else {
{
Log.report(logvisor::Error, "Unrecognized ztest '%s'", str.c_str()); Log.report(logvisor::Error, "Unrecognized ztest '%s'", str.c_str());
return false; return false;
} }
return true; return true;
} }
static std::string_view CullModeToStr(boo::CullMode cull) static std::string_view CullModeToStr(boo::CullMode cull) {
{ switch (cull) {
switch (cull)
{
case boo::CullMode::None: case boo::CullMode::None:
default: default:
return "boo::CullMode::None"sv; return "boo::CullMode::None"sv;
@ -452,8 +399,7 @@ static std::string_view CullModeToStr(boo::CullMode cull)
} }
} }
static bool StrToCullMode(std::string str, boo::CullMode& cull) static bool StrToCullMode(std::string str, boo::CullMode& cull) {
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower); std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (str == "none") if (str == "none")
cull = boo::CullMode::None; cull = boo::CullMode::None;
@ -461,21 +407,16 @@ static bool StrToCullMode(std::string str, boo::CullMode& cull)
cull = boo::CullMode::Backface; cull = boo::CullMode::Backface;
else if (str == "frontface") else if (str == "frontface")
cull = boo::CullMode::Frontface; cull = boo::CullMode::Frontface;
else else {
{
Log.report(logvisor::Error, "Unrecognized cull mode '%s'", str.c_str()); Log.report(logvisor::Error, "Unrecognized cull mode '%s'", str.c_str());
return false; return false;
} }
return true; return true;
} }
static std::string_view BoolToStr(bool b) static std::string_view BoolToStr(bool b) { return b ? "true"sv : "false"sv; }
{
return b ? "true"sv : "false"sv;
}
static bool StrToBool(std::string str, bool& b) static bool StrToBool(std::string str, bool& b) {
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower); std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (strtol(str.c_str(), nullptr, 0)) if (strtol(str.c_str(), nullptr, 0))
b = true; b = true;
@ -483,16 +424,14 @@ static bool StrToBool(std::string str, bool& b)
b = true; b = true;
else if (str == "false") else if (str == "false")
b = false; b = false;
else else {
{
Log.report(logvisor::Error, "Unrecognized bool '%s'", str.c_str()); Log.report(logvisor::Error, "Unrecognized bool '%s'", str.c_str());
return false; return false;
} }
return true; return true;
} }
bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std::pair<std::string, std::string>& out) bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std::pair<std::string, std::string>& out) {
{
std::string includesPass; std::string includesPass;
if (!includeFile(file, includesPass)) if (!includeFile(file, includesPass))
return false; return false;
@ -509,22 +448,18 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
std::unordered_map<std::string, std::pair<std::bitset<6>, std::set<std::string>>> shaderStageUses; std::unordered_map<std::string, std::pair<std::bitset<6>, std::set<std::string>>> shaderStageUses;
std::unordered_map<std::string, std::string> shaderBases; std::unordered_map<std::string, std::string> shaderBases;
auto _DoCompile = [&]() auto _DoCompile = [&]() {
{
if (stageBegin == includesPass.end()) if (stageBegin == includesPass.end())
return true; return true;
if (shaderName.empty()) if (shaderName.empty()) {
{
Log.report(logvisor::Error, "`#shader <name>` must be issued before stages"); Log.report(logvisor::Error, "`#shader <name>` must be issued before stages");
return false; return false;
} }
std::string stage(stageBegin, stageEnd); std::string stage(stageBegin, stageEnd);
for (const auto& define : m_defines) for (const auto& define : m_defines) {
{
std::string::size_type pos = 0; std::string::size_type pos = 0;
while ((pos = stage.find(define.first, pos)) != std::string::npos) while ((pos = stage.find(define.first, pos)) != std::string::npos) {
{
stage = std::string(stage.begin(), stage.begin() + pos) + define.second + stage = std::string(stage.begin(), stage.begin() + pos) + define.second +
std::string(stage.begin() + pos + define.first.size(), stage.end()); std::string(stage.begin() + pos + define.first.size(), stage.end());
} }
@ -533,12 +468,10 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
std::pair<std::bitset<6>, std::set<std::string>>& uses = shaderStageUses[shaderName]; std::pair<std::bitset<6>, std::set<std::string>>& uses = shaderStageUses[shaderName];
uses.first.set(size_t(stageType)); uses.first.set(size_t(stageType));
uses.second.insert(stagePlatforms); uses.second.insert(stagePlatforms);
return StageAction<CompileStageAction>(stagePlatforms, stageType, shaderName, return StageAction<CompileStageAction>(stagePlatforms, stageType, shaderName, shaderBase, stage, out.second);
shaderBase, stage, out.second);
}; };
auto DoCompile = [&](std::string platform, StageType type, auto DoCompile = [&](std::string platform, StageType type, std::string::const_iterator end,
std::string::const_iterator end, std::string::const_iterator begin) std::string::const_iterator begin) {
{
stageEnd = end; stageEnd = end;
bool ret = _DoCompile(); bool ret = _DoCompile();
stagePlatforms = std::move(platform); stagePlatforms = std::move(platform);
@ -546,33 +479,28 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
stageBegin = begin; stageBegin = begin;
return ret; return ret;
}; };
auto DoShader = [&]() auto DoShader = [&]() {
{
if (shaderBase.empty() && shaderStageUses.find(shaderName) == shaderStageUses.cend()) if (shaderBase.empty() && shaderStageUses.find(shaderName) == shaderStageUses.cend())
return true; return true;
std::pair<std::bitset<6>, std::set<std::string>>& uses = shaderStageUses[shaderName]; std::pair<std::bitset<6>, std::set<std::string>>& uses = shaderStageUses[shaderName];
if (uses.first.test(5)) if (uses.first.test(5))
return true; return true;
out.first += Format(ShaderHeaderTemplate, shaderName.c_str(), out.first += Format(ShaderHeaderTemplate, shaderName.c_str(), XXH64(shaderName.c_str(), shaderName.size(), 0));
XXH64(shaderName.c_str(), shaderName.size(), 0)); out.first += Format(StageObjectHeaderTemplate, shaderName.c_str(), shaderName.c_str(), shaderName.c_str(),
out.first += Format(StageObjectHeaderTemplate, shaderName.c_str(), shaderName.c_str(), shaderName.c_str());
shaderName.c_str(), shaderName.c_str());
if (!shaderBase.empty()) if (!shaderBase.empty()) {
{
shaderBases[shaderName] = shaderBase; shaderBases[shaderName] = shaderBase;
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i) {
{
if (uses.first.test(size_t(i))) if (uses.first.test(size_t(i)))
continue; continue;
std::string useBase = shaderBase; std::string useBase = shaderBase;
std::unordered_map<std::string, std::pair<std::bitset<6>, std::set<std::string>>>::const_iterator std::unordered_map<std::string, std::pair<std::bitset<6>, std::set<std::string>>>::const_iterator baseUses =
baseUses = shaderStageUses.find(useBase); shaderStageUses.find(useBase);
while (baseUses == shaderStageUses.cend() || !baseUses->second.first.test(size_t(i))) while (baseUses == shaderStageUses.cend() || !baseUses->second.first.test(size_t(i))) {
{
auto search = shaderBases.find(useBase); auto search = shaderBases.find(useBase);
if (search == shaderBases.cend()) if (search == shaderBases.cend())
break; break;
@ -581,21 +509,17 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
} }
if (baseUses == shaderStageUses.cend() || !baseUses->second.first.test(size_t(i))) if (baseUses == shaderStageUses.cend() || !baseUses->second.first.test(size_t(i)))
continue; continue;
for (const std::string& basePlatforms : baseUses->second.second) for (const std::string& basePlatforms : baseUses->second.second) {
{ StageAction<CompileSubStageAction>(basePlatforms, StageType(i), shaderName, useBase, {}, out.second);
StageAction<CompileSubStageAction>(basePlatforms, StageType(i), shaderName,
useBase, {}, out.second);
} }
} }
shaderBase.clear(); shaderBase.clear();
} }
out.second += Format("static const boo::VertexElementDescriptor %s_vtxfmtelems[] = {\n", shaderName.c_str()); out.second += Format("static const boo::VertexElementDescriptor %s_vtxfmtelems[] = {\n", shaderName.c_str());
for (const auto& attr : shaderAttributes) for (const auto& attr : shaderAttributes) {
{
const char* fmt; const char* fmt;
switch (attr.first & boo::VertexSemantic::SemanticMask) switch (attr.first & boo::VertexSemantic::SemanticMask) {
{
case boo::VertexSemantic::Position3: case boo::VertexSemantic::Position3:
fmt = "{boo::VertexSemantic::Position3%s, %d},\n"; fmt = "{boo::VertexSemantic::Position3%s, %d},\n";
break; break;
@ -631,34 +555,44 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
break; break;
} }
out.second += Format(fmt, out.second += Format(fmt,
(attr.first & boo::VertexSemantic::Instanced) != boo::VertexSemantic::None ? (attr.first & boo::VertexSemantic::Instanced) != boo::VertexSemantic::None
" | boo::VertexSemantic::Instanced" : "", attr.second); ? " | boo::VertexSemantic::Instanced"
: "",
attr.second);
} }
out.second += "};\n"; out.second += "};\n";
out.second += Format("const boo::VertexFormatInfo Shader_%s::VtxFmt = { %s_vtxfmtelems };\n\n", out.second += Format("const boo::VertexFormatInfo Shader_%s::VtxFmt = { %s_vtxfmtelems };\n\n", shaderName.c_str(),
shaderName.c_str(), shaderName.c_str()); shaderName.c_str());
out.second += Format("const boo::AdditionalPipelineInfo Shader_%s::PipelineInfo = {\n", shaderName.c_str()); out.second += Format("const boo::AdditionalPipelineInfo Shader_%s::PipelineInfo = {\n", shaderName.c_str());
out.second += BlendFactorToStr(shaderInfo.srcFac); out.second += ", "; out.second += BlendFactorToStr(shaderInfo.srcFac);
out.second += BlendFactorToStr(shaderInfo.dstFac); out.second += ", "; out.second += ", ";
out.second += PrimitiveToStr(shaderInfo.prim); out.second += ", "; out.second += BlendFactorToStr(shaderInfo.dstFac);
out.second += ZTestToStr(shaderInfo.depthTest); out.second += ",\n"; out.second += ", ";
out.second += BoolToStr(shaderInfo.depthWrite); out.second += ", "; out.second += PrimitiveToStr(shaderInfo.prim);
out.second += BoolToStr(shaderInfo.colorWrite); out.second += ", "; out.second += ", ";
out.second += BoolToStr(shaderInfo.alphaWrite); out.second += ", "; out.second += ZTestToStr(shaderInfo.depthTest);
out.second += CullModeToStr(shaderInfo.culling); out.second += ", "; out.second += ",\n";
out.second += BoolToStr(shaderInfo.depthWrite);
out.second += ", ";
out.second += BoolToStr(shaderInfo.colorWrite);
out.second += ", ";
out.second += BoolToStr(shaderInfo.alphaWrite);
out.second += ", ";
out.second += CullModeToStr(shaderInfo.culling);
out.second += ", ";
out.second += Format("%d, ", shaderInfo.patchSize); out.second += Format("%d, ", shaderInfo.patchSize);
out.second += BoolToStr(shaderInfo.overwriteAlpha); out.second += ", "; out.second += BoolToStr(shaderInfo.overwriteAlpha);
out.second += BoolToStr(shaderInfo.depthAttachment); out.second += ", "; out.second += ", ";
out.second += BoolToStr(shaderInfo.depthAttachment);
out.second += ", ";
out.second += "};\n\n"; out.second += "};\n\n";
uses.first.set(5); uses.first.set(5);
return true; return true;
}; };
auto AddAttribute = [&](std::string semantic, std::string idx, bool inst) auto AddAttribute = [&](std::string semantic, std::string idx, bool inst) {
{ if (shaderAttributesReset) {
if (shaderAttributesReset)
{
shaderAttributes.clear(); shaderAttributes.clear();
shaderAttributesReset = false; shaderAttributesReset = false;
} }
@ -685,8 +619,7 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::Weight | orsem, idxNum)); shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::Weight | orsem, idxNum));
else if (semantic == "modelview") else if (semantic == "modelview")
shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::ModelView | orsem, idxNum)); shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::ModelView | orsem, idxNum));
else else {
{
Log.report(logvisor::Error, "Unrecognized vertex semantic '%s'", semantic.c_str()); Log.report(logvisor::Error, "Unrecognized vertex semantic '%s'", semantic.c_str());
return false; return false;
} }
@ -696,8 +629,7 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
auto begin = includesPass.cbegin(); auto begin = includesPass.cbegin();
auto end = includesPass.cend(); auto end = includesPass.cend();
std::string* defineContinue = nullptr; std::string* defineContinue = nullptr;
while (begin != end) while (begin != end) {
{
std::string::const_iterator nextBegin; std::string::const_iterator nextBegin;
auto findPos = includesPass.find('\n', begin - includesPass.cbegin()); auto findPos = includesPass.find('\n', begin - includesPass.cbegin());
if (findPos == std::string::npos) if (findPos == std::string::npos)
@ -706,8 +638,7 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
nextBegin = includesPass.cbegin() + findPos + 1; nextBegin = includesPass.cbegin() + findPos + 1;
std::smatch subMatch; std::smatch subMatch;
if (defineContinue) if (defineContinue) {
{
std::string extraLine; std::string extraLine;
if (findPos == std::string::npos) if (findPos == std::string::npos)
extraLine = std::string(begin, end); extraLine = std::string(begin, end);
@ -720,143 +651,95 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
defineContinue->pop_back(); defineContinue->pop_back();
else else
defineContinue = nullptr; defineContinue = nullptr;
} } else if (std::regex_search(begin, nextBegin, subMatch, regDefine)) {
else if (std::regex_search(begin, nextBegin, subMatch, regDefine))
{
std::string& defOut = m_defines[subMatch[1].str()]; std::string& defOut = m_defines[subMatch[1].str()];
defOut = subMatch[2].str(); defOut = subMatch[2].str();
if (!defOut.empty() && defOut.back() == '\r') if (!defOut.empty() && defOut.back() == '\r')
defOut.pop_back(); defOut.pop_back();
if (!defOut.empty() && defOut.back() == '\\') if (!defOut.empty() && defOut.back() == '\\') {
{
defOut.pop_back(); defOut.pop_back();
defineContinue = &defOut; defineContinue = &defOut;
} }
} } else if (std::regex_search(begin, nextBegin, subMatch, regShaderEx)) {
else if (std::regex_search(begin, nextBegin, subMatch, regShaderEx))
{
stageEnd = begin; stageEnd = begin;
if (!_DoCompile() || !DoShader()) if (!_DoCompile() || !DoShader())
return false; return false;
shaderName = subMatch[1].str(); shaderName = subMatch[1].str();
shaderBase = subMatch[2].str(); shaderBase = subMatch[2].str();
shaderAttributesReset = true; shaderAttributesReset = true;
//shaderAttributes.clear(); // shaderAttributes.clear();
//shaderInfo = boo::AdditionalPipelineInfo(); // shaderInfo = boo::AdditionalPipelineInfo();
} } else if (std::regex_search(begin, nextBegin, subMatch, regShader)) {
else if (std::regex_search(begin, nextBegin, subMatch, regShader))
{
stageEnd = begin; stageEnd = begin;
if (!_DoCompile() || !DoShader()) if (!_DoCompile() || !DoShader())
return false; return false;
shaderName = subMatch[1].str(); shaderName = subMatch[1].str();
shaderAttributesReset = true; shaderAttributesReset = true;
//shaderAttributes.clear(); // shaderAttributes.clear();
//shaderInfo = boo::AdditionalPipelineInfo(); // shaderInfo = boo::AdditionalPipelineInfo();
} } else if (std::regex_search(begin, nextBegin, subMatch, regAttributeEx)) {
else if (std::regex_search(begin, nextBegin, subMatch, regAttributeEx))
{
if (!AddAttribute(subMatch[1].str(), subMatch[2].str(), false)) if (!AddAttribute(subMatch[1].str(), subMatch[2].str(), false))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regAttribute)) {
else if (std::regex_search(begin, nextBegin, subMatch, regAttribute))
{
if (!AddAttribute(subMatch[1].str(), "0", false)) if (!AddAttribute(subMatch[1].str(), "0", false))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regInstAttributeEx)) {
else if (std::regex_search(begin, nextBegin, subMatch, regInstAttributeEx))
{
if (!AddAttribute(subMatch[1].str(), subMatch[2].str(), true)) if (!AddAttribute(subMatch[1].str(), subMatch[2].str(), true))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regInstAttribute)) {
else if (std::regex_search(begin, nextBegin, subMatch, regInstAttribute))
{
if (!AddAttribute(subMatch[1].str(), "0", true)) if (!AddAttribute(subMatch[1].str(), "0", true))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regSrcFac)) {
else if (std::regex_search(begin, nextBegin, subMatch, regSrcFac))
{
if (!StrToBlendFactor(subMatch[1].str(), shaderInfo.srcFac)) if (!StrToBlendFactor(subMatch[1].str(), shaderInfo.srcFac))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regDstFac)) {
else if (std::regex_search(begin, nextBegin, subMatch, regDstFac))
{
if (!StrToBlendFactor(subMatch[1].str(), shaderInfo.dstFac)) if (!StrToBlendFactor(subMatch[1].str(), shaderInfo.dstFac))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regPrim)) {
else if (std::regex_search(begin, nextBegin, subMatch, regPrim))
{
if (!StrToPrimitive(subMatch[1].str(), shaderInfo.prim)) if (!StrToPrimitive(subMatch[1].str(), shaderInfo.prim))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regZTest)) {
else if (std::regex_search(begin, nextBegin, subMatch, regZTest))
{
if (!StrToZTest(subMatch[1].str(), shaderInfo.depthTest)) if (!StrToZTest(subMatch[1].str(), shaderInfo.depthTest))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regDepthWrite)) {
else if (std::regex_search(begin, nextBegin, subMatch, regDepthWrite))
{
if (!StrToBool(subMatch[1].str(), shaderInfo.depthWrite)) if (!StrToBool(subMatch[1].str(), shaderInfo.depthWrite))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regColorWrite)) {
else if (std::regex_search(begin, nextBegin, subMatch, regColorWrite))
{
if (!StrToBool(subMatch[1].str(), shaderInfo.colorWrite)) if (!StrToBool(subMatch[1].str(), shaderInfo.colorWrite))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regAlphaWrite)) {
else if (std::regex_search(begin, nextBegin, subMatch, regAlphaWrite))
{
if (!StrToBool(subMatch[1].str(), shaderInfo.alphaWrite)) if (!StrToBool(subMatch[1].str(), shaderInfo.alphaWrite))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regCulling)) {
else if (std::regex_search(begin, nextBegin, subMatch, regCulling))
{
if (!StrToCullMode(subMatch[1].str(), shaderInfo.culling)) if (!StrToCullMode(subMatch[1].str(), shaderInfo.culling))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regPatchSize)) {
else if (std::regex_search(begin, nextBegin, subMatch, regPatchSize))
{
auto str = subMatch[1].str(); auto str = subMatch[1].str();
char* endptr; char* endptr;
shaderInfo.patchSize = uint32_t(strtoul(str.c_str(), &endptr, 0)); shaderInfo.patchSize = uint32_t(strtoul(str.c_str(), &endptr, 0));
if (endptr == str.c_str()) if (endptr == str.c_str()) {
{
Log.report(logvisor::Error, "Non-unsigned-integer value for #patchsize directive"); Log.report(logvisor::Error, "Non-unsigned-integer value for #patchsize directive");
return false; return false;
} }
} } else if (std::regex_search(begin, nextBegin, subMatch, regOverwriteAlpha)) {
else if (std::regex_search(begin, nextBegin, subMatch, regOverwriteAlpha))
{
if (!StrToBool(subMatch[1].str(), shaderInfo.overwriteAlpha)) if (!StrToBool(subMatch[1].str(), shaderInfo.overwriteAlpha))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regDepthAttachment)) {
else if (std::regex_search(begin, nextBegin, subMatch, regDepthAttachment))
{
if (!StrToBool(subMatch[1].str(), shaderInfo.depthAttachment)) if (!StrToBool(subMatch[1].str(), shaderInfo.depthAttachment))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regVertex)) {
else if (std::regex_search(begin, nextBegin, subMatch, regVertex))
{
if (!DoCompile(subMatch[1].str(), StageType::Vertex, begin, nextBegin)) if (!DoCompile(subMatch[1].str(), StageType::Vertex, begin, nextBegin))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regFragment)) {
else if (std::regex_search(begin, nextBegin, subMatch, regFragment))
{
if (!DoCompile(subMatch[1].str(), StageType::Fragment, begin, nextBegin)) if (!DoCompile(subMatch[1].str(), StageType::Fragment, begin, nextBegin))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regGeometry)) {
else if (std::regex_search(begin, nextBegin, subMatch, regGeometry))
{
if (!DoCompile(subMatch[1].str(), StageType::Geometry, begin, nextBegin)) if (!DoCompile(subMatch[1].str(), StageType::Geometry, begin, nextBegin))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regControl)) {
else if (std::regex_search(begin, nextBegin, subMatch, regControl))
{
if (!DoCompile(subMatch[1].str(), StageType::Control, begin, nextBegin)) if (!DoCompile(subMatch[1].str(), StageType::Control, begin, nextBegin))
return false; return false;
} } else if (std::regex_search(begin, nextBegin, subMatch, regEvaluation)) {
else if (std::regex_search(begin, nextBegin, subMatch, regEvaluation))
{
if (!DoCompile(subMatch[1].str(), StageType::Evaluation, begin, nextBegin)) if (!DoCompile(subMatch[1].str(), StageType::Evaluation, begin, nextBegin))
return false; return false;
} }
@ -870,8 +753,7 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
out.first += "#define UNIVERSAL_PIPELINES_"; out.first += "#define UNIVERSAL_PIPELINES_";
out.first += baseName; out.first += baseName;
for (const auto& shader : shaderStageUses) for (const auto& shader : shaderStageUses) {
{
out.first += " \\\n"; out.first += " \\\n";
out.first += "::Shader_"; out.first += "::Shader_";
out.first += shader.first; out.first += shader.first;
@ -881,8 +763,7 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
out.first += "#define STAGES_"; out.first += "#define STAGES_";
out.first += baseName; out.first += baseName;
out.first += "(P, S)"; out.first += "(P, S)";
for (const auto& shader : shaderStageUses) for (const auto& shader : shaderStageUses) {
{
out.first += " \\\n"; out.first += " \\\n";
out.first += "::StageObject_"; out.first += "::StageObject_";
out.first += shader.first; out.first += shader.first;
@ -893,14 +774,11 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
return true; return true;
} }
bool Compiler::compile(std::string_view baseName, std::pair<std::string, std::string>& out) bool Compiler::compile(std::string_view baseName, std::pair<std::string, std::string>& out) {
{ out = {
out =
{
"#pragma once\n" "#pragma once\n"
"#include \"hecl/PipelineBase.hpp\"\n\n", "#include \"hecl/PipelineBase.hpp\"\n\n",
Format("#include \"%s.hpp\"\n\n", baseName.data()) Format("#include \"%s.hpp\"\n\n", baseName.data())};
};
for (const auto& file : m_inputFiles) for (const auto& file : m_inputFiles)
if (!compileFile(file, baseName, out)) if (!compileFile(file, baseName, out))
@ -909,4 +787,4 @@ bool Compiler::compile(std::string_view baseName, std::pair<std::string, std::st
return true; return true;
} }
} } // namespace hecl::shaderc

View File

@ -4,38 +4,28 @@
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
namespace hecl::shaderc namespace hecl::shaderc {
{
class Compiler class Compiler {
{ enum class StageType { Vertex, Fragment, Geometry, Control, Evaluation };
enum class StageType
{
Vertex,
Fragment,
Geometry,
Control,
Evaluation
};
std::vector<SystemString> m_inputFiles; std::vector<SystemString> m_inputFiles;
std::unordered_map<SystemString, std::string> m_fileContents; std::unordered_map<SystemString, std::string> m_fileContents;
const std::string* getFileContents(SystemStringView path); const std::string* getFileContents(SystemStringView path);
std::unordered_map<std::string, std::string> m_defines; std::unordered_map<std::string, std::string> m_defines;
template<typename Action, typename P> template <typename Action, typename P>
static bool StageAction(StageType type, static bool StageAction(StageType type, const std::string& name, const std::string& basename,
const std::string& name, const std::string& basename, const std::string& stage, const std::string& stage, std::string& implOut);
std::string& implOut); template <typename Action>
template<typename Action> static bool StageAction(const std::string& platforms, StageType type, const std::string& name,
static bool StageAction(const std::string& platforms, StageType type, const std::string& basename, const std::string& stage, std::string& implOut);
const std::string& name, const std::string& basename, const std::string& stage,
std::string& implOut);
bool includeFile(SystemStringView file, std::string& out, int depth = 0); bool includeFile(SystemStringView file, std::string& out, int depth = 0);
bool compileFile(SystemStringView file, std::string_view baseName, std::pair<std::string, std::string>& out); bool compileFile(SystemStringView file, std::string_view baseName, std::pair<std::string, std::string>& out);
public: public:
void addInputFile(SystemStringView file); void addInputFile(SystemStringView file);
void addDefine(std::string_view var, std::string_view val); void addDefine(std::string_view var, std::string_view val);
bool compile(std::string_view baseName, std::pair<std::string, std::string>& out); bool compile(std::string_view baseName, std::pair<std::string, std::string>& out);
}; };
} } // namespace hecl::shaderc

View File

@ -14,44 +14,32 @@
using namespace std::literals; using namespace std::literals;
struct HECLWindowCallback : boo::IWindowCallback struct HECLWindowCallback : boo::IWindowCallback {
{
bool m_sizeDirty = false; bool m_sizeDirty = false;
boo::SWindowRect m_latestSize; boo::SWindowRect m_latestSize;
virtual ~HECLWindowCallback(); virtual ~HECLWindowCallback();
void resized(const boo::SWindowRect& rect, bool /*sync*/) void resized(const boo::SWindowRect& rect, bool /*sync*/) {
{
m_sizeDirty = true; m_sizeDirty = true;
m_latestSize = rect; m_latestSize = rect;
} }
bool m_destroyed = false; bool m_destroyed = false;
void destroyed() void destroyed() { m_destroyed = true; }
{
m_destroyed = true;
}
void charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat) void charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat) {
{
hecl::Console::instance()->handleCharCode(charCode, mods, isRepeat); hecl::Console::instance()->handleCharCode(charCode, mods, isRepeat);
} }
void specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool isRepeat) void specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool isRepeat) {
{
hecl::Console::instance()->handleSpecialKeyDown(key, mods, isRepeat); hecl::Console::instance()->handleSpecialKeyDown(key, mods, isRepeat);
} }
void specialKeyUp(boo::ESpecialKey key, boo::EModifierKey mods) void specialKeyUp(boo::ESpecialKey key, boo::EModifierKey mods) {
{
hecl::Console::instance()->hecl::Console::handleSpecialKeyUp(key, mods); hecl::Console::instance()->hecl::Console::handleSpecialKeyUp(key, mods);
} }
}; };
HECLWindowCallback::~HECLWindowCallback() HECLWindowCallback::~HECLWindowCallback() {}
{
} struct HECLApplicationCallback : boo::IApplicationCallback {
struct HECLApplicationCallback : boo::IApplicationCallback
{
HECLWindowCallback m_windowCb; HECLWindowCallback m_windowCb;
hecl::Runtime::FileStoreManager m_fileStoreMgr; hecl::Runtime::FileStoreManager m_fileStoreMgr;
hecl::CVarManager m_cvarManager; hecl::CVarManager m_cvarManager;
@ -60,18 +48,15 @@ struct HECLApplicationCallback : boo::IApplicationCallback
bool m_running = true; bool m_running = true;
HECLApplicationCallback() HECLApplicationCallback()
: m_fileStoreMgr(_SYS_STR("heclTest")), : m_fileStoreMgr(_SYS_STR("heclTest")), m_cvarManager(m_fileStoreMgr), m_console(&m_cvarManager) {
m_cvarManager(m_fileStoreMgr), m_console.registerCommand(
m_console(&m_cvarManager) "quit"sv, "Quits application"sv, "",
{
m_console.registerCommand("quit"sv, "Quits application"sv, "",
std::bind(&HECLApplicationCallback::quit, this, std::placeholders::_1, std::placeholders::_2)); std::bind(&HECLApplicationCallback::quit, this, std::placeholders::_1, std::placeholders::_2));
} }
virtual ~HECLApplicationCallback(); virtual ~HECLApplicationCallback();
int appMain(boo::IApplication* app) int appMain(boo::IApplication* app) {
{
hecl::VerbosityLevel = 2; hecl::VerbosityLevel = 2;
/* Setup boo window */ /* Setup boo window */
@ -83,13 +68,11 @@ struct HECLApplicationCallback : boo::IApplicationCallback
boo::ObjToken<boo::IShaderPipeline> pipeline, pipeline2; boo::ObjToken<boo::IShaderPipeline> pipeline, pipeline2;
boo::ObjToken<boo::IShaderDataBinding> binding, binding2; boo::ObjToken<boo::IShaderDataBinding> binding, binding2;
struct VertexUBO struct VertexUBO {
{
float modelview[4][4] = {}; float modelview[4][4] = {};
float modelviewInv[4][4] = {}; float modelviewInv[4][4] = {};
float projection[4][4] = {}; float projection[4][4] = {};
VertexUBO() VertexUBO() {
{
modelview[0][0] = 1.0; modelview[0][0] = 1.0;
modelview[1][1] = 1.0; modelview[1][1] = 1.0;
modelview[2][2] = 1.0; modelview[2][2] = 1.0;
@ -108,9 +91,8 @@ struct HECLApplicationCallback : boo::IApplicationCallback
/* Make ramp texture */ /* Make ramp texture */
using Pixel = uint8_t[4]; using Pixel = uint8_t[4];
static Pixel tex[256][256]; static Pixel tex[256][256];
for (int i=0 ; i<256 ; ++i) for (int i = 0; i < 256; ++i)
for (int j=0 ; j<256 ; ++j) for (int j = 0; j < 256; ++j) {
{
tex[i][j][0] = uint8_t(i); tex[i][j][0] = uint8_t(i);
tex[i][j][1] = uint8_t(j); tex[i][j][1] = uint8_t(j);
tex[i][j][2] = 0; tex[i][j][2] = 0;
@ -126,15 +108,14 @@ struct HECLApplicationCallback : boo::IApplicationCallback
/* Compile HECL shader */ /* Compile HECL shader */
static std::string testShader = "HECLOpaque(Texture(0, UV(0)))"; static std::string testShader = "HECLOpaque(Texture(0, UV(0)))";
//static std::string testShader = "HECLOpaque(vec3(1.0,1.0,1.0),1.0)"; // static std::string testShader = "HECLOpaque(vec3(1.0,1.0,1.0),1.0)";
hecl::Backend::ShaderTag testShaderTag(testShader, 0, 1, 0, 0, boo::Primitive::TriStrips, hecl::Backend::ShaderTag testShaderTag(testShader, 0, 1, 0, 0, boo::Primitive::TriStrips,
hecl::Backend::ReflectionType::None, false, false, false, false); hecl::Backend::ReflectionType::None, false, false, false, false);
hecl::Frontend::Frontend FE; hecl::Frontend::Frontend FE;
hecl::Frontend::IR ir = FE.compileSource(testShader, "booTest"); hecl::Frontend::IR ir = FE.compileSource(testShader, "booTest");
hecl::HECLIR irObj(ir, testShaderTag, 0); hecl::HECLIR irObj(ir, testShaderTag, 0);
gfxF->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) gfxF->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) {
{
pipeline = conv->convert(ctx, irObj); pipeline = conv->convert(ctx, irObj);
pipeline2 = conv->convert(ctx, Shader_test{}); pipeline2 = conv->convert(ctx, Shader_test{});
@ -159,28 +140,25 @@ struct HECLApplicationCallback : boo::IApplicationCallback
testMeta.write(testMetaWriter); testMeta.write(testMetaWriter);
/* Make Tri-strip VBO */ /* Make Tri-strip VBO */
struct Vert struct Vert {
{
float pos[3]; float pos[3];
float norm[3]; float norm[3];
float uv[2]; float uv[2];
}; };
static const Vert quad[4] = static const Vert quad[4] = {{{0.5, 0.5}, {}, {1.0, 1.0}},
{ {{-0.5, 0.5}, {}, {0.0, 1.0}},
{{0.5,0.5},{},{1.0,1.0}}, {{0.5, -0.5}, {}, {1.0, 0.0}},
{{-0.5,0.5},{},{0.0,1.0}}, {{-0.5, -0.5}, {}, {0.0, 0.0}}};
{{0.5,-0.5},{},{1.0,0.0}},
{{-0.5,-0.5},{},{0.0,0.0}}
};
/* Now simple IBO */ /* Now simple IBO */
static const uint32_t ibo[4] = {0,1,2,3}; static const uint32_t ibo[4] = {0, 1, 2, 3};
/* Construct quad mesh against boo factory */ /* Construct quad mesh against boo factory */
hecl::Runtime::HMDLData testData(ctx, testMetaBuf, quad, ibo); hecl::Runtime::HMDLData testData(ctx, testMetaBuf, quad, ibo);
boo::ObjToken<boo::ITexture> texture = boo::ObjToken<boo::ITexture> texture = ctx.newStaticTexture(256, 256, 1, boo::TextureFormat::RGBA8,
ctx.newStaticTexture(256, 256, 1, boo::TextureFormat::RGBA8, boo::TextureClampMode::Repeat, tex, 256*256*4).get(); boo::TextureClampMode::Repeat, tex, 256 * 256 * 4)
.get();
/* Make vertex uniform buffer */ /* Make vertex uniform buffer */
vubo = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(VertexUBO), 1).get(); vubo = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(VertexUBO), 1).get();
@ -191,26 +169,21 @@ struct HECLApplicationCallback : boo::IApplicationCallback
return true; return true;
} BooTrace); } BooTrace);
m_mainWindow->showWindow(); m_mainWindow->showWindow();
m_windowCb.m_latestSize = m_mainWindow->getWindowFrame(); m_windowCb.m_latestSize = m_mainWindow->getWindowFrame();
boo::IGraphicsCommandQueue* gfxQ = m_mainWindow->getCommandQueue(); boo::IGraphicsCommandQueue* gfxQ = m_mainWindow->getCommandQueue();
size_t frameIdx = 0; size_t frameIdx = 0;
while (m_running) while (m_running) {
{
m_mainWindow->waitForRetrace(); m_mainWindow->waitForRetrace();
if (m_windowCb.m_destroyed) if (m_windowCb.m_destroyed) {
{
m_running = false; m_running = false;
break; break;
} }
if (m_windowCb.m_sizeDirty) if (m_windowCb.m_sizeDirty) {
{ gfxQ->resizeRenderTexture(renderTex, size_t(m_windowCb.m_latestSize.size[0]),
gfxQ->resizeRenderTexture(renderTex,
size_t(m_windowCb.m_latestSize.size[0]),
size_t(m_windowCb.m_latestSize.size[1])); size_t(m_windowCb.m_latestSize.size[1]));
m_windowCb.m_sizeDirty = false; m_windowCb.m_sizeDirty = false;
} }
@ -244,21 +217,13 @@ struct HECLApplicationCallback : boo::IApplicationCallback
gfxQ->stopRenderer(); gfxQ->stopRenderer();
return 0; return 0;
} }
void appQuitting(boo::IApplication* /*app*/) void appQuitting(boo::IApplication* /*app*/) { m_running = false; }
{
m_running = false;
}
void quit(hecl::Console* /*con*/, const std::vector<std::string>& /*args*/) void quit(hecl::Console* /*con*/, const std::vector<std::string>& /*args*/) { m_running = false; }
{
m_running = false;
}
}; };
void AthenaExcHandler(athena::error::Level level, void AthenaExcHandler(athena::error::Level level, const char* file, const char* /*function*/, int line, const char* fmt,
const char* file, const char* /*function*/, ...) {
int line, const char* fmt, ...)
{
static logvisor::Module Log("heclTest::AthenaExcHandler"); static logvisor::Module Log("heclTest::AthenaExcHandler");
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
@ -277,30 +242,27 @@ int main(int argc, const boo::SystemChar** argv)
logvisor::RegisterStandardExceptions(); logvisor::RegisterStandardExceptions();
logvisor::RegisterConsoleLogger(); logvisor::RegisterConsoleLogger();
HECLApplicationCallback appCb; HECLApplicationCallback appCb;
int ret = boo::ApplicationRun(boo::IApplication::EPlatformType::Auto, int ret = boo::ApplicationRun(boo::IApplication::EPlatformType::Auto, appCb, _SYS_STR("heclTest"),
appCb, _SYS_STR("heclTest"), _SYS_STR("HECL Test"), argc, argv); _SYS_STR("HECL Test"), argc, argv);
printf("IM DYING!!\n"); printf("IM DYING!!\n");
return ret; return ret;
} }
#else #else
using namespace Windows::ApplicationModel::Core; using namespace Windows::ApplicationModel::Core;
[Platform::MTAThread] [Platform::MTAThread] int WINAPIV main(Platform::Array<Platform::String ^> ^ params) {
int WINAPIV main(Platform::Array<Platform::String^>^ params)
{
logvisor::RegisterStandardExceptions(); logvisor::RegisterStandardExceptions();
logvisor::RegisterConsoleLogger(); logvisor::RegisterConsoleLogger();
HECLApplicationCallback appCb; HECLApplicationCallback appCb;
boo::ViewProvider^ viewProvider = boo::ViewProvider ^ viewProvider = ref new boo::ViewProvider(appCb, _SYS_STR("heclTest"), _SYS_STR("HECL Test"),
ref new boo::ViewProvider(appCb, _SYS_STR("heclTest"), _SYS_STR("HECL Test"), _SYS_STR("heclTest"), params, false); _SYS_STR("heclTest"), params, false);
CoreApplication::Run(viewProvider); CoreApplication::Run(viewProvider);
return 0; return 0;
} }
#endif #endif
#if _WIN32 && !WINDOWS_STORE #if _WIN32 && !WINDOWS_STORE
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int) int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int) {
{
int argc = 0; int argc = 0;
const boo::SystemChar** argv; const boo::SystemChar** argv;
if (lpCmdLine[0]) if (lpCmdLine[0])
@ -309,15 +271,12 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int)
GetModuleFileNameW(nullptr, selfPath, 1024); GetModuleFileNameW(nullptr, selfPath, 1024);
static const boo::SystemChar* booArgv[32] = {}; static const boo::SystemChar* booArgv[32] = {};
booArgv[0] = selfPath; booArgv[0] = selfPath;
for (int i=0 ; i<argc ; ++i) for (int i = 0; i < argc; ++i)
booArgv[i+1] = argv[i]; booArgv[i + 1] = argv[i];
logvisor::CreateWin32Console(); logvisor::CreateWin32Console();
return wmain(argc + 1, booArgv); return wmain(argc + 1, booArgv);
} }
#endif #endif
HECLApplicationCallback::~HECLApplicationCallback() HECLApplicationCallback::~HECLApplicationCallback() {}
{
}