diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index 3526f387..98363d9b 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -6,6 +6,7 @@ #include #include "typedefs.hpp" #include "util/stringutil.hpp" +#include "util/platform.hpp" #include #include "io/devices/StdfsDevice.hpp" @@ -44,6 +45,7 @@ void EnginePaths::prepare() { resourcesFolder.string() + " is not a directory" ); } + logger.info() << "executable path: " << platform::get_executable_path().string(); logger.info() << "resources folder: " << fs::canonical(resourcesFolder).u8string(); logger.info() << "user files folder: " << fs::canonical(userFilesFolder).u8string(); logger.info() << "project folder: " << fs::canonical(projectFolder).u8string(); diff --git a/src/objects/rigging.cpp b/src/objects/rigging.cpp index 3f50e905..1c0e9218 100644 --- a/src/objects/rigging.cpp +++ b/src/objects/rigging.cpp @@ -141,7 +141,7 @@ void SkeletonConfig::update( build_matrix(rotation, interpolation.getCurrent()) ); } else { - update(0, skeleton, root.get(), rotation); + update(0, skeleton, root.get(), build_matrix(rotation, position)); } } diff --git a/src/util/platform.cpp b/src/util/platform.cpp index 2cdd0b89..55ac1630 100644 --- a/src/util/platform.cpp +++ b/src/util/platform.cpp @@ -10,13 +10,22 @@ #include "stringutil.hpp" #include "typedefs.hpp" #include "debug/Logger.hpp" - -static debug::Logger logger("platform"); +#include "frontend/locale.hpp" #ifdef _WIN32 #include #pragma comment(lib, "winmm.lib") +#else +#include +#endif +namespace platform::internal { + std::filesystem::path get_executable_path(); +} + +static debug::Logger logger("platform"); + +#ifdef _WIN32 void platform::configure_encoding() { // set utf-8 encoding to console output SetConsoleOutputCP(CP_UTF8); @@ -83,9 +92,6 @@ bool platform::open_url(const std::string& url) { #else // _WIN32 -#include -#include "frontend/locale.hpp" - void platform::configure_encoding() { } @@ -158,3 +164,124 @@ void platform::open_folder(const std::filesystem::path& folder) { #endif } + +std::filesystem::path platform::get_executable_path() { +#ifdef _WIN32 + wchar_t buffer[MAX_PATH]; + DWORD result = GetModuleFileNameW(NULL, buffer, MAX_PATH); + if (result == 0) { + DWORD error = GetLastError(); + throw std::runtime_error("GetModuleFileName failed with code: " + std::to_string(error)); + } + + int size = WideCharToMultiByte( + CP_UTF8, 0, buffer, -1, nullptr, 0, nullptr, nullptr + ); + if (size == 0) { + throw std::runtime_error("could not get executable path"); + } + std::string str(size, 0); + size = WideCharToMultiByte( + CP_UTF8, 0, buffer, -1, str.data(), size, nullptr, nullptr + ); + if (size == 0) { + DWORD error = GetLastError(); + throw std::runtime_error("WideCharToMultiByte failed with code: " + std::to_string(error)); + } + str.resize(size - 1); + return std::filesystem::path(str); + +#elif defined(__APPLE__) + auto path = platform::internal::get_executable_path(); + if (path.empty()) { + throw std::runtime_error("could not get executable path"); + } + return path; +#else + char buffer[1024]; + ssize_t count = readlink("/proc/self/exe", buffer, sizeof(buffer)); + if (count != -1) { + return std::filesystem::canonical(std::filesystem::path( + std::string(buffer, static_cast(count)) + )); + } + throw std::runtime_error("could not get executable path"); +#endif +} + +void platform::new_engine_instance(const std::vector& args) { + auto executable = get_executable_path(); + +#ifdef _WIN32 + std::stringstream ss; + ss << util::quote(executable.u8string()); + for (int i = 0; i < args.size(); i++) { + ss << " " << util::quote(args[i]); + } + + auto toWString = [](const std::string& src) -> std::wstring { + if (src.empty()) + return L""; + int size = MultiByteToWideChar(CP_UTF8, 0, src.c_str(), -1, nullptr, 0); + if (size == 0) { + throw std::runtime_error( + "MultiByteToWideChar failed with code: " + + std::to_string(GetLastError()) + ); + } + std::vector buffer(size + 1); + buffer[size] = 0; + size = MultiByteToWideChar(CP_UTF8, 0, src.c_str(), -1, buffer.data(), size); + if (size == 0) { + throw std::runtime_error( + "MultiByteToWideChar failed with code: " + + std::to_string(GetLastError()) + ); + } + return std::wstring(buffer.data(), size + 1); + }; + + auto commandString = toWString(ss.str()); + + STARTUPINFOW si = { sizeof(si) }; + PROCESS_INFORMATION pi = { 0 }; + DWORD flags = CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS; + // | CREATE_NO_WINDOW; + BOOL success = CreateProcessW( + nullptr, + commandString.data(), + nullptr, + nullptr, + FALSE, + flags, + nullptr, + nullptr, + &si, + &pi + ); + if (success) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } else { + throw std::runtime_error( + "starting an engine instance failed with code: " + + std::to_string(GetLastError()) + ); + } +#else + std::stringstream ss; + ss << executable; + for (int i = 0; i < args.size(); i++) { + ss << " " << util::quote(args[i]); + } + ss << " >/dev/null &"; + + auto command = ss.str(); + if (int res = system(command.c_str())) { + throw std::runtime_error( + "starting an engine instance failed with code: " + + std::to_string(res) + ); + } +#endif +} diff --git a/src/util/platform.hpp b/src/util/platform.hpp index a638ee92..148c64c4 100644 --- a/src/util/platform.hpp +++ b/src/util/platform.hpp @@ -1,17 +1,24 @@ #pragma once #include +#include #include namespace platform { void configure_encoding(); - /// @return environment locale in ISO format ll_CC + /// @brief Get Environment locale in ISO format ll_CC std::string detect_locale(); /// @brief Open folder using system file manager asynchronously /// @param folder target folder void open_folder(const std::filesystem::path& folder); - /// Makes the current thread sleep for the specified amount of milliseconds. + /// @brief Makes the current thread sleep for the specified amount of milliseconds. void sleep(size_t millis); + /// @brief Get current process id int get_process_id(); + /// @brief Get current process running executable path + std::filesystem::path get_executable_path(); + /// @brief Run a separate engine instance with specified arguments + void new_engine_instance(const std::vector& args); + /// @brief Open URL in web browser bool open_url(const std::string& url); } diff --git a/src/util/platform_internal.cpp b/src/util/platform_internal.cpp new file mode 100644 index 00000000..90168219 --- /dev/null +++ b/src/util/platform_internal.cpp @@ -0,0 +1,24 @@ +#include + +#ifndef _WIN32 +#include +#endif + +#ifdef __APPLE__ +#include +#endif + +namespace platform::internal { + std::filesystem::path get_executable_path() { +#ifdef __APPLE__ + char buffer[1024]; + uint32_t size = sizeof(buffer); + if (_NSGetExecutablePath(buffer, &size) == 0) { + return std::filesystem::canonical(std::filesystem::path(buffer)); + } else { + return std::filesystem::path(); + } +#endif + return std::filesystem::path(); + } +}