From aae0dc56b704849d9048729c2c198bf635b74fdd Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Thu, 28 Dec 2017 21:56:31 -1000 Subject: [PATCH] Huge compile performance refactor --- hecl/DataSpecRegistry.hpp.in | 5 +- hecl/bintoc/CMakeLists.txt | 2 +- hecl/bintoc/bintoc.c | 5 +- hecl/blender/CMakeLists.txt | 12 +- hecl/driver/CMakeLists.txt | 8 +- hecl/driver/ToolAdd.hpp | 60 - hecl/driver/ToolBase.hpp | 4 +- hecl/driver/ToolClean.hpp | 70 -- hecl/driver/ToolCook.hpp | 2 +- hecl/driver/ToolExtract.hpp | 2 +- hecl/driver/ToolGroup.hpp | 69 -- hecl/driver/ToolHelp.hpp | 10 +- hecl/driver/ToolInit.hpp | 2 +- hecl/driver/ToolPackage.hpp | 2 +- hecl/driver/ToolRemove.hpp | 62 - hecl/driver/ToolSpec.hpp | 2 +- hecl/driver/main.cpp | 30 +- hecl/extern/athena | 2 +- hecl/extern/boo | 2 +- hecl/extern/libpng/pngconf.h | 4 + hecl/include/hecl/Backend/Backend.hpp | 5 +- hecl/include/hecl/Backend/GLSL.hpp | 5 +- hecl/include/hecl/Backend/GX.hpp | 9 +- hecl/include/hecl/Backend/HLSL.hpp | 5 +- hecl/include/hecl/Backend/Metal.hpp | 5 +- .../hecl/Backend/ProgrammableCommon.hpp | 9 +- .../hecl/Blender/BlenderConnection.hpp | 1017 ----------------- hecl/include/hecl/Blender/Connection.hpp | 706 ++++++++++++ hecl/include/hecl/Blender/Token.hpp | 27 + hecl/include/hecl/ClientProcess.hpp | 20 +- hecl/include/hecl/Database.hpp | 21 +- hecl/include/hecl/FourCC.hpp | 62 + hecl/include/hecl/HMDLMeta.hpp | 4 +- hecl/include/hecl/Runtime.hpp | 8 +- hecl/include/hecl/SystemChar.hpp | 4 +- hecl/include/hecl/hecl.hpp | 107 +- hecl/lib/Backend/GLSL.cpp | 26 +- hecl/lib/Backend/GX.cpp | 5 +- hecl/lib/Backend/HLSL.cpp | 5 +- hecl/lib/Backend/Metal.cpp | 8 +- hecl/lib/Backend/ProgrammableCommon.cpp | 5 +- hecl/lib/Blender/CMakeLists.txt | 2 +- .../{BlenderConnection.cpp => Connection.cpp} | 675 ++++++++--- hecl/lib/Blender/HMDL.cpp | 13 +- hecl/lib/CMakeLists.txt | 7 +- hecl/lib/ClientProcess.cpp | 18 +- hecl/lib/Frontend/Diagnostics.cpp | 2 +- hecl/lib/Project.cpp | 21 +- hecl/lib/Runtime/FileStoreManager.cpp | 5 +- hecl/lib/Runtime/HMDL_RT.cpp | 9 +- hecl/lib/Runtime/ShaderCacheManager.cpp | 69 +- hecl/lib/winsupport.cpp | 6 +- hecl/test/main.cpp | 7 +- 53 files changed, 1523 insertions(+), 1729 deletions(-) delete mode 100644 hecl/driver/ToolAdd.hpp delete mode 100644 hecl/driver/ToolClean.hpp delete mode 100644 hecl/driver/ToolGroup.hpp delete mode 100644 hecl/driver/ToolRemove.hpp delete mode 100644 hecl/include/hecl/Blender/BlenderConnection.hpp create mode 100644 hecl/include/hecl/Blender/Connection.hpp create mode 100644 hecl/include/hecl/Blender/Token.hpp create mode 100644 hecl/include/hecl/FourCC.hpp rename hecl/lib/Blender/{BlenderConnection.cpp => Connection.cpp} (72%) diff --git a/hecl/DataSpecRegistry.hpp.in b/hecl/DataSpecRegistry.hpp.in index 18ab522d2..a3d7ca855 100644 --- a/hecl/DataSpecRegistry.hpp.in +++ b/hecl/DataSpecRegistry.hpp.in @@ -8,14 +8,11 @@ #include "hecl/Database.hpp" -namespace hecl -{ -namespace Database +namespace hecl::Database { /* Centralized registry for DataSpec lookup */ std::vector DATA_SPEC_REGISTRY; } -} @HECL_DATASPEC_DECLS@ diff --git a/hecl/bintoc/CMakeLists.txt b/hecl/bintoc/CMakeLists.txt index db1d4c184..483ad5be4 100644 --- a/hecl/bintoc/CMakeLists.txt +++ b/hecl/bintoc/CMakeLists.txt @@ -13,7 +13,7 @@ macro(bintoc out in sym) endif() add_custom_command(OUTPUT ${theOut} COMMAND $ ARGS ${theIn} ${theOut} ${sym} - DEPENDS ${theIn}) + DEPENDS ${theIn} bintoc) endmacro() ################## diff --git a/hecl/bintoc/bintoc.c b/hecl/bintoc/bintoc.c index a5ae59e37..d6f604995 100644 --- a/hecl/bintoc/bintoc.c +++ b/hecl/bintoc/bintoc.c @@ -20,7 +20,8 @@ int main(int argc, char** argv) fprintf(stderr, "Unable to open %s for writing\n", argv[2]); return 1; } - fprintf(fout, "#include \n#include \nconst uint8_t %s[] =\n{\n", argv[3]); + fprintf(fout, "#include \n#include \n"); + fprintf(fout, "extern \"C\" const uint8_t %s[] =\n{\n", argv[3]); size_t totalSz = 0; size_t readSz; uint8_t buf[32]; @@ -32,7 +33,7 @@ int main(int argc, char** argv) fprintf(fout, "0x%02X, ", buf[b]); fprintf(fout, "\n"); } - fprintf(fout, "0x0};\nconst size_t %s_SZ = %zu;\n", argv[3], totalSz); + fprintf(fout, "0x0};\nextern \"C\" const size_t %s_SZ = %zu;\n", argv[3], totalSz); fclose(fin); fclose(fout); return 0; diff --git a/hecl/blender/CMakeLists.txt b/hecl/blender/CMakeLists.txt index fb7ac8df2..8e2be2513 100644 --- a/hecl/blender/CMakeLists.txt +++ b/hecl/blender/CMakeLists.txt @@ -14,20 +14,20 @@ list(APPEND PY_SOURCES hecl/mapu.py hecl/frme.py) -bintoc(hecl_blendershell.c hecl_blendershell.py HECL_BLENDERSHELL) +bintoc(hecl_blendershell.cpp hecl_blendershell.py HECL_BLENDERSHELL) add_custom_command(OUTPUT hecl.zip DEPENDS ${PY_SOURCES} COMMAND python ARGS zip_package.py ${CMAKE_CURRENT_BINARY_DIR}/hecl.zip WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Generating addon package") -bintoc(hecl_addon.c "${CMAKE_CURRENT_BINARY_DIR}/hecl.zip" HECL_ADDON) -bintoc(hecl_startup.c hecl_startup.blend HECL_STARTUP) +bintoc(hecl_addon.cpp "${CMAKE_CURRENT_BINARY_DIR}/hecl.zip" HECL_ADDON) +bintoc(hecl_startup.cpp hecl_startup.blend HECL_STARTUP) add_library(hecl-blender-addon hecl_blendershell.py - hecl_blendershell.c + hecl_blendershell.cpp zip_package.py hecl.zip - hecl_addon.c - hecl_startup.c + hecl_addon.cpp + hecl_startup.cpp ${PY_SOURCES}) diff --git a/hecl/driver/CMakeLists.txt b/hecl/driver/CMakeLists.txt index 9ed0e6886..2280145d7 100644 --- a/hecl/driver/CMakeLists.txt +++ b/hecl/driver/CMakeLists.txt @@ -5,11 +5,7 @@ add_executable(hecl main.cpp ToolExtract.hpp ToolInit.hpp ToolHelp.hpp - ToolGroup.hpp ToolCook.hpp - ToolClean.hpp - ToolAdd.hpp - ToolRemove.hpp ToolSpec.hpp ../DataSpecRegistry.hpp) if(COMMAND add_sanitizers) @@ -30,4 +26,8 @@ target_link_libraries(hecl hecl-common hecl-blender-addon athena-core nod logvisor athena-libyaml ${PNG_LIB} squish xxhash zeus boo ${ZLIB_LIBRARIES} ${LZO_LIB} ${PLAT_LIBS} ${BOO_SYS_LIBS}) + +if(COMMAND cotire) + cotire(hecl) +endif() endif() diff --git a/hecl/driver/ToolAdd.hpp b/hecl/driver/ToolAdd.hpp deleted file mode 100644 index aaf6ac62d..000000000 --- a/hecl/driver/ToolAdd.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef CTOOL_ADD -#define CTOOL_ADD - -#include "ToolBase.hpp" -#include - -class ToolAdd final : public ToolBase -{ -public: - ToolAdd(const ToolPassInfo& info) - : ToolBase(info) - { - } - - static void Help(HelpOutput& help) - { - help.secHead(_S("NAME")); - help.beginWrap(); - help.wrap(_S("hecl-add - Add working files to the HECL index\n")); - help.endWrap(); - - help.secHead(_S("SYNOPSIS")); - help.beginWrap(); - help.wrap(_S("hecl add [...]\n")); - help.endWrap(); - - help.secHead(_S("DESCRIPTION")); - help.beginWrap(); - help.wrap(_S("This command stages a file or glob-pattern of files within the project database ") - _S("for inclusion in the ")); - help.wrapBold(_S("hecl cook")); - help.wrap(_S(" process.\n\n") - _S("Files added in this manner automatically become 'explicit' database ") - _S("objects. 'Explicit objects' will not be removed in housekeeping tasks automatically ") - _S("performed by HECL's library functions, unless the user (re)moves the file ") - _S("using the filesystem.\n\n") - _S("For details on explicit vs. implicit objects, view the ")); - help.wrapBold(_S("hecl cook")); - help.wrap(_S(" documentation.\n")); - help.endWrap(); - - help.secHead(_S("OPTIONS")); - help.optionHead(_S("..."), _S("input file(s)")); - help.beginWrap(); - help.wrap(_S("Working file(s) containing production data to be cooked by HECL. ") - _S("Glob-strings may be specified (e.g. ")); - help.wrapBold(_S("*.blend")); - help.wrap(_S(") to automatically add all matching files to the database.\n")); - help.endWrap(); - } - - hecl::SystemString toolName() const {return _S("add");} - - int run() - { - return 0; - } -}; - -#endif // CTOOL_ADD diff --git a/hecl/driver/ToolBase.hpp b/hecl/driver/ToolBase.hpp index 412893994..16d5717f5 100644 --- a/hecl/driver/ToolBase.hpp +++ b/hecl/driver/ToolBase.hpp @@ -4,8 +4,8 @@ #include #include #include -#include -#include +#include +#include #ifndef _WIN32 #include diff --git a/hecl/driver/ToolClean.hpp b/hecl/driver/ToolClean.hpp deleted file mode 100644 index 8927176f6..000000000 --- a/hecl/driver/ToolClean.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef CTOOL_CLEAN -#define CTOOL_CLEAN - -#include "ToolBase.hpp" -#include - -class ToolClean final : public ToolBase -{ -public: - ToolClean(const ToolPassInfo& info) - : ToolBase(info) - { - } - - ~ToolClean() - { - } - - static void Help(HelpOutput& help) - { - help.secHead(_S("NAME")); - help.beginWrap(); - help.wrap(_S("hecl-clean - Delete cached cooked objects referenced via working files\n")); - help.endWrap(); - - help.secHead(_S("SYNOPSIS")); - help.beginWrap(); - help.wrap(_S("hecl clean [-ri] [...]\n")); - help.endWrap(); - - help.secHead(_S("DESCRIPTION")); - help.beginWrap(); - help.wrap(_S("This command performs an immediate deletion of cooked objects cached ") - _S("within the project database. It may operate on a subset of objects or the ") - _S("entire project.\n")); - help.endWrap(); - - help.secHead(_S("OPTIONS")); - help.optionHead(_S("..."), _S("clean path(s)")); - help.beginWrap(); - help.wrap(_S("When one or more paths are specified in the command, the clean process will ") - _S("restrict object deletion to only the working file(s) specified. If ")); - help.wrapBold(_S("-r")); - help.wrap(_S(" is also specifed, directories may be provided as well. If no path(s) specified, ") - _S("the entire project is cleaned.\n")); - help.endWrap(); - - help.optionHead(_S("-r"), _S("recursion")); - help.beginWrap(); - help.wrap(_S("Enables recursive file-matching for cleaning entire directories of working files.\n")); - help.endWrap(); - - help.optionHead(_S("-i"), _S("follow implicit links")); - help.beginWrap(); - help.wrap(_S("Enables implicit object traversal and cleaning. This is only useful if one or more paths ") - _S("are specified. For objects supporting implicit-gathering, this will query those ") - _S("objects for their current implicit links and ensure the linked-objects are cleaned ") - _S("as well.\n")); - help.endWrap(); - } - - hecl::SystemString toolName() const {return _S("clean");} - - int run() - { - return 0; - } -}; - -#endif // CTOOL_CLEAN diff --git a/hecl/driver/ToolCook.hpp b/hecl/driver/ToolCook.hpp index 47a92f331..15f6f24d7 100644 --- a/hecl/driver/ToolCook.hpp +++ b/hecl/driver/ToolCook.hpp @@ -2,7 +2,7 @@ #define CTOOL_COOK #include "ToolBase.hpp" -#include +#include #include "hecl/ClientProcess.hpp" class ToolCook final : public ToolBase diff --git a/hecl/driver/ToolExtract.hpp b/hecl/driver/ToolExtract.hpp index 3444930e0..a252f14b0 100644 --- a/hecl/driver/ToolExtract.hpp +++ b/hecl/driver/ToolExtract.hpp @@ -2,7 +2,7 @@ #define CTOOL_EXTRACT #include "ToolBase.hpp" -#include +#include #if _WIN32 #include diff --git a/hecl/driver/ToolGroup.hpp b/hecl/driver/ToolGroup.hpp deleted file mode 100644 index 78d5e5d6f..000000000 --- a/hecl/driver/ToolGroup.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef CTOOL_GROUP -#define CTOOL_GROUP - -#include "ToolBase.hpp" -#include - -class ToolGroup final : public ToolBase -{ -public: - ToolGroup(const ToolPassInfo& info) - : ToolBase(info) - { - if (!info.project) - LogModule.report(logvisor::Fatal, "hecl group must be ran within a project directory"); - } - - ~ToolGroup() - { - } - - static void Help(HelpOutput& help) - { - help.secHead(_S("NAME")); - help.beginWrap(); - help.wrap(_S("hecl-group - Fork a project directory as an explicit group\n")); - help.endWrap(); - - help.secHead(_S("SYNOPSIS")); - help.beginWrap(); - help.wrap(_S("hecl group [-D] \n")); - help.endWrap(); - - help.secHead(_S("DESCRIPTION")); - help.beginWrap(); - help.wrap(_S("This command turns a nested subdirectory of the project into a HECL group. ") - _S("Groups play an important role in the resulting structure of the packaged ") - _S("database. All objects in HECL belong to a group of some sort since the runtime ") - _S("only provides loading functions for groups. Ungrouped ") - _S("objects in the project root are individually added to 'loose groups'.\n\n With ")); - help.wrapBold(_S("hecl group")); - help.wrap(_S(", explicit groups may be defined (e.g. a stage, level, area, loadable segment). ")); - help.wrap(_S("Groups are defined by filesystem directories relative to the project root ") - _S("and may be loaded within the runtime using the relative path as a lookup-string. ") - _S("Sub-directories that aren't explicitly made into a group inherit the group-status ") - _S("of the parent directory.\n")); - help.endWrap(); - - help.secHead(_S("OPTIONS")); - help.optionHead(_S(""), _S("group directory path")); - help.beginWrap(); - help.wrap(_S("Directory to fork as an explicit group\n")); - help.endWrap(); - - help.optionHead(_S("-D"), _S("delete group")); - help.beginWrap(); - help.wrap(_S("Remove's directory's status as an explicit group; restoring its inheritance ") - _S("from the parent directory.\n")); - help.endWrap(); - } - - hecl::SystemString toolName() const {return _S("group");} - - int run() - { - return 0; - } -}; - -#endif // CTOOL_GROUP diff --git a/hecl/driver/ToolHelp.hpp b/hecl/driver/ToolHelp.hpp index 0ec1f3b5b..1e957eab8 100644 --- a/hecl/driver/ToolHelp.hpp +++ b/hecl/driver/ToolHelp.hpp @@ -2,7 +2,7 @@ #define CTOOL_HELP #include "ToolBase.hpp" -#include +#include #include class ToolHelp final : public ToolBase @@ -66,16 +66,8 @@ public: helpFunc = ToolSpec::Help; else if (toolName == _S("extract")) helpFunc = ToolExtract::Help; - else if (toolName == _S("add")) - helpFunc = ToolAdd::Help; - else if (toolName == _S("remove") || toolName == _S("rm")) - helpFunc = ToolRemove::Help; - else if (toolName == _S("group")) - helpFunc = ToolGroup::Help; else if (toolName == _S("cook")) helpFunc = ToolCook::Help; - else if (toolName == _S("clean")) - helpFunc = ToolClean::Help; else if (toolName == _S("package") || toolName == _S("pack")) helpFunc = ToolPackage::Help; else if (toolName == _S("help")) diff --git a/hecl/driver/ToolInit.hpp b/hecl/driver/ToolInit.hpp index b88950e53..72172617c 100644 --- a/hecl/driver/ToolInit.hpp +++ b/hecl/driver/ToolInit.hpp @@ -2,7 +2,7 @@ #define CTOOL_INIT #include "ToolBase.hpp" -#include +#include class ToolInit final : public ToolBase { diff --git a/hecl/driver/ToolPackage.hpp b/hecl/driver/ToolPackage.hpp index 02a8770b5..10102386a 100644 --- a/hecl/driver/ToolPackage.hpp +++ b/hecl/driver/ToolPackage.hpp @@ -4,7 +4,7 @@ #include #include #include "ToolBase.hpp" -#include +#include class ToolPackage final : public ToolBase { diff --git a/hecl/driver/ToolRemove.hpp b/hecl/driver/ToolRemove.hpp deleted file mode 100644 index 3c59363c7..000000000 --- a/hecl/driver/ToolRemove.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef CTOOL_REMOVE -#define CTOOL_REMOVE - -#include "ToolBase.hpp" -#include - -class ToolRemove final : public ToolBase -{ -public: - ToolRemove(const ToolPassInfo& info) - : ToolBase(info) - { - } - - ~ToolRemove() - { - } - - static void Help(HelpOutput& help) - { - help.secHead(_S("NAME")); - help.beginWrap(); - help.wrap(_S("hecl-rm\n")); - help.wrap(_S("hecl-remove - Remove working files from the HECL index\n")); - help.endWrap(); - - help.secHead(_S("SYNOPSIS")); - help.beginWrap(); - help.wrap(_S("hecl remove [-r] [...]\n")); - help.endWrap(); - - help.secHead(_S("DESCRIPTION")); - help.beginWrap(); - help.wrap(_S("This command removes a file, directory, or glob-pattern of files from the project database. ") - _S("Once a file is removed, any cooked cache objects are deleted automatically. ")); - help.wrapBold(_S("The working file itself is not deleted from the filesystem.\n")); - help.endWrap(); - - help.secHead(_S("OPTIONS")); - help.optionHead(_S("..."), _S("input file(s)")); - help.beginWrap(); - help.wrap(_S("Working file(s) to be removed from the project database. ") - _S("Glob-strings may be specified (e.g. ")); - help.wrapBold(_S("*.blend")); - help.wrap(_S(") to automatically remove all matching files from the database.\n")); - help.endWrap(); - - help.optionHead(_S("-r"), _S("recursion")); - help.beginWrap(); - help.wrap(_S("Enables recursive file-matching for removing entire directories of working files.\n")); - help.endWrap(); - } - - hecl::SystemString toolName() const {return _S("remove");} - - int run() - { - return 0; - } -}; - -#endif // CTOOL_REMOVE diff --git a/hecl/driver/ToolSpec.hpp b/hecl/driver/ToolSpec.hpp index 49014e5b6..77930284b 100644 --- a/hecl/driver/ToolSpec.hpp +++ b/hecl/driver/ToolSpec.hpp @@ -2,7 +2,7 @@ #define CTOOL_SPEC #include "ToolBase.hpp" -#include +#include #include class ToolSpec final : public ToolBase diff --git a/hecl/driver/main.cpp b/hecl/driver/main.cpp index 512c9ff92..2d1873ad1 100644 --- a/hecl/driver/main.cpp +++ b/hecl/driver/main.cpp @@ -7,15 +7,15 @@ #endif #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include #include "hecl/Database.hpp" -#include "hecl/Blender/BlenderConnection.hpp" +#include "hecl/Blender/Connection.hpp" #include "logvisor/logvisor.hpp" logvisor::Module LogModule("hecl::Driver"); @@ -24,11 +24,7 @@ logvisor::Module LogModule("hecl::Driver"); #include "ToolInit.hpp" #include "ToolSpec.hpp" #include "ToolExtract.hpp" -#include "ToolAdd.hpp" -#include "ToolRemove.hpp" -#include "ToolGroup.hpp" #include "ToolCook.hpp" -#include "ToolClean.hpp" #include "ToolPackage.hpp" #include "ToolHelp.hpp" @@ -58,7 +54,7 @@ static void printHelp(const hecl::SystemChar* pname) #elif HECL_VER hecl::Printf(_S(" Version " HECL_VER_S "\nUsage: %s extract|init|add|remove|group|cook|clean|package|help\n"), pname); #else - hecl::Printf(_S("\nUsage: %s extract|init|add|remove|group|cook|clean|package|help\n"), pname); + hecl::Printf(_S("\nUsage: %s extract|init|cook|package|help\n"), pname); #endif } @@ -68,7 +64,7 @@ static const hecl::SystemRegex regOPEN(_S("-o([^\"]*|\\S*)"), std::regex::ECMASc /* SIGINT will gracefully close blender connections and delete blends in progress */ static void SIGINTHandler(int sig) { - hecl::BlenderConnection::Shutdown(); + hecl::blender::Connection::Shutdown(); exit(1); } @@ -259,16 +255,8 @@ int main(int argc, const char** argv) tool.reset(new ToolSpec(info)); else if (toolName == _S("extract")) tool.reset(new ToolExtract(info)); - else if (toolName == _S("add")) - tool.reset(new ToolAdd(info)); - else if (toolName == _S("remove") || toolName == _S("rm")) - tool.reset(new ToolRemove(info)); - else if (toolName == _S("group")) - tool.reset(new ToolGroup(info)); else if (toolName == _S("cook")) tool.reset(new ToolCook(info)); - else if (toolName == _S("clean")) - tool.reset(new ToolClean(info)); else if (toolName == _S("package") || toolName == _S("pack")) tool.reset(new ToolPackage(info)); else if (toolName == _S("help")) @@ -304,14 +292,14 @@ int main(int argc, const char** argv) int retval = tool->run(); if (logvisor::ErrorCount > ErrorRef) { - hecl::BlenderConnection::Shutdown(); + hecl::blender::Connection::Shutdown(); #if WIN_PAUSE system("PAUSE"); #endif return -1; } - hecl::BlenderConnection::Shutdown(); + hecl::blender::Connection::Shutdown(); #if WIN_PAUSE system("PAUSE"); #endif diff --git a/hecl/extern/athena b/hecl/extern/athena index cee947877..017a921fd 160000 --- a/hecl/extern/athena +++ b/hecl/extern/athena @@ -1 +1 @@ -Subproject commit cee9478773927a99ce40e625b9cc20bfdea32597 +Subproject commit 017a921fdc0207590df519093fc06362ab04d457 diff --git a/hecl/extern/boo b/hecl/extern/boo index 867665cc7..fa8989bed 160000 --- a/hecl/extern/boo +++ b/hecl/extern/boo @@ -1 +1 @@ -Subproject commit 867665cc782cf2f5a9ade477904c95692f4b1ae1 +Subproject commit fa8989bed30bd5022c4951ae46adc4de50a261f1 diff --git a/hecl/extern/libpng/pngconf.h b/hecl/extern/libpng/pngconf.h index f1b795b47..860e3e112 100644 --- a/hecl/extern/libpng/pngconf.h +++ b/hecl/extern/libpng/pngconf.h @@ -47,8 +47,12 @@ #ifdef PNG_SETJMP_SUPPORTED /* Required for the definition of jmp_buf and the declaration of longjmp: */ +#ifdef __cplusplus +# include +#else # include #endif +#endif #ifdef PNG_CONVERT_tIME_SUPPORTED /* Required for struct tm: */ diff --git a/hecl/include/hecl/Backend/Backend.hpp b/hecl/include/hecl/Backend/Backend.hpp index 1ca3f97e2..fb02820d4 100644 --- a/hecl/include/hecl/Backend/Backend.hpp +++ b/hecl/include/hecl/Backend/Backend.hpp @@ -3,9 +3,7 @@ #include "hecl/Frontend.hpp" -namespace hecl -{ -namespace Backend +namespace hecl::Backend { using IR = Frontend::IR; @@ -76,7 +74,6 @@ public: virtual void reset(const IR& ir, Diagnostics& diag)=0; }; -} } #endif // HECLBACKEND_HPP diff --git a/hecl/include/hecl/Backend/GLSL.hpp b/hecl/include/hecl/Backend/GLSL.hpp index e415836b0..4367a6d64 100644 --- a/hecl/include/hecl/Backend/GLSL.hpp +++ b/hecl/include/hecl/Backend/GLSL.hpp @@ -3,9 +3,7 @@ #include "ProgrammableCommon.hpp" -namespace hecl -{ -namespace Backend +namespace hecl::Backend { #define HECL_GLSL_VERT_UNIFORM_BLOCK_NAME "HECLVertUniform" @@ -46,7 +44,6 @@ private: std::string EmitTexGenSource4(TexGenSrc src, int uvIdx) const; }; -} } #endif // HECLBACKEND_GLSL_HPP diff --git a/hecl/include/hecl/Backend/GX.hpp b/hecl/include/hecl/Backend/GX.hpp index 8c8e45bd0..b8a57a175 100644 --- a/hecl/include/hecl/Backend/GX.hpp +++ b/hecl/include/hecl/Backend/GX.hpp @@ -3,16 +3,14 @@ #include "Backend.hpp" #include -#include -#include +#include +#include #include #undef min #undef max -namespace hecl -{ -namespace Backend +namespace hecl::Backend { struct GX : IBackend @@ -573,7 +571,6 @@ private: TexMtx mtx, bool normalize, PTTexMtx pmtx); }; -} } #endif // HECLBACKEND_GX_HPP diff --git a/hecl/include/hecl/Backend/HLSL.hpp b/hecl/include/hecl/Backend/HLSL.hpp index 3def0e30e..f4ac0a7fb 100644 --- a/hecl/include/hecl/Backend/HLSL.hpp +++ b/hecl/include/hecl/Backend/HLSL.hpp @@ -3,9 +3,7 @@ #include "ProgrammableCommon.hpp" -namespace hecl -{ -namespace Backend +namespace hecl::Backend { struct HLSL : ProgrammableCommon @@ -42,7 +40,6 @@ private: std::string EmitTexGenSource4(TexGenSrc src, int uvIdx) const; }; -} } #endif // HECLBACKEND_HLSL_HPP diff --git a/hecl/include/hecl/Backend/Metal.hpp b/hecl/include/hecl/Backend/Metal.hpp index d3c190201..dd644d25f 100644 --- a/hecl/include/hecl/Backend/Metal.hpp +++ b/hecl/include/hecl/Backend/Metal.hpp @@ -5,9 +5,7 @@ #include "ProgrammableCommon.hpp" -namespace hecl -{ -namespace Backend +namespace hecl::Backend { struct Metal : ProgrammableCommon @@ -46,7 +44,6 @@ private: std::string EmitTexGenSource4(TexGenSrc src, int uvIdx) const; }; -} } #endif // BOO_HAS_METAL diff --git a/hecl/include/hecl/Backend/ProgrammableCommon.hpp b/hecl/include/hecl/Backend/ProgrammableCommon.hpp index 76c234053..3ec72978d 100644 --- a/hecl/include/hecl/Backend/ProgrammableCommon.hpp +++ b/hecl/include/hecl/Backend/ProgrammableCommon.hpp @@ -4,13 +4,11 @@ #include "Backend.hpp" #include "hecl/Runtime.hpp" #include -#include -#include +#include +#include #include -namespace hecl -{ -namespace Backend +namespace hecl::Backend { struct ProgrammableCommon : IBackend @@ -137,7 +135,6 @@ private: const std::string& a, const atInt8 swiz[4]) const; }; -} } #endif // HECLBACKEND_PROGCOMMON_HPP diff --git a/hecl/include/hecl/Blender/BlenderConnection.hpp b/hecl/include/hecl/Blender/BlenderConnection.hpp deleted file mode 100644 index 8dd7402fe..000000000 --- a/hecl/include/hecl/Blender/BlenderConnection.hpp +++ /dev/null @@ -1,1017 +0,0 @@ -#ifndef BLENDERCONNECTION_HPP -#define BLENDERCONNECTION_HPP - -#if _WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include -#else -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hecl/hecl.hpp" -#include "hecl/HMDLMeta.hpp" -#include -#include -#include "optional.hpp" - -namespace hecl -{ - -extern logvisor::Module BlenderLog; -extern class BlenderToken SharedBlenderToken; -class HMDLBuffers; - -struct PoolSkinIndex -{ - size_t m_poolSz = 0; - std::unique_ptr m_poolToSkinIndex; - - void allocate(size_t poolSz) - { - m_poolSz = poolSz; - if (poolSz) - m_poolToSkinIndex.reset(new uint32_t[poolSz]); - } -}; - -class BlenderConnection -{ -public: - enum class BlendType - { - None, - Mesh, - ColMesh, - Actor, - Area, - World, - MapArea, - MapUniverse, - Frame - }; -private: - std::atomic_bool m_lock = {false}; - bool m_pyStreamActive = false; - bool m_dataStreamActive = false; -#if _WIN32 - PROCESS_INFORMATION m_pinfo = {}; - std::thread m_consoleThread; - bool m_consoleThreadRunning = true; -#else - pid_t m_blenderProc = 0; -#endif - int m_readpipe[2]; - int m_writepipe[2]; - bool m_hasSlerp; - BlendType m_loadedType = BlendType::None; - bool m_loadedRigged = false; - ProjectPath m_loadedBlend; - std::string m_startupBlend; - hecl::SystemString m_errPath; - uint32_t _readStr(char* buf, uint32_t bufSz); - uint32_t _writeStr(const char* str, uint32_t len, int wpipe); - uint32_t _writeStr(const char* str, uint32_t len) { return _writeStr(str, len, m_writepipe[1]); } - uint32_t _writeStr(const char* str) { return _writeStr(str, strlen(str)); } - size_t _readBuf(void* buf, size_t len); - size_t _writeBuf(const void* buf, size_t len); - void _closePipe(); - void _blenderDied(); - -public: - BlenderConnection(int verbosityLevel=1); - ~BlenderConnection(); - - BlenderConnection(const BlenderConnection&)=delete; - BlenderConnection& operator=(const BlenderConnection&)=delete; - BlenderConnection(BlenderConnection&&)=delete; - BlenderConnection& operator=(BlenderConnection&&)=delete; - - bool hasSLERP() const {return m_hasSlerp;} - - bool createBlend(const ProjectPath& path, BlendType type); - BlendType getBlendType() const {return m_loadedType;} - bool getRigged() const {return m_loadedRigged;} - bool openBlend(const ProjectPath& path, bool force=false); - bool saveBlend(); - void deleteBlend(); - - enum class ANIMCurveType - { - Rotate, - Translate, - Scale - }; - - class PyOutStream : public std::ostream - { - friend class BlenderConnection; - BlenderConnection* m_parent; - bool m_deleteOnError; - struct StreamBuf : std::streambuf - { - PyOutStream& m_parent; - std::string m_lineBuf; - bool m_deleteOnError; - StreamBuf(PyOutStream& parent, bool deleteOnError) - : m_parent(parent), m_deleteOnError(deleteOnError) {} - StreamBuf(const StreamBuf& other) = delete; - StreamBuf(StreamBuf&& other) = default; - int_type overflow(int_type ch); - } m_sbuf; - PyOutStream(BlenderConnection* parent, bool deleteOnError) - : std::ostream(&m_sbuf), - m_parent(parent), - m_deleteOnError(deleteOnError), - m_sbuf(*this, deleteOnError) - { - m_parent->m_pyStreamActive = true; - m_parent->_writeStr("PYBEGIN"); - char readBuf[16]; - m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "READY")) - BlenderLog.report(logvisor::Fatal, "unable to open PyOutStream with blender"); - } - public: - PyOutStream(const PyOutStream& other) = delete; - PyOutStream(PyOutStream&& other) - : std::ostream(&m_sbuf), m_parent(other.m_parent), m_sbuf(std::move(other.m_sbuf)) - {other.m_parent = nullptr;} - ~PyOutStream() {close();} - void close() - { - if (m_parent && m_parent->m_lock) - { - m_parent->_writeStr("PYEND"); - char readBuf[16]; - m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "DONE")) - BlenderLog.report(logvisor::Fatal, "unable to close PyOutStream with blender"); - m_parent->m_pyStreamActive = false; - m_parent->m_lock = false; - } - } -#if __GNUC__ - __attribute__((__format__ (__printf__, 2, 3))) -#endif - void format(const char* fmt, ...) - { - if (!m_parent || !m_parent->m_lock) - BlenderLog.report(logvisor::Fatal, "lock not held for PyOutStream::format()"); - 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 - int length = vasprintf(&result, fmt, ap); -#endif - va_end(ap); - if (length > 0) - this->write(result, length); - free(result); - } - void linkBlend(const char* target, const char* objName, bool link=true); - void linkBackground(const char* target, const char* sceneName); - - void AABBToBMesh(const atVec3f& min, const atVec3f& max) - { - format("bm = bmesh.new()\n" - "bm.verts.new((%f,%f,%f))\n" - "bm.verts.new((%f,%f,%f))\n" - "bm.verts.new((%f,%f,%f))\n" - "bm.verts.new((%f,%f,%f))\n" - "bm.verts.new((%f,%f,%f))\n" - "bm.verts.new((%f,%f,%f))\n" - "bm.verts.new((%f,%f,%f))\n" - "bm.verts.new((%f,%f,%f))\n" - "bm.verts.ensure_lookup_table()\n" - "bm.edges.new((bm.verts[0], bm.verts[1]))\n" - "bm.edges.new((bm.verts[0], bm.verts[2]))\n" - "bm.edges.new((bm.verts[0], bm.verts[4]))\n" - "bm.edges.new((bm.verts[3], bm.verts[1]))\n" - "bm.edges.new((bm.verts[3], bm.verts[2]))\n" - "bm.edges.new((bm.verts[3], bm.verts[7]))\n" - "bm.edges.new((bm.verts[5], bm.verts[1]))\n" - "bm.edges.new((bm.verts[5], bm.verts[4]))\n" - "bm.edges.new((bm.verts[5], bm.verts[7]))\n" - "bm.edges.new((bm.verts[6], bm.verts[2]))\n" - "bm.edges.new((bm.verts[6], bm.verts[4]))\n" - "bm.edges.new((bm.verts[6], bm.verts[7]))\n", - min.vec[0], min.vec[1], min.vec[2], - max.vec[0], min.vec[1], min.vec[2], - min.vec[0], max.vec[1], min.vec[2], - max.vec[0], max.vec[1], min.vec[2], - min.vec[0], min.vec[1], max.vec[2], - max.vec[0], min.vec[1], max.vec[2], - min.vec[0], max.vec[1], max.vec[2], - max.vec[0], max.vec[1], max.vec[2]); - } - - void centerView() - { - *this << "for obj in bpy.context.scene.objects:\n" - " if obj.type == 'CAMERA' or obj.type == 'LAMP':\n" - " obj.hide = True\n" - "\n" - "bpy.context.user_preferences.view.smooth_view = 0\n" - "for window in bpy.context.window_manager.windows:\n" - " screen = window.screen\n" - " for area in screen.areas:\n" - " if area.type == 'VIEW_3D':\n" - " for region in area.regions:\n" - " if region.type == 'WINDOW':\n" - " override = {'scene': bpy.context.scene, 'window': window, 'screen': screen, 'area': area, 'region': region}\n" - " bpy.ops.view3d.view_all(override)\n" - " break\n" - "\n" - "for obj in bpy.context.scene.objects:\n" - " if obj.type == 'CAMERA' or obj.type == 'LAMP':\n" - " obj.hide = False\n"; - } - - class ANIMOutStream - { - BlenderConnection* m_parent; - unsigned m_curCount = 0; - unsigned m_totalCount = 0; - bool m_inCurve = false; - public: - using CurveType = ANIMCurveType; - ANIMOutStream(BlenderConnection* parent) - : m_parent(parent) - { - m_parent->_writeStr("PYANIM"); - char readBuf[16]; - m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "ANIMREADY")) - BlenderLog.report(logvisor::Fatal, "unable to open ANIMOutStream"); - } - ~ANIMOutStream() - { - char tp = -1; - m_parent->_writeBuf(&tp, 1); - char readBuf[16]; - m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "ANIMDONE")) - BlenderLog.report(logvisor::Fatal, "unable to close ANIMOutStream"); - } - void changeCurve(CurveType type, unsigned crvIdx, unsigned keyCount) - { - if (m_curCount != m_totalCount) - BlenderLog.report(logvisor::Fatal, "incomplete ANIMOutStream for change"); - m_curCount = 0; - m_totalCount = keyCount; - char tp = char(type); - m_parent->_writeBuf(&tp, 1); - struct - { - uint32_t ci; - uint32_t kc; - } info = {uint32_t(crvIdx), uint32_t(keyCount)}; - m_parent->_writeBuf(reinterpret_cast(&info), 8); - m_inCurve = true; - } - void write(unsigned frame, float val) - { - if (!m_inCurve) - BlenderLog.report(logvisor::Fatal, "changeCurve not called before write"); - if (m_curCount < m_totalCount) - { - struct - { - uint32_t frm; - float val; - } key = {uint32_t(frame), val}; - m_parent->_writeBuf(reinterpret_cast(&key), 8); - ++m_curCount; - } - else - BlenderLog.report(logvisor::Fatal, "ANIMOutStream keyCount overflow"); - } - }; - ANIMOutStream beginANIMCurve() - { - return ANIMOutStream(m_parent); - } - BlenderConnection& getConnection() {return *m_parent;} - }; - PyOutStream beginPythonOut(bool deleteOnError=false) - { - bool expect = false; - if (!m_lock.compare_exchange_strong(expect, true)) - BlenderLog.report(logvisor::Fatal, "lock already held for BlenderConnection::beginPythonOut()"); - return PyOutStream(this, deleteOnError); - } - - class DataStream - { - friend class BlenderConnection; - BlenderConnection* m_parent; - DataStream(BlenderConnection* parent) - : m_parent(parent) - { - m_parent->m_dataStreamActive = true; - m_parent->_writeStr("DATABEGIN"); - char readBuf[16]; - m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "READY")) - BlenderLog.report(logvisor::Fatal, "unable to open DataStream with blender"); - } - public: - DataStream(const DataStream& other) = delete; - DataStream(DataStream&& other) - : m_parent(other.m_parent) {other.m_parent = nullptr;} - ~DataStream() {close();} - void close() - { - if (m_parent && m_parent->m_lock) - { - m_parent->_writeStr("DATAEND"); - char readBuf[16]; - m_parent->_readStr(readBuf, 16); - if (strcmp(readBuf, "DONE")) - BlenderLog.report(logvisor::Fatal, "unable to close DataStream with blender"); - m_parent->m_dataStreamActive = false; - m_parent->m_lock = false; - } - } - - std::vector getMeshList() - { - m_parent->_writeStr("MESHLIST"); - uint32_t count; - m_parent->_readBuf(&count, 4); - std::vector retval; - retval.reserve(count); - for (uint32_t i=0 ; i_readStr(name, 128); - retval.push_back(name); - } - return retval; - } - - std::vector getLightList() - { - m_parent->_writeStr("LIGHTLIST"); - uint32_t count; - m_parent->_readBuf(&count, 4); - std::vector retval; - retval.reserve(count); - for (uint32_t i=0 ; i_readStr(name, 128); - retval.push_back(name); - } - return retval; - } - - std::pair getMeshAABB() - { - if (m_parent->m_loadedType != BlendType::Mesh && - m_parent->m_loadedType != BlendType::Actor) - BlenderLog.report(logvisor::Fatal, _S("%s is not a MESH or ACTOR blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); - - m_parent->_writeStr("MESHAABB"); - char readBuf[256]; - m_parent->_readStr(readBuf, 256); - if (strcmp(readBuf, "OK")) - BlenderLog.report(logvisor::Fatal, "unable get AABB: %s", readBuf); - - Vector3f minPt(*m_parent); - Vector3f maxPt(*m_parent); - return std::make_pair(minPt.val, maxPt.val); - } - - /* Vector types with integrated stream reading constructor */ - struct Vector2f - { - atVec2f val; - Vector2f() = default; - void read(BlenderConnection& conn) {conn._readBuf(&val, 8);} - Vector2f(BlenderConnection& conn) {read(conn);} - operator const atVec2f&() const {return val;} - }; - struct Vector3f - { - atVec3f val; - Vector3f() = default; - void read(BlenderConnection& conn) {conn._readBuf(&val, 12);} - Vector3f(BlenderConnection& conn) {read(conn);} - operator const atVec3f&() const {return val;} - }; - struct Vector4f - { - atVec4f val; - Vector4f() = default; - void read(BlenderConnection& conn) {conn._readBuf(&val, 16);} - Vector4f(BlenderConnection& conn) {read(conn);} - operator const atVec4f&() const {return val;} - }; - struct Matrix4f - { - atVec4f val[4]; - Matrix4f() = default; - void read(BlenderConnection& conn) {conn._readBuf(&val, 64);} - Matrix4f(BlenderConnection& conn) {read(conn);} - const atVec4f& operator[] (size_t idx) const {return val[idx];} - }; - struct Index - { - uint32_t val; - Index() = default; - void read(BlenderConnection& conn) {conn._readBuf(&val, 4);} - Index(BlenderConnection& conn) {read(conn);} - operator const uint32_t&() const {return val;} - }; - - static atVec3f MtxVecMul4RM(const Matrix4f& mtx, const Vector3f& vec); - static atVec3f MtxVecMul3RM(const Matrix4f& mtx, const Vector3f& vec); - - /** Intermediate mesh representation prepared by blender from a single mesh object */ - struct Mesh - { - HMDLTopology topology; - - /* Object transform in scene */ - Matrix4f sceneXf; - - /* Cumulative AABB */ - Vector3f aabbMin; - Vector3f aabbMax; - - /** HECL source and metadata of each material */ - struct Material - { - std::string name; - std::string source; - std::vector texs; - std::unordered_map iprops; - bool transparent; - - Material(BlenderConnection& conn); - bool operator==(const Material& other) const - { - return source == other.source && texs == other.texs && iprops == other.iprops; - } - }; - std::vector> materialSets; - - /* Vertex buffer data */ - std::vector pos; - std::vector norm; - uint32_t colorLayerCount = 0; - std::vector color; - uint32_t uvLayerCount = 0; - std::vector uv; - - /* Skinning data */ - std::vector boneNames; - struct SkinBind - { - uint32_t boneIdx; - float weight; - SkinBind(BlenderConnection& conn) {conn._readBuf(&boneIdx, 8);} - }; - std::vector> skins; - std::vector contiguousSkinVertCounts; - - void normalizeSkinBinds(); - - /** Islands of the same material/skinBank are represented here */ - struct Surface - { - Vector3f centroid; - Index materialIdx; - Vector3f aabbMin; - Vector3f aabbMax; - Vector3f reflectionNormal; - uint32_t skinBankIdx; - - /** Vertex indexing data (all primitives joined as degenerate tri-strip) */ - struct Vert - { - uint32_t iPos; - uint32_t iNorm; - uint32_t iColor[4] = {uint32_t(-1)}; - uint32_t iUv[8] = {uint32_t(-1)}; - uint32_t iSkin; - uint32_t iBankSkin = -1; - - Vert(BlenderConnection& conn, const Mesh& parent); - - bool operator==(const Vert& other) const - { - if (iPos != other.iPos) - return false; - if (iNorm != other.iNorm) - return false; - for (int i=0 ; i<4 ; ++i) - if (iColor[i] != other.iColor[i]) - return false; - for (int i=0 ; i<8 ; ++i) - if (iUv[i] != other.iUv[i]) - return false; - if (iSkin != other.iSkin) - return false; - return true; - } - }; - std::vector verts; - - Surface(BlenderConnection& conn, Mesh& parent, int skinSlotCount); - }; - std::vector surfaces; - - std::unordered_map customProps; - - struct SkinBanks - { - struct Bank - { - std::vector m_skinIdxs; - std::vector m_boneIdxs; - - void addSkins(const Mesh& parent, const std::vector& skinIdxs) - { - for (uint32_t sidx : skinIdxs) - { - m_skinIdxs.push_back(sidx); - for (const SkinBind& bind : parent.skins[sidx]) - { - bool found = false; - for (uint32_t bidx : m_boneIdxs) - { - if (bidx == bind.boneIdx) - { - found = true; - break; - } - } - if (!found) - m_boneIdxs.push_back(bind.boneIdx); - } - } - } - - size_t lookupLocalBoneIdx(uint32_t boneIdx) const - { - for (size_t i=0 ; i banks; - std::vector::iterator addSkinBank(int skinSlotCount) - { - banks.emplace_back(); - if (skinSlotCount > 0) - banks.back().m_skinIdxs.reserve(skinSlotCount); - return banks.end() - 1; - } - uint32_t addSurface(const Mesh& mesh, const Surface& surf, int skinSlotCount); - } skinBanks; - - using SurfProgFunc = std::function; - Mesh(BlenderConnection& conn, HMDLTopology topology, int skinSlotCount, SurfProgFunc& surfProg); - - Mesh getContiguousSkinningVersion() const; - - /** Prepares mesh representation for indexed access on modern APIs. - * Mesh must remain resident for accessing reference members - */ - HMDLBuffers getHMDLBuffers(bool absoluteCoords, PoolSkinIndex& poolSkinIndex) const; - }; - - /** Intermediate collision mesh representation prepared by blender from a single mesh object */ - struct ColMesh - { - /** HECL source and metadata of each material */ - struct Material - { - std::string name; - bool unknown; - bool surfaceStone; - bool surfaceMetal; - bool surfaceGrass; - bool surfaceIce; - bool pillar; - bool surfaceMetalGrating; - bool surfacePhazon; - bool surfaceDirt; - bool surfaceLava; - bool surfaceSPMetal; - bool surfaceStoneRock; - bool surfaceSnow; - bool surfaceMudSlow; - bool surfaceFabric; - bool halfPipe; - bool surfaceMud; - bool surfaceGlass; - bool unused3; - bool unused4; - bool surfaceShield; - bool surfaceSand; - bool surfaceMothOrSeedOrganics; - bool surfaceWeb; - bool projPassthrough; - bool solid; - bool u20; - bool camPassthrough; - bool surfaceWood; - bool surfaceOrganic; - bool u24; - bool surfaceRubber; - bool seeThrough; - bool scanPassthrough; - bool aiPassthrough; - bool ceiling; - bool wall; - bool floor; - bool aiBlock; - bool jumpNotAllowed; - bool spiderBall; - bool screwAttackWallJump; - - Material(BlenderConnection& conn); - }; - std::vector materials; - - std::vector verts; - - struct Edge - { - uint32_t verts[2]; - bool seam; - Edge(BlenderConnection& conn); - }; - std::vector edges; - - struct Triangle - { - uint32_t edges[3]; - uint32_t matIdx; - bool flip; - Triangle(BlenderConnection& conn); - }; - std::vector trianges; - - ColMesh(BlenderConnection& conn); - }; - - /** Intermediate world representation */ - struct World - { - struct Area - { - ProjectPath path; - Vector3f aabb[2]; - Matrix4f transform; - struct Dock - { - Vector3f verts[4]; - Index targetArea; - Index targetDock; - Dock(BlenderConnection& conn); - }; - std::vector docks; - Area(BlenderConnection& conn); - }; - std::vector areas; - World(BlenderConnection& conn); - }; - - /** Intermediate lamp representation */ - struct Light - { - /* Object transform in scene */ - Matrix4f sceneXf; - Vector3f color; - - uint32_t layer; - - enum class Type : uint32_t - { - Ambient, - Directional, - Custom, - Spot - } type; - - float energy; - float spotCutoff; - float constant; - float linear; - float quadratic; - bool shadow; - - std::string name; - - Light(BlenderConnection& conn); - }; - - /** Intermediate MapArea representation */ - struct MapArea - { - Index visType; - std::vector verts; - std::vector indices; - struct Surface - { - Vector3f normal; - Vector3f centerOfMass; - Index start; - Index count; - std::vector> borders; - Surface(BlenderConnection& conn); - }; - std::vector surfaces; - struct POI - { - uint32_t type; - uint32_t visMode; - uint32_t objid; - Matrix4f xf; - POI(BlenderConnection& conn); - }; - std::vector pois; - MapArea(BlenderConnection& conn); - }; - - /** Intermediate MapUniverse representation */ - struct MapUniverse - { - hecl::ProjectPath hexagonPath; - struct World - { - std::string name; - Matrix4f xf; - std::vector hexagons; - Vector4f color; - hecl::ProjectPath worldPath; - World(BlenderConnection& conn); - }; - std::vector worlds; - MapUniverse(BlenderConnection& conn); - }; - - static const char* MeshOutputModeString(HMDLTopology topology) - { - static const char* STRS[] = {"TRIANGLES", "TRISTRIPS"}; - return STRS[int(topology)]; - } - - - /** Compile mesh by context (MESH blends only) */ - Mesh compileMesh(HMDLTopology topology, int skinSlotCount=10, - Mesh::SurfProgFunc surfProg=[](int){}); - - /** Compile mesh by name (AREA blends only) */ - Mesh compileMesh(std::string_view name, HMDLTopology topology, int skinSlotCount=10, - Mesh::SurfProgFunc surfProg=[](int){}); - - /** Compile collision mesh by name (AREA blends only) */ - ColMesh compileColMesh(std::string_view name); - - /** Compile all meshes as collision meshes (CMESH blends only) */ - std::vector compileColMeshes(); - - /** Compile all meshes into one (AREA blends only) */ - Mesh compileAllMeshes(HMDLTopology topology, int skinSlotCount=10, float maxOctantLength=5.0, - Mesh::SurfProgFunc surfProg=[](int){}); - - /** Compile world intermediate (WORLD blends only) */ - World compileWorld(); - - /** Gather all lights in scene (AREA blends only) */ - std::vector compileLights(); - - /** Compile GUI into FRME data (FRAME blends only) */ - void compileGuiFrame(std::string_view pathOut, int version); - - /** Gather all texture paths in scene */ - std::vector getTextures(); - - /** Intermediate actor representation prepared by blender from a single HECL actor blend */ - struct Actor - { - struct Armature - { - std::string name; - struct Bone - { - std::string name; - Vector3f origin; - int32_t parent = -1; - std::vector children; - Bone(BlenderConnection& conn); - }; - std::vector bones; - const Bone* lookupBone(const char* name) const - { - for (const Bone& b : bones) - if (!b.name.compare(name)) - return &b; - return nullptr; - } - const Bone* getParent(const Bone* bone) const - { - if (bone->parent < 0) - return nullptr; - return &bones[bone->parent]; - } - const Bone* getChild(const Bone* bone, size_t child) const - { - if (child >= bone->children.size()) - return nullptr; - int32_t cIdx = bone->children[child]; - if (cIdx < 0) - return nullptr; - return &bones[cIdx]; - } - const Bone* getRoot() const - { - for (const Bone& b : bones) - if (b.parent < 0) - return &b; - return nullptr; - } - Armature(BlenderConnection& conn); - }; - std::vector armatures; - - struct Subtype - { - std::string name; - ProjectPath mesh; - int32_t armature = -1; - std::vector> overlayMeshes; - Subtype(BlenderConnection& conn); - }; - std::vector subtypes; - - struct Action - { - std::string name; - float interval; - bool additive; - bool looping; - std::vector frames; - struct Channel - { - std::string boneName; - uint32_t attrMask; - struct Key - { - Vector4f rotation; - Vector3f position; - Vector3f scale; - Key(BlenderConnection& conn, uint32_t attrMask); - }; - std::vector keys; - Channel(BlenderConnection& conn); - }; - std::vector channels; - std::vector> subtypeAABBs; - Action(BlenderConnection& conn); - }; - std::vector actions; - - Actor(BlenderConnection& conn); - }; - - Actor compileActor(); - Actor compileActorCharacterOnly(); - Actor::Action compileActionChannelsOnly(std::string_view name); - std::vector getArmatureNames(); - std::vector getSubtypeNames(); - std::vector getActionNames(); - std::vector getSubtypeOverlayNames(std::string_view name); - - struct Matrix3f - { - atVec3f m[3]; - inline atVec3f& operator[](size_t idx) {return m[idx];} - inline const atVec3f& operator[](size_t idx) const {return m[idx];} - }; - std::unordered_map getBoneMatrices(std::string_view name); - - bool renderPvs(std::string_view path, const atVec3f& location); - bool renderPvsLight(std::string_view path, std::string_view lightName); - - MapArea compileMapArea(); - MapUniverse compileMapUniverse(); - }; - DataStream beginData() - { - bool expect = false; - if (!m_lock.compare_exchange_strong(expect, true)) - BlenderLog.report(logvisor::Fatal, "lock already held for BlenderConnection::beginDataIn()"); - return DataStream(this); - } - - void quitBlender(); - - void closeStream() - { - if (m_lock) - deleteBlend(); - } - - static BlenderConnection& SharedConnection(); - static void Shutdown(); -}; - -class BlenderToken -{ - std::unique_ptr m_conn; -public: - BlenderConnection& getBlenderConnection() - { - if (!m_conn) - m_conn = std::make_unique(hecl::VerbosityLevel); - return *m_conn; - } - void shutdown() - { - if (m_conn) - { - m_conn->quitBlender(); - m_conn.reset(); - BlenderLog.report(logvisor::Info, "BlenderConnection Shutdown Successful"); - } - } - - BlenderToken() = default; - ~BlenderToken() { shutdown(); } - BlenderToken(const BlenderToken&)=delete; - BlenderToken& operator=(const BlenderToken&)=delete; - BlenderToken(BlenderToken&&)=default; - BlenderToken& operator=(BlenderToken&&)=default; -}; - -class HMDLBuffers -{ -public: - struct Surface; -private: - friend struct BlenderConnection::DataStream::Mesh; - HMDLBuffers(HMDLMeta&& meta, - size_t vboSz, const std::vector& iboData, - std::vector&& surfaces, - const BlenderConnection::DataStream::Mesh::SkinBanks& skinBanks) - : m_meta(std::move(meta)), - m_vboSz(vboSz), m_vboData(new uint8_t[vboSz]), - m_iboSz(iboData.size()*4), m_iboData(new uint8_t[iboData.size()*4]), - m_surfaces(std::move(surfaces)), m_skinBanks(skinBanks) - { - if (m_iboSz) - { - athena::io::MemoryWriter w(m_iboData.get(), m_iboSz); - w.enumerateLittle(iboData); - } - } -public: - HMDLMeta m_meta; - size_t m_vboSz; - std::unique_ptr m_vboData; - size_t m_iboSz; - std::unique_ptr m_iboData; - - struct Surface - { - Surface(const BlenderConnection::DataStream::Mesh::Surface& origSurf, - atUint32 start, atUint32 count) - : m_origSurf(origSurf), m_start(start), m_count(count) {} - const BlenderConnection::DataStream::Mesh::Surface& m_origSurf; - atUint32 m_start; - atUint32 m_count; - }; - std::vector m_surfaces; - - const BlenderConnection::DataStream::Mesh::SkinBanks& m_skinBanks; -}; - -} - -#endif // BLENDERCONNECTION_HPP diff --git a/hecl/include/hecl/Blender/Connection.hpp b/hecl/include/hecl/Blender/Connection.hpp new file mode 100644 index 000000000..67c72434f --- /dev/null +++ b/hecl/include/hecl/Blender/Connection.hpp @@ -0,0 +1,706 @@ +#ifndef BLENDERCONNECTION_HPP +#define BLENDERCONNECTION_HPP + +#if _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hecl/hecl.hpp" +#include "hecl/HMDLMeta.hpp" +#include "athena/Types.hpp" +#include "athena/MemoryWriter.hpp" +#include "optional.hpp" +#include "Token.hpp" + +namespace hecl::blender +{ + +extern logvisor::Module BlenderLog; +class HMDLBuffers; +class Connection; + +struct PoolSkinIndex +{ + size_t m_poolSz = 0; + std::unique_ptr m_poolToSkinIndex; + + void allocate(size_t poolSz) + { + m_poolSz = poolSz; + if (poolSz) + m_poolToSkinIndex.reset(new uint32_t[poolSz]); + } +}; + +enum class ANIMCurveType +{ + Rotate, + Translate, + Scale +}; + +class ANIMOutStream +{ + Connection* m_parent; + unsigned m_curCount = 0; + unsigned m_totalCount = 0; + bool m_inCurve = false; +public: + using CurveType = ANIMCurveType; + ANIMOutStream(Connection* parent); + ~ANIMOutStream(); + void changeCurve(CurveType type, unsigned crvIdx, unsigned keyCount); + void write(unsigned frame, float val); +}; + +class PyOutStream : public std::ostream +{ + friend class Connection; + Connection* m_parent; + bool m_deleteOnError; + struct StreamBuf : std::streambuf + { + PyOutStream& m_parent; + std::string m_lineBuf; + bool m_deleteOnError; + StreamBuf(PyOutStream& parent, bool deleteOnError) + : m_parent(parent), m_deleteOnError(deleteOnError) {} + StreamBuf(const StreamBuf& other) = delete; + StreamBuf(StreamBuf&& other) = default; + int_type overflow(int_type ch); + } m_sbuf; + PyOutStream(Connection* parent, bool deleteOnError); +public: + PyOutStream(const PyOutStream& other) = delete; + PyOutStream(PyOutStream&& other) + : std::ostream(&m_sbuf), m_parent(other.m_parent), m_sbuf(std::move(other.m_sbuf)) + {other.m_parent = nullptr;} + ~PyOutStream() {close();} + void close(); +#if __GNUC__ + __attribute__((__format__ (__printf__, 2, 3))) +#endif + void format(const char* fmt, ...); + void linkBlend(const char* target, const char* objName, bool link=true); + void linkBackground(const char* target, const char* sceneName); + void AABBToBMesh(const atVec3f& min, const atVec3f& max); + void centerView(); + + ANIMOutStream beginANIMCurve() + { + return ANIMOutStream(m_parent); + } + Connection& getConnection() {return *m_parent;} +}; + +/* Vector types with integrated stream reading constructor */ +struct Vector2f +{ + atVec2f val; + Vector2f() = default; + void read(Connection& conn); + Vector2f(Connection& conn) {read(conn);} + operator const atVec2f&() const {return val;} +}; +struct Vector3f +{ + atVec3f val; + Vector3f() = default; + void read(Connection& conn); + Vector3f(Connection& conn) {read(conn);} + operator const atVec3f&() const {return val;} +}; +struct Vector4f +{ + atVec4f val; + Vector4f() = default; + void read(Connection& conn); + Vector4f(Connection& conn) {read(conn);} + operator const atVec4f&() const {return val;} +}; +struct Matrix3f +{ + atVec3f m[3]; + inline atVec3f& operator[](size_t idx) {return m[idx];} + inline const atVec3f& operator[](size_t idx) const {return m[idx];} +}; +struct Matrix4f +{ + atVec4f val[4]; + Matrix4f() = default; + void read(Connection& conn); + Matrix4f(Connection& conn) {read(conn);} + const atVec4f& operator[] (size_t idx) const {return val[idx];} +}; +struct Index +{ + uint32_t val; + Index() = default; + void read(Connection& conn); + Index(Connection& conn) {read(conn);} + operator const uint32_t&() const {return val;} +}; + +atVec3f MtxVecMul4RM(const Matrix4f& mtx, const Vector3f& vec); +atVec3f MtxVecMul3RM(const Matrix4f& mtx, const Vector3f& vec); + +/** HECL source and metadata of each material */ +struct Material +{ + std::string name; + std::string source; + std::vector texs; + std::unordered_map iprops; + bool transparent; + + Material(Connection& conn); + bool operator==(const Material& other) const + { + return source == other.source && texs == other.texs && iprops == other.iprops; + } +}; + +/** Intermediate mesh representation prepared by blender from a single mesh object */ +struct Mesh +{ + HMDLTopology topology; + + /* Object transform in scene */ + Matrix4f sceneXf; + + /* Cumulative AABB */ + Vector3f aabbMin; + Vector3f aabbMax; + + std::vector> materialSets; + + /* Vertex buffer data */ + std::vector pos; + std::vector norm; + uint32_t colorLayerCount = 0; + std::vector color; + uint32_t uvLayerCount = 0; + std::vector uv; + + /* Skinning data */ + std::vector boneNames; + struct SkinBind + { + uint32_t boneIdx; + float weight; + SkinBind(Connection& conn); + }; + std::vector> skins; + std::vector contiguousSkinVertCounts; + + void normalizeSkinBinds(); + + /** Islands of the same material/skinBank are represented here */ + struct Surface + { + Vector3f centroid; + Index materialIdx; + Vector3f aabbMin; + Vector3f aabbMax; + Vector3f reflectionNormal; + uint32_t skinBankIdx; + + /** Vertex indexing data (all primitives joined as degenerate tri-strip) */ + struct Vert + { + uint32_t iPos; + uint32_t iNorm; + uint32_t iColor[4] = {uint32_t(-1)}; + uint32_t iUv[8] = {uint32_t(-1)}; + uint32_t iSkin; + uint32_t iBankSkin = -1; + + Vert(Connection& conn, const Mesh& parent); + bool operator==(const Vert& other) const; + }; + std::vector verts; + + Surface(Connection& conn, Mesh& parent, int skinSlotCount); + }; + std::vector surfaces; + + std::unordered_map customProps; + + struct SkinBanks + { + struct Bank + { + std::vector m_skinIdxs; + std::vector m_boneIdxs; + + void addSkins(const Mesh& parent, const std::vector& skinIdxs); + size_t lookupLocalBoneIdx(uint32_t boneIdx) const; + }; + std::vector banks; + std::vector::iterator addSkinBank(int skinSlotCount); + uint32_t addSurface(const Mesh& mesh, const Surface& surf, int skinSlotCount); + } skinBanks; + + using SurfProgFunc = std::function; + Mesh(Connection& conn, HMDLTopology topology, int skinSlotCount, SurfProgFunc& surfProg); + + Mesh getContiguousSkinningVersion() const; + + /** Prepares mesh representation for indexed access on modern APIs. + * Mesh must remain resident for accessing reference members + */ + HMDLBuffers getHMDLBuffers(bool absoluteCoords, PoolSkinIndex& poolSkinIndex) const; +}; + +/** Intermediate collision mesh representation prepared by blender from a single mesh object */ +struct ColMesh +{ + /** HECL source and metadata of each material */ + struct Material + { + std::string name; + bool unknown; + bool surfaceStone; + bool surfaceMetal; + bool surfaceGrass; + bool surfaceIce; + bool pillar; + bool surfaceMetalGrating; + bool surfacePhazon; + bool surfaceDirt; + bool surfaceLava; + bool surfaceSPMetal; + bool surfaceStoneRock; + bool surfaceSnow; + bool surfaceMudSlow; + bool surfaceFabric; + bool halfPipe; + bool surfaceMud; + bool surfaceGlass; + bool unused3; + bool unused4; + bool surfaceShield; + bool surfaceSand; + bool surfaceMothOrSeedOrganics; + bool surfaceWeb; + bool projPassthrough; + bool solid; + bool u20; + bool camPassthrough; + bool surfaceWood; + bool surfaceOrganic; + bool u24; + bool surfaceRubber; + bool seeThrough; + bool scanPassthrough; + bool aiPassthrough; + bool ceiling; + bool wall; + bool floor; + bool aiBlock; + bool jumpNotAllowed; + bool spiderBall; + bool screwAttackWallJump; + + Material(Connection& conn); + }; + std::vector materials; + + std::vector verts; + + struct Edge + { + uint32_t verts[2]; + bool seam; + Edge(Connection& conn); + }; + std::vector edges; + + struct Triangle + { + uint32_t edges[3]; + uint32_t matIdx; + bool flip; + Triangle(Connection& conn); + }; + std::vector trianges; + + ColMesh(Connection& conn); +}; + +/** Intermediate world representation */ +struct World +{ + struct Area + { + ProjectPath path; + Vector3f aabb[2]; + Matrix4f transform; + struct Dock + { + Vector3f verts[4]; + Index targetArea; + Index targetDock; + Dock(Connection& conn); + }; + std::vector docks; + Area(Connection& conn); + }; + std::vector areas; + World(Connection& conn); +}; + +/** Intermediate lamp representation */ +struct Light +{ + /* Object transform in scene */ + Matrix4f sceneXf; + Vector3f color; + + uint32_t layer; + + enum class Type : uint32_t + { + Ambient, + Directional, + Custom, + Spot + } type; + + float energy; + float spotCutoff; + float constant; + float linear; + float quadratic; + bool shadow; + + std::string name; + + Light(Connection& conn); +}; + +/** Intermediate MapArea representation */ +struct MapArea +{ + Index visType; + std::vector verts; + std::vector indices; + struct Surface + { + Vector3f normal; + Vector3f centerOfMass; + Index start; + Index count; + std::vector> borders; + Surface(Connection& conn); + }; + std::vector surfaces; + struct POI + { + uint32_t type; + uint32_t visMode; + uint32_t objid; + Matrix4f xf; + POI(Connection& conn); + }; + std::vector pois; + MapArea(Connection& conn); +}; + +/** Intermediate MapUniverse representation */ +struct MapUniverse +{ + hecl::ProjectPath hexagonPath; + struct World + { + std::string name; + Matrix4f xf; + std::vector hexagons; + Vector4f color; + hecl::ProjectPath worldPath; + World(Connection& conn); + }; + std::vector worlds; + MapUniverse(Connection& conn); +}; + +/** Intermediate bone representation used in Armature */ +struct Bone +{ + std::string name; + Vector3f origin; + int32_t parent = -1; + std::vector children; + Bone(Connection& conn); +}; + +/** Intermediate armature representation used in Actor */ +struct Armature +{ + std::string name; + std::vector bones; + const Bone* lookupBone(const char* name) const; + const Bone* getParent(const Bone* bone) const; + const Bone* getChild(const Bone* bone, size_t child) const; + const Bone* getRoot() const; + Armature(Connection& conn); +}; + +/** Intermediate action representation used in Actor */ +struct Action +{ + std::string name; + float interval; + bool additive; + bool looping; + std::vector frames; + struct Channel + { + std::string boneName; + uint32_t attrMask; + struct Key + { + Vector4f rotation; + Vector3f position; + Vector3f scale; + Key(Connection& conn, uint32_t attrMask); + }; + std::vector keys; + Channel(Connection& conn); + }; + std::vector channels; + std::vector> subtypeAABBs; + Action(Connection& conn); +}; + +/** Intermediate actor representation prepared by blender from a single HECL actor blend */ +struct Actor +{ + std::vector armatures; + + struct Subtype + { + std::string name; + ProjectPath mesh; + int32_t armature = -1; + std::vector> overlayMeshes; + Subtype(Connection& conn); + }; + std::vector subtypes; + std::vector actions; + + Actor(Connection& conn); +}; + +class DataStream +{ + friend class Connection; + Connection* m_parent; + DataStream(Connection* parent); +public: + DataStream(const DataStream& other) = delete; + DataStream(DataStream&& other) + : m_parent(other.m_parent) {other.m_parent = nullptr;} + ~DataStream() {close();} + void close(); + std::vector getMeshList(); + std::vector getLightList(); + std::pair getMeshAABB(); + static const char* MeshOutputModeString(HMDLTopology topology); + + /** Compile mesh by context (MESH blends only) */ + Mesh compileMesh(HMDLTopology topology, int skinSlotCount=10, + Mesh::SurfProgFunc surfProg=[](int){}); + + /** Compile mesh by name (AREA blends only) */ + Mesh compileMesh(std::string_view name, HMDLTopology topology, int skinSlotCount=10, + Mesh::SurfProgFunc surfProg=[](int){}); + + /** Compile collision mesh by name (AREA blends only) */ + ColMesh compileColMesh(std::string_view name); + + /** Compile all meshes as collision meshes (CMESH blends only) */ + std::vector compileColMeshes(); + + /** Compile all meshes into one (AREA blends only) */ + Mesh compileAllMeshes(HMDLTopology topology, int skinSlotCount=10, float maxOctantLength=5.0, + Mesh::SurfProgFunc surfProg=[](int){}); + + /** Compile world intermediate (WORLD blends only) */ + World compileWorld(); + + /** Gather all lights in scene (AREA blends only) */ + std::vector compileLights(); + + /** Compile GUI into FRME data (FRAME blends only) */ + void compileGuiFrame(std::string_view pathOut, int version); + + /** Gather all texture paths in scene */ + std::vector getTextures(); + + Actor compileActor(); + Actor compileActorCharacterOnly(); + Action compileActionChannelsOnly(std::string_view name); + std::vector getArmatureNames(); + std::vector getSubtypeNames(); + std::vector getActionNames(); + std::vector getSubtypeOverlayNames(std::string_view name); + + std::unordered_map getBoneMatrices(std::string_view name); + + bool renderPvs(std::string_view path, const atVec3f& location); + bool renderPvsLight(std::string_view path, std::string_view lightName); + + MapArea compileMapArea(); + MapUniverse compileMapUniverse(); +}; + +class Connection +{ + friend class DataStream; + friend class PyOutStream; + friend class ANIMOutStream; + friend struct PyOutStream::StreamBuf; + friend struct Mesh; + friend struct Material; + friend struct ColMesh; + friend struct World; + friend struct Light; + friend struct MapArea; + friend struct MapUniverse; + friend struct Actor; + friend struct Armature; + friend struct Action; + friend struct Bone; + friend struct Vector2f; + friend struct Vector3f; + friend struct Vector4f; + friend struct Matrix3f; + friend struct Matrix4f; + friend struct Index; + + std::atomic_bool m_lock = {false}; + bool m_pyStreamActive = false; + bool m_dataStreamActive = false; +#if _WIN32 + PROCESS_INFORMATION m_pinfo = {}; + std::thread m_consoleThread; + bool m_consoleThreadRunning = true; +#else + pid_t m_blenderProc = 0; +#endif + int m_readpipe[2]; + int m_writepipe[2]; + bool m_hasSlerp; + BlendType m_loadedType = BlendType::None; + bool m_loadedRigged = false; + ProjectPath m_loadedBlend; + std::string m_startupBlend; + hecl::SystemString m_errPath; + uint32_t _readStr(char* buf, uint32_t bufSz); + uint32_t _writeStr(const char* str, uint32_t len, int wpipe); + uint32_t _writeStr(const char* str, uint32_t len) { return _writeStr(str, len, m_writepipe[1]); } + uint32_t _writeStr(const char* str) { return _writeStr(str, strlen(str)); } + size_t _readBuf(void* buf, size_t len); + size_t _writeBuf(const void* buf, size_t len); + void _closePipe(); + void _blenderDied(); + +public: + Connection(int verbosityLevel=1); + ~Connection(); + + Connection(const Connection&)=delete; + Connection& operator=(const Connection&)=delete; + Connection(Connection&&)=delete; + Connection& operator=(Connection&&)=delete; + + bool hasSLERP() const {return m_hasSlerp;} + + bool createBlend(const ProjectPath& path, BlendType type); + BlendType getBlendType() const {return m_loadedType;} + const ProjectPath& getBlendPath() const {return m_loadedBlend;} + bool getRigged() const {return m_loadedRigged;} + bool openBlend(const ProjectPath& path, bool force=false); + bool saveBlend(); + void deleteBlend(); + + PyOutStream beginPythonOut(bool deleteOnError=false) + { + bool expect = false; + if (!m_lock.compare_exchange_strong(expect, true)) + BlenderLog.report(logvisor::Fatal, "lock already held for blender::Connection::beginPythonOut()"); + return PyOutStream(this, deleteOnError); + } + + DataStream beginData() + { + bool expect = false; + if (!m_lock.compare_exchange_strong(expect, true)) + BlenderLog.report(logvisor::Fatal, "lock already held for blender::Connection::beginDataIn()"); + return DataStream(this); + } + + void quitBlender(); + + void closeStream() + { + if (m_lock) + deleteBlend(); + } + + static Connection& SharedConnection(); + static void Shutdown(); +}; + +class HMDLBuffers +{ +public: + struct Surface; +private: + friend struct Mesh; + HMDLBuffers(HMDLMeta&& meta, + size_t vboSz, const std::vector& iboData, + std::vector&& surfaces, + const Mesh::SkinBanks& skinBanks); +public: + HMDLMeta m_meta; + size_t m_vboSz; + std::unique_ptr m_vboData; + size_t m_iboSz; + std::unique_ptr m_iboData; + + struct Surface + { + Surface(const Mesh::Surface& origSurf, + atUint32 start, atUint32 count) + : m_origSurf(origSurf), m_start(start), m_count(count) {} + const Mesh::Surface& m_origSurf; + atUint32 m_start; + atUint32 m_count; + }; + std::vector m_surfaces; + + const Mesh::SkinBanks& m_skinBanks; +}; + +} + +#endif // BLENDERCONNECTION_HPP diff --git a/hecl/include/hecl/Blender/Token.hpp b/hecl/include/hecl/Blender/Token.hpp new file mode 100644 index 000000000..1ace6b07e --- /dev/null +++ b/hecl/include/hecl/Blender/Token.hpp @@ -0,0 +1,27 @@ +#ifndef HECL_BLENDERTOKEN_HPP +#define HECL_BLENDERTOKEN_HPP + +#include + +namespace hecl::blender +{ +class Connection; + +class Token +{ + std::unique_ptr m_conn; +public: + Connection& getBlenderConnection(); + void shutdown(); + + Token() = default; + ~Token(); + Token(const Token&)=delete; + Token& operator=(const Token&)=delete; + Token(Token&&)=default; + Token& operator=(Token&&)=default; +}; + +} + +#endif // HECL_BLENDERTOKEN_HPP diff --git a/hecl/include/hecl/ClientProcess.hpp b/hecl/include/hecl/ClientProcess.hpp index d1c1d75b9..4dcda829d 100644 --- a/hecl/include/hecl/ClientProcess.hpp +++ b/hecl/include/hecl/ClientProcess.hpp @@ -3,8 +3,8 @@ #include "hecl.hpp" #include "Database.hpp" -#include "hecl/Blender/BlenderConnection.hpp" #include "boo/ThreadLocalPtr.hpp" +#include "hecl/Blender/Token.hpp" #include #include #include @@ -34,7 +34,7 @@ public: Lambda } m_type; bool m_complete = false; - virtual void run(BlenderToken& btok)=0; + virtual void run(blender::Token& btok)=0; Transaction(ClientProcess& parent, Type tp) : m_parent(parent), m_type(tp) {} }; struct BufferTransaction : Transaction @@ -43,7 +43,7 @@ public: void* m_targetBuf; size_t m_maxLen; size_t m_offset; - void run(BlenderToken& btok); + void run(blender::Token& btok); BufferTransaction(ClientProcess& parent, const ProjectPath& path, void* target, size_t maxLen, size_t offset) : Transaction(parent, Type::Buffer), @@ -55,15 +55,15 @@ public: ProjectPath m_path; Database::IDataSpec* m_dataSpec; bool m_returnResult = false; - void run(BlenderToken& btok); + void run(blender::Token& btok); CookTransaction(ClientProcess& parent, const ProjectPath& path, Database::IDataSpec* spec) : Transaction(parent, Type::Cook), m_path(path), m_dataSpec(spec) {} }; struct LambdaTransaction : Transaction { - std::function m_func; - void run(BlenderToken& btok); - LambdaTransaction(ClientProcess& parent, std::function&& func) + std::function m_func; + void run(blender::Token& btok); + LambdaTransaction(ClientProcess& parent, std::function&& func) : Transaction(parent, Type::Lambda), m_func(std::move(func)) {} }; private: @@ -77,7 +77,7 @@ private: ClientProcess& m_proc; int m_idx; std::thread m_thr; - BlenderToken m_blendTok; + blender::Token m_blendTok; bool m_didInit = false; Worker(ClientProcess& proc, int idx); void proc(); @@ -94,8 +94,8 @@ public: std::shared_ptr addCookTransaction(const hecl::ProjectPath& path, Database::IDataSpec* spec); std::shared_ptr - addLambdaTransaction(std::function&& func); - bool syncCook(const hecl::ProjectPath& path, Database::IDataSpec* spec, BlenderToken& btok); + addLambdaTransaction(std::function&& func); + bool syncCook(const hecl::ProjectPath& path, Database::IDataSpec* spec, blender::Token& btok); void swapCompletedQueue(std::list>& queue); void waitUntilComplete(); void shutdown(); diff --git a/hecl/include/hecl/Database.hpp b/hecl/include/hecl/Database.hpp index 38628bd90..ab212b5ed 100644 --- a/hecl/include/hecl/Database.hpp +++ b/hecl/include/hecl/Database.hpp @@ -13,16 +13,15 @@ #include #include #include -#include +#include -#include +#include "athena/IStreamReader.hpp" #include "logvisor/logvisor.hpp" #include "hecl.hpp" namespace hecl { -class BlenderToken; class ClientProcess; namespace Database @@ -71,7 +70,7 @@ class IDataSpec public: IDataSpec(const DataSpecEntry* specEntry) : m_specEntry(specEntry) {} virtual ~IDataSpec() {} - using FProgress = hecl::Database::FProgress; + using FProgress = Database::FProgress; using FCookProgress = std::function; /** @@ -107,20 +106,20 @@ public: virtual void doExtract(const ExtractPassInfo& info, FProgress progress) {(void)info;(void)progress;} - virtual bool canCook(const ProjectPath& path, BlenderToken& btok) + virtual bool canCook(const ProjectPath& path, blender::Token& btok) {(void)path;LogModule.report(logvisor::Error, "not implemented");return false;} virtual const DataSpecEntry* overrideDataSpec(const ProjectPath& path, const Database::DataSpecEntry* oldEntry, - BlenderToken& btok) const + blender::Token& btok) const {(void)path;return oldEntry;} virtual void doCook(const ProjectPath& path, const ProjectPath& cookedPath, - bool fast, BlenderToken& btok, FCookProgress progress) + bool fast, blender::Token& btok, FCookProgress progress) {(void)path;(void)cookedPath;(void)fast;(void)progress;} - virtual bool canPackage(const hecl::ProjectPath& path) + virtual bool canPackage(const ProjectPath& path) {(void)path;return false;} - virtual void doPackage(const hecl::ProjectPath& path, const hecl::Database::DataSpecEntry* entry, - bool fast, hecl::BlenderToken& btok, FProgress progress, ClientProcess* cp=nullptr) + virtual void doPackage(const ProjectPath& path, const Database::DataSpecEntry* entry, + bool fast, blender::Token& btok, FProgress progress, ClientProcess* cp=nullptr) {(void)path;} const DataSpecEntry* getDataSpecEntry() const {return m_specEntry;} @@ -263,7 +262,7 @@ private: std::unique_ptr m_lastPackageSpec; bool m_valid = false; public: - Project(const hecl::ProjectRootPath& rootPath); + Project(const ProjectRootPath& rootPath); operator bool() const {return m_valid;} /** diff --git a/hecl/include/hecl/FourCC.hpp b/hecl/include/hecl/FourCC.hpp new file mode 100644 index 000000000..30916de52 --- /dev/null +++ b/hecl/include/hecl/FourCC.hpp @@ -0,0 +1,62 @@ +#ifndef HECL_FOURCC_HPP +#define HECL_FOURCC_HPP + +#include +#include +#include + +namespace hecl +{ + +/** + * @brief FourCC representation used within HECL's database + * + * FourCCs are efficient, mnemonic four-char-sequences used to represent types + * while fitting comfortably in a 32-bit word. HECL uses a four-char array + * to remain endian-independent. + */ +class FourCC +{ +protected: + union + { + char fcc[4]; + uint32_t num; + }; +public: + FourCC() /* Sentinel FourCC */ + : num(0) {} + FourCC(const FourCC& other) + {num = other.num;} + FourCC(const char* name) + : num(*(uint32_t*)name) {} + FourCC(uint32_t n) + : num(n) {} + bool operator==(const FourCC& other) const {return num == other.num;} + bool operator!=(const FourCC& other) const {return num != other.num;} + bool operator==(const char* other) const {return num == *(uint32_t*)other;} + bool operator!=(const char* other) const {return num != *(uint32_t*)other;} + bool operator==(int32_t other) const { return num == other;} + bool operator!=(int32_t other) const { return num != other;} + bool operator==(uint32_t other) const {return num == other;} + bool operator!=(uint32_t other) const {return num != other;} + std::string toString() const {return std::string(fcc, 4);} + uint32_t toUint32() const {return num;} + operator uint32_t() const {return num;} + const char* getChars() const {return fcc;} + char* getChars() {return fcc;} +}; +#define FOURCC(chars) FourCC(SBIG(chars)) + +} + +namespace std +{ +template <> struct hash +{ + size_t operator()(const hecl::FourCC& val) const noexcept + {return val.toUint32();} +}; +} + +#endif // HECL_FOURCC_HPP diff --git a/hecl/include/hecl/HMDLMeta.hpp b/hecl/include/hecl/HMDLMeta.hpp index 794e656b6..66db1ba4d 100644 --- a/hecl/include/hecl/HMDLMeta.hpp +++ b/hecl/include/hecl/HMDLMeta.hpp @@ -1,8 +1,8 @@ #ifndef HMDLMETA_HPP #define HMDLMETA_HPP -#include -#include +#include "hecl/hecl.hpp" +#include "athena/DNA.hpp" namespace hecl { diff --git a/hecl/include/hecl/Runtime.hpp b/hecl/include/hecl/Runtime.hpp index a983e4833..9d98eaa9d 100644 --- a/hecl/include/hecl/Runtime.hpp +++ b/hecl/include/hecl/Runtime.hpp @@ -4,9 +4,9 @@ #include "hecl.hpp" #include "Frontend.hpp" #include "Backend/Backend.hpp" -#include -#include -#include +#include "boo/graphicsdev/IGraphicsDataFactory.hpp" +#include "athena/DNA.hpp" +#include "athena/FileReader.hpp" #include namespace hecl @@ -323,7 +323,7 @@ namespace std { template <> struct hash { - size_t operator()(const hecl::Runtime::ShaderTag& val) const NOEXCEPT + size_t operator()(const hecl::Runtime::ShaderTag& val) const noexcept {return val.valSizeT();} }; } diff --git a/hecl/include/hecl/SystemChar.hpp b/hecl/include/hecl/SystemChar.hpp index daa45d5a0..366ba7457 100644 --- a/hecl/include/hecl/SystemChar.hpp +++ b/hecl/include/hecl/SystemChar.hpp @@ -2,7 +2,7 @@ #define SYSTEMCHAR_HPP #ifndef _WIN32 -#include +#include #include #include #else @@ -12,7 +12,7 @@ #ifndef NOMINMAX #define NOMINMAX #endif -#include +#include #endif #include #include diff --git a/hecl/include/hecl/hecl.hpp b/hecl/include/hecl/hecl.hpp index f6272dd91..f00ce5732 100644 --- a/hecl/include/hecl/hecl.hpp +++ b/hecl/include/hecl/hecl.hpp @@ -2,7 +2,7 @@ #define HECL_HPP #ifndef _WIN32 -#include +#include #include #include #include @@ -18,15 +18,15 @@ #define NOMINMAX #endif #include -#include +#include #include #include "winsupport.hpp" #endif -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include @@ -34,9 +34,10 @@ #include #include #include "logvisor/logvisor.hpp" -#include +#include "athena/Global.hpp" #include "../extern/boo/xxhash/xxhash.h" #include "SystemChar.hpp" +#include "FourCC.hpp" namespace hecl { @@ -46,6 +47,43 @@ class Project; struct DataSpecEntry; } +namespace blender +{ +enum class BlendType +{ + None, + Mesh, + ColMesh, + Actor, + Area, + World, + MapArea, + MapUniverse, + Frame +}; + +class Connection; +class Token; +class DataStream; +class PyOutStream; +class ANIMOutStream; +struct Mesh; +struct Material; +struct ColMesh; +struct World; +struct Light; +struct MapArea; +struct MapUniverse; +struct Actor; +struct Armature; +struct Action; +struct Bone; +struct Matrix3f; +struct PoolSkinIndex; + +extern class Token SharedBlenderToken; +} + extern unsigned VerbosityLevel; extern bool GuiMode; extern logvisor::Module LogModule; @@ -480,46 +518,6 @@ typedef std::match_results SystemRegexMatch; class ProjectRootPath; -/** - * @brief FourCC representation used within HECL's database - * - * FourCCs are efficient, mnemonic four-char-sequences used to represent types - * while fitting comfortably in a 32-bit word. HECL uses a four-char array - * to remain endian-independent. - */ -class FourCC -{ -protected: - union - { - char fcc[4]; - uint32_t num; - }; -public: - FourCC() /* Sentinel FourCC */ - : num(0) {} - FourCC(const FourCC& other) - {num = other.num;} - FourCC(const char* name) - : num(*(uint32_t*)name) {} - FourCC(uint32_t n) - : num(n) {} - bool operator==(const FourCC& other) const {return num == other.num;} - bool operator!=(const FourCC& other) const {return num != other.num;} - bool operator==(const char* other) const {return num == *(uint32_t*)other;} - bool operator!=(const char* other) const {return num != *(uint32_t*)other;} - bool operator==(int32_t other) const { return num == other;} - bool operator!=(int32_t other) const { return num != other;} - bool operator==(uint32_t other) const {return num == other;} - bool operator!=(uint32_t other) const {return num != other;} - std::string toString() const {return std::string(fcc, 4);} - uint32_t toUint32() const {return num;} - operator uint32_t() const {return num;} - const char* getChars() const {return fcc;} - char* getChars() {return fcc;} -}; -#define FOURCC(chars) FourCC(SBIG(chars)) - /** * @brief Hash representation used for all storable and comparable objects * @@ -1465,27 +1463,16 @@ static inline double SBig(double val) {return val;} } -#if _MSC_VER -#define NOEXCEPT -#else -#define NOEXCEPT noexcept -#endif - namespace std { -template <> struct hash -{ - size_t operator()(const hecl::FourCC& val) const NOEXCEPT - {return val.toUint32();} -}; template <> struct hash { - size_t operator()(const hecl::ProjectPath& val) const NOEXCEPT + size_t operator()(const hecl::ProjectPath& val) const noexcept {return val.hash().valSizeT();} }; template <> struct hash { - size_t operator()(const hecl::Hash& val) const NOEXCEPT + size_t operator()(const hecl::Hash& val) const noexcept {return val.valSizeT();} }; } diff --git a/hecl/lib/Backend/GLSL.cpp b/hecl/lib/Backend/GLSL.cpp index 1ec88df29..7c1f96afe 100644 --- a/hecl/lib/Backend/GLSL.cpp +++ b/hecl/lib/Backend/GLSL.cpp @@ -5,11 +5,9 @@ #include #include -static logvisor::Module Log("hecl::Backend::GLSL"); +static logvisor::Module GLSL_Log("hecl::Backend::GLSL"); -namespace hecl -{ -namespace Backend +namespace hecl::Backend { std::string GLSL::EmitTexGenSource2(TexGenSrc src, int uvIdx) const @@ -364,7 +362,8 @@ std::string GLSL::makeFrag(const char* glslVer, bool alphaTest, } } -namespace Runtime + +namespace hecl::Runtime { static const char* STD_BLOCKNAMES[] = {HECL_GLSL_VERT_UNIFORM_BLOCK_NAME, @@ -407,7 +406,7 @@ struct GLSLBackendFactory : IShaderBackendFactory cachedSz += fragSource.size() + 1; if (m_backend.m_texMapEnd > 8) - Log.report(logvisor::Fatal, "maximum of 8 texture maps supported"); + GLSL_Log.report(logvisor::Fatal, "maximum of 8 texture maps supported"); objOut = static_cast(ctx). @@ -420,7 +419,7 @@ struct GLSLBackendFactory : IShaderBackendFactory tag.getDepthWrite(), true, false, tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None); if (!objOut) - Log.report(logvisor::Fatal, "unable to build shader"); + GLSL_Log.report(logvisor::Fatal, "unable to build shader"); ShaderCachedData dataOut(tag, cachedSz); athena::io::MemoryWriter w(dataOut.m_data.get(), dataOut.m_sz); @@ -448,7 +447,7 @@ struct GLSLBackendFactory : IShaderBackendFactory return nullptr; if (texMapEnd > 8) - Log.report(logvisor::Fatal, "maximum of 8 texture maps supported"); + GLSL_Log.report(logvisor::Fatal, "maximum of 8 texture maps supported"); auto ret = static_cast(ctx). @@ -460,7 +459,7 @@ struct GLSLBackendFactory : IShaderBackendFactory tag.getDepthWrite(), true, false, tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None); if (!ret) - Log.report(logvisor::Fatal, "unable to build shader"); + GLSL_Log.report(logvisor::Fatal, "unable to build shader"); return ret; } @@ -475,7 +474,7 @@ struct GLSLBackendFactory : IShaderBackendFactory size_t cachedSz = 3; if (m_backend.m_texMapEnd > 8) - Log.report(logvisor::Fatal, "maximum of 8 texture maps supported"); + GLSL_Log.report(logvisor::Fatal, "maximum of 8 texture maps supported"); std::vector> sources; sources.reserve(extensionSlots.size()); @@ -531,7 +530,7 @@ struct GLSLBackendFactory : IShaderBackendFactory (tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None) : boo::CullMode(slot.cullMode)); if (!ret) - Log.report(logvisor::Fatal, "unable to build shader"); + GLSL_Log.report(logvisor::Fatal, "unable to build shader"); returnFunc(ret); } @@ -564,7 +563,7 @@ struct GLSLBackendFactory : IShaderBackendFactory return false; if (texMapEnd > 8) - Log.report(logvisor::Fatal, "maximum of 8 texture maps supported"); + GLSL_Log.report(logvisor::Fatal, "maximum of 8 texture maps supported"); for (const ShaderCacheExtensions::ExtensionSlot& slot : extensionSlots) { @@ -614,7 +613,7 @@ struct GLSLBackendFactory : IShaderBackendFactory (tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None) : boo::CullMode(slot.cullMode)); if (!ret) - Log.report(logvisor::Fatal, "unable to build shader"); + GLSL_Log.report(logvisor::Fatal, "unable to build shader"); returnFunc(ret); } @@ -927,4 +926,3 @@ IShaderBackendFactory* _NewSPIRVBackendFactory() #endif } -} diff --git a/hecl/lib/Backend/GX.cpp b/hecl/lib/Backend/GX.cpp index 610829909..59649c0f1 100644 --- a/hecl/lib/Backend/GX.cpp +++ b/hecl/lib/Backend/GX.cpp @@ -1,9 +1,7 @@ #include "hecl/Backend/GX.hpp" #include -namespace hecl -{ -namespace Backend +namespace hecl::Backend { unsigned GX::addKColor(Diagnostics& diag, const SourceLocation& loc, const Color& color) @@ -773,4 +771,3 @@ void GX::reset(const IR& ir, Diagnostics& diag) } } -} diff --git a/hecl/lib/Backend/HLSL.cpp b/hecl/lib/Backend/HLSL.cpp index fd94354b7..dbc86b854 100644 --- a/hecl/lib/Backend/HLSL.cpp +++ b/hecl/lib/Backend/HLSL.cpp @@ -6,9 +6,7 @@ static logvisor::Module Log("hecl::Backend::HLSL"); -namespace hecl -{ -namespace Backend +namespace hecl::Backend { std::string HLSL::EmitTexGenSource2(TexGenSrc src, int uvIdx) const @@ -683,4 +681,3 @@ IShaderBackendFactory* _NewHLSLBackendFactory() } } -} diff --git a/hecl/lib/Backend/Metal.cpp b/hecl/lib/Backend/Metal.cpp index ed62300f8..e667a214d 100644 --- a/hecl/lib/Backend/Metal.cpp +++ b/hecl/lib/Backend/Metal.cpp @@ -6,9 +6,7 @@ static logvisor::Module Log("hecl::Backend::Metal"); -namespace hecl -{ -namespace Backend +namespace hecl::Backend { std::string Metal::EmitTexGenSource2(TexGenSrc src, int uvIdx) const @@ -432,7 +430,8 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp } } -namespace Runtime + +namespace hecl::Runtime { struct MetalBackendFactory : IShaderBackendFactory @@ -701,7 +700,6 @@ IShaderBackendFactory* _NewMetalBackendFactory() return new struct MetalBackendFactory(); } -} } #endif diff --git a/hecl/lib/Backend/ProgrammableCommon.cpp b/hecl/lib/Backend/ProgrammableCommon.cpp index f63718575..540d91935 100644 --- a/hecl/lib/Backend/ProgrammableCommon.cpp +++ b/hecl/lib/Backend/ProgrammableCommon.cpp @@ -1,9 +1,7 @@ #include "hecl/Backend/ProgrammableCommon.hpp" #include -namespace hecl -{ -namespace Backend +namespace hecl::Backend { unsigned ProgrammableCommon::addTexCoordGen(TexGenSrc src, int uvIdx, int mtx, bool normalize) @@ -337,4 +335,3 @@ std::string ProgrammableCommon::EmitSwizzle1(Diagnostics& diag, const SourceLoca } } -} diff --git a/hecl/lib/Blender/CMakeLists.txt b/hecl/lib/Blender/CMakeLists.txt index aec4808c4..a0d1d45fb 100644 --- a/hecl/lib/Blender/CMakeLists.txt +++ b/hecl/lib/Blender/CMakeLists.txt @@ -1,5 +1,5 @@ set(BLENDER_SOURCES - BlenderConnection.cpp + Connection.cpp HMDL.cpp) hecl_add_list(Blender BLENDER_SOURCES) diff --git a/hecl/lib/Blender/BlenderConnection.cpp b/hecl/lib/Blender/Connection.cpp similarity index 72% rename from hecl/lib/Blender/BlenderConnection.cpp rename to hecl/lib/Blender/Connection.cpp index f4fcdb3bf..d88068783 100644 --- a/hecl/lib/Blender/BlenderConnection.cpp +++ b/hecl/lib/Blender/Connection.cpp @@ -1,8 +1,8 @@ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include @@ -14,7 +14,7 @@ #include #include #include "logvisor/logvisor.hpp" -#include "hecl/Blender/BlenderConnection.hpp" +#include "hecl/Blender/Connection.hpp" #include "hecl/SteamFinder.hpp" #if _WIN32 @@ -26,7 +26,7 @@ namespace std { template <> struct hash> { - size_t operator()(const std::pair& val) const NOEXCEPT + size_t operator()(const std::pair& val) const noexcept { /* this will potentially truncate the second value if 32-bit size_t, * however, its application here is intended to operate in 16-bit indices */ @@ -37,11 +37,11 @@ template <> struct hash> using namespace std::literals; -namespace hecl +namespace hecl::blender { -logvisor::Module BlenderLog("hecl::BlenderConnection"); -BlenderToken SharedBlenderToken; +logvisor::Module BlenderLog("hecl::blender::Connection"); +Token SharedBlenderToken; #ifdef __APPLE__ #define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender" @@ -123,7 +123,7 @@ static int Write(int fd, const void* buf, size_t size) return -1; } -uint32_t BlenderConnection::_readStr(char* buf, uint32_t bufSz) +uint32_t Connection::_readStr(char* buf, uint32_t bufSz) { uint32_t readLen; int ret = Read(m_readpipe[0], &readLen, 4); @@ -160,7 +160,7 @@ uint32_t BlenderConnection::_readStr(char* buf, uint32_t bufSz) return readLen; } -uint32_t BlenderConnection::_writeStr(const char* buf, uint32_t len, int wpipe) +uint32_t Connection::_writeStr(const char* buf, uint32_t len, int wpipe) { int ret, nlerr; nlerr = Write(wpipe, &len, 4); @@ -175,7 +175,7 @@ err: return 0; } -size_t BlenderConnection::_readBuf(void* buf, size_t len) +size_t Connection::_readBuf(void* buf, size_t len) { int ret = Read(m_readpipe[0], buf, len); if (ret < 0) @@ -189,7 +189,7 @@ err: return 0; } -size_t BlenderConnection::_writeBuf(const void* buf, size_t len) +size_t Connection::_writeBuf(const void* buf, size_t len) { int ret = Write(m_writepipe[1], buf, len); if (ret < 0) @@ -200,7 +200,7 @@ err: return 0; } -void BlenderConnection::_closePipe() +void Connection::_closePipe() { close(m_readpipe[0]); close(m_writepipe[1]); @@ -213,7 +213,7 @@ void BlenderConnection::_closePipe() #endif } -void BlenderConnection::_blenderDied() +void Connection::_blenderDied() { std::this_thread::sleep_for(std::chrono::milliseconds(100)); FILE* errFp = hecl::Fopen(m_errPath.c_str(), _S("r")); @@ -243,7 +243,7 @@ static bool RegFileExists(const hecl::SystemChar* path) return !hecl::Stat(path, &theStat) && S_ISREG(theStat.st_mode); } -BlenderConnection::BlenderConnection(int verbosityLevel) +Connection::Connection(int verbosityLevel) { #if !WINDOWS_STORE BlenderLog.report(logvisor::Info, "Establishing BlenderConnection..."); @@ -558,13 +558,19 @@ BlenderConnection::BlenderConnection(int verbosityLevel) #endif } -BlenderConnection::~BlenderConnection() +Connection::~Connection() { _closePipe(); } +void Vector2f::read(Connection& conn) {conn._readBuf(&val, 8);} +void Vector3f::read(Connection& conn) {conn._readBuf(&val, 12);} +void Vector4f::read(Connection& conn) {conn._readBuf(&val, 16);} +void Matrix4f::read(Connection& conn) {conn._readBuf(&val, 64);} +void Index::read(Connection& conn) {conn._readBuf(&val, 4);} + std::streambuf::int_type -BlenderConnection::PyOutStream::StreamBuf::overflow(int_type ch) +PyOutStream::StreamBuf::overflow(int_type ch) { if (!m_parent.m_parent || !m_parent.m_parent->m_lock) BlenderLog.report(logvisor::Fatal, "lock not held for PyOutStream writing"); @@ -601,7 +607,7 @@ static const char* BlendTypeStrs[] = nullptr }; -bool BlenderConnection::createBlend(const ProjectPath& path, BlendType type) +bool Connection::createBlend(const ProjectPath& path, BlendType type) { if (m_lock) { @@ -624,7 +630,7 @@ bool BlenderConnection::createBlend(const ProjectPath& path, BlendType type) return false; } -bool BlenderConnection::openBlend(const ProjectPath& path, bool force) +bool Connection::openBlend(const ProjectPath& path, bool force) { if (m_lock) { @@ -666,7 +672,7 @@ bool BlenderConnection::openBlend(const ProjectPath& path, bool force) return false; } -bool BlenderConnection::saveBlend() +bool Connection::saveBlend() { if (m_lock) { @@ -682,7 +688,7 @@ bool BlenderConnection::saveBlend() return false; } -void BlenderConnection::deleteBlend() +void Connection::deleteBlend() { if (m_loadedBlend) { @@ -692,9 +698,58 @@ void BlenderConnection::deleteBlend() } } -void BlenderConnection::PyOutStream::linkBlend(const char* target, - const char* objName, - bool link) +PyOutStream::PyOutStream(Connection* parent, bool deleteOnError) +: std::ostream(&m_sbuf), +m_parent(parent), +m_deleteOnError(deleteOnError), +m_sbuf(*this, deleteOnError) +{ + m_parent->m_pyStreamActive = true; + m_parent->_writeStr("PYBEGIN"); + char readBuf[16]; + m_parent->_readStr(readBuf, 16); + if (strcmp(readBuf, "READY")) + BlenderLog.report(logvisor::Fatal, "unable to open PyOutStream with blender"); +} + +void PyOutStream::close() +{ + if (m_parent && m_parent->m_lock) + { + m_parent->_writeStr("PYEND"); + char readBuf[16]; + m_parent->_readStr(readBuf, 16); + if (strcmp(readBuf, "DONE")) + BlenderLog.report(logvisor::Fatal, "unable to close PyOutStream with blender"); + m_parent->m_pyStreamActive = false; + m_parent->m_lock = false; + } +} + +#if __GNUC__ +__attribute__((__format__ (__printf__, 2, 3))) +#endif +void PyOutStream::format(const char* fmt, ...) +{ + if (!m_parent || !m_parent->m_lock) + BlenderLog.report(logvisor::Fatal, "lock not held for PyOutStream::format()"); + 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 + int length = vasprintf(&result, fmt, ap); +#endif + va_end(ap); + if (length > 0) + this->write(result, length); + free(result); +} + +void PyOutStream::linkBlend(const char* target, const char* objName, bool link) { format("if '%s' not in bpy.data.scenes:\n" " with bpy.data.libraries.load('''%s''', link=%s, relative=True) as (data_from, data_to):\n" @@ -717,8 +772,7 @@ void BlenderConnection::PyOutStream::linkBlend(const char* target, objName, objName, target, objName); } -void BlenderConnection::PyOutStream::linkBackground(const char* target, - const char* sceneName) +void PyOutStream::linkBackground(const char* target, const char* sceneName) { format("if '%s' not in bpy.data.scenes:\n" " with bpy.data.libraries.load('''%s''', link=True, relative=True) as (data_from, data_to):\n" @@ -736,7 +790,120 @@ void BlenderConnection::PyOutStream::linkBackground(const char* target, sceneName, sceneName, target, sceneName); } -void BlenderConnection::DataStream::Mesh::normalizeSkinBinds() +void PyOutStream::AABBToBMesh(const atVec3f& min, const atVec3f& max) +{ + format("bm = bmesh.new()\n" + "bm.verts.new((%f,%f,%f))\n" + "bm.verts.new((%f,%f,%f))\n" + "bm.verts.new((%f,%f,%f))\n" + "bm.verts.new((%f,%f,%f))\n" + "bm.verts.new((%f,%f,%f))\n" + "bm.verts.new((%f,%f,%f))\n" + "bm.verts.new((%f,%f,%f))\n" + "bm.verts.new((%f,%f,%f))\n" + "bm.verts.ensure_lookup_table()\n" + "bm.edges.new((bm.verts[0], bm.verts[1]))\n" + "bm.edges.new((bm.verts[0], bm.verts[2]))\n" + "bm.edges.new((bm.verts[0], bm.verts[4]))\n" + "bm.edges.new((bm.verts[3], bm.verts[1]))\n" + "bm.edges.new((bm.verts[3], bm.verts[2]))\n" + "bm.edges.new((bm.verts[3], bm.verts[7]))\n" + "bm.edges.new((bm.verts[5], bm.verts[1]))\n" + "bm.edges.new((bm.verts[5], bm.verts[4]))\n" + "bm.edges.new((bm.verts[5], bm.verts[7]))\n" + "bm.edges.new((bm.verts[6], bm.verts[2]))\n" + "bm.edges.new((bm.verts[6], bm.verts[4]))\n" + "bm.edges.new((bm.verts[6], bm.verts[7]))\n", + min.vec[0], min.vec[1], min.vec[2], + max.vec[0], min.vec[1], min.vec[2], + min.vec[0], max.vec[1], min.vec[2], + max.vec[0], max.vec[1], min.vec[2], + min.vec[0], min.vec[1], max.vec[2], + max.vec[0], min.vec[1], max.vec[2], + min.vec[0], max.vec[1], max.vec[2], + max.vec[0], max.vec[1], max.vec[2]); +} + +void PyOutStream::centerView() +{ + *this << "for obj in bpy.context.scene.objects:\n" + " if obj.type == 'CAMERA' or obj.type == 'LAMP':\n" + " obj.hide = True\n" + "\n" + "bpy.context.user_preferences.view.smooth_view = 0\n" + "for window in bpy.context.window_manager.windows:\n" + " screen = window.screen\n" + " for area in screen.areas:\n" + " if area.type == 'VIEW_3D':\n" + " for region in area.regions:\n" + " if region.type == 'WINDOW':\n" + " override = {'scene': bpy.context.scene, 'window': window, 'screen': screen, 'area': area, 'region': region}\n" + " bpy.ops.view3d.view_all(override)\n" + " break\n" + "\n" + "for obj in bpy.context.scene.objects:\n" + " if obj.type == 'CAMERA' or obj.type == 'LAMP':\n" + " obj.hide = False\n"; +} + +ANIMOutStream::ANIMOutStream(Connection* parent) +: m_parent(parent) +{ + m_parent->_writeStr("PYANIM"); + char readBuf[16]; + m_parent->_readStr(readBuf, 16); + if (strcmp(readBuf, "ANIMREADY")) + BlenderLog.report(logvisor::Fatal, "unable to open ANIMOutStream"); +} + +ANIMOutStream::~ANIMOutStream() +{ + char tp = -1; + m_parent->_writeBuf(&tp, 1); + char readBuf[16]; + m_parent->_readStr(readBuf, 16); + if (strcmp(readBuf, "ANIMDONE")) + BlenderLog.report(logvisor::Fatal, "unable to close ANIMOutStream"); +} + +void ANIMOutStream::changeCurve(CurveType type, unsigned crvIdx, unsigned keyCount) +{ + if (m_curCount != m_totalCount) + BlenderLog.report(logvisor::Fatal, "incomplete ANIMOutStream for change"); + m_curCount = 0; + m_totalCount = keyCount; + char tp = char(type); + m_parent->_writeBuf(&tp, 1); + struct + { + uint32_t ci; + uint32_t kc; + } info = {uint32_t(crvIdx), uint32_t(keyCount)}; + m_parent->_writeBuf(reinterpret_cast(&info), 8); + m_inCurve = true; +} + +void ANIMOutStream::write(unsigned frame, float val) +{ + if (!m_inCurve) + BlenderLog.report(logvisor::Fatal, "changeCurve not called before write"); + if (m_curCount < m_totalCount) + { + struct + { + uint32_t frm; + float val; + } key = {uint32_t(frame), val}; + m_parent->_writeBuf(reinterpret_cast(&key), 8); + ++m_curCount; + } + else + BlenderLog.report(logvisor::Fatal, "ANIMOutStream keyCount overflow"); +} + +Mesh::SkinBind::SkinBind(Connection& conn) {conn._readBuf(&boneIdx, 8);} + +void Mesh::normalizeSkinBinds() { for (std::vector& skin : skins) { @@ -751,8 +918,7 @@ void BlenderConnection::DataStream::Mesh::normalizeSkinBinds() } } -BlenderConnection::DataStream::Mesh::Mesh -(BlenderConnection& conn, HMDLTopology topologyIn, int skinSlotCount, SurfProgFunc& surfProg) +Mesh::Mesh(Connection& conn, HMDLTopology topologyIn, int skinSlotCount, SurfProgFunc& surfProg) : topology(topologyIn), sceneXf(conn), aabbMin(conn), aabbMax(conn) { uint32_t matSetCount; @@ -873,8 +1039,7 @@ BlenderConnection::DataStream::Mesh::Mesh } } -BlenderConnection::DataStream::Mesh -BlenderConnection::DataStream::Mesh::getContiguousSkinningVersion() const +Mesh Mesh::getContiguousSkinningVersion() const { Mesh newMesh = *this; newMesh.pos.clear(); @@ -916,8 +1081,7 @@ BlenderConnection::DataStream::Mesh::getContiguousSkinningVersion() const return newMesh; } -BlenderConnection::DataStream::Mesh::Material::Material -(BlenderConnection& conn) +Material::Material(Connection& conn) { uint32_t bufSz; conn._readBuf(&bufSz, 4); @@ -939,8 +1103,8 @@ BlenderConnection::DataStream::Mesh::Material::Material SystemStringConv absolute(readStr); SystemString relative = - conn.m_loadedBlend.getProject().getProjectRootPath().getProjectRelativeFromAbsolute(absolute.sys_str()); - texs.emplace_back(conn.m_loadedBlend.getProject().getProjectWorkingPath(), relative); + conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(absolute.sys_str()); + texs.emplace_back(conn.getBlendPath().getProject().getProjectWorkingPath(), relative); } uint32_t iPropCount; @@ -960,8 +1124,7 @@ BlenderConnection::DataStream::Mesh::Material::Material conn._readBuf(&transparent, 1); } -BlenderConnection::DataStream::Mesh::Surface::Surface -(BlenderConnection& conn, Mesh& parent, int skinSlotCount) +Mesh::Surface::Surface(Connection& conn, Mesh& parent, int skinSlotCount) : centroid(conn), materialIdx(conn), aabbMin(conn), aabbMax(conn), reflectionNormal(conn) { @@ -981,8 +1144,7 @@ BlenderConnection::DataStream::Mesh::Surface::Surface skinBankIdx = parent.skinBanks.addSurface(parent, *this, skinSlotCount); } -BlenderConnection::DataStream::Mesh::Surface::Vert::Vert -(BlenderConnection& conn, const Mesh& parent) +Mesh::Surface::Vert::Vert(Connection& conn, const Mesh& parent) { conn._readBuf(&iPos, 4); conn._readBuf(&iNorm, 4); @@ -993,6 +1155,23 @@ BlenderConnection::DataStream::Mesh::Surface::Vert::Vert conn._readBuf(&iSkin, 4); } +bool Mesh::Surface::Vert::operator==(const Vert& other) const +{ + if (iPos != other.iPos) + return false; + if (iNorm != other.iNorm) + return false; + for (int i=0 ; i<4 ; ++i) + if (iColor[i] != other.iColor[i]) + return false; + for (int i=0 ; i<8 ; ++i) + if (iUv[i] != other.iUv[i]) + return false; + if (iSkin != other.iSkin) + return false; + return true; +} + static bool VertInBank(const std::vector& bank, uint32_t sIdx) { for (uint32_t idx : bank) @@ -1001,8 +1180,45 @@ static bool VertInBank(const std::vector& bank, uint32_t sIdx) return false; } -uint32_t BlenderConnection::DataStream::Mesh::SkinBanks::addSurface -(const Mesh& mesh, const Surface& surf, int skinSlotCount) +void Mesh::SkinBanks::Bank::addSkins(const Mesh& parent, const std::vector& skinIdxs) +{ + for (uint32_t sidx : skinIdxs) + { + m_skinIdxs.push_back(sidx); + for (const SkinBind& bind : parent.skins[sidx]) + { + bool found = false; + for (uint32_t bidx : m_boneIdxs) + { + if (bidx == bind.boneIdx) + { + found = true; + break; + } + } + if (!found) + m_boneIdxs.push_back(bind.boneIdx); + } + } +} + +size_t Mesh::SkinBanks::Bank::lookupLocalBoneIdx(uint32_t boneIdx) const +{ + for (size_t i=0 ; i::iterator Mesh::SkinBanks::addSkinBank(int skinSlotCount) +{ + banks.emplace_back(); + if (skinSlotCount > 0) + banks.back().m_skinIdxs.reserve(skinSlotCount); + return banks.end() - 1; +} + +uint32_t Mesh::SkinBanks::addSurface(const Mesh& mesh, const Surface& surf, int skinSlotCount) { if (banks.empty()) addSkinBank(skinSlotCount); @@ -1048,7 +1264,7 @@ uint32_t BlenderConnection::DataStream::Mesh::SkinBanks::addSurface return uint32_t(-1); } -BlenderConnection::DataStream::ColMesh::ColMesh(BlenderConnection& conn) +ColMesh::ColMesh(Connection& conn) { uint32_t matCount; conn._readBuf(&matCount, 4); @@ -1073,7 +1289,7 @@ BlenderConnection::DataStream::ColMesh::ColMesh(BlenderConnection& conn) trianges.emplace_back(conn); } -BlenderConnection::DataStream::ColMesh::Material::Material(BlenderConnection& conn) +ColMesh::Material::Material(Connection& conn) { uint32_t nameLen; conn._readBuf(&nameLen, 4); @@ -1085,17 +1301,17 @@ BlenderConnection::DataStream::ColMesh::Material::Material(BlenderConnection& co conn._readBuf(&unknown, 42); } -BlenderConnection::DataStream::ColMesh::Edge::Edge(BlenderConnection& conn) +ColMesh::Edge::Edge(Connection& conn) { conn._readBuf(this, 9); } -BlenderConnection::DataStream::ColMesh::Triangle::Triangle(BlenderConnection& conn) +ColMesh::Triangle::Triangle(Connection& conn) { conn._readBuf(this, 17); } -BlenderConnection::DataStream::World::Area::Dock::Dock(BlenderConnection& conn) +World::Area::Dock::Dock(Connection& conn) { verts[0].read(conn); verts[1].read(conn); @@ -1105,7 +1321,7 @@ BlenderConnection::DataStream::World::Area::Dock::Dock(BlenderConnection& conn) targetDock.read(conn); } -BlenderConnection::DataStream::World::Area::Area(BlenderConnection& conn) +World::Area::Area(Connection& conn) { std::string name; uint32_t nameLen; @@ -1116,7 +1332,7 @@ BlenderConnection::DataStream::World::Area::Area(BlenderConnection& conn) conn._readBuf(&name[0], nameLen); } - path.assign(conn.m_loadedBlend.getParentPath(), name); + path.assign(conn.getBlendPath().getParentPath(), name); aabb[0].read(conn); aabb[1].read(conn); transform.read(conn); @@ -1128,7 +1344,7 @@ BlenderConnection::DataStream::World::Area::Area(BlenderConnection& conn) docks.emplace_back(conn); } -BlenderConnection::DataStream::World::World(BlenderConnection& conn) +World::World(Connection& conn) { uint32_t areaCount; conn._readBuf(&areaCount, 4); @@ -1137,7 +1353,7 @@ BlenderConnection::DataStream::World::World(BlenderConnection& conn) areas.emplace_back(conn); } -BlenderConnection::DataStream::Light::Light(BlenderConnection& conn) +Light::Light(Connection& conn) : sceneXf(conn), color(conn) { conn._readBuf(&layer, 29); @@ -1151,7 +1367,7 @@ BlenderConnection::DataStream::Light::Light(BlenderConnection& conn) } } -BlenderConnection::DataStream::MapArea::Surface::Surface(BlenderConnection& conn) +MapArea::Surface::Surface(Connection& conn) { centerOfMass.read(conn); normal.read(conn); @@ -1168,13 +1384,13 @@ BlenderConnection::DataStream::MapArea::Surface::Surface(BlenderConnection& conn } } -BlenderConnection::DataStream::MapArea::POI::POI(BlenderConnection& conn) +MapArea::POI::POI(Connection& conn) { conn._readBuf(&type, 12); xf.read(conn); } -BlenderConnection::DataStream::MapArea::MapArea(BlenderConnection& conn) +MapArea::MapArea(Connection& conn) { visType.read(conn); @@ -1205,7 +1421,7 @@ BlenderConnection::DataStream::MapArea::MapArea(BlenderConnection& conn) pois.emplace_back(conn); } -BlenderConnection::DataStream::MapUniverse::World::World(BlenderConnection& conn) +MapUniverse::World::World(Connection& conn) { uint32_t nameLen; conn._readBuf(&nameLen, 4); @@ -1234,11 +1450,11 @@ BlenderConnection::DataStream::MapUniverse::World::World(BlenderConnection& conn conn._readBuf(&path[0], pathLen); hecl::SystemStringConv sysPath(path); - worldPath.assign(conn.m_loadedBlend.getProject().getProjectWorkingPath(), sysPath.sys_str()); + worldPath.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), sysPath.sys_str()); } } -BlenderConnection::DataStream::MapUniverse::MapUniverse(BlenderConnection& conn) +MapUniverse::MapUniverse(Connection& conn) { uint32_t pathLen; conn._readBuf(&pathLen, 4); @@ -1250,8 +1466,8 @@ BlenderConnection::DataStream::MapUniverse::MapUniverse(BlenderConnection& conn) hecl::SystemStringConv sysPath(path); SystemString pathRel = - conn.m_loadedBlend.getProject().getProjectRootPath().getProjectRelativeFromAbsolute(sysPath.sys_str()); - hexagonPath.assign(conn.m_loadedBlend.getProject().getProjectWorkingPath(), pathRel); + conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(sysPath.sys_str()); + hexagonPath.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), pathRel); } uint32_t worldCount; @@ -1261,7 +1477,7 @@ BlenderConnection::DataStream::MapUniverse::MapUniverse(BlenderConnection& conn) worlds.emplace_back(conn); } -BlenderConnection::DataStream::Actor::Actor(BlenderConnection& conn) +Actor::Actor(Connection& conn) { uint32_t armCount; conn._readBuf(&armCount, 4); @@ -1282,7 +1498,40 @@ BlenderConnection::DataStream::Actor::Actor(BlenderConnection& conn) actions.emplace_back(conn); } -BlenderConnection::DataStream::Actor::Armature::Armature(BlenderConnection& conn) +const Bone* Armature::lookupBone(const char* name) const +{ + for (const Bone& b : bones) + if (!b.name.compare(name)) + return &b; + return nullptr; +} + +const Bone* Armature::getParent(const Bone* bone) const +{ + if (bone->parent < 0) + return nullptr; + return &bones[bone->parent]; +} + +const Bone* Armature::getChild(const Bone* bone, size_t child) const +{ + if (child >= bone->children.size()) + return nullptr; + int32_t cIdx = bone->children[child]; + if (cIdx < 0) + return nullptr; + return &bones[cIdx]; +} + +const Bone* Armature::getRoot() const +{ + for (const Bone& b : bones) + if (b.parent < 0) + return &b; + return nullptr; +} + +Armature::Armature(Connection& conn) { uint32_t bufSz; conn._readBuf(&bufSz, 4); @@ -1296,7 +1545,7 @@ BlenderConnection::DataStream::Actor::Armature::Armature(BlenderConnection& conn bones.emplace_back(conn); } -BlenderConnection::DataStream::Actor::Armature::Bone::Bone(BlenderConnection& conn) +Bone::Bone(Connection& conn) { uint32_t bufSz; conn._readBuf(&bufSz, 4); @@ -1317,7 +1566,7 @@ BlenderConnection::DataStream::Actor::Armature::Bone::Bone(BlenderConnection& co } } -BlenderConnection::DataStream::Actor::Subtype::Subtype(BlenderConnection& conn) +Actor::Subtype::Subtype(Connection& conn) { uint32_t bufSz; conn._readBuf(&bufSz, 4); @@ -1333,8 +1582,8 @@ BlenderConnection::DataStream::Actor::Subtype::Subtype(BlenderConnection& conn) SystemStringConv meshPathAbs(meshPath); SystemString meshPathRel = - conn.m_loadedBlend.getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str()); - mesh.assign(conn.m_loadedBlend.getProject().getProjectWorkingPath(), meshPathRel); + conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str()); + mesh.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), meshPathRel); } conn._readBuf(&armature, 4); @@ -1358,14 +1607,14 @@ BlenderConnection::DataStream::Actor::Subtype::Subtype(BlenderConnection& conn) SystemStringConv meshPathAbs(meshPath); SystemString meshPathRel = - conn.m_loadedBlend.getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str()); + conn.getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(meshPathAbs.sys_str()); overlayMeshes.emplace_back(std::move(overlayName), - ProjectPath(conn.m_loadedBlend.getProject().getProjectWorkingPath(), meshPathRel)); + ProjectPath(conn.getBlendPath().getProject().getProjectWorkingPath(), meshPathRel)); } } } -BlenderConnection::DataStream::Actor::Action::Action(BlenderConnection& conn) +Action::Action(Connection& conn) { uint32_t bufSz; conn._readBuf(&bufSz, 4); @@ -1403,7 +1652,7 @@ BlenderConnection::DataStream::Actor::Action::Action(BlenderConnection& conn) } } -BlenderConnection::DataStream::Actor::Action::Channel::Channel(BlenderConnection& conn) +Action::Channel::Channel(Connection& conn) { uint32_t bufSz; conn._readBuf(&bufSz, 4); @@ -1419,7 +1668,7 @@ BlenderConnection::DataStream::Actor::Action::Channel::Channel(BlenderConnection keys.emplace_back(conn, attrMask); } -BlenderConnection::DataStream::Actor::Action::Channel::Key::Key(BlenderConnection& conn, uint32_t attrMask) +Action::Channel::Key::Key(Connection& conn, uint32_t attrMask) { if (attrMask & 1) rotation.read(conn); @@ -1431,15 +1680,93 @@ BlenderConnection::DataStream::Actor::Action::Channel::Key::Key(BlenderConnectio scale.read(conn); } -BlenderConnection::DataStream::Mesh -BlenderConnection::DataStream::compileMesh(HMDLTopology topology, - int skinSlotCount, - Mesh::SurfProgFunc surfProg) +DataStream::DataStream(Connection* parent) +: m_parent(parent) { - if (m_parent->m_loadedType != BlendType::Mesh) - BlenderLog.report(logvisor::Fatal, _S("%s is not a MESH blend"), + m_parent->m_dataStreamActive = true; + m_parent->_writeStr("DATABEGIN"); + char readBuf[16]; + m_parent->_readStr(readBuf, 16); + if (strcmp(readBuf, "READY")) + BlenderLog.report(logvisor::Fatal, "unable to open DataStream with blender"); +} + +void DataStream::close() +{ + if (m_parent && m_parent->m_lock) + { + m_parent->_writeStr("DATAEND"); + char readBuf[16]; + m_parent->_readStr(readBuf, 16); + if (strcmp(readBuf, "DONE")) + BlenderLog.report(logvisor::Fatal, "unable to close DataStream with blender"); + m_parent->m_dataStreamActive = false; + m_parent->m_lock = false; + } +} + +std::vector DataStream::getMeshList() +{ + m_parent->_writeStr("MESHLIST"); + uint32_t count; + m_parent->_readBuf(&count, 4); + std::vector retval; + retval.reserve(count); + for (uint32_t i=0 ; i_readStr(name, 128); + retval.push_back(name); + } + return retval; +} + +std::vector DataStream::getLightList() +{ + m_parent->_writeStr("LIGHTLIST"); + uint32_t count; + m_parent->_readBuf(&count, 4); + std::vector retval; + retval.reserve(count); + for (uint32_t i=0 ; i_readStr(name, 128); + retval.push_back(name); + } + return retval; +} + +std::pair DataStream::getMeshAABB() +{ + if (m_parent->m_loadedType != BlendType::Mesh && + m_parent->m_loadedType != BlendType::Actor) + BlenderLog.report(logvisor::Fatal, _S("%s is not a MESH or ACTOR blend"), m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->_writeStr("MESHAABB"); + char readBuf[256]; + m_parent->_readStr(readBuf, 256); + if (strcmp(readBuf, "OK")) + BlenderLog.report(logvisor::Fatal, "unable get AABB: %s", readBuf); + + Vector3f minPt(*m_parent); + Vector3f maxPt(*m_parent); + return std::make_pair(minPt.val, maxPt.val); +} + +const char* DataStream::MeshOutputModeString(HMDLTopology topology) +{ + static const char* STRS[] = {"TRIANGLES", "TRISTRIPS"}; + return STRS[int(topology)]; +} + +Mesh DataStream::compileMesh(HMDLTopology topology, int skinSlotCount, Mesh::SurfProgFunc surfProg) +{ + if (m_parent->getBlendType() != BlendType::Mesh) + BlenderLog.report(logvisor::Fatal, _S("%s is not a MESH blend"), + m_parent->getBlendPath().getAbsolutePath().data()); + char req[128]; snprintf(req, 128, "MESHCOMPILE %s %d", MeshOutputModeString(topology), skinSlotCount); @@ -1453,15 +1780,12 @@ BlenderConnection::DataStream::compileMesh(HMDLTopology topology, return Mesh(*m_parent, topology, skinSlotCount, surfProg); } -BlenderConnection::DataStream::Mesh -BlenderConnection::DataStream::compileMesh(std::string_view name, - HMDLTopology topology, - int skinSlotCount, - Mesh::SurfProgFunc surfProg) +Mesh DataStream::compileMesh(std::string_view name, HMDLTopology topology, + int skinSlotCount, Mesh::SurfProgFunc surfProg) { - if (m_parent->m_loadedType != BlendType::Area) + if (m_parent->getBlendType() != BlendType::Area) BlenderLog.report(logvisor::Fatal, _S("%s is not an AREA blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); char req[128]; snprintf(req, 128, "MESHCOMPILENAME %s %s %d", name.data(), @@ -1476,12 +1800,11 @@ BlenderConnection::DataStream::compileMesh(std::string_view name, return Mesh(*m_parent, topology, skinSlotCount, surfProg); } -BlenderConnection::DataStream::ColMesh -BlenderConnection::DataStream::compileColMesh(std::string_view name) +ColMesh DataStream::compileColMesh(std::string_view name) { - if (m_parent->m_loadedType != BlendType::Area) + if (m_parent->getBlendType() != BlendType::Area) BlenderLog.report(logvisor::Fatal, _S("%s is not an AREA blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); char req[128]; snprintf(req, 128, "MESHCOMPILENAMECOLLISION %s", name.data()); @@ -1495,12 +1818,11 @@ BlenderConnection::DataStream::compileColMesh(std::string_view name) return ColMesh(*m_parent); } -std::vector -BlenderConnection::DataStream::compileColMeshes() +std::vector DataStream::compileColMeshes() { - if (m_parent->m_loadedType != BlendType::ColMesh) + if (m_parent->getBlendType() != BlendType::ColMesh) BlenderLog.report(logvisor::Fatal, _S("%s is not a CMESH blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); char req[128]; snprintf(req, 128, "MESHCOMPILECOLLISIONALL"); @@ -1514,7 +1836,7 @@ BlenderConnection::DataStream::compileColMeshes() uint32_t meshCount; m_parent->_readBuf(&meshCount, 4); - std::vector ret; + std::vector ret; ret.reserve(meshCount); for (uint32_t i=0 ; im_loadedType != BlendType::Area) + if (m_parent->getBlendType() != BlendType::Area) BlenderLog.report(logvisor::Fatal, _S("%s is not an AREA blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); char req[128]; snprintf(req, 128, "MESHCOMPILEALL %s %d %f", @@ -1547,11 +1866,11 @@ BlenderConnection::DataStream::compileAllMeshes(HMDLTopology topology, return Mesh(*m_parent, topology, skinSlotCount, surfProg); } -std::vector BlenderConnection::DataStream::compileLights() +std::vector DataStream::compileLights() { - if (m_parent->m_loadedType != BlendType::Area) + if (m_parent->getBlendType() != BlendType::Area) BlenderLog.report(logvisor::Fatal, _S("%s is not an AREA blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); m_parent->_writeStr("LIGHTCOMPILEALL"); @@ -1563,7 +1882,7 @@ std::vector BlenderConnection::DataStream: uint32_t lightCount; m_parent->_readBuf(&lightCount, 4); - std::vector ret; + std::vector ret; ret.reserve(lightCount); for (uint32_t i=0 ; i BlenderConnection::DataStream: return ret; } -void BlenderConnection::DataStream::compileGuiFrame(std::string_view pathOut, int version) +void DataStream::compileGuiFrame(std::string_view pathOut, int version) { - if (m_parent->m_loadedType != BlendType::Frame) + if (m_parent->getBlendType() != BlendType::Frame) BlenderLog.report(logvisor::Fatal, _S("%s is not a FRAME blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); char req[512]; snprintf(req, 512, "FRAMECOMPILE '%s' %d", pathOut.data(), version); @@ -1595,7 +1914,7 @@ void BlenderConnection::DataStream::compileGuiFrame(std::string_view pathOut, in std::string readStr(readBuf); SystemStringConv absolute(readStr); - auto& proj = m_parent->m_loadedBlend.getProject(); + auto& proj = m_parent->getBlendPath().getProject(); SystemString relative; if (PathRelative(absolute.c_str())) relative = absolute.sys_str(); @@ -1608,7 +1927,7 @@ void BlenderConnection::DataStream::compileGuiFrame(std::string_view pathOut, in } } -std::vector BlenderConnection::DataStream::getTextures() +std::vector DataStream::getTextures() { m_parent->_writeStr("GETTEXTURES"); @@ -1630,18 +1949,18 @@ std::vector BlenderConnection::DataStream::getTextures() SystemStringConv absolute(readStr); SystemString relative = - m_parent->m_loadedBlend.getProject().getProjectRootPath().getProjectRelativeFromAbsolute(absolute.sys_str()); - texs.emplace_back(m_parent->m_loadedBlend.getProject().getProjectWorkingPath(), relative); + m_parent->getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(absolute.sys_str()); + texs.emplace_back(m_parent->getBlendPath().getProject().getProjectWorkingPath(), relative); } return texs; } -BlenderConnection::DataStream::Actor BlenderConnection::DataStream::compileActor() +Actor DataStream::compileActor() { - if (m_parent->m_loadedType != BlendType::Actor) + if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, _S("%s is not an ACTOR blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); m_parent->_writeStr("ACTORCOMPILE"); @@ -1653,12 +1972,11 @@ BlenderConnection::DataStream::Actor BlenderConnection::DataStream::compileActor return Actor(*m_parent); } -BlenderConnection::DataStream::Actor -BlenderConnection::DataStream::compileActorCharacterOnly() +Actor DataStream::compileActorCharacterOnly() { - if (m_parent->m_loadedType != BlendType::Actor) + if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, _S("%s is not an ACTOR blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); m_parent->_writeStr("ACTORCOMPILECHARACTERONLY"); @@ -1670,12 +1988,11 @@ BlenderConnection::DataStream::compileActorCharacterOnly() return Actor(*m_parent); } -BlenderConnection::DataStream::Actor::Action -BlenderConnection::DataStream::compileActionChannelsOnly(std::string_view name) +Action DataStream::compileActionChannelsOnly(std::string_view name) { - if (m_parent->m_loadedType != BlendType::Actor) + if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, _S("%s is not an ACTOR blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); char req[128]; snprintf(req, 128, "ACTIONCOMPILECHANNELSONLY %s", name.data()); @@ -1686,15 +2003,14 @@ BlenderConnection::DataStream::compileActionChannelsOnly(std::string_view name) if (strcmp(readBuf, "OK")) BlenderLog.report(logvisor::Fatal, "unable to compile action: %s", readBuf); - return Actor::Action(*m_parent); + return Action(*m_parent); } -BlenderConnection::DataStream::World -BlenderConnection::DataStream::compileWorld() +World DataStream::compileWorld() { - if (m_parent->m_loadedType != BlendType::World) + if (m_parent->getBlendType() != BlendType::World) BlenderLog.report(logvisor::Fatal, _S("%s is not an WORLD blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); m_parent->_writeStr("WORLDCOMPILE"); @@ -1706,11 +2022,11 @@ BlenderConnection::DataStream::compileWorld() return World(*m_parent); } -std::vector BlenderConnection::DataStream::getArmatureNames() +std::vector DataStream::getArmatureNames() { - if (m_parent->m_loadedType != BlendType::Actor) + if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, _S("%s is not an ACTOR blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); m_parent->_writeStr("GETARMATURENAMES"); @@ -1737,11 +2053,11 @@ std::vector BlenderConnection::DataStream::getArmatureNames() return ret; } -std::vector BlenderConnection::DataStream::getSubtypeNames() +std::vector DataStream::getSubtypeNames() { - if (m_parent->m_loadedType != BlendType::Actor) + if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, _S("%s is not an ACTOR blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); m_parent->_writeStr("GETSUBTYPENAMES"); @@ -1768,11 +2084,11 @@ std::vector BlenderConnection::DataStream::getSubtypeNames() return ret; } -std::vector BlenderConnection::DataStream::getActionNames() +std::vector DataStream::getActionNames() { - if (m_parent->m_loadedType != BlendType::Actor) + if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, _S("%s is not an ACTOR blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); m_parent->_writeStr("GETACTIONNAMES"); @@ -1799,11 +2115,11 @@ std::vector BlenderConnection::DataStream::getActionNames() return ret; } -std::vector BlenderConnection::DataStream::getSubtypeOverlayNames(std::string_view name) +std::vector DataStream::getSubtypeOverlayNames(std::string_view name) { - if (m_parent->m_loadedType != BlendType::Actor) + if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, _S("%s is not an ACTOR blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); char req[128]; snprintf(req, 128, "GETSUBTYPEOVERLAYNAMES %s", name.data()); @@ -1832,15 +2148,15 @@ std::vector BlenderConnection::DataStream::getSubtypeOverlayNames(s return ret; } -std::unordered_map -BlenderConnection::DataStream::getBoneMatrices(std::string_view name) +std::unordered_map +DataStream::getBoneMatrices(std::string_view name) { if (name.empty()) return {}; - if (m_parent->m_loadedType != BlendType::Actor) + if (m_parent->getBlendType() != BlendType::Actor) BlenderLog.report(logvisor::Fatal, _S("%s is not an ACTOR blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); char req[128]; snprintf(req, 128, "GETBONEMATRICES %s", name.data()); @@ -1883,14 +2199,14 @@ BlenderConnection::DataStream::getBoneMatrices(std::string_view name) } -bool BlenderConnection::DataStream::renderPvs(std::string_view path, const atVec3f& location) +bool DataStream::renderPvs(std::string_view path, const atVec3f& location) { if (path.empty()) return false; - if (m_parent->m_loadedType != BlendType::Area) + if (m_parent->getBlendType() != BlendType::Area) BlenderLog.report(logvisor::Fatal, _S("%s is not an AREA blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); char req[256]; snprintf(req, 256, "RENDERPVS %s %f %f %f", path.data(), @@ -1901,19 +2217,19 @@ bool BlenderConnection::DataStream::renderPvs(std::string_view path, const atVec m_parent->_readStr(readBuf, 256); if (strcmp(readBuf, "OK")) BlenderLog.report(logvisor::Fatal, "unable to render PVS for: %s; %s", - m_parent->m_loadedBlend.getAbsolutePathUTF8().data(), readBuf); + m_parent->getBlendPath().getAbsolutePathUTF8().data(), readBuf); return true; } -bool BlenderConnection::DataStream::renderPvsLight(std::string_view path, std::string_view lightName) +bool DataStream::renderPvsLight(std::string_view path, std::string_view lightName) { if (path.empty()) return false; - if (m_parent->m_loadedType != BlendType::Area) + if (m_parent->getBlendType() != BlendType::Area) BlenderLog.report(logvisor::Fatal, _S("%s is not an AREA blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); char req[256]; snprintf(req, 256, "RENDERPVSLIGHT %s %s", path.data(), lightName.data()); @@ -1923,16 +2239,16 @@ bool BlenderConnection::DataStream::renderPvsLight(std::string_view path, std::s m_parent->_readStr(readBuf, 256); if (strcmp(readBuf, "OK")) BlenderLog.report(logvisor::Fatal, "unable to render PVS light %s for: %s; %s", lightName.data(), - m_parent->m_loadedBlend.getAbsolutePathUTF8().data(), readBuf); + m_parent->getBlendPath().getAbsolutePathUTF8().data(), readBuf); return true; } -BlenderConnection::DataStream::MapArea BlenderConnection::DataStream::compileMapArea() +MapArea DataStream::compileMapArea() { - if (m_parent->m_loadedType != BlendType::MapArea) + if (m_parent->getBlendType() != BlendType::MapArea) BlenderLog.report(logvisor::Fatal, _S("%s is not a MAPAREA blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); m_parent->_writeStr("MAPAREACOMPILE"); @@ -1940,16 +2256,16 @@ BlenderConnection::DataStream::MapArea BlenderConnection::DataStream::compileMap m_parent->_readStr(readBuf, 256); if (strcmp(readBuf, "OK")) BlenderLog.report(logvisor::Fatal, "unable to compile map area: %s; %s", - m_parent->m_loadedBlend.getAbsolutePathUTF8().data(), readBuf); + m_parent->getBlendPath().getAbsolutePathUTF8().data(), readBuf); return {*m_parent}; } -BlenderConnection::DataStream::MapUniverse BlenderConnection::DataStream::compileMapUniverse() +MapUniverse DataStream::compileMapUniverse() { - if (m_parent->m_loadedType != BlendType::MapUniverse) + if (m_parent->getBlendType() != BlendType::MapUniverse) BlenderLog.report(logvisor::Fatal, _S("%s is not a MAPUNIVERSE blend"), - m_parent->m_loadedBlend.getAbsolutePath().data()); + m_parent->getBlendPath().getAbsolutePath().data()); m_parent->_writeStr("MAPUNIVERSECOMPILE"); @@ -1957,12 +2273,12 @@ BlenderConnection::DataStream::MapUniverse BlenderConnection::DataStream::compil m_parent->_readStr(readBuf, 256); if (strcmp(readBuf, "OK")) BlenderLog.report(logvisor::Fatal, "unable to compile map universe: %s; %s", - m_parent->m_loadedBlend.getAbsolutePathUTF8().data(), readBuf); + m_parent->getBlendPath().getAbsolutePathUTF8().data(), readBuf); return {*m_parent}; } -void BlenderConnection::quitBlender() +void Connection::quitBlender() { char lineBuf[256]; if (m_lock) @@ -1985,14 +2301,49 @@ void BlenderConnection::quitBlender() _readStr(lineBuf, sizeof(lineBuf)); } -BlenderConnection& BlenderConnection::SharedConnection() +Connection& Connection::SharedConnection() { return SharedBlenderToken.getBlenderConnection(); } -void BlenderConnection::Shutdown() +void Connection::Shutdown() { SharedBlenderToken.shutdown(); } +Connection& Token::getBlenderConnection() +{ + if (!m_conn) + m_conn = std::make_unique(hecl::VerbosityLevel); + return *m_conn; +} + +void Token::shutdown() +{ + if (m_conn) + { + m_conn->quitBlender(); + m_conn.reset(); + BlenderLog.report(logvisor::Info, "BlenderConnection Shutdown Successful"); + } +} + +Token::~Token() { shutdown(); } + +HMDLBuffers::HMDLBuffers(HMDLMeta&& meta, + size_t vboSz, const std::vector& iboData, + std::vector&& surfaces, + const Mesh::SkinBanks& skinBanks) +: m_meta(std::move(meta)), + m_vboSz(vboSz), m_vboData(new uint8_t[vboSz]), + m_iboSz(iboData.size()*4), m_iboData(new uint8_t[iboData.size()*4]), + m_surfaces(std::move(surfaces)), m_skinBanks(skinBanks) +{ + if (m_iboSz) + { + athena::io::MemoryWriter w(m_iboData.get(), m_iboSz); + w.enumerateLittle(iboData); + } +} + } diff --git a/hecl/lib/Blender/HMDL.cpp b/hecl/lib/Blender/HMDL.cpp index b0259db84..8643bef85 100644 --- a/hecl/lib/Blender/HMDL.cpp +++ b/hecl/lib/Blender/HMDL.cpp @@ -1,11 +1,11 @@ -#include "hecl/Blender/BlenderConnection.hpp" +#include "hecl/Blender/Connection.hpp" #include -#include +#include -namespace hecl +namespace hecl::blender { -atVec3f BlenderConnection::DataStream::MtxVecMul4RM(const Matrix4f& mtx, const Vector3f& vec) +atVec3f MtxVecMul4RM(const Matrix4f& mtx, const Vector3f& vec) { atVec3f res; res.vec[0] = mtx[0].vec[0] * vec.val.vec[0] + mtx[0].vec[1] * vec.val.vec[1] + mtx[0].vec[2] * vec.val.vec[2] + mtx[0].vec[3]; @@ -14,7 +14,7 @@ atVec3f BlenderConnection::DataStream::MtxVecMul4RM(const Matrix4f& mtx, const V return res; } -atVec3f BlenderConnection::DataStream::MtxVecMul3RM(const Matrix4f& mtx, const Vector3f& vec) +atVec3f MtxVecMul3RM(const Matrix4f& mtx, const Vector3f& vec) { atVec3f res; res.vec[0] = mtx[0].vec[0] * vec.val.vec[0] + mtx[0].vec[1] * vec.val.vec[1] + mtx[0].vec[2] * vec.val.vec[2]; @@ -23,8 +23,7 @@ atVec3f BlenderConnection::DataStream::MtxVecMul3RM(const Matrix4f& mtx, const V return res; } -HMDLBuffers BlenderConnection::DataStream::Mesh::getHMDLBuffers(bool absoluteCoords, - PoolSkinIndex& poolSkinIndex) const +HMDLBuffers Mesh::getHMDLBuffers(bool absoluteCoords, PoolSkinIndex& poolSkinIndex) const { /* If skinned, compute max weight vec count */ size_t weightCount = 0; diff --git a/hecl/lib/CMakeLists.txt b/hecl/lib/CMakeLists.txt index f3cd31dff..111a6d71b 100644 --- a/hecl/lib/CMakeLists.txt +++ b/hecl/lib/CMakeLists.txt @@ -39,6 +39,7 @@ add_library(hecl-common ../include/hecl/CVar.hpp ../include/hecl/CVarManager.hpp ../include/hecl/hecl.hpp + ../include/hecl/FourCC.hpp ../include/hecl/HMDLMeta.hpp ../include/hecl/Backend/Backend.hpp ../include/hecl/Backend/GX.hpp @@ -46,7 +47,8 @@ add_library(hecl-common ../include/hecl/Backend/GLSL.hpp ../include/hecl/Backend/HLSL.hpp ../include/hecl/Backend/Metal.hpp - ../include/hecl/Blender/BlenderConnection.hpp + ../include/hecl/Blender/Connection.hpp + ../include/hecl/Blender/Token.hpp ../include/hecl/SteamFinder.hpp ../include/hecl/Frontend.hpp ../include/hecl/Database.hpp @@ -67,6 +69,9 @@ add_library(hecl-common if(COMMAND add_sanitizers) add_sanitizers(hecl-common) endif() +if(COMMAND cotire) + cotire(hecl-common) +endif() if(WINDOWS_STORE) set_property(TARGET hecl-common PROPERTY VS_WINRT_COMPONENT TRUE) diff --git a/hecl/lib/ClientProcess.cpp b/hecl/lib/ClientProcess.cpp index 1d82fab9a..b350b0ecb 100644 --- a/hecl/lib/ClientProcess.cpp +++ b/hecl/lib/ClientProcess.cpp @@ -1,7 +1,7 @@ #include "hecl/ClientProcess.hpp" #include "hecl/Database.hpp" #include "athena/FileReader.hpp" -#include "hecl/Blender/BlenderConnection.hpp" +#include "hecl/Blender/Connection.hpp" #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -14,7 +14,7 @@ namespace hecl { -static logvisor::Module Log("hecl::ClientProcess"); +static logvisor::Module CP_Log("hecl::ClientProcess"); ThreadLocalPtr ClientProcess::ThreadWorker; @@ -29,13 +29,13 @@ static int GetCPUCount() #endif } -void ClientProcess::BufferTransaction::run(BlenderToken& btok) +void ClientProcess::BufferTransaction::run(blender::Token& btok) { athena::io::FileReader r(m_path.getAbsolutePath(), 32 * 1024, false); if (r.hasError()) { - Log.report(logvisor::Fatal, _S("unable to background-buffer '%s'"), - m_path.getAbsolutePath().data()); + CP_Log.report(logvisor::Fatal, _S("unable to background-buffer '%s'"), + m_path.getAbsolutePath().data()); return; } if (m_offset) @@ -44,14 +44,14 @@ void ClientProcess::BufferTransaction::run(BlenderToken& btok) m_complete = true; } -void ClientProcess::CookTransaction::run(BlenderToken& btok) +void ClientProcess::CookTransaction::run(blender::Token& btok) { m_dataSpec->setThreadProject(); m_returnResult = m_parent.syncCook(m_path, m_dataSpec, btok); m_complete = true; } -void ClientProcess::LambdaTransaction::run(BlenderToken& btok) +void ClientProcess::LambdaTransaction::run(blender::Token& btok) { m_func(btok); m_complete = true; @@ -137,7 +137,7 @@ ClientProcess::addCookTransaction(const hecl::ProjectPath& path, Database::IData } std::shared_ptr -ClientProcess::addLambdaTransaction(std::function&& func) +ClientProcess::addLambdaTransaction(std::function&& func) { std::unique_lock lk(m_mutex); auto ret = std::make_shared(*this, std::move(func)); @@ -146,7 +146,7 @@ ClientProcess::addLambdaTransaction(std::function&& func) return ret; } -bool ClientProcess::syncCook(const hecl::ProjectPath& path, Database::IDataSpec* spec, BlenderToken& btok) +bool ClientProcess::syncCook(const hecl::ProjectPath& path, Database::IDataSpec* spec, blender::Token& btok) { if (spec->canCook(path, btok)) { diff --git a/hecl/lib/Frontend/Diagnostics.cpp b/hecl/lib/Frontend/Diagnostics.cpp index 18f255c77..bcb844254 100644 --- a/hecl/lib/Frontend/Diagnostics.cpp +++ b/hecl/lib/Frontend/Diagnostics.cpp @@ -1,7 +1,7 @@ #include "hecl/hecl.hpp" #include "hecl/Frontend.hpp" -#include +#include /* ANSI sequences */ #define RED "\x1b[1;31m" diff --git a/hecl/lib/Project.cpp b/hecl/lib/Project.cpp index 878fcc79c..4a837673e 100644 --- a/hecl/lib/Project.cpp +++ b/hecl/lib/Project.cpp @@ -1,7 +1,7 @@ #include -#include -#include -#include +#include +#include +#include #include #if _WIN32 @@ -10,12 +10,10 @@ #endif #include "hecl/Database.hpp" -#include "hecl/Blender/BlenderConnection.hpp" +#include "hecl/Blender/Connection.hpp" #include "hecl/ClientProcess.hpp" -namespace hecl -{ -namespace Database +namespace hecl::Database { logvisor::Module LogModule("hecl::Database"); @@ -397,7 +395,7 @@ static void VisitFile(const ProjectPath& path, bool force, bool fast, { for (auto& spec : specInsts) { - if (spec->canCook(path, hecl::SharedBlenderToken)) + if (spec->canCook(path, hecl::blender::SharedBlenderToken)) { if (cp) { @@ -406,7 +404,7 @@ static void VisitFile(const ProjectPath& path, bool force, bool fast, else { const DataSpecEntry* override = spec->overrideDataSpec(path, spec->getDataSpecEntry(), - hecl::SharedBlenderToken); + hecl::blender::SharedBlenderToken); if (!override) continue; ProjectPath cooked = path.getCookedPath(*override); @@ -416,7 +414,7 @@ static void VisitFile(const ProjectPath& path, bool force, bool fast, path.getModtime() > cooked.getModtime()) { progress.reportFile(override); - spec->doCook(path, cooked, fast, hecl::SharedBlenderToken, + spec->doCook(path, cooked, fast, hecl::blender::SharedBlenderToken, [&](const SystemChar* extra) { progress.reportFile(override, extra); @@ -539,7 +537,7 @@ bool Project::packagePath(const ProjectPath& path, FProgress progress, bool fast if (m_lastPackageSpec->canPackage(path)) { - m_lastPackageSpec->doPackage(path, specEntry, fast, hecl::SharedBlenderToken, progress, cp); + m_lastPackageSpec->doPackage(path, specEntry, fast, hecl::blender::SharedBlenderToken, progress, cp); return true; } @@ -579,4 +577,3 @@ const ProjectPath* Project::lookupBridgePath(uint64_t id) const } } -} diff --git a/hecl/lib/Runtime/FileStoreManager.cpp b/hecl/lib/Runtime/FileStoreManager.cpp index eeab2d8af..56de3605a 100644 --- a/hecl/lib/Runtime/FileStoreManager.cpp +++ b/hecl/lib/Runtime/FileStoreManager.cpp @@ -8,9 +8,7 @@ using namespace Windows::Storage; #endif -namespace hecl -{ -namespace Runtime +namespace hecl::Runtime { static logvisor::Module Log("FileStoreManager"); @@ -53,4 +51,3 @@ FileStoreManager::FileStoreManager(SystemStringView domain) } } -} diff --git a/hecl/lib/Runtime/HMDL_RT.cpp b/hecl/lib/Runtime/HMDL_RT.cpp index bdf03f94a..8f422e64b 100644 --- a/hecl/lib/Runtime/HMDL_RT.cpp +++ b/hecl/lib/Runtime/HMDL_RT.cpp @@ -2,11 +2,9 @@ #include "hecl/Runtime.hpp" #include -namespace hecl +namespace hecl::Runtime { -namespace Runtime -{ -static logvisor::Module Log("HMDL"); +static logvisor::Module HMDL_Log("HMDL"); HMDLData::HMDLData(boo::IGraphicsDataFactory::Context& ctx, const void* metaData, const void* vbo, const void* ibo) @@ -17,7 +15,7 @@ HMDLData::HMDLData(boo::IGraphicsDataFactory::Context& ctx, meta.read(r); } if (meta.magic != 'TACO') - Log.report(logvisor::Fatal, "invalid HMDL magic"); + HMDL_Log.report(logvisor::Fatal, "invalid HMDL magic"); m_vbo = ctx.newStaticBuffer(boo::BufferUse::Vertex, vbo, meta.vertStride, meta.vertCount); m_ibo = ctx.newStaticBuffer(boo::BufferUse::Index, ibo, 4, meta.indexCount); @@ -102,4 +100,3 @@ boo::ObjToken ShaderTag::newVertexFormat(boo::IGraphicsDataF } } -} diff --git a/hecl/lib/Runtime/ShaderCacheManager.cpp b/hecl/lib/Runtime/ShaderCacheManager.cpp index b42358760..97b6825c6 100644 --- a/hecl/lib/Runtime/ShaderCacheManager.cpp +++ b/hecl/lib/Runtime/ShaderCacheManager.cpp @@ -8,9 +8,7 @@ #include "hecl/Backend/GLSL.hpp" #include "hecl/Backend/Metal.hpp" -namespace hecl -{ -namespace Runtime +namespace hecl::Runtime { #if BOO_HAS_GL IShaderBackendFactory* _NewGLSLBackendFactory(); @@ -25,7 +23,7 @@ IShaderBackendFactory* _NewMetalBackendFactory(); IShaderBackendFactory* _NewSPIRVBackendFactory(); #endif -static logvisor::Module Log("ShaderCacheManager"); +static logvisor::Module SCM_Log("ShaderCacheManager"); static uint64_t IDX_MAGIC = SBig(uint64_t(0xDEADFEEDC001D00D)); static uint64_t DAT_MAGIC = SBig(uint64_t(0xC001D00DDEADBABE)); static uint64_t ZERO64 = 0; @@ -88,8 +86,8 @@ void ShaderCacheManager::bootstrapIndex() FILE* idxFp = hecl::Fopen(idxFilename.c_str(), _S("wb")); if (!idxFp) - Log.report(logvisor::Fatal, _S("unable to write shader cache index at %s"), - idxFilename.c_str()); + SCM_Log.report(logvisor::Fatal, _S("unable to write shader cache index at %s"), + idxFilename.c_str()); fwrite(&IDX_MAGIC, 1, 8, idxFp); fwrite(&m_timeHash, 1, 8, idxFp); fwrite(&m_extensionsHash, 1, 8, idxFp); @@ -103,8 +101,8 @@ void ShaderCacheManager::bootstrapIndex() FILE* datFp = hecl::Fopen(datFilename.c_str(), _S("wb")); if (!datFp) - Log.report(logvisor::Fatal, _S("unable to write shader cache data at %s"), - datFilename.c_str()); + SCM_Log.report(logvisor::Fatal, _S("unable to write shader cache data at %s"), + datFilename.c_str()); fwrite(&DAT_MAGIC, 1, 8, datFp); fwrite(&m_timeHash, 1, 8, datFp); fclose(datFp); @@ -125,8 +123,8 @@ ShaderCacheManager::ShaderCacheManager(const FileStoreManager& storeMgr, { boo::IGraphicsDataFactory::Platform plat = gfxFactory->platform(); if (m_extensions && m_extensions.m_plat != plat) - Log.report(logvisor::Fatal, "ShaderCacheExtension backend mismatch (should be %s)", - gfxFactory->platformName()); + SCM_Log.report(logvisor::Fatal, "ShaderCacheExtension backend mismatch (should be %s)", + gfxFactory->platformName()); m_extensionsHash = m_extensions.hashExtensions(); switch (plat) @@ -153,7 +151,7 @@ ShaderCacheManager::ShaderCacheManager(const FileStoreManager& storeMgr, break; #endif default: - Log.report(logvisor::Fatal, _S("unsupported backend %s"), gfxFactory->platformName()); + SCM_Log.report(logvisor::Fatal, _S("unsupported backend %s"), gfxFactory->platformName()); } reload(); @@ -241,7 +239,7 @@ ShaderCachedData ShaderCacheManager::lookupData(const Hash& hash) const IndexEntry& ent = m_entries[search->second]; if (ent.m_compOffset + ent.m_compSize > m_datFr.length()) { - Log.report(logvisor::Warning, "shader cache not long enough to read entry, might be corrupt"); + SCM_Log.report(logvisor::Warning, "shader cache not long enough to read entry, might be corrupt"); return {}; } @@ -280,19 +278,19 @@ bool ShaderCacheManager::addData(const ShaderCachedData& data) uLong cBound = compressBound(data.m_sz); void* compBuf = malloc(cBound); if (compress((Bytef*)compBuf, &cBound, (Bytef*)data.m_data.get(), data.m_sz) != Z_OK) - Log.report(logvisor::Fatal, "unable to deflate data"); + SCM_Log.report(logvisor::Fatal, "unable to deflate data"); /* Open index for writing (non overwriting) */ athena::io::FileWriter idxFw(m_idxFr.filename(), false); if (idxFw.hasError()) - Log.report(logvisor::Fatal, _S("unable to append shader cache index at %s"), - m_idxFr.filename().c_str()); + SCM_Log.report(logvisor::Fatal, _S("unable to append shader cache index at %s"), + m_idxFr.filename().c_str()); /* Open data for writing (non overwriting) */ athena::io::FileWriter datFw(m_datFr.filename(), false); if (datFw.hasError()) - Log.report(logvisor::Fatal, _S("unable to append shader cache data at %s"), - m_datFr.filename().c_str()); + SCM_Log.report(logvisor::Fatal, _S("unable to append shader cache data at %s"), + m_datFr.filename().c_str()); size_t targetOffset = 0; auto search = m_entryLookup.find(data.m_tag); @@ -398,7 +396,7 @@ ShaderCacheManager::buildShader(const ShaderTag& tag, std::string_view source, { factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool { - Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.data(), tag.val64()); + SCM_Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.data(), tag.val64()); boo::ObjToken build = buildFromCache(foundData, ctx); if (build) { @@ -413,13 +411,13 @@ ShaderCacheManager::buildShader(const ShaderTag& tag, std::string_view source, m_pipelineLookup[tag] = ret; return ret; } - Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.data()); + SCM_Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.data()); } factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool { hecl::Frontend::IR ir = FE.compileSource(source, diagName); - Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.data(), tag.val64()); + SCM_Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.data(), tag.val64()); FE.getDiagnostics().reset(diagName); boo::ObjToken build; addData(m_factory->buildShaderFromIR(tag, ir, FE.getDiagnostics(), ctx, build)); @@ -445,7 +443,7 @@ ShaderCacheManager::buildShader(const ShaderTag& tag, const hecl::Frontend::IR& { factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool { - Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.data(), tag.val64()); + SCM_Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.data(), tag.val64()); boo::ObjToken build = buildFromCache(foundData, ctx); if (build) { @@ -460,12 +458,12 @@ ShaderCacheManager::buildShader(const ShaderTag& tag, const hecl::Frontend::IR& m_pipelineLookup[tag] = ret; return ret; } - Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.data()); + SCM_Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.data()); } factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool { - Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.data(), tag.val64()); + SCM_Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.data(), tag.val64()); FE.getDiagnostics().reset(diagName); boo::ObjToken build; addData(m_factory->buildShaderFromIR(tag, ir, FE.getDiagnostics(), ctx, build)); @@ -486,8 +484,8 @@ ShaderCacheManager::buildExtendedFromCache(const ShaderCachedData& foundData, [&](const boo::ObjToken& shader){shaders.push_back(shader);})) return {}; if (shaders.size() != m_extensions.m_extensionSlots.size()) - Log.report(logvisor::Fatal, "buildShaderFromCache returned %" PRISize " times, expected %" PRISize, - shaders.size(), m_extensions.m_extensionSlots.size()); + SCM_Log.report(logvisor::Fatal, "buildShaderFromCache returned %" PRISize " times, expected %" PRISize, + shaders.size(), m_extensions.m_extensionSlots.size()); return shaders; } @@ -506,7 +504,7 @@ ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, std::string_view s { factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool { - Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.data(), tag.val64()); + SCM_Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.data(), tag.val64()); ret->m_pipelines = buildExtendedFromCache(foundData, ctx); return ret->m_pipelines.size() != 0; }); @@ -516,7 +514,7 @@ ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, std::string_view s m_pipelineLookup[tag] = ret; return ret; } - Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.data()); + SCM_Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.data()); } hecl::Frontend::IR ir = FE.compileSource(source, diagName); @@ -525,13 +523,13 @@ ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, std::string_view s { ret->m_pipelines.reserve(m_extensions.m_extensionSlots.size()); FE.getDiagnostics().reset(diagName); - Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.data(), tag.val64()); + SCM_Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.data(), tag.val64()); ShaderCachedData data = m_factory->buildExtendedShaderFromIR(tag, ir, FE.getDiagnostics(), m_extensions.m_extensionSlots, ctx, [&](const boo::ObjToken& shader){ret->m_pipelines.push_back(shader);}); if (ret->m_pipelines.size() != m_extensions.m_extensionSlots.size()) - Log.report(logvisor::Fatal, "buildShaderFromIR returned %" PRISize " times, expected %" PRISize, - ret->m_pipelines.size(), m_extensions.m_extensionSlots.size()); + SCM_Log.report(logvisor::Fatal, "buildShaderFromIR returned %" PRISize " times, expected %" PRISize, + ret->m_pipelines.size(), m_extensions.m_extensionSlots.size()); addData(data); return true; }); @@ -554,7 +552,7 @@ ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const hecl::Fronte { factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool { - Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.data(), tag.val64()); + SCM_Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.data(), tag.val64()); ret->m_pipelines = buildExtendedFromCache(foundData, ctx); return ret->m_pipelines.size() != 0; }); @@ -564,20 +562,20 @@ ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const hecl::Fronte m_pipelineLookup[tag] = ret; return ret; } - Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.data()); + SCM_Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.data()); } factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool { ret->m_pipelines.reserve(m_extensions.m_extensionSlots.size()); FE.getDiagnostics().reset(diagName); - Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.data(), tag.val64()); + SCM_Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.data(), tag.val64()); ShaderCachedData data = m_factory->buildExtendedShaderFromIR(tag, ir, FE.getDiagnostics(), m_extensions.m_extensionSlots, ctx, [&](const boo::ObjToken& shader){ret->m_pipelines.push_back(shader);}); if (ret->m_pipelines.size() != m_extensions.m_extensionSlots.size()) - Log.report(logvisor::Fatal, "buildShaderFromIR returned %" PRISize " times, expected %" PRISize, - ret->m_pipelines.size(), m_extensions.m_extensionSlots.size()); + SCM_Log.report(logvisor::Fatal, "buildShaderFromIR returned %" PRISize " times, expected %" PRISize, + ret->m_pipelines.size(), m_extensions.m_extensionSlots.size()); addData(data); return true; }); @@ -586,4 +584,3 @@ ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const hecl::Fronte } } -} diff --git a/hecl/lib/winsupport.cpp b/hecl/lib/winsupport.cpp index 35b21eb4a..033ff276f 100644 --- a/hecl/lib/winsupport.cpp +++ b/hecl/lib/winsupport.cpp @@ -1,6 +1,6 @@ -#include -#include -#include +#include +#include +#include #include #include "hecl/winsupport.hpp" diff --git a/hecl/test/main.cpp b/hecl/test/main.cpp index 7ba252aaf..6da14996b 100644 --- a/hecl/test/main.cpp +++ b/hecl/test/main.cpp @@ -4,18 +4,15 @@ #include "hecl/Runtime.hpp" #include "hecl/HMDLMeta.hpp" -#include +#include #include #include #include -namespace hecl -{ -namespace Database +namespace hecl::Database { std::vector DATA_SPEC_REGISTRY; } -} struct HECLWindowCallback : boo::IWindowCallback {