diff --git a/.github/workflows/pragma-linux-ci.yml b/.github/workflows/pragma-linux-ci.yml
index ee76c0158..bbff97d8a 100644
--- a/.github/workflows/pragma-linux-ci.yml
+++ b/.github/workflows/pragma-linux-ci.yml
@@ -43,7 +43,7 @@ jobs:
uses: ./pragma/github_actions/build
id: build-pragma
with:
- build-args: "--with-pfm --with-all-pfm-modules --with-vr --with-networking --with-lua-debugger=0"
+ build-args: "--with-pfm --with-all-pfm-modules --with-vr --with-networking --with-lua-debugger=0 --with-swiftshader"
- name: Create Release Archive
shell: bash
diff --git a/.github/workflows/pragma-windows-ci.yml b/.github/workflows/pragma-windows-ci.yml
index 99807aad4..14b17fdd8 100644
--- a/.github/workflows/pragma-windows-ci.yml
+++ b/.github/workflows/pragma-windows-ci.yml
@@ -56,7 +56,7 @@ jobs:
uses: ./pragma/github_actions/build
id: build-pragma
with:
- build-args: "--with-pfm --with-all-pfm-modules --with-vr --with-networking --with-lua-debugger=0 --cmake-arg=\"-DCMAKE_SYSTEM_VERSION=10.0.22621.0\" --vcvars \"C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvars64.bat\""
+ build-args: "--with-pfm --with-all-pfm-modules --with-vr --with-networking --with-lua-debugger=0 --with-swiftshader --cmake-arg=\"-DCMAKE_SYSTEM_VERSION=10.0.22621.0\" --vcvars \"C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvars64.bat\""
- name: Create Release Archive
shell: bash
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ca2ce91ce..008324e7a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1112,7 +1112,6 @@ add_dependencies(pragma_updater sharedutils-static)
add_dependencies(pragma_server server)
add_dependencies(pragma client server)
-add_dependencies(pragma pragma_server)
add_dependencies(pragma pragma_updater)
set_property(TARGET pragma PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_INSTALL_PREFIX}")
@@ -1167,6 +1166,9 @@ endfunction(pragma_install)
pragma_install(pragma ".")
pragma_install(pragma_server ".")
+if(WIN32)
+ pragma_install(pragma_console ".")
+endif()
pragma_install(alsoundsystem "${BINARY_OUTPUT_DIR}")
pragma_install(client "${BINARY_OUTPUT_DIR}")
@@ -1194,8 +1196,12 @@ pragma_install(wgui "${BINARY_OUTPUT_DIR}")
pragma_install(util_unicode "${BINARY_OUTPUT_DIR}")
message("Custom install targets: ${PRAGMA_INSTALL_CUSTOM_TARGETS}")
+set(PRAGMA_INSTALL_DEPENDENCIES pragma pragma_server iclient iserver udm_convert ${PRAGMA_INSTALL_CUSTOM_TARGETS})
+if(WIN32)
+ list(APPEND PRAGMA_INSTALL_DEPENDENCIES pragma_console)
+endif()
add_custom_target(pragma-install
- DEPENDS pragma iclient iserver udm_convert ${PRAGMA_INSTALL_CUSTOM_TARGETS}
+ DEPENDS ${PRAGMA_DEPENDENCIES}
COMMAND
"${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=${PRAGMA_INSTALL_COMPONENT}
-DBUILD_TYPE=${CONFIG_BUILD_TYPE}
diff --git a/README.md b/README.md
index 799df99f3..f2feb43ef 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[![Build Windows](https://github.com/Silverlan/pragma/actions/workflows/pragma-windows-ci.yml/badge.svg?branch=main)](https://github.com/Silverlan/pragma/actions/workflows/pragma-windows-ci.yml) [![Build Linux](https://github.com/Silverlan/pragma/actions/workflows/pragma-linux-ci.yml/badge.svg?branch=main)](https://github.com/Silverlan/pragma/actions/workflows/pragma-linux-ci.yml)
+[![Build Windows](https://github.com/Silverlan/pragma/actions/workflows/pragma-windows-ci.yml/badge.svg?branch=main)](https://github.com/Silverlan/pragma/actions/workflows/pragma-windows-ci.yml) [![Build Linux](https://github.com/Silverlan/pragma/actions/workflows/pragma-linux-ci.yml/badge.svg?branch=main)](https://github.com/Silverlan/pragma/actions/workflows/pragma-linux-ci.yml) [![License](https://img.shields.io/github/license/Silverlan/pragma)](#license) [![CodeFactor](https://img.shields.io/codefactor/grade/github/Silverlan/pragma)](https://www.codefactor.io/repository/github/Silverlan/pragma)
@@ -98,7 +98,7 @@ Running the build-script with the arguments above will build and install Pragma
| Parameter | Description | Default |
| --------------------------------------- | -------------------------------------------------------------------------------------------- | ---------------- |
| `--help` | Display this help | |
-| `--generator ` | The generator to use. | Windows: `Visual Studio 17 2022`
Linux: `Unix Makefiles` |
+| `--generator ` | The generator to use. | Windows: `Visual Studio 17 2022`
Linux: `Ninja Multi-Config` |
| `--c-compiler` | [Linux only] The C-compiler to use. | `clang-18` |
| `--cxx-compiler` | [Linux only] The C++-compiler to use. | `clang++-18` |
| `--no-sudo` | [Linux only] Will not run sudo commands. System packages will have to be installed manually. | `0` |
@@ -111,6 +111,8 @@ Running the build-script with the arguments above will build and install Pragma
| `--with-vr <1/0>` | Include Virtual Reality support. | `0` |
| `--with-networking <1/0>` | Include networking module(s) for multiplayer support. | `0` |
| `--with-lua-debugger <1/0>` | Include Lua-debugger support. | `0` |
+| `--with-swiftshader <1/0>` | Include SwiftShader support for CPU-only rendering. | `0` |
+| `--build-swiftshader <1/0>` | Builds SwiftShader from source instead of downloading prebuilt binaries. | `0` |
| `--build-cycles <1/0>` | Build the Cycles library (otherwise uses pre-built binaries). Requires --with-all-pfm-modules| `0` |
| `--build <1/0>` | Build Pragma after configurating and generating build files. | `1` |
| `--build-all <1/0>` | Build all dependencies instead of downloading prebuilt binaries where available. | `0` |
diff --git a/build_scripts/build.py b/build_scripts/build.py
index 50ec7d956..6ba57f542 100644
--- a/build_scripts/build.py
+++ b/build_scripts/build.py
@@ -19,8 +19,6 @@
else:
defaultGenerator = "Visual Studio 17 2022"
parser.add_argument('--generator', help='The generator to use.', default=defaultGenerator)
-if platform == "win32":
- parser.add_argument('--vcvars', help='Path to vcvars64.bat.', default="\"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat\"")
parser.add_argument("--with-essential-client-modules", type=str2bool, nargs='?', const=True, default=True, help="Include essential modules required to run Pragma.")
parser.add_argument("--with-common-modules", type=str2bool, nargs='?', const=True, default=True, help="Include non-essential but commonly used modules (e.g. audio and physics modules).")
parser.add_argument("--with-pfm", type=str2bool, nargs='?', const=True, default=False, help="Include the Pragma Filmmaker.")
@@ -30,9 +28,11 @@
parser.add_argument("--with-networking", type=str2bool, nargs='?', const=True, default=False, help="Include networking module(s) for multiplayer support.")
parser.add_argument("--with-common-entities", type=str2bool, nargs='?', const=True, default=True, help="Include addons with support for common entity types.")
parser.add_argument("--with-lua-debugger", type=str2bool, nargs='?', const=True, default=False, help="Include Lua-debugger support.")
+parser.add_argument("--with-swiftshader", type=str2bool, nargs='?', const=True, default=False, help="Include SwiftShader support for CPU-only rendering.")
parser.add_argument('--vtune-include-path', help='The include path to the VTune profiler (required for CPU profiling).', default='')
parser.add_argument('--vtune-library-path', help='The path to the "libittnotify" library of the VTune profiler (required for CPU profiling).', default='')
parser.add_argument("--build", type=str2bool, nargs='?', const=True, default=True, help="Build Pragma after configurating and generating build files.")
+parser.add_argument("--build-swiftshader", type=str2bool, nargs='?', const=True, default=False, help="Builds SwiftShader from source instead of downloading prebuilt binaries.")
parser.add_argument("--build-all", type=str2bool, nargs='?', const=True, default=False, help="Build all dependencies instead of downloading prebuilt binaries where available. Enabling this may significantly increase the disk space requirement and build time.")
parser.add_argument('--build-config', help='The build configuration to use.', default='RelWithDebInfo')
parser.add_argument('--build-directory', help='Directory to write the build files to. Can be relative or absolute.', default='build')
@@ -87,8 +87,6 @@
no_sudo = args["no_sudo"]
no_confirm = args["no_confirm"]
generator = args["generator"]
-#if platform == "win32":
-# vcvars = args["vcvars
with_essential_client_modules = args["with_essential_client_modules"]
with_common_modules = args["with_common_modules"]
with_pfm = args["with_pfm"]
@@ -98,6 +96,8 @@
with_networking = args["with_networking"]
with_common_entities = args["with_common_entities"]
with_lua_debugger = args["with_lua_debugger"]
+with_swiftshader = args["with_swiftshader"]
+build_swiftshader = args["build_swiftshader"]
vtune_include_path = args["vtune_include_path"]
vtune_library_path = args["vtune_library_path"]
build = args["build"]
@@ -122,8 +122,6 @@
print("c_compiler: " +c_compiler)
print("generator: " +generator)
-#if platform == "win32":
-# print("vcvars: " +vcvars)
print("with_essential_client_modules: " +str(with_essential_client_modules))
print("with_common_modules: " +str(with_common_modules))
print("with_pfm: " +str(with_pfm))
@@ -131,6 +129,8 @@
print("with_all_pfm_modules: " +str(with_all_pfm_modules))
print("with_vr: " +str(with_vr))
print("with_lua_debugger: " +str(with_lua_debugger))
+print("with_swiftshader: " +str(with_swiftshader))
+print("build_swiftshader: " +str(build_swiftshader))
print("rerun: " +str(rerun))
print("update: " +str(update))
print("build: " +str(build))
@@ -493,6 +493,40 @@ def execscript(filepath):
os.chdir("../../")
os.chdir("../../")
+########## SwiftShader ##########
+if with_swiftshader:
+ os.chdir(deps_dir)
+ swiftshader_root = normalize_path(os.getcwd() +"/swiftshader")
+ swiftshader_modules_dir = install_dir +"/modules/swiftshader/"
+
+ swiftshader_bin_dir = swiftshader_root +"/build/bin/"
+ if build_swiftshader:
+ if not Path(swiftshader_root).is_dir():
+ print_msg("SwiftShader not found. Downloading...")
+ git_clone("https://github.com/Silverlan/swiftshader.git")
+ os.chdir("swiftshader")
+ reset_to_commit("8f431ea")
+
+ print_msg("Building SwiftShader...")
+ os.chdir("build")
+ cmake_configure("..",generator)
+ cmake_build("Release")
+ else:
+ if not Path(swiftshader_root).is_dir():
+ mkpath(swiftshader_bin_dir)
+ os.chdir(swiftshader_bin_dir)
+ print_msg("Downloading prebuilt SwiftShader...")
+ if platform == "win32":
+ http_extract("https://github.com/Silverlan/swiftshader/releases/download/latest/swiftshader.zip")
+ else:
+ http_extract("https://github.com/Silverlan/swiftshader/releases/download/latest/swiftshader.tar.gz",format="tar.gz")
+ print_msg("Installing SwiftShader...")
+ mkpath(swiftshader_modules_dir)
+ if platform == "win32":
+ cp(swiftshader_bin_dir +"/vulkan-1.dll",swiftshader_modules_dir)
+ else:
+ cp(swiftshader_bin_dir +"/libvulkan.so.1",swiftshader_modules_dir)
+
########## vcpkg ##########
os.chdir(deps_dir)
if platform == "win32":
@@ -703,8 +737,6 @@ def execbuildscript(filepath):
l["install_system_packages"] = install_system_packages
# l["harfbuzz_include_dir"] = harfbuzz_include_dir
# l["harfbuzz_lib"] = harfbuzz_lib
- #else:
- # l["vcvars"] = "vcvars"
if platform == "win32":
l["determine_vs_installation_path"] = determine_vs_installation_path
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index d2fb198cc..49f0cac05 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -26,5 +26,8 @@ set_target_properties(client PROPERTIES FOLDER core)
set_target_properties(pragma PROPERTIES FOLDER core)
set_target_properties(pragma_server PROPERTIES FOLDER core)
set_target_properties(wms_shared PROPERTIES FOLDER core)
+if(WIN32)
+ set_target_properties(pragma_console PROPERTIES FOLDER core)
+endif()
set(CMAKE_CXX_STANDARD 20)
diff --git a/core/client/src/c_launchparameters.cpp b/core/client/src/c_launchparameters.cpp
index 9227665e5..414a12241 100644
--- a/core/client/src/c_launchparameters.cpp
+++ b/core/client/src/c_launchparameters.cpp
@@ -18,6 +18,7 @@ std::optional g_launchParamHeight {};
std::optional g_titleBarColor {};
std::optional g_borderColor {};
bool g_launchParamExperimentalMemoryOptimizationEnabled = false;
+bool g_cpuRendering = false;
bool g_windowless = false;
static void LPARAM_windowed(const std::vector &argv) { g_launchParamWindowedMode = true; }
@@ -111,7 +112,14 @@ static void LPARAM_border_bar_color(const std::vector &argv)
g_borderColor = Color::CreateFromHexColor(strHex);
}
-static void LPARAM_EXPERIMENTAL_MEMORY_OPTIMIZATION(const std::vector &argv) {g_launchParamExperimentalMemoryOptimizationEnabled = (argv.empty() || util::to_boolean(argv.front())); }
+static void LPARAM_EXPERIMENTAL_MEMORY_OPTIMIZATION(const std::vector &argv) { g_launchParamExperimentalMemoryOptimizationEnabled = (argv.empty() || util::to_boolean(argv.front())); }
+
+static void LPARAM_cpu_rendering(const std::vector &argv)
+{
+ g_cpuRendering = (argv.empty() || util::to_boolean(argv.front()));
+ // Without optimizations enabled, loading with CPU rendering will take a very long time
+ g_launchParamExperimentalMemoryOptimizationEnabled = true;
+}
REGISTER_LAUNCH_PARAMETER_HELP(-windowed, LPARAM_windowed, "-window -startwindowed -sw", "start in windowed mode");
REGISTER_LAUNCH_PARAMETER(-window, LPARAM_windowed);
@@ -138,3 +146,4 @@ REGISTER_LAUNCH_PARAMETER_HELP(-windowless, LPARAM_windowless, "<1/0>", "If enab
REGISTER_LAUNCH_PARAMETER_HELP(-title_bar_color, LPARAM_title_bar_color, "", "Hex color for the window title bar.");
REGISTER_LAUNCH_PARAMETER_HELP(-border_color, LPARAM_border_bar_color, "", "Hex color for the window border.");
REGISTER_LAUNCH_PARAMETER_HELP(-experimental_memory_optimization, LPARAM_EXPERIMENTAL_MEMORY_OPTIMIZATION, "<1/0>", "Enables experimental code for RAM usage reduction.");
+REGISTER_LAUNCH_PARAMETER_HELP(-cpu_rendering, LPARAM_cpu_rendering, "<1/0>", "If enabled, the CPU will be used for rendering instead of GPU.");
diff --git a/core/client/src/rendering/c_render_context.cpp b/core/client/src/rendering/c_render_context.cpp
index 74ef65e03..aa5b0b3ff 100644
--- a/core/client/src/rendering/c_render_context.cpp
+++ b/core/client/src/rendering/c_render_context.cpp
@@ -27,6 +27,7 @@ static spdlog::logger &LOGGER_VALIDATION = pragma::register_logger("prosper_vali
RenderContext::RenderContext() : m_monitor(nullptr), m_renderAPI {"vulkan"} {}
RenderContext::~RenderContext() { m_graphicsAPILib = nullptr; }
DLLNETWORK std::optional g_customTitle;
+extern bool g_cpuRendering;
void RenderContext::InitializeRenderAPI()
{
auto &renderAPI = GetRenderAPI();
@@ -38,7 +39,24 @@ void RenderContext::InitializeRenderAPI()
std::string location;
std::string modulePath;
getRenderApiPath(renderAPI, location, modulePath);
- m_graphicsAPILib = util::load_library_module(modulePath, util::get_default_additional_library_search_directories(modulePath), {}, &outErr);
+
+ auto additionalSearchDirectories = util::get_default_additional_library_search_directories(modulePath);
+ if(g_cpuRendering) {
+ if(renderAPI == "vulkan") {
+ if(filemanager::exists("modules/swiftshader/")) {
+ auto p = util::Path::CreatePath(util::get_program_path());
+ p += "modules/swiftshader/";
+ additionalSearchDirectories.push_back(p.GetString());
+
+ spdlog::info("-cpu_rendering option has been specified. SwiftShader will be used for rendering instead of Vulkan driver.");
+ }
+ else
+ spdlog::error("-cpu_rendering option requires SwiftShader module, which is not installed! Ignoring option...");
+ }
+ else
+ spdlog::error("-cpu_rendering option is only supported for Vulkan render API! Ignoring option...");
+ }
+ m_graphicsAPILib = util::load_library_module(modulePath, additionalSearchDirectories, {}, &outErr);
return (m_graphicsAPILib != nullptr);
};
std::string err;
diff --git a/core/pragma/CMakeLists.txt b/core/pragma/CMakeLists.txt
index 61d4eed7a..8a8103ea5 100644
--- a/core/pragma/CMakeLists.txt
+++ b/core/pragma/CMakeLists.txt
@@ -11,4 +11,14 @@ else()
set_target_properties(pragma PROPERTIES VS_DEBUGGER_COMMAND_ARGUMENTS "-console -luaext")
endif()
+if(WIN32)
+ def_project(pragma_console exe ${APP_ICON_RESOURCE_WINDOWS})
+ set_target_properties(pragma_console PROPERTIES VS_DEBUGGER_COMMAND_ARGUMENTS "-console -luaext")
+
+ # This is required so that the executable can be launched from within a Windows terminal
+ set_target_properties(pragma_console PROPERTIES LINK_FLAGS "/SUBSYSTEM:CONSOLE")
+
+ set_target_properties(pragma_console PROPERTIES OUTPUT_NAME "pragma" SUFFIX ".com")
+ target_sources(pragma_console PRIVATE ${APP_ICON_RESOURCE_WINDOWS})
+endif()
diff --git a/core/pragma/include/pragma/pragma_executable.hpp b/core/pragma/include/pragma/pragma_executable.hpp
index f58b977ff..811274cf1 100644
--- a/core/pragma/include/pragma/pragma_executable.hpp
+++ b/core/pragma/include/pragma/pragma_executable.hpp
@@ -110,23 +110,6 @@ namespace pragma {
const char *runEngineSymbol = server ? "RunEngine" : "RunCEngine";
#ifdef _WIN32
- if(!server) {
- // Check if Vulkan drivers are installed
- auto bt = IDTRYAGAIN;
- while(bt == IDTRYAGAIN) {
- auto hVulkan = LoadLibrary("vulkan-1.dll");
- if(hVulkan != NULL)
- break;
- std::stringstream msg;
- msg << "Vulkan drivers not found! Please make sure your GPU drivers are up to date, and that your graphics vendor supports Vulkan for your GPU model.";
- msg << " You may have to explicitly enable the Vulkan RT during driver installation.";
- bt = MessageBox(nullptr, msg.str().c_str(), "Critical Error", MB_CANCELTRYCONTINUE | MB_ICONERROR);
- if(bt == IDCANCEL)
- return MODULE_NULL;
- else if(bt == IDCONTINUE)
- break;
- }
- }
#if ENABLE_GDEBUGGER_SUPPORT == 1
HINSTANCE hEngine = LoadLibrary(library);
#else
diff --git a/core/pragma/src/main.cpp b/core/pragma/src/main.cpp
index 81cae01c8..7af279378 100644
--- a/core/pragma/src/main.cpp
+++ b/core/pragma/src/main.cpp
@@ -14,6 +14,7 @@ try {
"materials/logo/pragma_window_icon.png",
"-title_bar_color",
"#262626",
+ "-console",
};
auto cargs = pragma::merge_arguments(argc, argv, extraArgs);
auto hModule = pragma::launch_pragma(cargs.size(), cargs.data());
diff --git a/core/pragma_server/CMakeLists.txt b/core/pragma_server/CMakeLists.txt
index a1979f43b..daa751601 100644
--- a/core/pragma_server/CMakeLists.txt
+++ b/core/pragma_server/CMakeLists.txt
@@ -9,4 +9,7 @@ if(UNIX)
target_link_libraries(pragma_server "pthread")
else()
set_target_properties(pragma_server PROPERTIES VS_DEBUGGER_COMMAND_ARGUMENTS "-console -luaext")
+
+ # This is required so that the executable can be launched from within a Windows terminal
+ set_target_properties(pragma_server PROPERTIES LINK_FLAGS "/SUBSYSTEM:CONSOLE")
endif()
diff --git a/core/shared/include/pragma/util/rig_config.hpp b/core/shared/include/pragma/util/rig_config.hpp
index 072b1955c..8709f3e9d 100644
--- a/core/shared/include/pragma/util/rig_config.hpp
+++ b/core/shared/include/pragma/util/rig_config.hpp
@@ -79,6 +79,7 @@ namespace pragma::ik {
SwivelHingeJoint,
TwistJoint,
AngularJoint,
+ DistanceJoint,
Count,
};
@@ -89,7 +90,11 @@ namespace pragma::ik {
std::optional axisB {};
std::optional maxAngle {};
float rigidity = 1.f;
- std::optional anchorPosition {};
+ union {
+ std::optional anchorPosition {};
+ std::optional anchorPositionA;
+ };
+ std::optional anchorPositionB {};
std::optional measurementAxisA {};
};
@@ -130,6 +135,7 @@ namespace pragma::ik {
PRigConfigJoint AddTwistLimit(const pragma::GString &bone0, const pragma::GString &bone1, const Vector3 &axisA, const Vector3 &axisB, umath::Degree maxAngle, float rigidity = 1.f, const std::optional &measurementAxisA = {});
PRigConfigJoint AddSwivelHingeJoint(const pragma::GString &bone0, const pragma::GString &bone1, const Vector3 &axisA, const Vector3 &axisB, float rigidity = 1.f);
PRigConfigJoint AddTwistJoint(const pragma::GString &bone0, const pragma::GString &bone1, const Vector3 &axisA, const Vector3 &axisB, float rigidity);
+ PRigConfigJoint AddDistanceJoint(const pragma::GString &bone0, const pragma::GString &bone1, float rigidity = 1.f);
PRigConfigJoint AddAngularJoint(const pragma::GString &bone0, const pragma::GString &bone1, float rigidity = 1.f);
void RemoveConstraints(const pragma::GString &bone);
diff --git a/core/shared/src/console/console.cpp b/core/shared/src/console/console.cpp
index afc068da1..1c170a7b5 100644
--- a/core/shared/src/console/console.cpp
+++ b/core/shared/src/console/console.cpp
@@ -18,6 +18,16 @@
#include
#endif
+#ifdef _WIN32
+#pragma comment(lib, "Dbghelp.lib")
+bool is_console_subsystem()
+{
+ // See https://stackoverflow.com/a/1440163/1879228
+ PIMAGE_NT_HEADERS nth = ImageNtHeader((PVOID)GetModuleHandle(NULL));
+ return nth->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI;
+}
+#endif
+
DebugConsole::DebugConsole() : _cinbuf(0), _coutbuf(0), _cerrbuf(0) {}
DebugConsole::~DebugConsole() {}
@@ -25,19 +35,21 @@ DebugConsole::~DebugConsole() {}
void DebugConsole::open()
{
#ifdef _WIN32
- AllocConsole();
- AttachConsole(GetCurrentProcessId());
- this->_cinbuf = std::cin.rdbuf();
- this->_console_cin.open("CONIN$");
- std::cin.rdbuf(this->_console_cin.rdbuf());
- this->_coutbuf = std::cout.rdbuf();
- this->_console_cout.open("CONOUT$");
- std::cout.rdbuf(this->_console_cout.rdbuf());
- this->_cerrbuf = std::cerr.rdbuf();
- this->_console_cerr.open("CONOUT$");
- std::cerr.rdbuf(this->_console_cerr.rdbuf());
+ if(!is_console_subsystem()) {
+ AllocConsole();
+ AttachConsole(GetCurrentProcessId());
+ this->_cinbuf = std::cin.rdbuf();
+ this->_console_cin.open("CONIN$");
+ std::cin.rdbuf(this->_console_cin.rdbuf());
+ this->_coutbuf = std::cout.rdbuf();
+ this->_console_cout.open("CONOUT$");
+ std::cout.rdbuf(this->_console_cout.rdbuf());
+ this->_cerrbuf = std::cerr.rdbuf();
+ this->_console_cerr.open("CONOUT$");
+ std::cerr.rdbuf(this->_console_cerr.rdbuf());
- freopen("CON", "w", stdout); // Redirect printf, etc.
+ freopen("CON", "w", stdout); // Redirect printf, etc.
+ }
// Enable ANSI color codes under Windows
HANDLE handleOut = GetStdHandle(STD_OUTPUT_HANDLE);
@@ -79,37 +91,44 @@ void DebugConsole::open()
}
#else
- int flags = fcntl(0, F_GETFL, 0);
- fcntl(0, F_SETFL, flags | O_NONBLOCK);
- //this->_cinbuf = std::cin.rdbuf();
- //this->_coutbuf = std::cout.rdbuf();
- //this->_cerrbuf = std::cerr.rdbuf();
+ int flags = fcntl(0, F_GETFL, 0);
+ fcntl(0, F_SETFL, flags | O_NONBLOCK);
+ //this->_cinbuf = std::cin.rdbuf();
+ //this->_coutbuf = std::cout.rdbuf();
+ //this->_cerrbuf = std::cerr.rdbuf();
#endif
}
void DebugConsole::close()
{
#ifdef _WIN32
- this->_console_cout.close();
- std::cout.rdbuf(this->_coutbuf);
- //this->_console_cin.close(); // This used to work until windows 7, now it blocks the process until new input is received
- //std::cin.rdbuf(this->_cinbuf);
- this->_console_cerr.close();
- std::cerr.rdbuf(this->_cerrbuf);
+ auto isConsoleSubSys = is_console_subsystem();
+ if(!isConsoleSubSys) {
+ this->_console_cout.close();
+ std::cout.rdbuf(this->_coutbuf);
+ //this->_console_cin.close(); // This used to work until windows 7, now it blocks the process until new input is received
+ //std::cin.rdbuf(this->_cinbuf);
+ this->_console_cerr.close();
+ std::cerr.rdbuf(this->_cerrbuf);
+ }
INPUT_RECORD input;
unsigned long numEvents;
- WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &input, 0, &numEvents); // Workaround: Writes to the console to make sure the thread can end properly
- //CloseHandle(GetStdHandle(STD_INPUT_HANDLE)); // Doesn't work?
- fclose(stdin);
- fclose(stdout);
- fclose(stderr);
- FreeConsole();
+ // Workaround: Writes to the console to make sure the thread can end properly
+ // Note: This only seems to work with the windows-subsystem
+ WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &input, 0, &numEvents);
+ if(!isConsoleSubSys) {
+ //CloseHandle(GetStdHandle(STD_INPUT_HANDLE)); // Doesn't work?
+ fclose(stdin);
+ fclose(stdout);
+ fclose(stderr);
+ FreeConsole();
+ }
#else
- int flags = fcntl(0, F_GETFL, 0);
- fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
+ int flags = fcntl(0, F_GETFL, 0);
+ fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
//see https://stackoverflow.com/questions/55602283/how-to-write-data-to-stdin-to-be-consumed-by-a-separate-thread-waiting-on-input for details
- //std::cout.rdbuf(this->_coutbuf);
- //ssstd::cerr.rdbuf(this->_cerrbuf);
+ //std::cout.rdbuf(this->_coutbuf);
+ //ssstd::cerr.rdbuf(this->_cerrbuf);
//fwrite("\n", 1, 1, stdin);
//std::cin.putback('\n'); //This actually does not work.
//We have to fiddle with the owning pts directly.
diff --git a/core/shared/src/console/debugconsole.cpp b/core/shared/src/console/debugconsole.cpp
index f391c0f1d..bd7520287 100644
--- a/core/shared/src/console/debugconsole.cpp
+++ b/core/shared/src/console/debugconsole.cpp
@@ -22,65 +22,63 @@
#endif
#ifdef __linux__
- //https://stackoverflow.com/a/76104592
- // Returns 1 on success, 0 when not done, and -1 on failure (check errno)
+//https://stackoverflow.com/a/76104592
+// Returns 1 on success, 0 when not done, and -1 on failure (check errno)
// str is initially expected to be an empty string and should only altered by this function.
-static int getline_async_thread_safe( std::string& str,const int& fd = 0, char delim = '\n') {
- int chars_read;
- do {
- char buf[2] = { 0 };
- pollfd fd_stdin {0,POLLIN,0};
-
- //sigemptyset(&signalset);
- ppoll(&fd_stdin,1,NULL,nullptr);
- chars_read = (int) read(fd, buf, 1);
- if (chars_read == 1) {
- if (*buf == delim) {
- return 1;
- }
- str.append(buf);
- } else {
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- chars_read = 0;
- break;
- }
- }
- } while (chars_read > 0);
-
- return chars_read;
+static int getline_async_thread_safe(std::string &str, const int &fd = 0, char delim = '\n')
+{
+ int chars_read;
+ do {
+ char buf[2] = {0};
+ pollfd fd_stdin {0, POLLIN, 0};
+
+ //sigemptyset(&signalset);
+ ppoll(&fd_stdin, 1, NULL, nullptr);
+ chars_read = (int)read(fd, buf, 1);
+ if(chars_read == 1) {
+ if(*buf == delim) {
+ return 1;
+ }
+ str.append(buf);
+ }
+ else {
+ if(errno == EAGAIN || errno == EWOULDBLOCK) {
+ chars_read = 0;
+ break;
+ }
+ }
+ } while(chars_read > 0);
+
+ return chars_read;
}
#endif
-
-
extern Engine *engine;
static std::atomic_bool bCheckInput = true;
static void KeyboardInput()
{
//TODO: Rewrite this to use non-blocking algorythms
- std::string line;
+ std::string line;
#ifdef _WIN32
while(bCheckInput) {
std::getline(std::cin, line);
if(bCheckInput)
engine->ConsoleInput(line);
- }
+ }
#else
- int retval;
- while(bCheckInput) {
- retval = getline_async_thread_safe(line);
- if (retval > 0) {
- // Process std::string output
- // Make sure to reset string if continuing through loop
- if(bCheckInput)
- engine->ConsoleInput(line);
-
- line = "";
-
- }
- // line = "";
-
- }
+ int retval;
+ while(bCheckInput) {
+ retval = getline_async_thread_safe(line);
+ if(retval > 0) {
+ // Process std::string output
+ // Make sure to reset string if continuing through loop
+ if(bCheckInput)
+ engine->ConsoleInput(line);
+
+ line = "";
+ }
+ // line = "";
+ }
#endif
}
@@ -106,6 +104,9 @@ Engine::ConsoleInstance::ConsoleInstance()
util::set_thread_name(*consoleThread, "pr_console_input_listener");
}
+#ifdef _WIN32
+bool is_console_subsystem();
+#endif
Engine::ConsoleInstance::~ConsoleInstance()
{
#ifdef __linux__
@@ -113,7 +114,14 @@ Engine::ConsoleInstance::~ConsoleInstance()
bCheckInput = false;
#endif
console->close();
-#ifdef __linux__
+#ifdef _WIN32
+ if(is_console_subsystem() && consoleThread) {
+ // There's no way to cancel the blocking std::getline in the console thread if it is attached
+ // to a parent console, so we have to force terminate the thread.
+ // TODO: Do this properly by implementing an asynchronous non-blocking input method.
+ TerminateThread(consoleThread->native_handle(), 0);
+ }
+#else
//It is impossible to unblock KeyboardInput by putting \n. I have to cancel the thread.
auto natConsoleThread = consoleThread->native_handle();
pthread_cancel(natConsoleThread);
diff --git a/core/shared/src/util/rig_config.cpp b/core/shared/src/util/rig_config.cpp
index 342ae0e0d..a614d5819 100644
--- a/core/shared/src/util/rig_config.cpp
+++ b/core/shared/src/util/rig_config.cpp
@@ -165,8 +165,15 @@ std::optional pragma::ik::RigConfig::load_from_udm_data(u
joint = rig.AddAngularJoint(bone0, bone1, rigidity);
break;
}
+ case RigConfigJoint::Type::DistanceJoint:
+ {
+ float rigidity = 1.f;
+ udmJoint["rigidity"] >> rigidity;
+ joint = rig.AddDistanceJoint(bone0, bone1, rigidity);
+ break;
+ }
}
- static_assert(umath::to_integral(RigConfigJoint::Type::Count) == 6u, "Update this list when new joint types are added!");
+ static_assert(umath::to_integral(RigConfigJoint::Type::Count) == 7u, "Update this list when new joint types are added!");
if(joint)
udmJoint["measurementAxisA"] >> joint->measurementAxisA;
@@ -340,6 +347,16 @@ pragma::ik::PRigConfigJoint pragma::ik::RigConfig::AddTwistJoint(const pragma::G
j->type = RigConfigJoint::Type::TwistJoint;
return j;
}
+pragma::ik::PRigConfigJoint pragma::ik::RigConfig::AddDistanceJoint(const pragma::GString &bone0, const pragma::GString &bone1, float rigidity)
+{
+ m_joints.push_back(std::make_shared());
+ auto &j = m_joints.back();
+ j->bone0 = bone0;
+ j->bone1 = bone1;
+ j->rigidity = rigidity;
+ j->type = RigConfigJoint::Type::DistanceJoint;
+ return j;
+}
pragma::ik::PRigConfigJoint pragma::ik::RigConfig::AddAngularJoint(const pragma::GString &bone0, const pragma::GString &bone1, float rigidity)
{
m_joints.push_back(std::make_shared());