From 323b04f542659a397795f6288219c8a79dd8a8dc Mon Sep 17 00:00:00 2001 From: Hirek Date: Tue, 23 Dec 2025 21:01:29 +0100 Subject: [PATCH 1/3] Wiper shader improvements --- shaders/mat_rain_windscreen.frag | 42 +++++++++++++++----------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/shaders/mat_rain_windscreen.frag b/shaders/mat_rain_windscreen.frag index f7f057ca..e441083d 100644 --- a/shaders/mat_rain_windscreen.frag +++ b/shaders/mat_rain_windscreen.frag @@ -25,6 +25,7 @@ layout(location = 1) out vec4 out_motion; #include #include #include +#include uniform sampler2D diffuse; uniform sampler2D raindropsatlas; @@ -34,10 +35,6 @@ uniform float specular_intensity = 1.0; uniform float wobble_strength = 0.002; uniform float wobble_speed = 30.0; -float hash(vec2 p) { - return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); -} - vec4 getDropTex(float choice, vec2 uv) { vec2 offset; if (choice < 0.25) offset = vec2(0.0, 0.0); @@ -54,13 +51,14 @@ void main() { if (tex_color.a < 0.01) discard; vec2 rainCoord = f_coord; + float gridSize = ceil(param[2].x); const float numDrops = 20000.0; const float cycleDuration = 4.0; - const float squareMin = 0.0035; - const float squareMax = 0.008; + + float squareMin = 0.5 / gridSize; + float squareMax = 1.2 / gridSize; - float gridSize = ceil(param[2].x); vec2 cell = floor(rainCoord * gridSize); vec3 dropLayer = vec3(0.0); @@ -76,37 +74,37 @@ void main() { float side; float mixFactor = GetMixFactor(neighborCenter, side); - if(mixFactor < hash(neighborCell + vec2(mix(0., .2137, side), 0.))) { + uint seed = Hash(uvec3(neighborCell, side)); + + if(mixFactor < RandF(seed)) { continue; } - - float i = neighborCell.x + neighborCell.y * gridSize; // Show a percentage of droplets given by rain intensity param - float activationSeed = hash(vec2(i, 0.333 + side)); + float activationSeed = RandF(seed); if (activationSeed > rain_params.x) continue; // kropla nieaktywna // Randomly modulate droplet center & size - vec2 dropCenter = (neighborCell + vec2(hash(vec2(i, 0.12 + side)), hash(vec2(i, 0.34 + side)))) / gridSize; - float squareSize = mix(squareMin, squareMax, hash(vec2(i, 0.56 + side))); + vec2 dropCenter = (neighborCell + vec2(RandF(seed), RandF(seed))) / gridSize; + float squareSize = mix(squareMin, squareMax, RandF(seed)); - float lifeTime = time + hash(vec2(i, 0.78 + side)) * cycleDuration; + float lifeTime = time + RandF(seed) * cycleDuration; float phase = fract(lifeTime / cycleDuration); - float active = clamp(1.0 - phase, 0.0, 1.0); + float actiwe = clamp(1.0 - phase, 0.0, 1.0); // Gravity influence (TODO add vehicle speed & wind here!) float gravityStart = 0.5; float gravityPhase = smoothstep(gravityStart, 1.0, phase); - float dropMass = mix(0.3, 1.2, hash(vec2(i, 0.21 + side))); + float dropMass = mix(0.3, 1.2, RandF(seed)); float gravitySpeed = 0.15 * dropMass; vec2 gravityOffset = vec2(0.0, gravityPhase * gravitySpeed * phase); // Random wobble - bool hasWobble = (hash(vec2(i, 0.91 + side)) < 0.10); + bool hasWobble = (RandF(seed) < 0.10); vec2 wobbleOffset = vec2(0.0); if (hasWobble && gravityPhase > 0.0) { - float intensity = sin(time * wobble_speed + i) * wobble_strength * gravityPhase; + float intensity = sin(time * wobble_speed + RandF(seed) * 100.) * wobble_strength * gravityPhase; wobbleOffset = vec2(intensity, 0.0); } @@ -125,7 +123,7 @@ void main() { if (mask > 0.001) { vec2 localUV = (diff + squareSize * 0.5) / squareSize; - float choice = hash(vec2(i, 0.99 + side)); + float choice = RandF(seed); vec4 dropTex = getDropTex(choice, localUV); float sharpAlpha = smoothstep(0.3, 0.9, dropTex.a); @@ -139,15 +137,15 @@ void main() { float sparkle = 0.0; if (hasWobble) { - sparkle = pow(abs(sin(f_coord.x * 8.0 + time * 2.0 + hash(vec2(i, 0.9 + side)) * 6.2831)), 40.0) + sparkle = pow(abs(sin(f_coord.x * 8.0 + time * 2.0 + RandF(seed) * 6.2831)), 40.0) * mix(0.2, 1.0, sunFactor); } vec3 specularColor = vec3(1.0) * specular_intensity * sparkle; vec3 dropLit = dropTex.rgb * dynBright + specularColor * sharpAlpha; - dropLayer += dropLit * sharpAlpha * active * blackAlpha * mask; - dropMaskSum += sharpAlpha * active * blackAlpha * mask; + dropLayer += dropLit * sharpAlpha * actiwe * blackAlpha * mask; + dropMaskSum += sharpAlpha * actiwe * blackAlpha * mask; } } } From 1cafe159175947cd0c774acbfb8a5ac720bd4e7c Mon Sep 17 00:00:00 2001 From: Hirek Date: Sat, 3 Jan 2026 15:48:13 +0100 Subject: [PATCH 2/3] Change debug window binding to Shift + F12 --- drivermode.cpp | 5 +++++ driveruilayer.cpp | 17 ++++++++++++----- driveruilayer.h | 2 ++ uilayer.h | 3 ++- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/drivermode.cpp b/drivermode.cpp index 5b34c827..5a96e5a2 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -444,6 +444,11 @@ driver_mode::on_key( int const Key, int const Scancode, int const Action, int co // give the ui first shot at the input processing... if( !anyModifier && true == m_userinterface->on_key( Key, Action ) ) { return; } + if (Key == (GLFW_MOD_SHIFT | GLFW_KEY_F12) && Action == GLFW_PRESS) + { + m_userinterface->showDebugUI(); + return; + } // ...if the input is left untouched, pass it on if( true == m_input.keyboard.key( Key, Action ) ) { return; } diff --git a/driveruilayer.cpp b/driveruilayer.cpp index 33e787ac..481fe601 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -87,6 +87,11 @@ void driver_ui::render_menu_contents() { } } +void driver_ui::showDebugUI() +{ + m_debugpanel.is_open = !m_debugpanel.is_open; +} + // potentially processes provided input key. returns: true if key was processed, false otherwise bool driver_ui::on_key( int const Key, int const Action ) { @@ -101,8 +106,7 @@ driver_ui::on_key( int const Key, int const Action ) { case GLFW_KEY_F10: case GLFW_KEY_F12: { // ui mode selectors - if( ( true == Global.ctrlState ) - || ( true == Global.shiftState ) ) { + if( ( true == Global.ctrlState )) { // only react to keys without modifiers return false; } @@ -157,10 +161,13 @@ driver_ui::on_key( int const Key, int const Action ) { return true; } - case GLFW_KEY_F12: { + case GLFW_KEY_F12 : { // debug panel - m_debugpanel.is_open = !m_debugpanel.is_open; - return true; + if (Global.shiftState) + { + m_debugpanel.is_open = !m_debugpanel.is_open; + return true; + } } default: { diff --git a/driveruilayer.h b/driveruilayer.h index 487feaa6..3c1ea344 100644 --- a/driveruilayer.h +++ b/driveruilayer.h @@ -27,6 +27,7 @@ public: // constructors driver_ui(); // methods + void showDebugUI() override; // potentially processes provided input key. returns: true if the input was processed, false otherwise bool on_key( int const Key, int const Action ) override; @@ -43,6 +44,7 @@ public: protected: void render_menu_contents() override; + private: // methods // sets visibility of the cursor diff --git a/uilayer.h b/uilayer.h index 3cd80c4d..3cb4ddbf 100644 --- a/uilayer.h +++ b/uilayer.h @@ -75,13 +75,14 @@ public: // destructor virtual ~ui_layer(); -// methods + // methods static bool init( GLFWwindow *Window ); static void imgui_style(); // assign texturing hardware unit static void set_unit( GLint const Textureunit ) { m_textureunit = GL_TEXTURE0 + Textureunit; } static void shutdown(); + virtual void showDebugUI() {}; // potentially processes provided input key. returns: true if the input was processed, false otherwise virtual bool on_key( int Key, int Action ); // potentially processes provided mouse movement. returns: true if the input was processed, false otherwise From f9c95e2de04a7fb67bd80fdf5c306ea6d999a983 Mon Sep 17 00:00:00 2001 From: Hirek Date: Sat, 3 Jan 2026 18:02:15 +0100 Subject: [PATCH 3/3] Add brush mode in editor mode --- application.cpp | 1213 ++++++++++++++++++++++++-------------------- editormode.cpp | 672 +++++++++++++----------- editormode.h | 120 ++--- editoruilayer.cpp | 68 +-- editoruilayer.h | 53 +- editoruipanels.cpp | 806 +++++++++++++++-------------- editoruipanels.h | 61 +-- uilayer.cpp | 337 ++++++------ utilities.cpp | 608 +++++++++++----------- utilities.h | 480 +++++++++--------- 10 files changed, 2319 insertions(+), 2099 deletions(-) diff --git a/application.cpp b/application.cpp index 8d1c965a..0bc4feb9 100644 --- a/application.cpp +++ b/application.cpp @@ -41,11 +41,11 @@ http://mozilla.org/MPL/2.0/. #include "translation.h" #ifdef _WIN32 -#pragma comment (lib, "dsound.lib") -#pragma comment (lib, "winmm.lib") -#pragma comment (lib, "setupapi.lib") -#pragma comment (lib, "dbghelp.lib") -#pragma comment (lib, "version.lib") +#pragma comment(lib, "dsound.lib") +#pragma comment(lib, "winmm.lib") +#pragma comment(lib, "setupapi.lib") +#pragma comment(lib, "dbghelp.lib") +#pragma comment(lib, "version.lib") #endif #ifdef __unix__ @@ -60,129 +60,142 @@ ui_layer uilayerstaticinitializer; #ifdef _WIN32 extern "C" { - GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window ); + GLFWAPI HWND glfwGetWin32Window(GLFWwindow *window); } -LRESULT APIENTRY WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); +LRESULT APIENTRY WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); extern HWND Hwnd; extern WNDPROC BaseWindowProc; #endif // user input callbacks -void focus_callback( GLFWwindow *window, int focus ) { +void focus_callback(GLFWwindow *window, int focus) +{ Application.on_focus_change(focus != 0); } -void framebuffer_resize_callback( GLFWwindow *, int w, int h ) { - Global.fb_size = glm::ivec2(w, h); +void framebuffer_resize_callback(GLFWwindow *, int w, int h) +{ + Global.fb_size = glm::ivec2(w, h); } -void window_resize_callback( GLFWwindow *, int w, int h ) { - Global.window_size = glm::ivec2(w, h); +void window_resize_callback(GLFWwindow *, int w, int h) +{ + Global.window_size = glm::ivec2(w, h); Application.on_window_resize(w, h); } -void cursor_pos_callback( GLFWwindow *window, double x, double y ) { - Global.cursor_pos = glm::ivec2(x, y); - Application.on_cursor_pos( x, y ); -} - -void mouse_button_callback( GLFWwindow* window, int button, int action, int mods ) +void cursor_pos_callback(GLFWwindow *window, double x, double y) { - Application.on_mouse_button( button, action, mods ); + Global.cursor_pos = glm::ivec2(x, y); + Application.on_cursor_pos(x, y); } -void scroll_callback( GLFWwindow* window, double xoffset, double yoffset ) { - Application.on_scroll( xoffset, yoffset ); +void mouse_button_callback(GLFWwindow *window, int button, int action, int mods) +{ + Application.on_mouse_button(button, action, mods); } -void key_callback( GLFWwindow *window, int key, int scancode, int action, int mods ) { +void scroll_callback(GLFWwindow *window, double xoffset, double yoffset) +{ + Application.on_scroll(xoffset, yoffset); +} - Application.on_key( key, scancode, action, mods ); +void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) +{ + + Application.on_key(key, scancode, action, mods); } void char_callback(GLFWwindow *window, unsigned int c) { - Application.on_char(c); + Application.on_char(c); } // public: void eu07_application::queue_screenshot() { - m_screenshot_queued = true; + m_screenshot_queued = true; } int eu07_application::run_crashgui() { - bool autoup = false; + bool autoup = false; - while (!glfwWindowShouldClose(m_windows.front())) - { - glfwPollEvents(); + while (!glfwWindowShouldClose(m_windows.front())) + { + glfwPollEvents(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - ui_layer::begin_ui_frame_internal(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + ui_layer::begin_ui_frame_internal(); - bool y, n; + bool y, n; - if (Global.asLang == "pl") { - ImGui::Begin(u8"Raportowanie błędów", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoResize); - ImGui::TextUnformatted(u8"Podczas ostatniego uruchomienia symulatora wystąpił błąd.\nWysłać raport o błędzie do deweloperów?\n"); - ImGui::TextUnformatted((u8"Usługa udostępniana przez " + crashreport_get_provider() + "\n").c_str()); - y = ImGui::Button(u8"Tak", ImVec2S(60, 0)); ImGui::SameLine(); - ImGui::Checkbox(u8"W przyszłości przesyłaj raporty o błędach automatycznie", &autoup); + if (Global.asLang == "pl") + { + ImGui::Begin(u8"Raportowanie błędów", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoResize); + ImGui::TextUnformatted(u8"Podczas ostatniego uruchomienia symulatora wystąpił błąd.\nWysłać raport o błędzie do deweloperów?\n"); + ImGui::TextUnformatted((u8"Usługa udostępniana przez " + crashreport_get_provider() + "\n").c_str()); + y = ImGui::Button(u8"Tak", ImVec2S(60, 0)); + ImGui::SameLine(); + ImGui::Checkbox(u8"W przyszłości przesyłaj raporty o błędach automatycznie", &autoup); - ImGui::SameLine(); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) - { - ImGui::BeginTooltip(); - ImGui::TextUnformatted(u8"W celu wyłączenia tej funkcji będzie trzeba skasować plik crashdumps/autoupload_enabled.conf"); - ImGui::EndTooltip(); - } + ImGui::SameLine(); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::TextUnformatted(u8"W celu wyłączenia tej funkcji będzie trzeba skasować plik crashdumps/autoupload_enabled.conf"); + ImGui::EndTooltip(); + } - ImGui::NewLine(); - n = ImGui::Button(u8"Nie", ImVec2S(60, 0)); - ImGui::End(); - } else { - ImGui::Begin("Crash reporting", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoResize); - ImGui::TextUnformatted("Crash occurred during last launch of the simulator.\nSend crash report to developers?\n"); - ImGui::TextUnformatted(("Service provided by " + crashreport_get_provider() + "\n").c_str()); - y = ImGui::Button("Yes", ImVec2S(60, 0)); ImGui::SameLine(); - ImGui::Checkbox("In future send crash reports automatically", &autoup); + ImGui::NewLine(); + n = ImGui::Button(u8"Nie", ImVec2S(60, 0)); + ImGui::End(); + } + else + { + ImGui::Begin("Crash reporting", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoResize); + ImGui::TextUnformatted("Crash occurred during last launch of the simulator.\nSend crash report to developers?\n"); + ImGui::TextUnformatted(("Service provided by " + crashreport_get_provider() + "\n").c_str()); + y = ImGui::Button("Yes", ImVec2S(60, 0)); + ImGui::SameLine(); + ImGui::Checkbox("In future send crash reports automatically", &autoup); - ImGui::SameLine(); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) - { - ImGui::BeginTooltip(); - ImGui::TextUnformatted("To disable this feature remove file crashdumps/autoupload_enabled.conf"); - ImGui::EndTooltip(); - } + ImGui::SameLine(); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::TextUnformatted("To disable this feature remove file crashdumps/autoupload_enabled.conf"); + ImGui::EndTooltip(); + } - ImGui::NewLine(); - n = ImGui::Button("No", ImVec2S(60, 0)); - ImGui::End(); - } + ImGui::NewLine(); + n = ImGui::Button("No", ImVec2S(60, 0)); + ImGui::End(); + } - ui_layer::render_internal(); - glfwSwapBuffers(m_windows.front()); + ui_layer::render_internal(); + glfwSwapBuffers(m_windows.front()); - if (y) { - crashreport_upload_accept(); - if (autoup) - crashreport_set_autoupload(); - return 0; - } + if (y) + { + crashreport_upload_accept(); + if (autoup) + crashreport_set_autoupload(); + return 0; + } - if (n) { - crashreport_upload_reject(); - return 0; - } - } - return -1; + if (n) + { + crashreport_upload_reject(); + return 0; + } + } + return -1; } void eu07_application::DiscordRPCService() { @@ -204,15 +217,15 @@ void eu07_application::DiscordRPCService() discord_rpc.startTimestamp = static_cast(now_c); discord_rpc.largeImageText = "MaSzyna"; - // run loop - while (!glfwWindowShouldClose(m_windows.front()) && !m_modestack.empty()) + // run loop + while (!glfwWindowShouldClose(m_windows.front()) && !m_modestack.empty()) { auto currentMode = m_modestack.top(); - if (currentMode == mode::launcher) - { + if (currentMode == mode::launcher) + { // in launcher mode - - discord_rpc.state = Translations.lookup_c("In main menu"); + + discord_rpc.state = Translations.lookup_c("In main menu"); discord_rpc.details = Translations.lookup_c("Browsing scenarios..."); discord_rpc.largeImageKey = ""; discord_rpc.largeImageText = "MaSzyna"; @@ -221,7 +234,7 @@ void eu07_application::DiscordRPCService() std::this_thread::sleep_for(std::chrono::milliseconds(5000)); // update RPC every 5 secs continue; - } + } else if (currentMode == mode::scenarioloader) { std::string rpcScnName = Global.SceneryFile; @@ -233,7 +246,7 @@ void eu07_application::DiscordRPCService() std::replace(rpcScnName.begin(), rpcScnName.end(), '_', ' '); } - // realworld timestamp from datetime + // realworld timestamp from datetime static std::string state = Translations.lookup_s("Scenery: ") + rpcScnName; discord_rpc.state = state.c_str(); discord_rpc.details = Translations.lookup_c("Loading scenery..."); @@ -247,7 +260,7 @@ void eu07_application::DiscordRPCService() continue; } - if (currentMode != mode::driver) + if (currentMode != mode::driver) continue; if (Global.applicationQuitOrder) @@ -256,8 +269,8 @@ void eu07_application::DiscordRPCService() if (simulation::is_ready) { std::string PlayerVehicle; - if (simulation::Train != nullptr) - { + if (simulation::Train != nullptr) + { PlayerVehicle = simulation::Train->name(); // make to upper for (auto &c : PlayerVehicle) @@ -280,160 +293,169 @@ void eu07_application::DiscordRPCService() discord_rpc.smallImageKey = "halt"; discord_rpc.smallImageText = Translations.lookup_c("Stopped"); } - } - - - + } Discord_UpdatePresence(&discord_rpc); } std::this_thread::sleep_for(std::chrono::milliseconds(5000)); // update RPC every 5 secs - } + } #endif } -int -eu07_application::init( int Argc, char *Argv[] ) { +int eu07_application::init(int Argc, char *Argv[]) +{ - int result { 0 }; + int result{0}; // start logging service std::thread sLoggingService(LogService); Global.threads.emplace("LogService", std::move(sLoggingService)); - init_debug(); - init_files(); - if( ( result = init_settings( Argc, Argv ) ) != 0 ) { + init_debug(); + init_files(); + if ((result = init_settings(Argc, Argv)) != 0) + { ErrorLog("Failed to initialize settings! Maybe you're missing eu07.ini file?"); - return result; - } + return result; + } + WriteLog("Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")"); + WriteLog("For online documentation and additional files refer to: http://eu07.pl"); + WriteLog("Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, " + "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others"); - WriteLog( "Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")" ); - WriteLog( "For online documentation and additional files refer to: http://eu07.pl" ); - WriteLog( "Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, " - "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others" ); + if (!crashreport_get_provider().empty()) + WriteLog("Crashdump analysis provided by " + crashreport_get_provider() + "\n"); - if (!crashreport_get_provider().empty()) - WriteLog("Crashdump analysis provided by " + crashreport_get_provider() + "\n"); + { + WriteLog("// settings"); + std::stringstream settingspipe; + Global.export_as_text(settingspipe); + WriteLog(settingspipe.str()); + } - { - WriteLog( "// settings" ); - std::stringstream settingspipe; - Global.export_as_text( settingspipe ); - WriteLog( settingspipe.str() ); - } - - // cruel way to prevent crashes because of threaded upload from python + // cruel way to prevent crashes because of threaded upload from python if (Global.NvRenderer) Global.python_threadedupload = false; - WriteLog( "// startup" ); + WriteLog("// startup"); - if( ( result = init_glfw() ) != 0 ) { + if ((result = init_glfw()) != 0) + { ErrorLog("Failed to initialize glfw!"); - return result; - } - if( needs_ogl() && ( result = init_ogl() ) != 0 ) { + return result; + } + if (needs_ogl() && (result = init_ogl()) != 0) + { ErrorLog("Failed to initialize ogl!"); - return result; - } + return result; + } - if (crashreport_is_pending()) { // run crashgui as early as possible + if (crashreport_is_pending()) + { // run crashgui as early as possible if ((result = run_crashgui()) != 0) { ErrorLog("Failed to run crash gui!"); return result; } - } + } - if( ( result = init_locale() ) != 0 ) { + if ((result = init_locale()) != 0) + { ErrorLog("Failed to initialize locales! Maybe you're missing lang directory?"); - return result; - } + return result; + } - if( ( result = init_gfx() ) != 0 ) { + if ((result = init_gfx()) != 0) + { ErrorLog("Failed to initialize GFX!"); - return result; - } + return result; + } - if( ( result = init_ui() ) != 0 ) { // ui now depends on activated renderer + if ((result = init_ui()) != 0) + { // ui now depends on activated renderer ErrorLog("Failed to init UI!"); return result; - } - if( ( result = init_audio() ) != 0 ) { + } + if ((result = init_audio()) != 0) + { ErrorLog("Failed to initialize OpenAL"); return result; - } - if( ( result = init_data() ) != 0 ) { + } + if ((result = init_data()) != 0) + { ErrorLog("Failed to load data/ contents! Maybe your installation is broken?"); return result; - } - crashreport_add_info("python_enabled", Global.python_enabled ? "yes" : "no"); - if( Global.python_enabled ) { - m_taskqueue.init(); - } - if( ( result = init_modes() ) != 0 ) { + } + crashreport_add_info("python_enabled", Global.python_enabled ? "yes" : "no"); + if (Global.python_enabled) + { + m_taskqueue.init(); + } + if ((result = init_modes()) != 0) + { ErrorLog("Failed to initialize game modes"); return result; - } + } - // Run DiscordRPC service + // Run DiscordRPC service std::thread sDiscordRPC(&eu07_application::DiscordRPCService, this); Global.threads.emplace("DiscordRPC", std::move(sDiscordRPC)); if (!init_network()) return -1; - return result; + return result; } - - -double eu07_application::generate_sync() { +double eu07_application::generate_sync() +{ if (Timer::GetDeltaTime() == 0.0) return 0.0; double sync = 0.0; - for (const TDynamicObject* vehicle : simulation::Vehicles.sequence()) { - auto const pos { vehicle->GetPosition() }; - sync += pos.x + pos.y + pos.z; + for (const TDynamicObject *vehicle : simulation::Vehicles.sequence()) + { + auto const pos{vehicle->GetPosition()}; + sync += pos.x + pos.y + pos.z; } sync += Random(1.0, 100.0); return sync; } -void eu07_application::queue_quit(bool direct) { - if (direct || !m_modes[m_modestack.top()]->is_command_processor()) { - glfwSetWindowShouldClose(m_windows[0], GLFW_TRUE); - return; - } +void eu07_application::queue_quit(bool direct) +{ + if (direct || !m_modes[m_modestack.top()]->is_command_processor()) + { + glfwSetWindowShouldClose(m_windows[0], GLFW_TRUE); + return; + } - command_relay relay; - relay.post(user_command::quitsimulation, 0.0, 0.0, GLFW_PRESS, 0); + command_relay relay; + relay.post(user_command::quitsimulation, 0.0, 0.0, GLFW_PRESS, 0); } -bool -eu07_application::is_server() const { +bool eu07_application::is_server() const +{ - return ( m_network && m_network->servers ); + return (m_network && m_network->servers); } -bool -eu07_application::is_client() const { +bool eu07_application::is_client() const +{ - return ( m_network && m_network->client ); + return (m_network && m_network->client); } -int -eu07_application::run() { - auto frame{ 0 }; - // main application loop - while (!glfwWindowShouldClose( m_windows.front() ) && !m_modestack.empty()) - { - Timer::subsystem.mainloop_total.start(); - glfwPollEvents(); +int eu07_application::run() +{ + auto frame{0}; + // main application loop + while (!glfwWindowShouldClose(m_windows.front()) && !m_modestack.empty()) + { + Timer::subsystem.mainloop_total.start(); + glfwPollEvents(); - if (m_headtrack) - m_headtrack->update(); + if (m_headtrack) + m_headtrack->update(); begin_ui_frame(); @@ -448,7 +470,8 @@ eu07_application::run() { double frameStartTime = Timer::GetTime(); - if (m_modes[m_modestack.top()]->is_command_processor()) { + if (m_modes[m_modestack.top()]->is_command_processor()) + { // active mode is doing real calculations (e.g. drivermode) int loop_remaining = MAX_NETWORK_PER_FRAME; while (--loop_remaining > 0) @@ -486,7 +509,8 @@ eu07_application::run() { loop_remaining = -1; } // if we're master - else { + else + { // just push local commands to execution add_to_dequemap(commands_to_exec, local_commands); @@ -497,7 +521,7 @@ eu07_application::run() { simulation::Commands.push_commands(commands_to_exec); // do actual frame processing (depending on mode) - if (!m_modes[ m_modestack.top() ]->update()) + if (!m_modes[m_modestack.top()]->update()) return 0; // update continuous commands @@ -518,9 +542,9 @@ eu07_application::run() { if (m_network && m_network->client) { // verify sync - if (sync != slave_sync) { - WriteLog("net: desync! calculated: " + std::to_string(sync) - + ", received: " + std::to_string(slave_sync), logtype::net); + if (sync != slave_sync) + { + WriteLog("net: desync! calculated: " + std::to_string(sync) + ", received: " + std::to_string(slave_sync), logtype::net); Global.desync = slave_sync - sync; } @@ -531,25 +555,30 @@ eu07_application::run() { } } - if (!loop_remaining) { + if (!loop_remaining) + { // loop break forced by counter float received = m_network->client->get_frame_counter(); float awaiting = m_network->client->get_awaiting_frames(); // TODO: don't meddle with mode progresbar m_modes[m_modestack.top()]->set_progress(100.0f * (received - awaiting) / received); - } else { + } + else + { m_modes[m_modestack.top()]->set_progress(0.0f, 0.0f); } - } else { + } + else + { // active mode is loader // clear local command queue simulation::Commands.pop_intercept_queue(); // do actual frame processing - if (!m_modes[ m_modestack.top() ]->update()) - return 0; + if (!m_modes[m_modestack.top()]->update()) + return 0; } // ------------------------------------------------------------------- @@ -557,29 +586,31 @@ eu07_application::run() { m_taskqueue.update(); opengl_texture::reset_unit_cache(); - if (!GfxRenderer->Render()) - break; + if (!GfxRenderer->Render()) + break; - GfxRenderer->SwapBuffers(); + GfxRenderer->SwapBuffers(); - if (m_modestack.empty()) - return 0; + if (m_modestack.empty()) + return 0; - m_modes[ m_modestack.top() ]->on_event_poll(); + m_modes[m_modestack.top()]->on_event_poll(); - if (m_screenshot_queued) { - m_screenshot_queued = false; - GfxRenderer->MakeScreenshot(); - } + if (m_screenshot_queued) + { + m_screenshot_queued = false; + GfxRenderer->MakeScreenshot(); + } if (m_network) m_network->update(); - auto const frametime{ Timer::subsystem.mainloop_total.stop() }; - if( Global.minframetime.count() != 0.0f && ( Global.minframetime - frametime ).count() > 0.0f ) { - std::this_thread::sleep_for( Global.minframetime - frametime ); - } - } + auto const frametime{Timer::subsystem.mainloop_total.stop()}; + if (Global.minframetime.count() != 0.0f && (Global.minframetime - frametime).count() > 0.0f) + { + std::this_thread::sleep_for(Global.minframetime - frametime); + } + } Global.applicationQuitOrder = true; auto it = Global.threads.find("LogService"); if (it != Global.threads.end()) @@ -598,33 +629,33 @@ eu07_application::run() { } // issues request for a worker thread to perform specified task. returns: true if task was scheduled -bool -eu07_application::request( python_taskqueue::task_request const &Task ) { +bool eu07_application::request(python_taskqueue::task_request const &Task) +{ - auto const result { m_taskqueue.insert( Task ) }; - if( ( false == result ) - && ( Task.input != nullptr ) ) { - // clean up allocated resources since the worker won't - } - return result; + auto const result{m_taskqueue.insert(Task)}; + if ((false == result) && (Task.input != nullptr)) + { + // clean up allocated resources since the worker won't + } + return result; } // ensures the main thread holds the python gil and can safely execute python calls -void -eu07_application::acquire_python_lock() { +void eu07_application::acquire_python_lock() +{ - m_taskqueue.acquire_lock(); + m_taskqueue.acquire_lock(); } // frees the python gil and swaps out the main thread -void -eu07_application::release_python_lock() { +void eu07_application::release_python_lock() +{ - m_taskqueue.release_lock(); + m_taskqueue.release_lock(); } -void -eu07_application::exit() { +void eu07_application::exit() +{ Global.applicationQuitOrder = true; auto it = Global.threads.find("LogService"); if (it != Global.threads.end()) @@ -640,59 +671,70 @@ eu07_application::exit() { it->second.join(); } - for (auto &mode : m_modes) mode.reset(); - GfxRenderer->Shutdown(); + GfxRenderer->Shutdown(); m_network.reset(); -// SafeDelete( simulation::Train ); - SafeDelete( simulation::Region ); + // SafeDelete( simulation::Train ); + SafeDelete(simulation::Region); - ui_layer::shutdown(); + ui_layer::shutdown(); - for( auto *window : m_windows ) { - glfwDestroyWindow( window ); - } - m_taskqueue.exit(); - glfwTerminate(); + for (auto *window : m_windows) + { + glfwDestroyWindow(window); + } + m_taskqueue.exit(); + glfwTerminate(); if (!Global.exec_on_exit.empty()) system(Global.exec_on_exit.c_str()); } -void -eu07_application::render_ui() { +void eu07_application::render_ui() +{ - if( m_modestack.empty() ) { return; } + if (m_modestack.empty()) + { + return; + } - m_modes[ m_modestack.top() ]->render_ui(); + m_modes[m_modestack.top()]->render_ui(); } -void eu07_application::begin_ui_frame() { +void eu07_application::begin_ui_frame() +{ - if( m_modestack.empty() ) { return; } + if (m_modestack.empty()) + { + return; + } - m_modes[ m_modestack.top() ]->begin_ui_frame(); + m_modes[m_modestack.top()]->begin_ui_frame(); } -bool -eu07_application::pop_mode() { - if( m_modestack.empty() ) { return false; } +bool eu07_application::pop_mode() +{ + if (m_modestack.empty()) + { + return false; + } - m_modes[ m_modestack.top() ]->exit(); - m_modestack.pop(); - return true; + m_modes[m_modestack.top()]->exit(); + m_modestack.pop(); + return true; } -bool -eu07_application::push_mode( mode const Mode ) { +bool eu07_application::push_mode(mode const Mode) +{ - if( Mode >= count_ ) + if (Mode >= count_) return false; - if (!m_modes[Mode]) { + if (!m_modes[Mode]) + { if (Mode == launcher) m_modes[Mode] = std::make_shared(); if (Mode == scenarioloader) @@ -706,44 +748,50 @@ eu07_application::push_mode( mode const Mode ) { return false; } - m_modes[ Mode ]->enter(); - m_modestack.push( Mode ); + m_modes[Mode]->enter(); + m_modestack.push(Mode); - return true; + return true; } -void -eu07_application::set_title( std::string const &Title ) { +void eu07_application::set_title(std::string const &Title) +{ - glfwSetWindowTitle( m_windows.front(), Title.c_str() ); + glfwSetWindowTitle(m_windows.front(), Title.c_str()); } -void -eu07_application::set_progress( float const Progress, float const Subtaskprogress ) { +void eu07_application::set_progress(float const Progress, float const Subtaskprogress) +{ - if( m_modestack.empty() ) { return; } + if (m_modestack.empty()) + { + return; + } - m_modes[ m_modestack.top() ]->set_progress( Progress, Subtaskprogress ); + m_modes[m_modestack.top()]->set_progress(Progress, Subtaskprogress); } -void -eu07_application::set_tooltip( std::string const &Tooltip ) { +void eu07_application::set_tooltip(std::string const &Tooltip) +{ - if( m_modestack.empty() ) { return; } + if (m_modestack.empty()) + { + return; + } - m_modes[ m_modestack.top() ]->set_tooltip( Tooltip ); + m_modes[m_modestack.top()]->set_tooltip(Tooltip); } -void -eu07_application::set_cursor( int const Mode ) { +void eu07_application::set_cursor(int const Mode) +{ - ui_layer::set_cursor( Mode ); + ui_layer::set_cursor(Mode); } -void -eu07_application::set_cursor_pos( double const Horizontal, double const Vertical ) { +void eu07_application::set_cursor_pos(double const Horizontal, double const Vertical) +{ - glfwSetCursorPos( m_windows.front(), Horizontal, Vertical ); + glfwSetCursorPos(m_windows.front(), Horizontal, Vertical); } /* @@ -757,63 +805,78 @@ eu07_application::get_input_hint( user_command const Command ) const { } */ -void -eu07_application::on_key( int const Key, int const Scancode, int const Action, int const Mods ) { +void eu07_application::on_key(int const Key, int const Scancode, int const Action, int const Mods) +{ - if (ui_layer::key_callback(Key, Scancode, Action, Mods)) - return; + if (ui_layer::key_callback(Key, Scancode, Action, Mods)) + return; - if( m_modestack.empty() ) { return; } + if (m_modestack.empty()) + { + return; + } - #ifdef __unix__ +#ifdef __unix__ if (Key == GLFW_KEY_LEFT_SHIFT || Key == GLFW_KEY_RIGHT_SHIFT) Global.shiftState = Action == GLFW_PRESS; if (Key == GLFW_KEY_LEFT_CONTROL || Key == GLFW_KEY_RIGHT_CONTROL) Global.ctrlState = Action == GLFW_PRESS; if (Key == GLFW_KEY_LEFT_ALT || Key == GLFW_KEY_RIGHT_ALT) Global.altState = Action == GLFW_PRESS; - #endif +#endif - m_modes[ m_modestack.top() ]->on_key( Key, Scancode, Action, Mods ); + m_modes[m_modestack.top()]->on_key(Key, Scancode, Action, Mods); } -void -eu07_application::on_cursor_pos( double const Horizontal, double const Vertical ) { +void eu07_application::on_cursor_pos(double const Horizontal, double const Vertical) +{ - if( m_modestack.empty() ) { return; } + if (m_modestack.empty()) + { + return; + } - m_modes[ m_modestack.top() ]->on_cursor_pos( Horizontal, Vertical ); + m_modes[m_modestack.top()]->on_cursor_pos(Horizontal, Vertical); } -void -eu07_application::on_mouse_button( int const Button, int const Action, int const Mods ) { +void eu07_application::on_mouse_button(int const Button, int const Action, int const Mods) +{ - if (ui_layer::mouse_button_callback(Button, Action, Mods)) - return; + if (ui_layer::mouse_button_callback(Button, Action, Mods)) + return; - if( m_modestack.empty() ) { return; } + if (m_modestack.empty()) + { + return; + } - m_modes[ m_modestack.top() ]->on_mouse_button( Button, Action, Mods ); + m_modes[m_modestack.top()]->on_mouse_button(Button, Action, Mods); } -void -eu07_application::on_scroll( double const Xoffset, double const Yoffset ) { +void eu07_application::on_scroll(double const Xoffset, double const Yoffset) +{ - if (ui_layer::scroll_callback(Xoffset, Yoffset)) - return; + if (ui_layer::scroll_callback(Xoffset, Yoffset)) + return; - if( m_modestack.empty() ) { return; } + if (m_modestack.empty()) + { + return; + } - m_modes[ m_modestack.top() ]->on_scroll( Xoffset, Yoffset ); + m_modes[m_modestack.top()]->on_scroll(Xoffset, Yoffset); } -void eu07_application::on_char(unsigned int c) { - if (ui_layer::char_callback(c)) - return; +void eu07_application::on_char(unsigned int c) +{ + if (ui_layer::char_callback(c)) + return; } -void eu07_application::on_focus_change(bool focus) { - if( Global.bInactivePause && m_network.has_value() && !m_network->client) {// jeśli ma być pauzowanie okna w tle +void eu07_application::on_focus_change(bool focus) +{ + if (Global.bInactivePause && m_network.has_value() && !m_network->client) + { // jeśli ma być pauzowanie okna w tle command_relay relay; relay.post(user_command::focuspauseset, focus ? 1.0 : 0.0, 0.0, GLFW_PRESS, 0); } @@ -821,53 +884,51 @@ void eu07_application::on_focus_change(bool focus) { void eu07_application::on_window_resize(int w, int h) { - if (m_modestack.empty()) - return; - m_modes[m_modestack.top()]->on_window_resize(w, h); + if (m_modestack.empty()) + return; + m_modes[m_modestack.top()]->on_window_resize(w, h); } +GLFWwindow *eu07_application::window(int const Windowindex, bool visible, int width, int height, GLFWmonitor *monitor, bool keep_ownership, bool share_ctx) +{ -GLFWwindow * -eu07_application::window(int const Windowindex, bool visible, int width, int height, GLFWmonitor *monitor, bool keep_ownership , bool share_ctx) { + if (Windowindex >= 0) + { + return (Windowindex < m_windows.size() ? m_windows[Windowindex] : nullptr); + } + // for index -1 create a new child window - if( Windowindex >= 0 ) { - return ( - Windowindex < m_windows.size() ? - m_windows[ Windowindex ] : - nullptr ); - } - // for index -1 create a new child window + auto const *vmode{glfwGetVideoMode(monitor ? monitor : glfwGetPrimaryMonitor())}; - auto const *vmode { glfwGetVideoMode( monitor ? monitor : glfwGetPrimaryMonitor() ) }; + // match requested video mode to current to allow for + // fullwindow creation when resolution is the same + glfwWindowHint(GLFW_RED_BITS, vmode->redBits); + glfwWindowHint(GLFW_GREEN_BITS, vmode->greenBits); + glfwWindowHint(GLFW_BLUE_BITS, vmode->blueBits); + glfwWindowHint(GLFW_REFRESH_RATE, vmode->refreshRate); - // match requested video mode to current to allow for - // fullwindow creation when resolution is the same - glfwWindowHint( GLFW_RED_BITS, vmode->redBits ); - glfwWindowHint( GLFW_GREEN_BITS, vmode->greenBits ); - glfwWindowHint( GLFW_BLUE_BITS, vmode->blueBits ); - glfwWindowHint( GLFW_REFRESH_RATE, vmode->refreshRate ); + glfwWindowHint(GLFW_VISIBLE, visible); - glfwWindowHint( GLFW_VISIBLE, visible ); - - auto *childwindow = glfwCreateWindow( width, height, "eu07window", monitor, - share_ctx ? m_windows.front() : nullptr); + auto *childwindow = glfwCreateWindow(width, height, "eu07window", monitor, share_ctx ? m_windows.front() : nullptr); if (!childwindow) return nullptr; if (keep_ownership) - m_windows.emplace_back( childwindow ); + m_windows.emplace_back(childwindow); glfwFocusWindow(m_windows.front()); // restore focus to main window - return childwindow; + return childwindow; } // private: -GLFWmonitor* eu07_application::find_monitor(const std::string &str) const { - int monitor_count; +GLFWmonitor *eu07_application::find_monitor(const std::string &str) const +{ + int monitor_count; GLFWmonitor **monitors = glfwGetMonitors(&monitor_count); - for (size_t i = 0; i < monitor_count; i++) { + for (size_t i = 0; i < monitor_count; i++) + { if (describe_monitor(monitors[i]) == str) return monitors[i]; } @@ -875,7 +936,8 @@ GLFWmonitor* eu07_application::find_monitor(const std::string &str) const { return nullptr; } -std::string eu07_application::describe_monitor(GLFWmonitor *monitor) const { +std::string eu07_application::describe_monitor(GLFWmonitor *monitor) const +{ std::string name(glfwGetMonitorName(monitor)); std::replace(std::begin(name), std::end(name), ' ', '_'); @@ -892,28 +954,29 @@ bool eu07_application::needs_ogl() const return !Global.NvRenderer; } -void eu07_application::init_debug() { +void eu07_application::init_debug() +{ -#if defined(_MSC_VER) && defined (_DEBUG) - // memory leaks - _CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) | _CRTDBG_LEAK_CHECK_DF ); - /* - // floating point operation errors - auto state { _clearfp() }; - state = _control87( 0, 0 ); - // this will turn on FPE for #IND and zerodiv - state = _control87( state & ~( _EM_ZERODIVIDE | _EM_INVALID ), _MCW_EM ); - */ +#if defined(_MSC_VER) && defined(_DEBUG) + // memory leaks + _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF); + /* + // floating point operation errors + auto state { _clearfp() }; + state = _control87( 0, 0 ); + // this will turn on FPE for #IND and zerodiv + state = _control87( state & ~( _EM_ZERODIVIDE | _EM_INVALID ), _MCW_EM ); + */ #endif } -void -eu07_application::init_files() { +void eu07_application::init_files() +{ #ifdef _WIN32 - DeleteFile( "log.txt" ); - DeleteFile( "errors.txt" ); - CreateDirectory( "logs", NULL ); + DeleteFile("log.txt"); + DeleteFile("errors.txt"); + CreateDirectory("logs", NULL); #elif __unix__ unlink("log.txt"); unlink("errors.txt"); @@ -922,11 +985,11 @@ eu07_application::init_files() { } namespace fs = std::filesystem; -int -eu07_application::init_settings( int Argc, char *Argv[] ) { - Global.asVersion = VERSION_INFO; +int eu07_application::init_settings(int Argc, char *Argv[]) +{ + Global.asVersion = VERSION_INFO; - fs::path iniPath; + fs::path iniPath; #ifdef _WIN32 if (const char *appdata = std::getenv("APPDATA")) @@ -949,318 +1012,345 @@ eu07_application::init_settings( int Argc, char *Argv[] ) { Global.LoadIniFile("eu07.ini"); } - // process command line arguments - for( int i = 1; i < Argc; ++i ) { + // process command line arguments + for (int i = 1; i < Argc; ++i) + { - std::string token { Argv[ i ] }; + std::string token{Argv[i]}; - if( token == "-s" ) { - if( i + 1 < Argc ) { - Global.SceneryFile = ToLower( Argv[ ++i ] ); - } - } - else if( token == "-v" ) { - if( i + 1 < Argc ) { - Global.local_start_vehicle = ToLower( Argv[ ++i ] ); - } - } - else { - std::cout - << "usage: " << std::string( Argv[ 0 ] ) - << " [-s sceneryfilepath]" - << " [-v vehiclename]" - << std::endl; - return -1; - } - } + if (token == "-s") + { + if (i + 1 < Argc) + { + Global.SceneryFile = ToLower(Argv[++i]); + } + } + else if (token == "-v") + { + if (i + 1 < Argc) + { + Global.local_start_vehicle = ToLower(Argv[++i]); + } + } + else + { + std::cout << "usage: " << std::string(Argv[0]) << " [-s sceneryfilepath]" + << " [-v vehiclename]" << std::endl; + return -1; + } + } - return 0; + return 0; } -int -eu07_application::init_locale() { +int eu07_application::init_locale() +{ Translations.init(); - return 0; + return 0; } -int -eu07_application::init_glfw() { - { - int glfw_major, glfw_minor, glfw_rev; - glfwGetVersion(&glfw_major, &glfw_minor, &glfw_rev); - m_glfwversion = glfw_major * 10000 + glfw_minor * 100 + glfw_minor; - } +int eu07_application::init_glfw() +{ + { + int glfw_major, glfw_minor, glfw_rev; + glfwGetVersion(&glfw_major, &glfw_minor, &glfw_rev); + m_glfwversion = glfw_major * 10000 + glfw_minor * 100 + glfw_minor; + } #ifdef GLFW_ANGLE_PLATFORM_TYPE - if (m_glfwversion >= 30400) { - int platform = GLFW_ANGLE_PLATFORM_TYPE_NONE; - if (Global.gfx_angleplatform == "opengl") - platform = GLFW_ANGLE_PLATFORM_TYPE_OPENGL; - else if (Global.gfx_angleplatform == "opengles") - platform = GLFW_ANGLE_PLATFORM_TYPE_OPENGLES; - else if (Global.gfx_angleplatform == "d3d9") - platform = GLFW_ANGLE_PLATFORM_TYPE_D3D9; - else if (Global.gfx_angleplatform == "d3d11") - platform = GLFW_ANGLE_PLATFORM_TYPE_D3D11; - else if (Global.gfx_angleplatform == "vulkan") - platform = GLFW_ANGLE_PLATFORM_TYPE_VULKAN; - else if (Global.gfx_angleplatform == "metal") - platform = GLFW_ANGLE_PLATFORM_TYPE_METAL; + if (m_glfwversion >= 30400) + { + int platform = GLFW_ANGLE_PLATFORM_TYPE_NONE; + if (Global.gfx_angleplatform == "opengl") + platform = GLFW_ANGLE_PLATFORM_TYPE_OPENGL; + else if (Global.gfx_angleplatform == "opengles") + platform = GLFW_ANGLE_PLATFORM_TYPE_OPENGLES; + else if (Global.gfx_angleplatform == "d3d9") + platform = GLFW_ANGLE_PLATFORM_TYPE_D3D9; + else if (Global.gfx_angleplatform == "d3d11") + platform = GLFW_ANGLE_PLATFORM_TYPE_D3D11; + else if (Global.gfx_angleplatform == "vulkan") + platform = GLFW_ANGLE_PLATFORM_TYPE_VULKAN; + else if (Global.gfx_angleplatform == "metal") + platform = GLFW_ANGLE_PLATFORM_TYPE_METAL; - glfwInitHint(GLFW_ANGLE_PLATFORM_TYPE, platform); - } + glfwInitHint(GLFW_ANGLE_PLATFORM_TYPE, platform); + } #endif - if( glfwInit() == GLFW_FALSE ) { - ErrorLog( "Bad init: failed to initialize glfw" ); - return -1; - } + if (glfwInit() == GLFW_FALSE) + { + ErrorLog("Bad init: failed to initialize glfw"); + return -1; + } { int monitor_count; GLFWmonitor **monitors = glfwGetMonitors(&monitor_count); WriteLog("available monitors:"); - for (size_t i = 0; i < monitor_count; i++) { + for (size_t i = 0; i < monitor_count; i++) + { WriteLog(describe_monitor(monitors[i])); } } - auto *monitor { find_monitor(Global.fullscreen_monitor) }; + auto *monitor{find_monitor(Global.fullscreen_monitor)}; if (!monitor) monitor = glfwGetPrimaryMonitor(); - glfwWindowHint( GLFW_AUTO_ICONIFY, GLFW_FALSE ); - if ((Global.gfx_skippipeline || Global.LegacyRenderer) && Global.iMultisampling > 0) { - glfwWindowHint( GLFW_SAMPLES, 1 << Global.iMultisampling ); - } + glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE); + if ((Global.gfx_skippipeline || Global.LegacyRenderer) && Global.iMultisampling > 0) + { + glfwWindowHint(GLFW_SAMPLES, 1 << Global.iMultisampling); + } - crashreport_add_info("gfxrenderer", Global.GfxRenderer); + crashreport_add_info("gfxrenderer", Global.GfxRenderer); - if (!needs_ogl()) - { - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - } - else { - if( !Global.LegacyRenderer ) { - Global.bUseVBO = true; - // activate core profile for opengl 3.3 renderer - if( !Global.gfx_usegles ) { - glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE ); - glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE ); - glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 ); - glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 ); - } - else { + if (!needs_ogl()) + { + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + } + else + { + if (!Global.LegacyRenderer) + { + Global.bUseVBO = true; + // activate core profile for opengl 3.3 renderer + if (!Global.gfx_usegles) + { + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + } + else + { #ifdef GLFW_CONTEXT_CREATION_API - if (m_glfwversion >= 30200) - glfwWindowHint( GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API ); + if (m_glfwversion >= 30200) + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); #endif - glfwWindowHint( GLFW_CLIENT_API, GLFW_OPENGL_ES_API ); - glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 ); - glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 0 ); - } - } else { - if (Global.gfx_usegles) { - ErrorLog("legacy renderer not supported in gles mode"); - return -1; - } - Global.gfx_shadergamma = false; - glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE ); - glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 2 ); - glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 1 ); - } + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + } + } + else + { + if (Global.gfx_usegles) + { + ErrorLog("legacy renderer not supported in gles mode"); + return -1; + } + Global.gfx_shadergamma = false; + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); + } - if (Global.gfx_gldebug) - glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE ); - } + if (Global.gfx_gldebug) + glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); + } - glfwWindowHint(GLFW_SRGB_CAPABLE, !Global.gfx_shadergamma); + glfwWindowHint(GLFW_SRGB_CAPABLE, !Global.gfx_shadergamma); - if( Global.fullscreen_windowed ) { - auto const mode = glfwGetVideoMode( monitor ); - Global.window_size.x = mode->width; - Global.window_size.y = mode->height; - Global.bFullScreen = true; - } + if (Global.fullscreen_windowed) + { + auto const mode = glfwGetVideoMode(monitor); + Global.window_size.x = mode->width; + Global.window_size.y = mode->height; + Global.bFullScreen = true; + } - auto *mainwindow = window( - -1, true, Global.window_size.x, Global.window_size.y, ( Global.bFullScreen ? monitor : nullptr ), true, false ); + auto *mainwindow = window(-1, true, Global.window_size.x, Global.window_size.y, (Global.bFullScreen ? monitor : nullptr), true, false); - if( mainwindow == nullptr ) { - ErrorLog( "Bad init: failed to create glfw window" ); - return -1; - } + if (mainwindow == nullptr) + { + ErrorLog("Bad init: failed to create glfw window"); + return -1; + } - glfwMakeContextCurrent( mainwindow ); - glfwSwapInterval( Global.VSync ? 1 : 0 ); //vsync + glfwMakeContextCurrent(mainwindow); + glfwSwapInterval(Global.VSync ? 1 : 0); // vsync - { - int width, height; + { + int width, height; - glfwGetFramebufferSize( mainwindow, &width, &height ); - framebuffer_resize_callback( mainwindow, width, height ); + glfwGetFramebufferSize(mainwindow, &width, &height); + framebuffer_resize_callback(mainwindow, width, height); - glfwGetWindowSize( mainwindow, &width, &height ); - window_resize_callback( mainwindow, width, height ); - } + glfwGetWindowSize(mainwindow, &width, &height); + window_resize_callback(mainwindow, width, height); + } #ifdef _WIN32 -// setup wrapper for base glfw window proc, to handle copydata messages - Hwnd = glfwGetWin32Window( mainwindow ); - BaseWindowProc = ( WNDPROC )::SetWindowLongPtr( Hwnd, GWLP_WNDPROC, (LONG_PTR)WndProc ); - // switch off the topmost flag - ::SetWindowPos( Hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE ); + // setup wrapper for base glfw window proc, to handle copydata messages + Hwnd = glfwGetWin32Window(mainwindow); + BaseWindowProc = (WNDPROC)::SetWindowLongPtr(Hwnd, GWLP_WNDPROC, (LONG_PTR)WndProc); + // switch off the topmost flag + ::SetWindowPos(Hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); #endif - return 0; + return 0; } -void -eu07_application::init_callbacks() { +void eu07_application::init_callbacks() +{ - auto *window { m_windows.front() }; - glfwSetWindowSizeCallback( window, window_resize_callback ); - glfwSetFramebufferSizeCallback( window, framebuffer_resize_callback ); - glfwSetCursorPosCallback( window, cursor_pos_callback ); - glfwSetMouseButtonCallback( window, mouse_button_callback ); - glfwSetKeyCallback( window, key_callback ); - glfwSetScrollCallback( window, scroll_callback ); - glfwSetCharCallback(window, char_callback); - glfwSetWindowFocusCallback( window, focus_callback ); + auto *window{m_windows.front()}; + glfwSetWindowSizeCallback(window, window_resize_callback); + glfwSetFramebufferSizeCallback(window, framebuffer_resize_callback); + glfwSetCursorPosCallback(window, cursor_pos_callback); + glfwSetMouseButtonCallback(window, mouse_button_callback); + glfwSetKeyCallback(window, key_callback); + glfwSetScrollCallback(window, scroll_callback); + glfwSetCharCallback(window, char_callback); + glfwSetWindowFocusCallback(window, focus_callback); } -int -eu07_application::init_ogl() { - if (!Global.gfx_usegles) - { - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) - { - ErrorLog( "Bad init: failed to initialize glad" ); - return -1; - } - } - else - { - if (!gladLoadGLES2Loader((GLADloadproc)glfwGetProcAddress)) - { - ErrorLog( "Bad init: failed to initialize glad" ); - return -1; - } - } +int eu07_application::init_ogl() +{ + if (!Global.gfx_usegles) + { + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + ErrorLog("Bad init: failed to initialize glad"); + return -1; + } + } + else + { + if (!gladLoadGLES2Loader((GLADloadproc)glfwGetProcAddress)) + { + ErrorLog("Bad init: failed to initialize glad"); + return -1; + } + } - return 0; + return 0; } -int -eu07_application::init_ui() { - if( false == ui_layer::init( m_windows.front() ) ) { - return -1; - } - init_callbacks(); - return 0; +int eu07_application::init_ui() +{ + if (false == ui_layer::init(m_windows.front())) + { + return -1; + } + init_callbacks(); + return 0; } -int -eu07_application::init_gfx() { +int eu07_application::init_gfx() +{ - if( Global.GfxRenderer == "default" ) { - // default render path - GfxRenderer = gfx_renderer_factory::get_instance()->create("modern"); - } + if (Global.GfxRenderer == "default") + { + // default render path + GfxRenderer = gfx_renderer_factory::get_instance()->create("modern"); + } else if (Global.GfxRenderer == "experimental") { GfxRenderer = gfx_renderer_factory::get_instance()->create(Global.GfxRenderer); } - else { - // legacy render path - GfxRenderer = gfx_renderer_factory::get_instance()->create("legacy"); - Global.DisabledLogTypes |= static_cast( logtype::material ); - } + else + { + // legacy render path + GfxRenderer = gfx_renderer_factory::get_instance()->create("legacy"); + Global.DisabledLogTypes |= static_cast(logtype::material); + } - if (!GfxRenderer) { - ErrorLog("no renderer found!"); - return -1; - } + if (!GfxRenderer) + { + ErrorLog("no renderer found!"); + return -1; + } - if( false == GfxRenderer->Init( m_windows.front() ) ) { - return -1; - } + if (false == GfxRenderer->Init(m_windows.front())) + { + return -1; + } for (const global_settings::extraviewport_config &conf : Global.extra_viewports) - if (!GfxRenderer->AddViewport(conf)) + if (!GfxRenderer->AddViewport(conf)) return -1; - if (!Global.headtrack_conf.joy.empty()) - m_headtrack.emplace(); + if (!Global.headtrack_conf.joy.empty()) + m_headtrack.emplace(); - return 0; + return 0; } -int -eu07_application::init_audio() { +int eu07_application::init_audio() +{ - if( Global.bSoundEnabled ) { - Global.bSoundEnabled &= audio::renderer.init(); - } - // NOTE: lack of audio isn't deemed a failure serious enough to throw in the towel - return 0; + if (Global.bSoundEnabled) + { + Global.bSoundEnabled &= audio::renderer.init(); + } + // NOTE: lack of audio isn't deemed a failure serious enough to throw in the towel + return 0; } -int -eu07_application::init_data() { +int eu07_application::init_data() +{ - // HACK: grab content of the first {} block in load_unit_weights using temporary parser, then parse it normally. on any error our weight list will be empty string - auto loadweights { cParser( cParser( "data/load_weights.txt", cParser::buffer_FILE ).getToken( true, "{}" ), cParser::buffer_TEXT ) }; - while( true == loadweights.getTokens( 2 ) ) { - std::pair weightpair; - loadweights - >> weightpair.first - >> weightpair.second; - weightpair.first.erase( weightpair.first.end() - 1 ); // trim trailing ':' from the key - simulation::Weights.emplace( weightpair.first, weightpair.second ); - } - cParser override_parser( "data/sound_overrides.txt", cParser::buffer_FILE ); - deserialize_map( simulation::Sound_overrides, override_parser); + // HACK: grab content of the first {} block in load_unit_weights using temporary parser, then parse it normally. on any error our weight list will be empty string + auto loadweights{cParser(cParser("data/load_weights.txt", cParser::buffer_FILE).getToken(true, "{}"), cParser::buffer_TEXT)}; + while (true == loadweights.getTokens(2)) + { + std::pair weightpair; + loadweights >> weightpair.first >> weightpair.second; + weightpair.first.erase(weightpair.first.end() - 1); // trim trailing ':' from the key + simulation::Weights.emplace(weightpair.first, weightpair.second); + } + cParser override_parser("data/sound_overrides.txt", cParser::buffer_FILE); + deserialize_map(simulation::Sound_overrides, override_parser); - return 0; + return 0; } -int -eu07_application::init_modes() { +int eu07_application::init_modes() +{ Global.local_random_engine.seed(std::random_device{}()); - if ((!Global.network_servers.empty() || Global.network_client) && Global.SceneryFile.empty()) { + if ((!Global.network_servers.empty() || Global.network_client) && Global.SceneryFile.empty()) + { ErrorLog("launcher mode is currently not supported in network mode"); return -1; - } + } - // activate the default mode + // activate the default mode if (Global.SceneryFile.empty()) - push_mode( mode::launcher ); + push_mode(mode::launcher); else - push_mode( mode::scenarioloader ); + push_mode(mode::scenarioloader); - return 0; + return 0; } -bool eu07_application::init_network() { - if (!Global.network_servers.empty() || Global.network_client) { +bool eu07_application::init_network() +{ + if (!Global.network_servers.empty() || Global.network_client) + { // create network manager m_network.emplace(); } - for (auto const &pair : Global.network_servers) { + for (auto const &pair : Global.network_servers) + { // create all servers m_network->create_server(pair.first, pair.second); } - if (Global.network_client) { + if (Global.network_client) + { // create client m_network->connect(Global.network_client->first, Global.network_client->second); - } else { + } + else + { // we're simulation master if (!Global.random_seed) Global.random_seed = std::random_device{}(); @@ -1275,8 +1365,7 @@ bool eu07_application::init_network() { tmp = std::gmtime(&utc_now); memcpy(&tm_utc, tmp, sizeof(tm)); - int64_t offset = (tm_local.tm_hour * 3600 + tm_local.tm_min * 60 + tm_local.tm_sec) - - (tm_utc.tm_hour * 3600 + tm_utc.tm_min * 60 + tm_utc.tm_sec); + int64_t offset = (tm_local.tm_hour * 3600 + tm_local.tm_min * 60 + tm_local.tm_sec) - (tm_utc.tm_hour * 3600 + tm_utc.tm_min * 60 + tm_utc.tm_sec); Global.starting_timestamp = utc_now + offset; Global.ready_to_load = true; diff --git a/editormode.cpp b/editormode.cpp index af2c25cc..a256d2e4 100644 --- a/editormode.cpp +++ b/editormode.cpp @@ -21,238 +21,322 @@ http://mozilla.org/MPL/2.0/. #include "renderer.h" #include "AnimModel.h" -bool -editor_mode::editormode_input::init() { +bool editor_mode::editormode_input::init() +{ - return ( - mouse.init() - && keyboard.init() ); + return (mouse.init() && keyboard.init()); } -void -editor_mode::editormode_input::poll() { +void editor_mode::editormode_input::poll() +{ - keyboard.poll(); + keyboard.poll(); } -editor_mode::editor_mode() { +editor_mode::editor_mode() +{ - m_userinterface = std::make_shared(); + m_userinterface = std::make_shared(); } // initializes internal data structures of the mode. returns: true on success, false otherwise -bool -editor_mode::init() { +bool editor_mode::init() +{ - Camera.Init( { 0, 15, 0 }, { glm::radians( -30.0 ), glm::radians( 180.0 ), 0 }, nullptr ); + Camera.Init({0, 15, 0}, {glm::radians(-30.0), glm::radians(180.0), 0}, nullptr); - return m_input.init(); + return m_input.init(); } // mode-specific update of simulation data. returns: false on error, true otherwise -bool -editor_mode::update() { +bool editor_mode::update() +{ - Timer::UpdateTimers( true ); + Timer::UpdateTimers(true); - simulation::State.update_clocks(); - simulation::Environment.update(); + simulation::State.update_clocks(); + simulation::Environment.update(); - // render time routines follow: - auto const deltarealtime = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu + // render time routines follow: + auto const deltarealtime = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu - // fixed step render time routines: - fTime50Hz += deltarealtime; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek - while( fTime50Hz >= 1.0 / 50.0 ) { + // fixed step render time routines: + fTime50Hz += deltarealtime; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek + while (fTime50Hz >= 1.0 / 50.0) + { #ifdef _WIN32 - Console::Update(); // to i tak trzeba wywoływać + Console::Update(); // to i tak trzeba wywoływać #endif - m_userinterface->update(); - // decelerate camera - Camera.Velocity *= 0.65; - if( std::abs( Camera.Velocity.x ) < 0.01 ) { Camera.Velocity.x = 0.0; } - if( std::abs( Camera.Velocity.y ) < 0.01 ) { Camera.Velocity.y = 0.0; } - if( std::abs( Camera.Velocity.z ) < 0.01 ) { Camera.Velocity.z = 0.0; } + m_userinterface->update(); + if (mouseHold) + { + auto const mode = static_cast(m_userinterface.get())->mode(); + auto const rotation_mode = static_cast(m_userinterface.get())->rot_mode(); + auto const fixed_rotation_value = static_cast(m_userinterface.get())->rot_val(); + int Action = GLFW_REPEAT; + int Button = GLFW_MOUSE_BUTTON_LEFT; + { + GfxRenderer->Pick_Node_Callback( + [this, mode, rotation_mode, fixed_rotation_value, Action, Button](scene::basic_node *node) + { + editor_ui *ui = static_cast(m_userinterface.get()); - fTime50Hz -= 1.0 / 50.0; - } + if (mode == nodebank_panel::BRUSH) + { + const std::string *src = ui->get_active_node_template(); + // std::string name = "editor_" + std::to_string(LocalRandom(0.0, 100000.0)); + std::string name = "editor_" + generate_uuid_v4(); - // variable step render time routines: - update_camera( deltarealtime ); + if (!src) + return; - simulation::Region->update_sounds(); - audio::renderer.update( Global.iPause ? 0.0 : deltarealtime ); + glm::vec3 newPos = GfxRenderer->Mouse_Position(); + float distance = glm::distance(newPos, oldPos); + if (distance < ui->getSpacing()) + return; + TAnimModel *cloned = simulation::State.create_model(*src, name, Camera.Pos + newPos); + oldPos = newPos; + if (!cloned) + return; - GfxRenderer->Update( deltarealtime ); + // if (!m_dragging) + // return; - simulation::is_ready = true; + m_node = cloned; - return true; + if (rotation_mode == functions_panel::RANDOM) + { + auto const rotation{glm::vec3{0, LocalRandom(0.0, 360.0), 0}}; + + m_editor.rotate(m_node, rotation, 1); + } + else if (rotation_mode == functions_panel::FIXED) + { + + auto const rotation{glm::vec3{0, fixed_rotation_value, 0}}; + + m_editor.rotate(m_node, rotation, 0); + } + // Application.set_cursor( GLFW_CURSOR_DISABLED ); + ui->set_node(m_node); + } + }); + } + } + // decelerate camera + Camera.Velocity *= 0.65; + if (std::abs(Camera.Velocity.x) < 0.01) + { + Camera.Velocity.x = 0.0; + } + if (std::abs(Camera.Velocity.y) < 0.01) + { + Camera.Velocity.y = 0.0; + } + if (std::abs(Camera.Velocity.z) < 0.01) + { + Camera.Velocity.z = 0.0; + } + + fTime50Hz -= 1.0 / 50.0; + } + + // variable step render time routines: + update_camera(deltarealtime); + + simulation::Region->update_sounds(); + audio::renderer.update(Global.iPause ? 0.0 : deltarealtime); + + GfxRenderer->Update(deltarealtime); + + simulation::is_ready = true; + + return true; } -void -editor_mode::update_camera( double const Deltatime ) { +void editor_mode::update_camera(double const Deltatime) +{ - // uwzględnienie ruchu wywołanego klawiszami - Camera.Update(); - // reset window state, it'll be set again if applicable in a check below - Global.CabWindowOpen = false; - // all done, update camera position to the new value - Global.pCamera = Camera; + // uwzględnienie ruchu wywołanego klawiszami + Camera.Update(); + // reset window state, it'll be set again if applicable in a check below + Global.CabWindowOpen = false; + // all done, update camera position to the new value + Global.pCamera = Camera; } // maintenance method, called when the mode is activated -void -editor_mode::enter() { +void editor_mode::enter() +{ - m_statebackup = { Global.pCamera, FreeFlyModeFlag, Global.ControlPicking }; + m_statebackup = {Global.pCamera, FreeFlyModeFlag, Global.ControlPicking}; - Camera = Global.pCamera; - // NOTE: camera placement is effectively a copy of drivermode DistantView( true ) - // TBD, TODO: refactor into a common vehicle method? - if( false == FreeFlyModeFlag ) { + Camera = Global.pCamera; + // NOTE: camera placement is effectively a copy of drivermode DistantView( true ) + // TBD, TODO: refactor into a common vehicle method? + if (false == FreeFlyModeFlag) + { - auto const *vehicle { Camera.m_owner }; - auto const cab { - ( vehicle->MoverParameters->CabOccupied == 0 ? - 1 : - vehicle->MoverParameters->CabOccupied ) }; - auto const left { vehicle->VectorLeft() * cab }; - Camera.Pos = - Math3D::vector3( Camera.Pos.x, vehicle->GetPosition().y, Camera.Pos.z ) - + left * vehicle->GetWidth() - + Math3D::vector3( 1.25 * left.x, 1.6, 1.25 * left.z ); - Camera.m_owner = nullptr; - Camera.LookAt = vehicle->GetPosition(); - Camera.RaLook(); // jednorazowe przestawienie kamery - FreeFlyModeFlag = true; - } - Global.ControlPicking = true; - EditorModeFlag = true; + auto const *vehicle{Camera.m_owner}; + auto const cab{(vehicle->MoverParameters->CabOccupied == 0 ? 1 : vehicle->MoverParameters->CabOccupied)}; + auto const left{vehicle->VectorLeft() * cab}; + Camera.Pos = Math3D::vector3(Camera.Pos.x, vehicle->GetPosition().y, Camera.Pos.z) + left * vehicle->GetWidth() + Math3D::vector3(1.25 * left.x, 1.6, 1.25 * left.z); + Camera.m_owner = nullptr; + Camera.LookAt = vehicle->GetPosition(); + Camera.RaLook(); // jednorazowe przestawienie kamery + FreeFlyModeFlag = true; + } + Global.ControlPicking = true; + EditorModeFlag = true; - Application.set_cursor( GLFW_CURSOR_NORMAL ); + Application.set_cursor(GLFW_CURSOR_NORMAL); } // maintenance method, called when the mode is deactivated -void -editor_mode::exit() { +void editor_mode::exit() +{ - EditorModeFlag = false; - Global.ControlPicking = m_statebackup.picking; - FreeFlyModeFlag = m_statebackup.freefly; - Global.pCamera = m_statebackup.camera; + EditorModeFlag = false; + Global.ControlPicking = m_statebackup.picking; + FreeFlyModeFlag = m_statebackup.freefly; + Global.pCamera = m_statebackup.camera; - Application.set_cursor( - ( Global.ControlPicking ? - GLFW_CURSOR_NORMAL : - GLFW_CURSOR_DISABLED ) ); + Application.set_cursor((Global.ControlPicking ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED)); - if( false == Global.ControlPicking ) { - Application.set_cursor_pos( 0, 0 ); - } + if (false == Global.ControlPicking) + { + Application.set_cursor_pos(0, 0); + } } -void -editor_mode::on_key( int const Key, int const Scancode, int const Action, int const Mods ) { +void editor_mode::on_key(int const Key, int const Scancode, int const Action, int const Mods) +{ #ifndef __unix__ Global.shiftState = (Mods & GLFW_MOD_SHIFT) ? true : false; Global.ctrlState = (Mods & GLFW_MOD_CONTROL) ? true : false; Global.altState = (Mods & GLFW_MOD_ALT) ? true : false; #endif - bool anyModifier = Mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT); + bool anyModifier = Mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT); - // give the ui first shot at the input processing... - if( !anyModifier && true == m_userinterface->on_key( Key, Action ) ) { return; } - // ...if the input is left untouched, pass it on - if( true == m_input.keyboard.key( Key, Action ) ) { return; } + // give the ui first shot at the input processing... + if (!anyModifier && true == m_userinterface->on_key(Key, Action)) + { + return; + } + // ...if the input is left untouched, pass it on + if (true == m_input.keyboard.key(Key, Action)) + { + return; + } - if( Action == GLFW_RELEASE ) { return; } + if (Action == GLFW_RELEASE) + { + return; + } - // legacy hardcoded keyboard commands - // TODO: replace with current command system, move to input object(s) - switch( Key ) { + // legacy hardcoded keyboard commands + // TODO: replace with current command system, move to input object(s) + switch (Key) + { - case GLFW_KEY_F11: { - - if( Action != GLFW_PRESS ) { break; } - // mode switch - // TODO: unsaved changes warning - if( ( false == Global.ctrlState ) - && ( false == Global.shiftState ) ) { - Application.pop_mode(); - } - // scenery export - if( Global.ctrlState - && Global.shiftState ) { - simulation::State.export_as_text( Global.SceneryFile ); - } - break; - } - - case GLFW_KEY_F12: { - // quick debug mode toggle - if( Global.ctrlState - && Global.shiftState ) { - DebugModeFlag = !DebugModeFlag; - } - break; - } - - // TODO: ensure delete method can play nice with history stack - case GLFW_KEY_DELETE: { - TAnimModel *model = dynamic_cast(m_node); - if (!model) - break; - - m_node = nullptr; - m_dragging = false; - //Application.set_cursor( GLFW_CURSOR_NORMAL ); - static_cast( m_userinterface.get() )->set_node(nullptr); - - simulation::State.delete_model(model); + case GLFW_KEY_F11: + { + if (Action != GLFW_PRESS) + { break; - } + } + // mode switch + // TODO: unsaved changes warning + if ((false == Global.ctrlState) && (false == Global.shiftState)) + { + Application.pop_mode(); + } + // scenery export + if (Global.ctrlState && Global.shiftState) + { + simulation::State.export_as_text(Global.SceneryFile); + } + break; + } - default: { - break; - } - } + case GLFW_KEY_F12: + { + // quick debug mode toggle + if (Global.ctrlState && Global.shiftState) + { + DebugModeFlag = !DebugModeFlag; + } + break; + } + + // TODO: ensure delete method can play nice with history stack + case GLFW_KEY_DELETE: + { + TAnimModel *model = dynamic_cast(m_node); + if (!model) + break; + + m_node = nullptr; + m_dragging = false; + // Application.set_cursor( GLFW_CURSOR_NORMAL ); + static_cast(m_userinterface.get())->set_node(nullptr); + + simulation::State.delete_model(model); + + break; + } + + default: + { + break; + } + } } -void -editor_mode::on_cursor_pos( double const Horizontal, double const Vertical ) { +void editor_mode::on_cursor_pos(double const Horizontal, double const Vertical) +{ - auto const mousemove { glm::dvec2{ Horizontal, Vertical } - m_input.mouse.position() }; - m_input.mouse.position( Horizontal, Vertical ); + auto const mousemove{glm::dvec2{Horizontal, Vertical} - m_input.mouse.position()}; + m_input.mouse.position(Horizontal, Vertical); - if( m_input.mouse.button( GLFW_MOUSE_BUTTON_LEFT ) == GLFW_RELEASE ) { return; } - if( m_node == nullptr ) { return; } + if (m_input.mouse.button(GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE) + { + return; + } + if (m_node == nullptr) + { + return; + } - if( m_takesnapshot ) { - // take a snapshot of selected node(s) - // TODO: implement this - m_takesnapshot = false; - } + if (m_takesnapshot) + { + // take a snapshot of selected node(s) + // TODO: implement this + m_takesnapshot = false; + } - if( mode_translation() ) { - // move selected node - if( mode_translation_vertical() ) { - auto const translation { mousemove.y * -0.01f }; - m_editor.translate( m_node, translation ); - } - else { - auto const mouseworldposition { Camera.Pos + GfxRenderer->Mouse_Position() }; - m_editor.translate( m_node, mouseworldposition, mode_snap() ); - } - } + if (mode_translation()) + { + // move selected node + if (mode_translation_vertical()) + { + auto const translation{mousemove.y * -0.01f}; + m_editor.translate(m_node, translation); + } + else + { + auto const mouseworldposition{Camera.Pos + GfxRenderer->Mouse_Position()}; + m_editor.translate(m_node, mouseworldposition, mode_snap()); + } + } else if (mode_rotationY()) { // rotate selected node // auto const rotation{glm::vec3{mousemove.y, mousemove.x, 0} * 0.25f}; auto const rotation{glm::vec3{0, mousemove.x, 0} * 0.25f}; auto const quantization{(mode_snap() ? 5.f : // TODO: put quantization value in a variable - 0.f)}; + 0.f)}; m_editor.rotate(m_node, rotation, quantization); } else if (mode_rotationZ()) @@ -262,7 +346,7 @@ editor_mode::on_cursor_pos( double const Horizontal, double const Vertical ) { // auto const rotation{glm::vec3{mousemove.y, mousemove.x, 0} * 0.25f}; auto const rotation{glm::vec3{0, 0, mousemove.x} * 0.25f}; auto const quantization{(mode_snap() ? 5.f : // TODO: put quantization value in a variable - 0.f)}; + 0.f)}; m_editor.rotate(m_node, rotation, quantization); } else if (mode_rotationX()) @@ -271,7 +355,7 @@ editor_mode::on_cursor_pos( double const Horizontal, double const Vertical ) { // auto const rotation{glm::vec3{mousemove.y, mousemove.x, 0} * 0.25f}; auto const rotation{glm::vec3{mousemove.y, 0, 0} * 0.25f}; auto const quantization{(mode_snap() ? 5.f : // TODO: put quantization value in a variable - 0.f)}; + 0.f)}; m_editor.rotate(m_node, rotation, quantization); } } @@ -307,161 +391,171 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods m_input.mouse.button( Button, Action ); } */ -void -editor_mode::on_mouse_button( int const Button, int const Action, int const Mods ) { +void editor_mode::on_mouse_button(int const Button, int const Action, int const Mods) +{ - // give the ui first shot at the input processing... - if( true == m_userinterface->on_mouse_button( Button, Action ) ) { return; } + // give the ui first shot at the input processing... - if( Button == GLFW_MOUSE_BUTTON_LEFT ) { - - if( Action == GLFW_PRESS ) { - // left button press - auto const mode = static_cast( m_userinterface.get() )->mode(); - auto const rotation_mode = static_cast( m_userinterface.get() )->rot_mode(); - auto const fixed_rotation_value = - static_cast(m_userinterface.get())->rot_val(); - - m_node = nullptr; - - GfxRenderer->Pick_Node_Callback([this, mode, rotation_mode, fixed_rotation_value, - Action, Button](scene::basic_node *node) { - editor_ui *ui = static_cast(m_userinterface.get()); - - if (mode == nodebank_panel::MODIFY) { - if (!m_dragging) - return; - - m_node = node; - //if( m_node ) - //Application.set_cursor( GLFW_CURSOR_DISABLED ); - //else - //m_dragging = false; - ui->set_node(m_node); - } - else if (mode == nodebank_panel::COPY) { - if (node && typeid(*node) == typeid(TAnimModel)) { - std::string as_text; - node->export_as_text(as_text); - - ui->add_node_template(as_text); - } - - m_dragging = false; - } - else if (mode == nodebank_panel::ADD) { - const std::string *src = ui->get_active_node_template(); - std::string name = "editor_" + std::to_string(LocalRandom(0.0, 100000.0)); - - if (!src) - return; - - TAnimModel *cloned = simulation::State.create_model(*src, name, Camera.Pos + GfxRenderer->Mouse_Position()); - - if (!cloned) - return; - - if (!m_dragging) - return; - - - m_node = cloned; - - if (rotation_mode == functions_panel::RANDOM) - { - auto const rotation{glm::vec3{0, LocalRandom(0.0, 360.0), 0}}; - - m_editor.rotate(m_node, rotation, 1); - } - else if (rotation_mode == functions_panel::FIXED) - { - - auto const rotation{glm::vec3{0, fixed_rotation_value, 0}}; - - m_editor.rotate(m_node, rotation, 0); - - } - //Application.set_cursor( GLFW_CURSOR_DISABLED ); - ui->set_node( m_node ); - } - }); - - m_dragging = true; - } - else { - // left button release - //if( m_node ) - //Application.set_cursor( GLFW_CURSOR_NORMAL ); - m_dragging = false; - // prime history stack for another snapshot - m_takesnapshot = true; - } - } - if (Button == GLFW_MOUSE_BUTTON_RIGHT) + if (Button == GLFW_MOUSE_BUTTON_LEFT) { + auto const mode = static_cast(m_userinterface.get())->mode(); + auto const rotation_mode = static_cast(m_userinterface.get())->rot_mode(); + auto const fixed_rotation_value = static_cast(m_userinterface.get())->rot_val(); - /*if (Action == GLFW_PRESS) + if (true == m_userinterface->on_mouse_button(Button, Action)) + { + return; + } + if (Action == GLFW_PRESS) { // left button press - auto const mode = static_cast(m_userinterface.get())->mode(); - + mouseHold = true; m_node = nullptr; - GfxRenderer->Pick_Node_Callback([this, mode](scene::basic_node *node) { - editor_ui *ui = static_cast(m_userinterface.get()); + GfxRenderer->Pick_Node_Callback( + [this, mode, rotation_mode, fixed_rotation_value, Action, Button](scene::basic_node *node) + { + editor_ui *ui = static_cast(m_userinterface.get()); + if (mode == nodebank_panel::MODIFY) + { + if (!m_dragging) + return; - if (mode == nodebank_panel::MODIFY) - { - if (!m_dragging) - return; + m_node = node; + // if( m_node ) + // Application.set_cursor( GLFW_CURSOR_DISABLED ); + // else + // m_dragging = false; + ui->set_node(m_node); + } + else if (mode == nodebank_panel::COPY) + { + if (node && typeid(*node) == typeid(TAnimModel)) + { + std::string as_text; + node->export_as_text(as_text); - m_node = node; - if (m_node) - Application.set_cursor(GLFW_CURSOR_DISABLED); - else - m_dragging = false; - ui->set_node(m_node); - } - }); + ui->add_node_template(as_text); + } + + m_dragging = false; + } + else if (mode == nodebank_panel::ADD) + { + const std::string *src = ui->get_active_node_template(); + std::string name = "editor_" + generate_uuid_v4(); + + if (!src) + return; + + TAnimModel *cloned = simulation::State.create_model(*src, name, Camera.Pos + GfxRenderer->Mouse_Position()); + + if (!cloned) + return; + + if (!m_dragging) + return; + + m_node = cloned; + + if (rotation_mode == functions_panel::RANDOM) + { + auto const rotation{glm::vec3{0, LocalRandom(0.0, 360.0), 0}}; + + m_editor.rotate(m_node, rotation, 1); + } + else if (rotation_mode == functions_panel::FIXED) + { + + auto const rotation{glm::vec3{0, fixed_rotation_value, 0}}; + + m_editor.rotate(m_node, rotation, 0); + } + // Application.set_cursor( GLFW_CURSOR_DISABLED ); + ui->set_node(m_node); + } + }); m_dragging = true; } else { + if (Action == GLFW_RELEASE) + mouseHold = false; + // left button release - if (m_node) - Application.set_cursor(GLFW_CURSOR_NORMAL); + // if( m_node ) + // Application.set_cursor( GLFW_CURSOR_NORMAL ); m_dragging = false; // prime history stack for another snapshot m_takesnapshot = true; + } + } + if (Button == GLFW_MOUSE_BUTTON_RIGHT) + { + + /*if (Action == GLFW_PRESS) + { + // left button press + auto const mode = static_cast(m_userinterface.get())->mode(); + + m_node = nullptr; + + GfxRenderer->Pick_Node_Callback([this, mode](scene::basic_node *node) { + editor_ui *ui = static_cast(m_userinterface.get()); + + if (mode == nodebank_panel::MODIFY) + { + if (!m_dragging) + return; + + m_node = node; + if (m_node) + Application.set_cursor(GLFW_CURSOR_DISABLED); + else + m_dragging = false; + ui->set_node(m_node); + } + }); + + m_dragging = true; + } + else + { + // left button release + if (m_node) + Application.set_cursor(GLFW_CURSOR_NORMAL); + m_dragging = false; + // prime history stack for another snapshot + m_takesnapshot = true; }*/ } - m_input.mouse.button( Button, Action ); + m_input.mouse.button(Button, Action); } -void -editor_mode::on_event_poll() { +void editor_mode::on_event_poll() +{ - m_input.poll(); + m_input.poll(); } -bool -editor_mode::is_command_processor() const { +bool editor_mode::is_command_processor() const +{ - return false; + return false; } -bool -editor_mode::mode_translation() const { +bool editor_mode::mode_translation() const +{ - return ( false == Global.altState ); + return (false == Global.altState); } -bool -editor_mode::mode_translation_vertical() const { +bool editor_mode::mode_translation_vertical() const +{ - return ( true == Global.shiftState ); + return (true == Global.shiftState); } bool editor_mode::mode_rotationY() const @@ -480,8 +574,8 @@ bool editor_mode::mode_rotationZ() const return ((true == Global.altState) && (true == Global.ctrlState) && (true == Global.shiftState)); } -bool -editor_mode::mode_snap() const { +bool editor_mode::mode_snap() const +{ - return ((false == Global.altState) && (true == Global.ctrlState) && (false == Global.shiftState)); + return ((false == Global.altState) && (true == Global.ctrlState) && (false == Global.shiftState)); } diff --git a/editormode.h b/editormode.h index 6e127f5a..4b412e57 100644 --- a/editormode.h +++ b/editormode.h @@ -16,68 +16,72 @@ http://mozilla.org/MPL/2.0/. #include "sceneeditor.h" #include "scenenode.h" -class editor_mode : public application_mode { +class editor_mode : public application_mode +{ -public: -// constructors - editor_mode(); -// methods - // initializes internal data structures of the mode. returns: true on success, false otherwise - bool init() override; - // mode-specific update of simulation data. returns: false on error, true otherwise - bool update() override; - // maintenance method, called when the mode is activated - void enter() override; - // maintenance method, called when the mode is deactivated - void exit() override; - // input handlers - void on_key( int Key, int Scancode, int Action, int Mods ) override; - void on_cursor_pos( double Horizontal, double Vertical ) override; - void on_mouse_button( int Button, int Action, int Mods ) override; - void on_scroll( double const Xoffset, double const Yoffset ) override { ; } - void on_window_resize( int w, int h ) override { ; } - void on_event_poll() override; - bool is_command_processor() const override; + public: + // constructors + editor_mode(); + // methods + // initializes internal data structures of the mode. returns: true on success, false otherwise + bool init() override; + // mode-specific update of simulation data. returns: false on error, true otherwise + bool update() override; + // maintenance method, called when the mode is activated + void enter() override; + // maintenance method, called when the mode is deactivated + void exit() override; + // input handlers + void on_key(int Key, int Scancode, int Action, int Mods) override; + void on_cursor_pos(double Horizontal, double Vertical) override; + void on_mouse_button(int Button, int Action, int Mods) override; + void on_scroll(double const Xoffset, double const Yoffset) override + { + ; + } + void on_window_resize(int w, int h) override + { + ; + } + void on_event_poll() override; + bool is_command_processor() const override; -private: -// types - struct editormode_input { + private: + // types + struct editormode_input + { - editormouse_input mouse; - editorkeyboard_input keyboard; + editormouse_input mouse; + editorkeyboard_input keyboard; - bool init(); - void poll(); - }; + bool init(); + void poll(); + }; - struct state_backup { + struct state_backup + { - TCamera camera; - bool freefly; - bool picking; - }; -// methods - void - update_camera( double const Deltatime ); - bool - mode_translation() const; - bool - mode_translation_vertical() const; - bool - mode_rotationY() const; - bool - mode_rotationX() const; - bool - mode_rotationZ() const; - bool - mode_snap() const; -// members - state_backup m_statebackup; // helper, cached variables to be restored on mode exit - editormode_input m_input; - TCamera Camera; - double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys - scene::basic_editor m_editor; - scene::basic_node *m_node; // currently selected scene node - bool m_takesnapshot { true }; // helper, hints whether snapshot of selected node(s) should be taken before modification - bool m_dragging = false; + TCamera camera; + bool freefly; + bool picking; + }; + // methods + void update_camera(double const Deltatime); + bool mode_translation() const; + bool mode_translation_vertical() const; + bool mode_rotationY() const; + bool mode_rotationX() const; + bool mode_rotationZ() const; + bool mode_snap() const; + // members + state_backup m_statebackup; // helper, cached variables to be restored on mode exit + editormode_input m_input; + TCamera Camera; + double fTime50Hz{0.0}; // bufor czasu dla komunikacji z PoKeys + scene::basic_editor m_editor; + scene::basic_node *m_node; // currently selected scene node + bool m_takesnapshot{true}; // helper, hints whether snapshot of selected node(s) should be taken before modification + bool m_dragging = false; + glm::vec3 oldPos; + bool mouseHold{false}; }; diff --git a/editoruilayer.cpp b/editoruilayer.cpp index d8ac95fc..41b0527f 100644 --- a/editoruilayer.cpp +++ b/editoruilayer.cpp @@ -14,64 +14,68 @@ http://mozilla.org/MPL/2.0/. #include "scenenode.h" #include "renderer.h" -editor_ui::editor_ui() { +editor_ui::editor_ui() +{ - clear_panels(); - // bind the panels with ui object. maybe not the best place for this but, eh + clear_panels(); + // bind the panels with ui object. maybe not the best place for this but, eh - add_external_panel( &m_itempropertiespanel ); - add_external_panel( &m_nodebankpanel ); - add_external_panel( &m_functionspanel ); + add_external_panel(&m_itempropertiespanel); + add_external_panel(&m_nodebankpanel); + add_external_panel(&m_functionspanel); } // updates state of UI elements -void -editor_ui::update() { +void editor_ui::update() +{ - set_tooltip( "" ); + set_tooltip(""); - if( Global.ControlPicking && DebugModeFlag ) { - const auto sceneryNode = GfxRenderer->Pick_Node(); + if (Global.ControlPicking && DebugModeFlag) + { + const auto sceneryNode = GfxRenderer->Pick_Node(); const std::string content = sceneryNode ? sceneryNode->tooltip() : ""; - set_tooltip(content); - } + set_tooltip(content); + } - ui_layer::update(); - m_itempropertiespanel.update( m_node ); - m_functionspanel.update( m_node ); + ui_layer::update(); + m_itempropertiespanel.update(m_node); + m_functionspanel.update(m_node); } -void -editor_ui::set_node( scene::basic_node * Node ) { - - m_node = Node; +void editor_ui::set_node(scene::basic_node *Node) +{ + m_node = Node; } -void -editor_ui::add_node_template(const std::string &desc) { +void editor_ui::add_node_template(const std::string &desc) +{ m_nodebankpanel.add_template(desc); } -std::string const * -editor_ui::get_active_node_template() { +std::string const *editor_ui::get_active_node_template() +{ return m_nodebankpanel.get_active_template(); } -nodebank_panel::edit_mode -editor_ui::mode() { +nodebank_panel::edit_mode editor_ui::mode() +{ return m_nodebankpanel.mode; } +float editor_ui::getSpacing() +{ + return m_nodebankpanel.spacing; +} -functions_panel::rotation_mode -editor_ui::rot_mode() { +functions_panel::rotation_mode editor_ui::rot_mode() +{ return m_functionspanel.rot_mode; } -float -editor_ui::rot_val() { +float editor_ui::rot_val() +{ return m_functionspanel.rot_value; } -bool -editor_ui::rot_from_last() +bool editor_ui::rot_from_last() { return m_functionspanel.rot_from_last; } \ No newline at end of file diff --git a/editoruilayer.h b/editoruilayer.h index 2330d533..4b104528 100644 --- a/editoruilayer.h +++ b/editoruilayer.h @@ -12,40 +12,35 @@ http://mozilla.org/MPL/2.0/. #include "uilayer.h" #include "editoruipanels.h" -namespace scene { +namespace scene +{ class basic_node; } -class editor_ui : public ui_layer { +class editor_ui : public ui_layer +{ -public: -// constructors - editor_ui(); -// methods - // updates state of UI elements - void - update() override; - void - set_node( scene::basic_node * Node ); - void - add_node_template(const std::string &desc); - float - rot_val(); - bool - rot_from_last(); - functions_panel::rotation_mode - rot_mode(); - const std::string * - get_active_node_template(); - nodebank_panel::edit_mode - mode(); + public: + // constructors + editor_ui(); + // methods + // updates state of UI elements + void update() override; + void set_node(scene::basic_node *Node); + void add_node_template(const std::string &desc); + float rot_val(); + bool rot_from_last(); + functions_panel::rotation_mode rot_mode(); + const std::string *get_active_node_template(); + nodebank_panel::edit_mode mode(); + float getSpacing(); -private: -// members - itemproperties_panel m_itempropertiespanel { "Node Properties", true }; - functions_panel m_functionspanel { "Functions", true }; - nodebank_panel m_nodebankpanel{ "Node Bank", true }; - scene::basic_node * m_node { nullptr }; // currently bound scene node, if any + private: + // members + itemproperties_panel m_itempropertiespanel{"Node Properties", true}; + functions_panel m_functionspanel{"Functions", true}; + nodebank_panel m_nodebankpanel{"Node Bank", true}; + scene::basic_node *m_node{nullptr}; // currently bound scene node, if any }; diff --git a/editoruipanels.cpp b/editoruipanels.cpp index fc65b5c6..91a29ed0 100644 --- a/editoruipanels.cpp +++ b/editoruipanels.cpp @@ -17,346 +17,346 @@ http://mozilla.org/MPL/2.0/. #include "Track.h" #include "Event.h" #include "MemCell.h" +#include "editoruilayer.h" #include "renderer.h" #include "utilities.h" -void -itemproperties_panel::update( scene::basic_node const *Node ) { +void itemproperties_panel::update(scene::basic_node const *Node) +{ m_node = Node; - if( false == is_open ) { return; } + if (false == is_open) + { + return; + } - text_lines.clear(); - m_grouplines.clear(); + text_lines.clear(); + m_grouplines.clear(); - std::string textline; + std::string textline; - // scenario inspector - auto const *node { Node }; - auto const &camera { Global.pCamera }; + // scenario inspector + auto const *node{Node}; + auto const &camera{Global.pCamera}; - if( node == nullptr ) { - auto const mouseposition { camera.Pos + GfxRenderer->Mouse_Position() }; - textline = "mouse location: [" + to_string( mouseposition.x, 2 ) + ", " + to_string( mouseposition.y, 2 ) + ", " + to_string( mouseposition.z, 2 ) + "]"; - text_lines.emplace_back( textline, Global.UITextColor ); - return; - } -/* - // TODO: bind receiver in the constructor - if( ( m_itemproperties != nullptr ) - && ( m_itemproperties->node != nullptr ) ) { - // fetch node data; skip properties which were changed until they're retrieved by the observer - auto const *node { m_itemproperties->node }; + if (node == nullptr) + { + auto const mouseposition{camera.Pos + GfxRenderer->Mouse_Position()}; + textline = "mouse location: [" + to_string(mouseposition.x, 2) + ", " + to_string(mouseposition.y, 2) + ", " + to_string(mouseposition.z, 2) + "]"; + text_lines.emplace_back(textline, Global.UITextColor); + return; + } + /* + // TODO: bind receiver in the constructor + if( ( m_itemproperties != nullptr ) + && ( m_itemproperties->node != nullptr ) ) { + // fetch node data; skip properties which were changed until they're retrieved by the observer + auto const *node { m_itemproperties->node }; - if( m_itemproperties->name.second == false ) { - m_itemproperties->name.first = ( node->name().empty() ? "(none)" : node->name() ); - } - if( m_itemproperties->location.second == false ) { - m_itemproperties->location.first = node->location(); - } - } -*/ - textline = - "name: " + ( node->name().empty() ? "(none)" : Bezogonkow( node->name() ) ) - + "\nlocation: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]" - + " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ camera.Pos.x, 0.0, camera.Pos.z } ), 1 ) + " m)"; - text_lines.emplace_back( textline, Global.UITextColor ); + if( m_itemproperties->name.second == false ) { + m_itemproperties->name.first = ( node->name().empty() ? "(none)" : node->name() ); + } + if( m_itemproperties->location.second == false ) { + m_itemproperties->location.first = node->location(); + } + } + */ + textline = "name: " + (node->name().empty() ? "(none)" : Bezogonkow(node->name())) + "\nlocation: [" + to_string(node->location().x, 2) + ", " + to_string(node->location().y, 2) + ", " + + to_string(node->location().z, 2) + "]" + + " (distance: " + to_string(glm::length(glm::dvec3{node->location().x, 0.0, node->location().z} - glm::dvec3{camera.Pos.x, 0.0, camera.Pos.z}), 1) + " m)"; + text_lines.emplace_back(textline, Global.UITextColor); - // subclass-specific data - // TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer? - if( typeid( *node ) == typeid( TAnimModel ) ) { + // subclass-specific data + // TBD, TODO: specialized data dump method in each node subclass, or data imports in the panel for provided subclass pointer? + if (typeid(*node) == typeid(TAnimModel)) + { - auto const *subnode = static_cast( node ); + auto const *subnode = static_cast(node); - textline = "angle_x: " + to_string(clamp_circular(subnode->vAngle.x, 360.f), 2) + " deg, " + - "angle_y: " + to_string(clamp_circular(subnode->vAngle.y, 360.f), 2) + " deg, " + + textline = "angle_x: " + to_string(clamp_circular(subnode->vAngle.x, 360.f), 2) + " deg, " + "angle_y: " + to_string(clamp_circular(subnode->vAngle.y, 360.f), 2) + " deg, " + "angle_z: " + to_string(clamp_circular(subnode->vAngle.z, 360.f), 2) + " deg"; - textline += ";\nlights: "; - if( subnode->iNumLights > 0 ) { - textline += '['; - for( int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx ) { - textline += to_string( subnode->lsLights[ lightidx ] ); - if( lightidx < subnode->iNumLights - 1 ) { - textline += ", "; - } - } - textline += ']'; - } - else { - textline += "(none)"; - } - text_lines.emplace_back( textline, Global.UITextColor ); + textline += ";\nlights: "; + if (subnode->iNumLights > 0) + { + textline += '['; + for (int lightidx = 0; lightidx < subnode->iNumLights; ++lightidx) + { + textline += to_string(subnode->lsLights[lightidx]); + if (lightidx < subnode->iNumLights - 1) + { + textline += ", "; + } + } + textline += ']'; + } + else + { + textline += "(none)"; + } + text_lines.emplace_back(textline, Global.UITextColor); - // 3d shape - auto modelfile { ( - ( subnode->pModel != nullptr ) ? - subnode->pModel->NameGet() : - "(none)" ) }; - if( modelfile.find( szModelPath ) == 0 ) { - // don't include 'models/' in the path - modelfile.erase( 0, std::string{ szModelPath }.size() ); - } - // texture - auto texturefile { ( - ( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ? - GfxRenderer->Material( subnode->Material()->replacable_skins[ 1 ] )->GetName() : - "(none)" ) }; - if( texturefile.find( szTexturePath ) == 0 ) { - // don't include 'textures/' in the path - texturefile.erase( 0, std::string{ szTexturePath }.size() ); - } - text_lines.emplace_back( "mesh: " + modelfile, Global.UITextColor ); - text_lines.emplace_back( "skin: " + texturefile, Global.UITextColor ); - } - else if( typeid( *node ) == typeid( TTrack ) ) { + // 3d shape + auto modelfile{((subnode->pModel != nullptr) ? subnode->pModel->NameGet() : "(none)")}; + if (modelfile.find(szModelPath) == 0) + { + // don't include 'models/' in the path + modelfile.erase(0, std::string{szModelPath}.size()); + } + // texture + auto texturefile{((subnode->Material()->replacable_skins[1] != null_handle) ? GfxRenderer->Material(subnode->Material()->replacable_skins[1])->GetName() : "(none)")}; + if (texturefile.find(szTexturePath) == 0) + { + // don't include 'textures/' in the path + texturefile.erase(0, std::string{szTexturePath}.size()); + } + text_lines.emplace_back("mesh: " + modelfile, Global.UITextColor); + text_lines.emplace_back("skin: " + texturefile, Global.UITextColor); + } + else if (typeid(*node) == typeid(TTrack)) + { - auto const *subnode = static_cast( node ); + auto const *subnode = static_cast(node); - std::string isolatedlist; - for (const TIsolated *iso : subnode->Isolated) { - if (!isolatedlist.empty()) - isolatedlist += ", "; - isolatedlist += iso->asName; - } + std::string isolatedlist; + for (const TIsolated *iso : subnode->Isolated) + { + if (!isolatedlist.empty()) + isolatedlist += ", "; + isolatedlist += iso->asName; + } - // basic attributes - textline = - "isolated: " + ( !isolatedlist.empty() ? isolatedlist : "(none)" ) - + "\nvelocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity ) - + "\nwidth: " + to_string( subnode->fTrackWidth ) + " m" - + "\nfriction: " + to_string( subnode->fFriction, 2 ) - + "\nquality: " + to_string( subnode->iQualityFlag ); - text_lines.emplace_back( textline, Global.UITextColor ); - // textures - auto texturefile { ( - ( subnode->m_material1 != null_handle ) ? - GfxRenderer->Material( subnode->m_material1 )->GetName() : - "(none)" ) }; - if( texturefile.find( szTexturePath ) == 0 ) { - texturefile.erase( 0, std::string{ szTexturePath }.size() ); - } - auto texturefile2{ ( - ( subnode->m_material2 != null_handle ) ? - GfxRenderer->Material( subnode->m_material2 )->GetName() : - "(none)" ) }; - if( texturefile2.find( szTexturePath ) == 0 ) { - texturefile2.erase( 0, std::string{ szTexturePath }.size() ); - } - textline = "skins:\n " + texturefile + "\n " + texturefile2; - text_lines.emplace_back( textline, Global.UITextColor ); - // paths - textline = "paths: "; - for( auto const &path : subnode->m_paths ) { - textline += - "\n [" - + to_string( path.points[ segment_data::point::start ].x, 3 ) + ", " - + to_string( path.points[ segment_data::point::start ].y, 3 ) + ", " - + to_string( path.points[ segment_data::point::start ].z, 3 ) + "]->" - + " [" - + to_string( path.points[ segment_data::point::end ].x, 3 ) + ", " - + to_string( path.points[ segment_data::point::end ].y, 3 ) + ", " - + to_string( path.points[ segment_data::point::end ].z, 3 ) + "] "; - } - text_lines.emplace_back( textline, Global.UITextColor ); - // events - textline.clear(); + // basic attributes + textline = "isolated: " + (!isolatedlist.empty() ? isolatedlist : "(none)") + "\nvelocity: " + to_string(subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity) + + "\nwidth: " + to_string(subnode->fTrackWidth) + " m" + "\nfriction: " + to_string(subnode->fFriction, 2) + "\nquality: " + to_string(subnode->iQualityFlag); + text_lines.emplace_back(textline, Global.UITextColor); + // textures + auto texturefile{((subnode->m_material1 != null_handle) ? GfxRenderer->Material(subnode->m_material1)->GetName() : "(none)")}; + if (texturefile.find(szTexturePath) == 0) + { + texturefile.erase(0, std::string{szTexturePath}.size()); + } + auto texturefile2{((subnode->m_material2 != null_handle) ? GfxRenderer->Material(subnode->m_material2)->GetName() : "(none)")}; + if (texturefile2.find(szTexturePath) == 0) + { + texturefile2.erase(0, std::string{szTexturePath}.size()); + } + textline = "skins:\n " + texturefile + "\n " + texturefile2; + text_lines.emplace_back(textline, Global.UITextColor); + // paths + textline = "paths: "; + for (auto const &path : subnode->m_paths) + { + textline += "\n [" + to_string(path.points[segment_data::point::start].x, 3) + ", " + to_string(path.points[segment_data::point::start].y, 3) + ", " + + to_string(path.points[segment_data::point::start].z, 3) + "]->" + " [" + to_string(path.points[segment_data::point::end].x, 3) + ", " + + to_string(path.points[segment_data::point::end].y, 3) + ", " + to_string(path.points[segment_data::point::end].z, 3) + "] "; + } + text_lines.emplace_back(textline, Global.UITextColor); + // events + textline.clear(); - std::vector< std::pair< std::string, TTrack::event_sequence const * > > const eventsequences { - { "ev0", &subnode->m_events0 }, { "ev0all", &subnode->m_events0all }, - { "ev1", &subnode->m_events1 }, { "ev1all", &subnode->m_events1all }, - { "ev2", &subnode->m_events2 }, { "ev2all", &subnode->m_events2all } }; + std::vector> const eventsequences{{"ev0", &subnode->m_events0}, {"ev0all", &subnode->m_events0all}, + {"ev1", &subnode->m_events1}, {"ev1all", &subnode->m_events1all}, + {"ev2", &subnode->m_events2}, {"ev2all", &subnode->m_events2all}}; - for( auto const &eventsequence : eventsequences ) { + for (auto const &eventsequence : eventsequences) + { - if( eventsequence.second->empty() ) { continue; } + if (eventsequence.second->empty()) + { + continue; + } - textline += ( textline.empty() ? "" : "\n" ) + eventsequence.first + ": ["; - for( auto const &event : *( eventsequence.second ) ) { - if( textline.back() != '[' ) { - textline += ", "; - } - textline += ( - event.second != nullptr ? - Bezogonkow( event.second->m_name ) : - event.first + " (missing)" ); - } - textline += "] "; - } - text_lines.emplace_back( textline, Global.UITextColor ); - } - else if( typeid( *node ) == typeid( TMemCell ) ) { + textline += (textline.empty() ? "" : "\n") + eventsequence.first + ": ["; + for (auto const &event : *(eventsequence.second)) + { + if (textline.back() != '[') + { + textline += ", "; + } + textline += (event.second != nullptr ? Bezogonkow(event.second->m_name) : event.first + " (missing)"); + } + textline += "] "; + } + text_lines.emplace_back(textline, Global.UITextColor); + } + else if (typeid(*node) == typeid(TMemCell)) + { - auto const *subnode = static_cast( node ); + auto const *subnode = static_cast(node); - textline = - "data: [" + subnode->Text() + "]" - + " [" + to_string( subnode->Value1(), 2 ) + "]" - + " [" + to_string( subnode->Value2(), 2 ) + "]"; - text_lines.emplace_back( textline, Global.UITextColor ); - textline = "track: " + ( subnode->asTrackName.empty() ? "(none)" : Bezogonkow( subnode->asTrackName ) ); - text_lines.emplace_back( textline, Global.UITextColor ); - } + textline = "data: [" + subnode->Text() + "]" + " [" + to_string(subnode->Value1(), 2) + "]" + " [" + to_string(subnode->Value2(), 2) + "]"; + text_lines.emplace_back(textline, Global.UITextColor); + textline = "track: " + (subnode->asTrackName.empty() ? "(none)" : Bezogonkow(subnode->asTrackName)); + text_lines.emplace_back(textline, Global.UITextColor); + } - update_group(); + update_group(); } -void -itemproperties_panel::update_group() { +void itemproperties_panel::update_group() +{ - auto const grouphandle { m_node->group() }; + auto const grouphandle{m_node->group()}; - if( grouphandle == null_handle ) { - m_grouphandle = null_handle; - m_groupprefix.clear(); - return; - } + if (grouphandle == null_handle) + { + m_grouphandle = null_handle; + m_groupprefix.clear(); + return; + } - auto const &nodegroup { scene::Groups.group( grouphandle ) }; + auto const &nodegroup{scene::Groups.group(grouphandle)}; - if( m_grouphandle != grouphandle ) { - // calculate group name from shared prefix of item names - std::vector> names; - // build list of custom item and event names - for( auto const *node : nodegroup.nodes ) { - auto const &name { node->name() }; - if( name.empty() || name == "none" ) { continue; } - names.emplace_back( name ); - } - for( auto const *event : nodegroup.events ) { - auto const &name { event->m_name }; - if( name.empty() || name == "none" ) { continue; } - names.emplace_back( name ); - } - // find the common prefix - if( names.size() > 1 ) { - m_groupprefix = names.front(); - for( auto const &name : names ) { - // NOTE: first calculation runs over two instances of the same name, but, eh - auto const prefixlength{ len_common_prefix( m_groupprefix, name ) }; - if( prefixlength > 0 ) { - m_groupprefix = m_groupprefix.substr( 0, prefixlength ); - } - else { - m_groupprefix.clear(); - break; - } - } - } - else { - // less than two names to compare means no prefix - m_groupprefix.clear(); - } - m_grouphandle = grouphandle; - } + if (m_grouphandle != grouphandle) + { + // calculate group name from shared prefix of item names + std::vector> names; + // build list of custom item and event names + for (auto const *node : nodegroup.nodes) + { + auto const &name{node->name()}; + if (name.empty() || name == "none") + { + continue; + } + names.emplace_back(name); + } + for (auto const *event : nodegroup.events) + { + auto const &name{event->m_name}; + if (name.empty() || name == "none") + { + continue; + } + names.emplace_back(name); + } + // find the common prefix + if (names.size() > 1) + { + m_groupprefix = names.front(); + for (auto const &name : names) + { + // NOTE: first calculation runs over two instances of the same name, but, eh + auto const prefixlength{len_common_prefix(m_groupprefix, name)}; + if (prefixlength > 0) + { + m_groupprefix = m_groupprefix.substr(0, prefixlength); + } + else + { + m_groupprefix.clear(); + break; + } + } + } + else + { + // less than two names to compare means no prefix + m_groupprefix.clear(); + } + m_grouphandle = grouphandle; + } - m_grouplines.emplace_back( - "nodes: " + to_string( static_cast( nodegroup.nodes.size() ) ) - + "\nevents: " + to_string( static_cast( nodegroup.events.size() ) ), - Global.UITextColor ); - m_grouplines.emplace_back( - "names prefix: " + ( m_groupprefix.empty() ? "(none)" : m_groupprefix ), - Global.UITextColor ); + m_grouplines.emplace_back("nodes: " + to_string(static_cast(nodegroup.nodes.size())) + "\nevents: " + to_string(static_cast(nodegroup.events.size())), Global.UITextColor); + m_grouplines.emplace_back("names prefix: " + (m_groupprefix.empty() ? "(none)" : m_groupprefix), Global.UITextColor); } +void itemproperties_panel::render() +{ -void -itemproperties_panel::render() { + if (false == is_open) + { + return; + } + if (true == text_lines.empty()) + { + return; + } - if( false == is_open ) { return; } - if( true == text_lines.empty() ) { return; } + auto flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoCollapse | (size.x > 0 ? ImGuiWindowFlags_NoResize : 0); - auto flags = - ImGuiWindowFlags_NoFocusOnAppearing - | ImGuiWindowFlags_NoCollapse - | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); - - if( size.x > 0 ) { - ImGui::SetNextWindowSize( ImVec2S( size.x, size.y ) ); - } - if( size_min.x > 0 ) { - ImGui::SetNextWindowSizeConstraints( ImVec2S( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); - } - auto const panelname { ( - title.empty() ? - m_name : - title ) - + "###" + m_name }; - if( true == ImGui::Begin( panelname.c_str(), nullptr, flags ) ) { - // header section - for( auto const &line : text_lines ) { - ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); - } - // group section + if (size.x > 0) + { + ImGui::SetNextWindowSize(ImVec2S(size.x, size.y)); + } + if (size_min.x > 0) + { + ImGui::SetNextWindowSizeConstraints(ImVec2S(size_min.x, size_min.y), ImVec2(size_max.x, size_max.y)); + } + auto const panelname{(title.empty() ? m_name : title) + "###" + m_name}; + if (true == ImGui::Begin(panelname.c_str(), nullptr, flags)) + { + // header section + for (auto const &line : text_lines) + { + ImGui::TextColored(ImVec4(line.color.r, line.color.g, line.color.b, line.color.a), line.data.c_str()); + } + // group section render_group(); - } - ImGui::End(); + } + ImGui::End(); } -bool -itemproperties_panel::render_group() { +bool itemproperties_panel::render_group() +{ - if( m_node == nullptr ) { return false; } - if( m_grouplines.empty() ) { return false; } + if (m_node == nullptr) + { + return false; + } + if (m_grouplines.empty()) + { + return false; + } - if( false == ImGui::CollapsingHeader( "Parent Group" ) ) { return false; } + if (false == ImGui::CollapsingHeader("Parent Group")) + { + return false; + } - for( auto const &line : m_grouplines ) { - ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); - } + for (auto const &line : m_grouplines) + { + ImGui::TextColored(ImVec4(line.color.r, line.color.g, line.color.b, line.color.a), line.data.c_str()); + } - return true; + return true; } +nodebank_panel::nodebank_panel(std::string const &Name, bool const Isopen) : ui_panel(Name, Isopen) +{ + size_min = {100, 50}; + size_max = {1000, 1000}; - -nodebank_panel::nodebank_panel( std::string const &Name, bool const Isopen ) : ui_panel( Name, Isopen ) { - size_min = { 100, 50 }; - size_max = { 1000, 1000 }; - - memset( m_nodesearch, 0, sizeof( m_nodesearch ) ); + memset(m_nodesearch, 0, sizeof(m_nodesearch)); std::ifstream file; file.open("nodebank.txt", std::ios_base::in | std::ios_base::binary); std::string line; - while( std::getline( file, line ) ) { - if( line.size() < 4 ) { - continue; - } - auto const labelend { line.find( "node" ) }; - auto const nodedata { ( - labelend == std::string::npos ? "" : - labelend == 0 ? line : - line.substr( labelend ) ) }; - auto const label { ( - labelend == std::string::npos ? line : - labelend == 0 ? generate_node_label( nodedata ) : - line.substr( 0, labelend ) ) }; + while (std::getline(file, line)) + { + if (line.size() < 4) + { + continue; + } + auto const labelend{line.find("node")}; + auto const nodedata{(labelend == std::string::npos ? "" : labelend == 0 ? line : line.substr(labelend))}; + auto const label{(labelend == std::string::npos ? line : labelend == 0 ? generate_node_label(nodedata) : line.substr(0, labelend))}; - m_nodebank.push_back( { label, std::make_shared( nodedata ) } ); - } - // sort alphabetically content of each group - auto groupbegin { m_nodebank.begin() }; - auto groupend { groupbegin }; - while( groupbegin != m_nodebank.end() ) { - groupbegin = - std::find_if( - groupend, m_nodebank.end(), - []( auto const &Entry ) { - return ( false == Entry.second->empty() ); } ); - groupend = - std::find_if( - groupbegin, m_nodebank.end(), - []( auto const &Entry ) { - return ( Entry.second->empty() ); } ); - std::sort( - groupbegin, groupend, - []( auto const &Left, auto const &Right ) { - return ( Left.first < Right.first ); } ); - } + m_nodebank.push_back({label, std::make_shared(nodedata)}); + } + // sort alphabetically content of each group + auto groupbegin{m_nodebank.begin()}; + auto groupend{groupbegin}; + while (groupbegin != m_nodebank.end()) + { + groupbegin = std::find_if(groupend, m_nodebank.end(), [](auto const &Entry) { return (false == Entry.second->empty()); }); + groupend = std::find_if(groupbegin, m_nodebank.end(), [](auto const &Entry) { return (Entry.second->empty()); }); + std::sort(groupbegin, groupend, [](auto const &Left, auto const &Right) { return (Left.first < Right.first); }); + } } -void -nodebank_panel::nodebank_reload(){ +void nodebank_panel::nodebank_reload() +{ m_nodebank.clear(); std::ifstream file; file.open("nodebank.txt", std::ios_base::in | std::ios_base::binary); @@ -368,12 +368,8 @@ nodebank_panel::nodebank_reload(){ continue; } auto const labelend{line.find("node")}; - auto const nodedata{ - (labelend == std::string::npos ? "" : labelend == 0 ? line : line.substr(labelend))}; - auto const label{ - (labelend == std::string::npos ? - line : - labelend == 0 ? generate_node_label(nodedata) : line.substr(0, labelend))}; + auto const nodedata{(labelend == std::string::npos ? "" : labelend == 0 ? line : line.substr(labelend))}; + auto const label{(labelend == std::string::npos ? line : labelend == 0 ? generate_node_label(nodedata) : line.substr(0, labelend))}; m_nodebank.push_back({label, std::make_shared(nodedata)}); } @@ -382,114 +378,117 @@ nodebank_panel::nodebank_reload(){ auto groupend{groupbegin}; while (groupbegin != m_nodebank.end()) { - groupbegin = std::find_if(groupend, m_nodebank.end(), [](auto const &Entry) { - return (false == Entry.second->empty()); - }); - groupend = std::find_if(groupbegin, m_nodebank.end(), - [](auto const &Entry) { return (Entry.second->empty()); }); - std::sort(groupbegin, groupend, - [](auto const &Left, auto const &Right) { return (Left.first < Right.first); }); + groupbegin = std::find_if(groupend, m_nodebank.end(), [](auto const &Entry) { return (false == Entry.second->empty()); }); + groupend = std::find_if(groupbegin, m_nodebank.end(), [](auto const &Entry) { return (Entry.second->empty()); }); + std::sort(groupbegin, groupend, [](auto const &Left, auto const &Right) { return (Left.first < Right.first); }); } } -void -nodebank_panel::render() { +void nodebank_panel::render() +{ - if( false == is_open ) { return; } + if (false == is_open) + { + return; + } - auto flags = - ImGuiWindowFlags_NoFocusOnAppearing - | ImGuiWindowFlags_NoCollapse - | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + auto flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoCollapse | (size.x > 0 ? ImGuiWindowFlags_NoResize : 0); - if( size.x > 0 ) { - ImGui::SetNextWindowSize( ImVec2S( size.x, size.y ) ); - } - if( size_min.x > 0 ) { - ImGui::SetNextWindowSizeConstraints( ImVec2S( size_min.x, size_min.y ), ImVec2S( size_max.x, size_max.y ) ); - } - auto const panelname { ( - title.empty() ? - name() : - title ) - + "###" + name() }; + if (size.x > 0) + { + ImGui::SetNextWindowSize(ImVec2S(size.x, size.y)); + } + if (size_min.x > 0) + { + ImGui::SetNextWindowSizeConstraints(ImVec2S(size_min.x, size_min.y), ImVec2S(size_max.x, size_max.y)); + } + auto const panelname{(title.empty() ? name() : title) + "###" + name()}; - if( true == ImGui::Begin( panelname.c_str(), nullptr, flags ) ) { + if (true == ImGui::Begin(panelname.c_str(), nullptr, flags)) + { - ImGui::RadioButton("Modify node", (int*)&mode, MODIFY); - ImGui::SameLine(); - ImGui::RadioButton("Insert from bank", (int*)&mode, ADD); + ImGui::RadioButton("Modify node", (int *)&mode, MODIFY); ImGui::SameLine(); - ImGui::RadioButton( "Copy to bank", (int*)&mode, COPY ); + ImGui::RadioButton("Insert from bank", (int *)&mode, ADD); + ImGui::SameLine(); + ImGui::RadioButton("Brush mode", (int *)&mode, BRUSH); + ImGui::SameLine(); + ImGui::RadioButton("Copy to bank", (int *)&mode, COPY); ImGui::SameLine(); if (ImGui::Button("Reload Nodebank")) { nodebank_reload(); - } - + } - ImGui::PushItemWidth(-1); - ImGui::InputTextWithHint( "Search", "Search node bank", m_nodesearch, IM_ARRAYSIZE( m_nodesearch ) ); - if (ImGui::ListBoxHeader("##nodebank", ImVec2(-1, -1))) - { - auto idx { 0 }; - auto isvisible { false }; - auto const searchfilter { std::string( m_nodesearch ) }; - for (auto const &entry : m_nodebank) { - if( entry.second->empty() ) { - // special case, header indicator - isvisible = ImGui::CollapsingHeader( entry.first.c_str() ); - } - else { - if( false == isvisible ) { - continue; - } - if( ( false == searchfilter.empty() ) - && ( false == contains( entry.first, searchfilter ) ) ) { - continue; - } - auto const label { " " + entry.first + "##" + std::to_string( idx ) }; - if( ImGui::Selectable( label.c_str(), entry.second == m_selectedtemplate ) ) - m_selectedtemplate = entry.second; - ++idx; - } - } - ImGui::ListBoxFooter(); - } - } + if (mode == BRUSH) + { + ImGui::SliderFloat("Spacing", &spacing, 0.1f, 20.0f, "%.1f m"); + } - ImGui::End(); + ImGui::PushItemWidth(-1); + ImGui::InputTextWithHint("Search", "Search node bank", m_nodesearch, IM_ARRAYSIZE(m_nodesearch)); + if (ImGui::ListBoxHeader("##nodebank", ImVec2(-1, -1))) + { + auto idx{0}; + auto isvisible{false}; + auto const searchfilter{std::string(m_nodesearch)}; + for (auto const &entry : m_nodebank) + { + if (entry.second->empty()) + { + // special case, header indicator + isvisible = ImGui::CollapsingHeader(entry.first.c_str()); + } + else + { + if (false == isvisible) + { + continue; + } + if ((false == searchfilter.empty()) && (false == contains(entry.first, searchfilter))) + { + continue; + } + auto const label{" " + entry.first + "##" + std::to_string(idx)}; + if (ImGui::Selectable(label.c_str(), entry.second == m_selectedtemplate)) + m_selectedtemplate = entry.second; + ++idx; + } + } + ImGui::ListBoxFooter(); + } + } + + ImGui::End(); } -void -nodebank_panel::add_template(const std::string &desc) { +void nodebank_panel::add_template(const std::string &desc) +{ - auto const label { generate_node_label( desc ) }; - m_nodebank.push_back( { label, std::make_shared( desc ) } ); + auto const label{generate_node_label(desc)}; + m_nodebank.push_back({label, std::make_shared(desc)}); std::ofstream file; file.open("nodebank.txt", std::ios_base::out | std::ios_base::app | std::ios_base::binary); file << label << " " << desc; } -const std::string *nodebank_panel::get_active_template() { +const std::string *nodebank_panel::get_active_template() +{ return m_selectedtemplate.get(); } -std::string -nodebank_panel::generate_node_label( std::string Input ) const { +std::string nodebank_panel::generate_node_label(std::string Input) const +{ - auto tokenizer{ cParser( Input ) }; - tokenizer.getTokens( 9, false ); // skip leading tokens - auto model{ tokenizer.getToken( false ) }; - auto texture{ tokenizer.getToken( false ) }; - replace_slashes( model ); - erase_extension( model ); - replace_slashes( texture ); - return ( - texture == "none" ? - model : - model + " (" + texture + ")" ); + auto tokenizer{cParser(Input)}; + tokenizer.getTokens(9, false); // skip leading tokens + auto model{tokenizer.getToken(false)}; + auto texture{tokenizer.getToken(false)}; + replace_slashes(model); + erase_extension(model); + replace_slashes(texture); + return (texture == "none" ? model : model + " (" + texture + ")"); } void functions_panel::update(scene::basic_node const *Node) @@ -509,46 +508,43 @@ void functions_panel::update(scene::basic_node const *Node) // scenario inspector auto const *node{Node}; auto const &camera{Global.pCamera}; - - - - } -void -functions_panel::render() { +void functions_panel::render() +{ - if( false == is_open ) { return; } + if (false == is_open) + { + return; + } - auto flags = - ImGuiWindowFlags_NoFocusOnAppearing - | ImGuiWindowFlags_NoCollapse - | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + auto flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoCollapse | (size.x > 0 ? ImGuiWindowFlags_NoResize : 0); + + if (size.x > 0) + { + ImGui::SetNextWindowSize(ImVec2S(size.x, size.y)); + } + if (size_min.x > 0) + { + ImGui::SetNextWindowSizeConstraints(ImVec2S(size_min.x, size_min.y), ImVec2(size_max.x, size_max.y)); + } + auto const panelname{(title.empty() ? m_name : title) + "###" + m_name}; + if (true == ImGui::Begin(panelname.c_str(), nullptr, flags)) + { + // header section - if( size.x > 0 ) { - ImGui::SetNextWindowSize( ImVec2S( size.x, size.y ) ); - } - if( size_min.x > 0 ) { - ImGui::SetNextWindowSizeConstraints( ImVec2S( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); - } - auto const panelname { ( - title.empty() ? - m_name : - title ) - + "###" + m_name }; - if( true == ImGui::Begin( panelname.c_str(), nullptr, flags ) ) { - // header section - ImGui::RadioButton("Random rotation", (int *)&rot_mode, RANDOM); ImGui::RadioButton("Fixed rotation", (int *)&rot_mode, FIXED); - if(rot_mode == FIXED){ - //ImGui::Checkbox("Get rotation from last object", &rot_from_last); + if (rot_mode == FIXED) + { + // ImGui::Checkbox("Get rotation from last object", &rot_from_last); ImGui::SliderFloat("Rotation Value", &rot_value, 0.0f, 360.0f, "%.1f"); - }; + }; ImGui::RadioButton("Default rotation", (int *)&rot_mode, DEFAULT); - for( auto const &line : text_lines ) { - ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); - } - } - ImGui::End(); + for (auto const &line : text_lines) + { + ImGui::TextColored(ImVec4(line.color.r, line.color.g, line.color.b, line.color.a), line.data.c_str()); + } + } + ImGui::End(); } \ No newline at end of file diff --git a/editoruipanels.h b/editoruipanels.h index 5aed376f..41292bb5 100644 --- a/editoruipanels.h +++ b/editoruipanels.h @@ -26,52 +26,55 @@ struct item_properties { changeable rotation {}; }; */ -class itemproperties_panel : public ui_panel { +class itemproperties_panel : public ui_panel +{ -public: - itemproperties_panel( std::string const &Name, bool const Isopen ) - : ui_panel( Name, Isopen ) - {} + public: + itemproperties_panel(std::string const &Name, bool const Isopen) : ui_panel(Name, Isopen) {} - void update( scene::basic_node const *Node ); + void update(scene::basic_node const *Node); void render() override; -private: -// methods - void update_group(); + private: + // methods + void update_group(); bool render_group(); -// members - scene::basic_node const *m_node { nullptr }; // scene node bound to the panel - scene::group_handle m_grouphandle { null_handle }; // scene group bound to the panel - std::string m_groupprefix; - std::vector m_grouplines; + // members + scene::basic_node const *m_node{nullptr}; // scene node bound to the panel + scene::group_handle m_grouphandle{null_handle}; // scene group bound to the panel + std::string m_groupprefix; + std::vector m_grouplines; }; -class nodebank_panel : public ui_panel { +class nodebank_panel : public ui_panel +{ -public: - enum edit_mode { + public: + enum edit_mode + { MODIFY, COPY, ADD, - BRUSH + BRUSH }; edit_mode mode = MODIFY; - nodebank_panel( std::string const &Name, bool const Isopen ); + float spacing{1.0f}; + + nodebank_panel(std::string const &Name, bool const Isopen); void nodebank_reload(); void render() override; void add_template(const std::string &desc); - const std::string* get_active_template(); + const std::string *get_active_template(); -private: -// methods: - std::string generate_node_label( std::string Input ) const; -// members: - std::vector>> m_nodebank; - char m_nodesearch[ 128 ]; - std::shared_ptr m_selectedtemplate; + private: + // methods: + std::string generate_node_label(std::string Input) const; + // members: + std::vector>> m_nodebank; + char m_nodesearch[128]; + std::shared_ptr m_selectedtemplate; }; class functions_panel : public ui_panel @@ -87,18 +90,16 @@ class functions_panel : public ui_panel rotation_mode rot_mode = DEFAULT; float rot_value = 0.0f; - bool rot_from_last = false; + bool rot_from_last = false; functions_panel(std::string const &Name, bool const Isopen) : ui_panel(Name, Isopen) {} void update(scene::basic_node const *Node); void render() override; - private: // methods - // members scene::basic_node const *m_node{nullptr}; // scene node bound to the panel scene::group_handle m_grouphandle{null_handle}; // scene group bound to the panel diff --git a/uilayer.cpp b/uilayer.cpp index 094d5b9a..c419309c 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -23,7 +23,7 @@ http://mozilla.org/MPL/2.0/. GLFWwindow *ui_layer::m_window{nullptr}; ImGuiIO *ui_layer::m_imguiio{nullptr}; -GLint ui_layer::m_textureunit { GL_TEXTURE0 }; +GLint ui_layer::m_textureunit{GL_TEXTURE0}; bool ui_layer::m_cursorvisible; ImFont *ui_layer::font_default{nullptr}; ImFont *ui_layer::font_mono{nullptr}; @@ -33,8 +33,8 @@ ui_panel::ui_panel(std::string Identifier, bool const Isopen) : is_open(Isopen), void ui_panel::render() { - if (false == is_open) - return; + if (false == is_open) + return; int flags = window_flags; if (flags == -1) @@ -47,32 +47,30 @@ void ui_panel::render() if (pos.x != -1 && pos.y != -1) ImGui::SetNextWindowPos(ImVec2(pos.x, pos.y), ImGuiCond_Always); if (size.x > 0) - ImGui::SetNextWindowSize(ImVec2S(size.x, size.y), ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2S(size.x, size.y), ImGuiCond_Always); else if (size_min.x == -1) - ImGui::SetNextWindowSize(ImVec2(0, 0), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(0, 0), ImGuiCond_FirstUseEver); - if (size_min.x > 0) - ImGui::SetNextWindowSizeConstraints(ImVec2S(size_min.x, size_min.y), ImVec2S(size_max.x, size_max.y)); + if (size_min.x > 0) + ImGui::SetNextWindowSizeConstraints(ImVec2S(size_min.x, size_min.y), ImVec2S(size_max.x, size_max.y)); auto const panelname{(title.empty() ? m_name : title) + "###" + m_name}; - if (ImGui::Begin(panelname.c_str(), &is_open, flags)) { - render_contents(); + if (ImGui::Begin(panelname.c_str(), &is_open, flags)) + { + render_contents(); - popups.remove_if([](const std::unique_ptr &popup) - { - return popup->render(); - }); + popups.remove_if([](const std::unique_ptr &popup) { return popup->render(); }); } - ImGui::End(); + ImGui::End(); } void ui_panel::render_contents() { - for (auto const &line : text_lines) - { - ImGui::TextColored(ImVec4(line.color.r, line.color.g, line.color.b, line.color.a), line.data.c_str()); - } + for (auto const &line : text_lines) + { + ImGui::TextColored(ImVec4(line.color.r, line.color.g, line.color.b, line.color.a), line.data.c_str()); + } } void ui_panel::register_popup(std::unique_ptr &&popup) @@ -82,17 +80,17 @@ void ui_panel::register_popup(std::unique_ptr &&popup) void ui_expandable_panel::render_contents() { - ImGui::Checkbox(STR_C("expand"), &is_expanded); - ui_panel::render_contents(); + ImGui::Checkbox(STR_C("expand"), &is_expanded); + ui_panel::render_contents(); } void ui_log_panel::render_contents() { ImGui::PushFont(ui_layer::font_mono); - for (const std::string &s : log_scrollback) - ImGui::TextUnformatted(s.c_str()); - if (ImGui::GetScrollY() == ImGui::GetScrollMaxY()) + for (const std::string &s : log_scrollback) + ImGui::TextUnformatted(s.c_str()); + if (ImGui::GetScrollY() == ImGui::GetScrollMaxY()) ImGui::SetScrollHereY(1.0f); ImGui::PopFont(); @@ -102,33 +100,33 @@ ui_layer::ui_layer() { if (Global.loading_log) add_external_panel(&m_logpanel); - m_logpanel.size = { 700, 400 }; + m_logpanel.size = {700, 400}; } ui_layer::~ui_layer() {} bool ui_layer::key_callback(int key, int scancode, int action, int mods) { - ImGui_ImplGlfw_KeyCallback(m_window, key, scancode, action, mods); - return m_imguiio->WantCaptureKeyboard; + ImGui_ImplGlfw_KeyCallback(m_window, key, scancode, action, mods); + return m_imguiio->WantCaptureKeyboard; } bool ui_layer::char_callback(unsigned int c) { - ImGui_ImplGlfw_CharCallback(m_window, c); - return m_imguiio->WantCaptureKeyboard; + ImGui_ImplGlfw_CharCallback(m_window, c); + return m_imguiio->WantCaptureKeyboard; } bool ui_layer::scroll_callback(double xoffset, double yoffset) { - ImGui_ImplGlfw_ScrollCallback(m_window, xoffset, yoffset); - return m_imguiio->WantCaptureMouse; + ImGui_ImplGlfw_ScrollCallback(m_window, xoffset, yoffset); + return m_imguiio->WantCaptureMouse; } bool ui_layer::mouse_button_callback(int button, int action, int mods) { - ImGui_ImplGlfw_MouseButtonCallback(m_window, button, action, mods); - return m_imguiio->WantCaptureMouse; + ImGui_ImplGlfw_MouseButtonCallback(m_window, button, action, mods); + return m_imguiio->WantCaptureMouse; } void ui_layer::load_random_background() @@ -138,20 +136,21 @@ void ui_layer::load_random_background() if (f.is_regular_file()) images.emplace_back(std::filesystem::relative(f.path(), "textures/").string()); - if (!images.empty()) { + if (!images.empty()) + { std::string &selected = images[std::lround(LocalRandom(images.size() - 1))]; set_background(selected); } } -static ImVec4 imvec_lerp(const ImVec4& a, const ImVec4& b, float t) +static ImVec4 imvec_lerp(const ImVec4 &a, const ImVec4 &b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); } void ui_layer::imgui_style() { - ImVec4* colors = ImGui::GetStyle().Colors; + ImVec4 *colors = ImGui::GetStyle().Colors; colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImGuiCol_TextDisabled] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f); @@ -204,29 +203,28 @@ void ui_layer::imgui_style() colors[ImGuiCol_TabUnfocused] = imvec_lerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); colors[ImGuiCol_TabUnfocusedActive] = imvec_lerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); - ImGui::GetStyle().ScaleAllSizes(Global.ui_scale); + ImGui::GetStyle().ScaleAllSizes(Global.ui_scale); } bool ui_layer::init(GLFWwindow *Window) { - m_window = Window; + m_window = Window; - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - m_imguiio = &ImGui::GetIO(); + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + m_imguiio = &ImGui::GetIO(); m_imguiio->ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange; - // m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - // m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; + // m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + // m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; - static const ImWchar ranges[] = - { - 0x0020, 0x00FF, // Basic Latin + Latin Supplement - 0x0100, 0x017F, // Latin Extended-A - 0x2070, 0x2079, // superscript - 0x2500, 0x256C, // box drawings - 0, - }; + static const ImWchar ranges[] = { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0100, 0x017F, // Latin Extended-A + 0x2070, 0x2079, // superscript + 0x2500, 0x256C, // box drawings + 0, + }; if (FileExists("fonts/dejavusans.ttf")) font_default = m_imguiio->Fonts->AddFontFromFileTTF("fonts/dejavusans.ttf", Global.ui_fontsize, nullptr, &ranges[0]); @@ -246,67 +244,73 @@ bool ui_layer::init(GLFWwindow *Window) imgui_style(); - ImGui_ImplGlfw_InitForOpenGL(m_window, false); + ImGui_ImplGlfw_InitForOpenGL(m_window, false); - if (!GfxRenderer->GetImguiRenderer() || !GfxRenderer->GetImguiRenderer()->Init()) - { - return false; - } + if (!GfxRenderer->GetImguiRenderer() || !GfxRenderer->GetImguiRenderer()->Init()) + { + return false; + } - return true; + return true; } void ui_layer::shutdown() { - ImGui::EndFrame(); + ImGui::EndFrame(); - GfxRenderer->GetImguiRenderer()->Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); + GfxRenderer->GetImguiRenderer()->Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); } bool ui_layer::on_key(int const Key, int const Action) { - if (Action == GLFW_PRESS) - { - if (Key == GLFW_KEY_PRINT_SCREEN) { - Application.queue_screenshot(); - return true; - } + if (Action == GLFW_PRESS) + { + if (Key == GLFW_KEY_PRINT_SCREEN) + { + Application.queue_screenshot(); + return true; + } - if (Key == GLFW_KEY_F9) { - m_logpanel.is_open = !m_logpanel.is_open; - return true; - } + if (Key == GLFW_KEY_F9) + { + m_logpanel.is_open = !m_logpanel.is_open; + return true; + } - if (Key == GLFW_KEY_F10) { - m_quit_active = !m_quit_active; - return true; - } + if (Key == GLFW_KEY_F10) + { + m_quit_active = !m_quit_active; + return true; + } - if (m_quit_active) - { - if (Key == GLFW_KEY_Y) { - Application.queue_quit(false); - return true; - } else if (Key == GLFW_KEY_N) { - m_quit_active = false; - return true; - } - } - } + if (m_quit_active) + { + if (Key == GLFW_KEY_Y) + { + Application.queue_quit(false); + return true; + } + else if (Key == GLFW_KEY_N) + { + m_quit_active = false; + return true; + } + } + } - return false; + return false; } bool ui_layer::on_cursor_pos(double const Horizontal, double const Vertical) { - return false; + return false; } bool ui_layer::on_mouse_button(int const Button, int const Action) { - return false; + return false; } void ui_layer::on_window_resize(int w, int h) @@ -315,13 +319,13 @@ void ui_layer::on_window_resize(int w, int h) panel->on_window_resize(w, h); } - void ui_layer::update() { - for (auto *panel : m_panels) - panel->update(); + for (auto *panel : m_panels) + panel->update(); - for (auto it = m_ownedpanels.rbegin(); it != m_ownedpanels.rend(); it++) { + for (auto it = m_ownedpanels.rbegin(); it != m_ownedpanels.rend(); it++) + { (*it)->update(); if (!(*it)->is_open) m_ownedpanels.erase(std::next(it).base()); @@ -330,27 +334,27 @@ void ui_layer::update() void ui_layer::render() { - render_background(); - render_panels(); - render_tooltip(); - render_menu(); - render_quit_widget(); + render_background(); + render_panels(); + render_tooltip(); + render_menu(); + render_quit_widget(); - // template method implementation - render_(); + // template method implementation + render_(); - render_internal(); + render_internal(); } void ui_layer::render_internal() { - ImGui::Render(); - GfxRenderer->GetImguiRenderer()->Render(); + ImGui::Render(); + GfxRenderer->GetImguiRenderer()->Render(); } void ui_layer::begin_ui_frame() { - begin_ui_frame_internal(); + begin_ui_frame_internal(); } void ui_layer::begin_ui_frame_internal() @@ -362,25 +366,25 @@ void ui_layer::begin_ui_frame_internal() void ui_layer::render_quit_widget() { - if (!m_quit_active) - return; + if (!m_quit_active) + return; - ImGui::SetNextWindowSize(ImVec2(0, 0)); - ImGui::Begin(STR_C("Quit"), &m_quit_active, ImGuiWindowFlags_NoResize); - ImGui::TextUnformatted(STR_C("Quit simulation?")); - if (ImGui::Button(STR_C("Yes"))) - Application.queue_quit(false); + ImGui::SetNextWindowSize(ImVec2(0, 0)); + ImGui::Begin(STR_C("Quit"), &m_quit_active, ImGuiWindowFlags_NoResize); + ImGui::TextUnformatted(STR_C("Quit simulation?")); + if (ImGui::Button(STR_C("Yes"))) + Application.queue_quit(false); - ImGui::SameLine(); - if (ImGui::Button(STR_C("No"))) - m_quit_active = false; - ImGui::End(); + ImGui::SameLine(); + if (ImGui::Button(STR_C("No"))) + m_quit_active = false; + ImGui::End(); } void ui_layer::set_cursor(int const Mode) { - glfwSetInputMode(m_window, GLFW_CURSOR, Mode); - m_cursorvisible = (Mode != GLFW_CURSOR_DISABLED); + glfwSetInputMode(m_window, GLFW_CURSOR, Mode); + m_cursorvisible = (Mode != GLFW_CURSOR_DISABLED); } void ui_layer::set_progress(std::string const &Text) @@ -401,25 +405,26 @@ void ui_layer::set_background(std::string const &Filename) void ui_layer::clear_panels() { - m_panels.clear(); + m_panels.clear(); m_ownedpanels.clear(); } void ui_layer::add_owned_panel(ui_panel *Panel) { for (auto &panel : m_ownedpanels) - if (panel->name() == Panel->name()) { + if (panel->name() == Panel->name()) + { delete Panel; return; } Panel->is_open = true; - m_ownedpanels.emplace_back( Panel ); + m_ownedpanels.emplace_back(Panel); } void ui_layer::render_panels() { - for (auto *panel : m_panels) + for (auto *panel : m_panels) panel->render(); for (auto &panel : m_ownedpanels) panel->render(); @@ -431,64 +436,66 @@ void ui_layer::render_panels() void ui_layer::render_tooltip() { if (!m_cursorvisible || m_imguiio->WantCaptureMouse || m_tooltip.empty()) - return; + return; - ImGui::BeginTooltip(); - ImGui::TextUnformatted(m_tooltip.c_str()); - ImGui::EndTooltip(); + ImGui::BeginTooltip(); + ImGui::TextUnformatted(m_tooltip.c_str()); + ImGui::EndTooltip(); } void ui_layer::render_menu_contents() { if (ImGui::BeginMenu(STR_C("General"))) - { - bool flag = DebugModeFlag; - if (ImGui::MenuItem(STR_C("Debug mode"), nullptr, &flag)) { - command_relay relay; - relay.post(user_command::debugtoggle, 0.0, 0.0, GLFW_RELEASE, 0); - } - ImGui::MenuItem(STR_C("Quit"), "F10", &m_quit_active); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu(STR_C("Tools"))) - { - static bool log = Global.iWriteLogEnabled & 1; - - ImGui::MenuItem(STR_C("Logging to log.txt"), nullptr, &log); - if (log) - Global.iWriteLogEnabled |= 1; - else - Global.iWriteLogEnabled &= ~1; - - if (ImGui::MenuItem(STR_C("Screenshot"), "PrtScr")) - Application.queue_screenshot(); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu(STR_C("Windows"))) - { - ImGui::MenuItem(STR_C("Log"), "F9", &m_logpanel.is_open); - if (DebugModeFlag) { - ImGui::MenuItem(STR_C("ImGui Demo"), nullptr, &m_imgui_demo); - bool ret = ImGui::MenuItem(STR_C("Headlight config"), nullptr, GfxRenderer->Debug_Ui_State(std::nullopt)); - - GfxRenderer->Debug_Ui_State(ret); + { + bool flag = DebugModeFlag; + if (ImGui::MenuItem(STR_C("Debug mode"), nullptr, &flag)) + { + command_relay relay; + relay.post(user_command::debugtoggle, 0.0, 0.0, GLFW_RELEASE, 0); } - ImGui::EndMenu(); - } + ImGui::MenuItem(STR_C("Quit"), "F10", &m_quit_active); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu(STR_C("Tools"))) + { + static bool log = Global.iWriteLogEnabled & 1; + + ImGui::MenuItem(STR_C("Logging to log.txt"), nullptr, &log); + if (log) + Global.iWriteLogEnabled |= 1; + else + Global.iWriteLogEnabled &= ~1; + + if (ImGui::MenuItem(STR_C("Screenshot"), "PrtScr")) + Application.queue_screenshot(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu(STR_C("Windows"))) + { + ImGui::MenuItem(STR_C("Log"), "F9", &m_logpanel.is_open); + if (DebugModeFlag) + { + ImGui::MenuItem(STR_C("ImGui Demo"), nullptr, &m_imgui_demo); + bool ret = ImGui::MenuItem(STR_C("Headlight config"), nullptr, GfxRenderer->Debug_Ui_State(std::nullopt)); + + GfxRenderer->Debug_Ui_State(ret); + } + ImGui::EndMenu(); + } } void ui_layer::render_menu() { - glm::dvec2 mousepos = Global.cursor_pos; + glm::dvec2 mousepos = Global.cursor_pos; - if (!((Global.ControlPicking && mousepos.y < 50.0f) || m_imguiio->WantCaptureMouse) || m_suppress_menu) - return; + if (!((Global.ControlPicking && mousepos.y < 50.0f) || m_imguiio->WantCaptureMouse) || m_suppress_menu) + return; - if (ImGui::BeginMainMenuBar()) - { - render_menu_contents(); - ImGui::EndMainMenuBar(); - } + if (ImGui::BeginMainMenuBar()) + { + render_menu_contents(); + ImGui::EndMainMenuBar(); + } } void ui_layer::render_background() diff --git a/utilities.cpp b/utilities.cpp index 9569b0ab..3e25c769 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -37,73 +37,82 @@ bool DebugTractionFlag = false; double Max0R(double x1, double x2) { - if (x1 > x2) - return x1; - else - return x2; + if (x1 > x2) + return x1; + else + return x2; } double Min0R(double x1, double x2) { - if (x1 < x2) - return x1; - else - return x2; + if (x1 < x2) + return x1; + else + return x2; } // shitty replacement for Borland timestamp function // TODO: replace with something sensible -std::string Now() { +std::string Now() +{ - std::time_t timenow = std::time( nullptr ); - std::tm tm = *std::localtime( &timenow ); - std::stringstream converter; - converter << std::put_time( &tm, "%c" ); - return converter.str(); + std::time_t timenow = std::time(nullptr); + std::tm tm = *std::localtime(&timenow); + std::stringstream converter; + converter << std::put_time(&tm, "%c"); + return converter.str(); } // zwraca różnicę czasu // jeśli pierwsza jest aktualna, a druga rozkładowa, to ujemna oznacza opóżnienie // na dłuższą metę trzeba uwzględnić datę, jakby opóżnienia miały przekraczać 12h (towarowych) -double CompareTime(double t1h, double t1m, double t2h, double t2m) { +double CompareTime(double t1h, double t1m, double t2h, double t2m) +{ - if ((t2h < 0)) - return 0; - else - { - auto t = (t2h - t1h) * 60 + t2m - t1m; // jeśli t2=00:05, a t1=23:50, to różnica wyjdzie ujemna - if ((t < -720)) // jeśli różnica przekracza 12h na minus - t = t + 1440; // to dodanie doby minut;else - if ((t > 720)) // jeśli przekracza 12h na plus - t = t - 1440; // to odjęcie doby minut - return t; - } + if ((t2h < 0)) + return 0; + else + { + auto t = (t2h - t1h) * 60 + t2m - t1m; // jeśli t2=00:05, a t1=23:50, to różnica wyjdzie ujemna + if ((t < -720)) // jeśli różnica przekracza 12h na minus + t = t + 1440; // to dodanie doby minut;else + if ((t > 720)) // jeśli przekracza 12h na plus + t = t - 1440; // to odjęcie doby minut + return t; + } } -bool SetFlag( int &Flag, int const Value ) { +bool SetFlag(int &Flag, int const Value) +{ - if( Value > 0 ) { - if( false == TestFlag( Flag, Value ) ) { - Flag |= Value; - return true; // true, gdy było wcześniej 0 i zostało ustawione - } - } - else if( Value < 0 ) { - // Value jest ujemne, czyli zerowanie flagi - return ClearFlag( Flag, -Value ); - } - return false; + if (Value > 0) + { + if (false == TestFlag(Flag, Value)) + { + Flag |= Value; + return true; // true, gdy było wcześniej 0 i zostało ustawione + } + } + else if (Value < 0) + { + // Value jest ujemne, czyli zerowanie flagi + return ClearFlag(Flag, -Value); + } + return false; } -bool ClearFlag( int &Flag, int const Value ) { +bool ClearFlag(int &Flag, int const Value) +{ - if( true == TestFlag( Flag, Value ) ) { - Flag &= ~Value; - return true; - } - else { - return false; - } + if (true == TestFlag(Flag, Value)) + { + Flag &= ~Value; + return true; + } + else + { + return false; + } } double Random(double a, double b) @@ -119,6 +128,31 @@ int RandomInt(int min, int max) return dist(engine); } +std::string generate_uuid_v4() +{ + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dist(0, 255); + + std::array bytes; + for (auto &b : bytes) + b = static_cast(dist(gen)); + + // UUID v4 (RFC 4122) + bytes[6] = (bytes[6] & 0x0F) | 0x40; + bytes[8] = (bytes[8] & 0x3F) | 0x80; + + char buf[37]; // 36 znaków + \0 + std::snprintf(buf, sizeof(buf), + "%02x%02x%02x%02x-" + "%02x%02x-" + "%02x%02x-" + "%02x%02x-" + "%02x%02x%02x%02x%02x%02x", + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]); + + return std::string(buf); +} double LocalRandom(double a, double b) { @@ -128,46 +162,52 @@ double LocalRandom(double a, double b) bool FuzzyLogic(double Test, double Threshold, double Probability) { - if ((Test > Threshold) && (!DebugModeFlag)) - return - (Random() < Probability * Threshold * 1.0 / Test) /*im wiekszy Test tym wieksza szansa*/; - else - return false; + if ((Test > Threshold) && (!DebugModeFlag)) + return (Random() < Probability * Threshold * 1.0 / Test) /*im wiekszy Test tym wieksza szansa*/; + else + return false; } bool FuzzyLogicAI(double Test, double Threshold, double Probability) { - if ((Test > Threshold)) - return - (Random() < Probability * Threshold * 1.0 / Test) /*im wiekszy Test tym wieksza szansa*/; - else - return false; + if ((Test > Threshold)) + return (Random() < Probability * Threshold * 1.0 / Test) /*im wiekszy Test tym wieksza szansa*/; + else + return false; } std::string DUE(std::string s) /*Delete Before Equal sign*/ { - //DUE = Copy(s, Pos("=", s) + 1, length(s)); + // DUE = Copy(s, Pos("=", s) + 1, length(s)); return s.substr(s.find("=") + 1, s.length()); } std::string DWE(std::string s) /*Delete After Equal sign*/ { - size_t ep = s.find("="); + size_t ep = s.find("="); if (ep != std::string::npos) - //DWE = Copy(s, 1, ep - 1); + // DWE = Copy(s, 1, ep - 1); return s.substr(0, ep); - else - return s; + else + return s; } -std::string ExchangeCharInString( std::string const &Source, char const From, char const To ) +std::string ExchangeCharInString(std::string const &Source, char const From, char const To) { - std::string replacement; replacement.reserve( Source.size() ); - std::for_each( - std::begin( Source ), std::end( Source ), - [&](char const idx) { - if( idx != From ) { replacement += idx; } - else { replacement += To; } } ); + std::string replacement; + replacement.reserve(Source.size()); + std::for_each(std::begin(Source), std::end(Source), + [&](char const idx) + { + if (idx != From) + { + replacement += idx; + } + else + { + replacement += To; + } + }); return replacement; } @@ -175,20 +215,20 @@ std::string ExchangeCharInString( std::string const &Source, char const From, ch std::vector &Split(const std::string &s, char delim, std::vector &elems) { // dzieli tekst na wektor tekstow - std::stringstream ss(s); - std::string item; - while (std::getline(ss, item, delim)) - { - elems.push_back(item); - } - return elems; + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) + { + elems.push_back(item); + } + return elems; } std::vector Split(const std::string &s, char delim) { // dzieli tekst na wektor tekstow - std::vector elems; - Split(s, delim, elems); - return elems; + std::vector elems; + Split(s, delim, elems); + return elems; } std::vector Split(const std::string &s) @@ -203,17 +243,16 @@ std::vector Split(const std::string &s) return elems; } -std::pair -split_string_and_number( std::string const &Key ) { +std::pair split_string_and_number(std::string const &Key) +{ - auto const indexstart{ Key.find_first_of( "-1234567890" ) }; - auto const indexend{ Key.find_first_not_of( "-1234567890", indexstart ) }; - if( indexstart != std::string::npos ) { - return { - Key.substr( 0, indexstart ), - std::stoi( Key.substr( indexstart, indexend - indexstart ) ) }; - } - return { Key, 0 }; + auto const indexstart{Key.find_first_of("-1234567890")}; + auto const indexend{Key.find_first_not_of("-1234567890", indexstart)}; + if (indexstart != std::string::npos) + { + return {Key.substr(0, indexstart), std::stoi(Key.substr(indexstart, indexend - indexstart))}; + } + return {Key, 0}; } std::string to_string(int Value) @@ -256,14 +295,14 @@ std::string to_string(double Value, int precision) std::string to_string(double const Value, int const Precision, int const Width) { std::ostringstream converter; - converter << std::setw( Width ) << std::fixed << std::setprecision(Precision) << Value; + converter << std::setw(Width) << std::fixed << std::setprecision(Precision) << Value; return converter.str(); }; -std::string to_hex_str( int const Value, int const Width ) +std::string to_hex_str(int const Value, int const Width) { std::ostringstream converter; - converter << "0x" << std::uppercase << std::setfill( '0' ) << std::setw( Width ) << std::hex << Value; + converter << "0x" << std::uppercase << std::setfill('0') << std::setw(Width) << std::hex << Value; return converter.str(); }; @@ -283,77 +322,67 @@ bool string_starts_with(const std::string &string, const std::string &begin) return string.compare(0, begin.length(), begin) == 0; } -std::string const fractionlabels[] = { " ", u8"¹", u8"²", u8"³", u8"⁴", u8"⁵", u8"⁶", u8"⁷", u8"⁸", u8"⁹" }; +std::string const fractionlabels[] = {" ", u8"¹", u8"²", u8"³", u8"⁴", u8"⁵", u8"⁶", u8"⁷", u8"⁸", u8"⁹"}; -std::string to_minutes_str( float const Minutes, bool const Leadingzero, int const Width ) { +std::string to_minutes_str(float const Minutes, bool const Leadingzero, int const Width) +{ - float minutesintegral; - auto const minutesfractional { std::modf( Minutes, &minutesintegral ) }; - auto const width { Width - 1 }; - auto minutes = ( - std::string( width - 1, ' ' ) - + ( Leadingzero ? - to_string( 100 + minutesintegral ).substr( 1, 2 ) : - to_string( minutesintegral, 0 ) ) ); - return ( - minutes.substr( minutes.size() - width, width ) - + fractionlabels[ static_cast( std::floor( minutesfractional * 10 + 0.1 ) ) ] ); + float minutesintegral; + auto const minutesfractional{std::modf(Minutes, &minutesintegral)}; + auto const width{Width - 1}; + auto minutes = (std::string(width - 1, ' ') + (Leadingzero ? to_string(100 + minutesintegral).substr(1, 2) : to_string(minutesintegral, 0))); + return (minutes.substr(minutes.size() - width, width) + fractionlabels[static_cast(std::floor(minutesfractional * 10 + 0.1))]); } +int stol_def(const std::string &str, const int &DefaultValue) +{ -int stol_def(const std::string &str, const int &DefaultValue) { - - int result { DefaultValue }; - std::stringstream converter; - converter << str; - converter >> result; - return result; + int result{DefaultValue}; + std::stringstream converter; + converter << str; + converter >> result; + return result; } -std::string ToLower(std::string const &text) { +std::string ToLower(std::string const &text) +{ - auto lowercase { text }; - std::transform( - std::begin( text ), std::end( text ), - std::begin( lowercase ), - []( unsigned char c ) { return std::tolower( c ); } ); + auto lowercase{text}; + std::transform(std::begin(text), std::end(text), std::begin(lowercase), [](unsigned char c) { return std::tolower(c); }); return lowercase; } -std::string ToUpper(std::string const &text) { +std::string ToUpper(std::string const &text) +{ - auto uppercase { text }; - std::transform( - std::begin( text ), std::end( text ), - std::begin( uppercase ), - []( unsigned char c ) { return std::toupper( c ); } ); - return uppercase; + auto uppercase{text}; + std::transform(std::begin(text), std::end(text), std::begin(uppercase), [](unsigned char c) { return std::toupper(c); }); + return uppercase; } // replaces polish letters with basic ascii -void -win1250_to_ascii( std::string &Input ) { +void win1250_to_ascii(std::string &Input) +{ - std::unordered_map const charmap { - { 165, 'A' }, { 198, 'C' }, { 202, 'E' }, { 163, 'L' }, { 209, 'N' }, { 211, 'O' }, { 140, 'S' }, { 143, 'Z' }, { 175, 'Z' }, - { 185, 'a' }, { 230, 'c' }, { 234, 'e' }, { 179, 'l' }, { 241, 'n' }, { 243, 'o' }, { 156, 's' }, { 159, 'z' }, { 191, 'z' } - }; - std::unordered_map::const_iterator lookup; - for( auto &input : Input ) { - if( ( lookup = charmap.find( input ) ) != charmap.end() ) - input = lookup->second; - } + std::unordered_map const charmap{{165, 'A'}, {198, 'C'}, {202, 'E'}, {163, 'L'}, {209, 'N'}, {211, 'O'}, {140, 'S'}, {143, 'Z'}, {175, 'Z'}, + {185, 'a'}, {230, 'c'}, {234, 'e'}, {179, 'l'}, {241, 'n'}, {243, 'o'}, {156, 's'}, {159, 'z'}, {191, 'z'}}; + std::unordered_map::const_iterator lookup; + for (auto &input : Input) + { + if ((lookup = charmap.find(input)) != charmap.end()) + input = lookup->second; + } } -std::string win1250_to_utf8(const std::string &Input) { - std::unordered_map const charmap { - { 165, u8"Ą" }, { 198, u8"Ć" }, { 202, u8"Ę" }, { 163, u8"Ł" }, { 209, u8"Ń" }, { 211, u8"Ó" }, { 140, u8"Ś" }, { 143, u8"Ź" }, { 175, u8"Ż" }, - { 185, u8"ą" }, { 230, u8"ć" }, { 234, u8"ę" }, { 179, u8"ł" }, { 241, u8"ń" }, { 243, u8"ó" }, { 156, u8"ś" }, { 159, u8"ź" }, { 191, u8"ż" } - }; +std::string win1250_to_utf8(const std::string &Input) +{ + std::unordered_map const charmap{{165, u8"Ą"}, {198, u8"Ć"}, {202, u8"Ę"}, {163, u8"Ł"}, {209, u8"Ń"}, {211, u8"Ó"}, {140, u8"Ś"}, {143, u8"Ź"}, {175, u8"Ż"}, + {185, u8"ą"}, {230, u8"ć"}, {234, u8"ę"}, {179, u8"ł"}, {241, u8"ń"}, {243, u8"ó"}, {156, u8"ś"}, {159, u8"ź"}, {191, u8"ż"}}; std::string output; std::unordered_map::const_iterator lookup; - for( auto &input : Input ) { - if( ( lookup = charmap.find( input ) ) != charmap.end() ) + for (auto &input : Input) + { + if ((lookup = charmap.find(input)) != charmap.end()) output += lookup->second; else output += input; @@ -362,213 +391,220 @@ std::string win1250_to_utf8(const std::string &Input) { } // Ra: tymczasowe rozwiązanie kwestii zagranicznych (czeskich) napisów -char charsetconversiontable[] = - "E?,?\"_++?%Sstzz" - " ^^L$A|S^CS<--RZo±,l'uP.,as>L\"lz" - "RAAAALCCCEEEEIIDDNNOOOOxRUUUUYTB" - "raaaalccceeeeiiddnnoooo-ruuuuyt?"; +char charsetconversiontable[] = "E?,?\"_++?%Sstzz" + " ^^L$A|S^CS<--RZo±,l'uP.,as>L\"lz" + "RAAAALCCCEEEEIIDDNNOOOOxRUUUUYTB" + "raaaalccceeeeiiddnnoooo-ruuuuyt?"; // wycięcie liter z ogonkami -std::string Bezogonkow(std::string Input, bool const Underscorestospaces) { +std::string Bezogonkow(std::string Input, bool const Underscorestospaces) +{ - char const extendedcharsetbit { static_cast( 0x80 ) }; - char const space { ' ' }; - char const underscore { '_' }; + char const extendedcharsetbit{static_cast(0x80)}; + char const space{' '}; + char const underscore{'_'}; - for( auto &input : Input ) { - if( input & extendedcharsetbit ) { - input = charsetconversiontable[ input ^ extendedcharsetbit ]; - } - else if( input < space ) { - input = space; - } - else if( Underscorestospaces && ( input == underscore ) ) { - input = space; - } - } + for (auto &input : Input) + { + if (input & extendedcharsetbit) + { + input = charsetconversiontable[input ^ extendedcharsetbit]; + } + else if (input < space) + { + input = space; + } + else if (Underscorestospaces && (input == underscore)) + { + input = space; + } + } - return Input; + return Input; } -template <> -bool -extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) { +template <> bool extract_value(bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default) +{ - auto value = extract_value( Key, Input ); - if( false == value.empty() ) { - // set the specified variable to retrieved value - Variable = ( ToLower( value ) == "yes" ); - return true; // located the variable - } - else { - // set the variable to provided default value - if( false == Default.empty() ) { - Variable = ( ToLower( Default ) == "yes" ); - } - return false; // couldn't locate the variable in provided input - } + auto value = extract_value(Key, Input); + if (false == value.empty()) + { + // set the specified variable to retrieved value + Variable = (ToLower(value) == "yes"); + return true; // located the variable + } + else + { + // set the variable to provided default value + if (false == Default.empty()) + { + Variable = (ToLower(Default) == "yes"); + } + return false; // couldn't locate the variable in provided input + } } -bool FileExists( std::string const &Filename ) { +bool FileExists(std::string const &Filename) +{ return std::filesystem::exists(Filename); } -std::pair -FileExists( std::vector const &Names, std::vector const &Extensions ) { +std::pair FileExists(std::vector const &Names, std::vector const &Extensions) +{ - for( auto const &name : Names ) { - for( auto const &extension : Extensions ) { - if( FileExists( name + extension ) ) { - return { name, extension }; - } - } - } - // nothing found - return { {}, {} }; + for (auto const &name : Names) + { + for (auto const &extension : Extensions) + { + if (FileExists(name + extension)) + { + return {name, extension}; + } + } + } + // nothing found + return {{}, {}}; } // returns time of last modification for specified file -std::time_t -last_modified( std::string const &Filename ) { - std::string fn = Filename; - struct stat filestat; - if( ::stat( fn.c_str(), &filestat ) == 0 ) +std::time_t last_modified(std::string const &Filename) +{ + std::string fn = Filename; + struct stat filestat; + if (::stat(fn.c_str(), &filestat) == 0) return filestat.st_mtime; - else + else return 0; } // potentially erases file extension from provided file name. returns: true if extension was removed, false otherwise -bool -erase_extension( std::string &Filename ) { +bool erase_extension(std::string &Filename) +{ - auto const extensionpos { Filename.rfind( '.' ) }; + auto const extensionpos{Filename.rfind('.')}; - if( extensionpos == std::string::npos ) { return false; } + if (extensionpos == std::string::npos) + { + return false; + } - if( extensionpos != Filename.rfind( ".." ) + 1 ) { - // we can get extension for .mat or, in legacy files, some image format. just trim it and set it to material file extension - Filename.erase( extensionpos ); - return true; - } - return false; + if (extensionpos != Filename.rfind("..") + 1) + { + // we can get extension for .mat or, in legacy files, some image format. just trim it and set it to material file extension + Filename.erase(extensionpos); + return true; + } + return false; } -void -erase_leading_slashes( std::string &Filename ) { +void erase_leading_slashes(std::string &Filename) +{ - while( Filename[ 0 ] == '/' ) { - Filename.erase( 0, 1 ); - } + while (Filename[0] == '/') + { + Filename.erase(0, 1); + } } // potentially replaces backward slashes in provided file path with unix-compatible forward slashes -void -replace_slashes( std::string &Filename ) { +void replace_slashes(std::string &Filename) +{ - std::replace( - std::begin( Filename ), std::end( Filename ), - '\\', '/' ); + std::replace(std::begin(Filename), std::end(Filename), '\\', '/'); } // returns potential path part from provided file name -std::string -substr_path( std::string const &Filename ) { +std::string substr_path(std::string const &Filename) +{ - return ( - Filename.rfind( '/' ) != std::string::npos ? - Filename.substr( 0, Filename.rfind( '/' ) + 1 ) : - "" ); + return (Filename.rfind('/') != std::string::npos ? Filename.substr(0, Filename.rfind('/') + 1) : ""); } // returns length of common prefix between two provided strings -std::ptrdiff_t -len_common_prefix( std::string const &Left, std::string const &Right ) { +std::ptrdiff_t len_common_prefix(std::string const &Left, std::string const &Right) +{ - auto const *left { Left.data() }; - auto const *right { Right.data() }; - // compare up to the length of the shorter string - return ( Right.size() <= Left.size() ? - std::distance( right, std::mismatch( right, right + Right.size(), left ).first ) : - std::distance( left, std::mismatch( left, left + Left.size(), right ).first ) ); + auto const *left{Left.data()}; + auto const *right{Right.data()}; + // compare up to the length of the shorter string + return (Right.size() <= Left.size() ? std::distance(right, std::mismatch(right, right + Right.size(), left).first) : std::distance(left, std::mismatch(left, left + Left.size(), right).first)); } // returns true if provided string ends with another provided string -bool -ends_with( std::string_view String, std::string_view Suffix ) { +bool ends_with(std::string_view String, std::string_view Suffix) +{ - return ( String.size() >= Suffix.size() ) - && ( 0 == String.compare( String.size() - Suffix.size(), Suffix.size(), Suffix ) ); + return (String.size() >= Suffix.size()) && (0 == String.compare(String.size() - Suffix.size(), Suffix.size(), Suffix)); } // returns true if provided string begins with another provided string -bool -starts_with( std::string_view const String, std::string_view Prefix ) { +bool starts_with(std::string_view const String, std::string_view Prefix) +{ - return ( String.size() >= Prefix.size() ) - && ( 0 == String.compare( 0, Prefix.size(), Prefix ) ); + return (String.size() >= Prefix.size()) && (0 == String.compare(0, Prefix.size(), Prefix)); } // returns true if provided string contains another provided string -bool -contains( std::string_view const String, std::string_view Substring ) { +bool contains(std::string_view const String, std::string_view Substring) +{ - return ( String.find( Substring ) != std::string::npos ); + return (String.find(Substring) != std::string::npos); } -bool -contains( std::string_view const String, char Character ) { +bool contains(std::string_view const String, char Character) +{ - return ( String.find( Character ) != std::string::npos ); + return (String.find(Character) != std::string::npos); } // helper, restores content of a 3d vector from provided input stream // TODO: review and clean up the helper routines, there's likely some redundant ones -glm::dvec3 LoadPoint( cParser &Input ) { - // pobranie współrzędnych punktu - glm::dvec3 point; - Input.getTokens( 3 ); - Input - >> point.x - >> point.y - >> point.z; - return point; +glm::dvec3 LoadPoint(cParser &Input) +{ + // pobranie współrzędnych punktu + glm::dvec3 point; + Input.getTokens(3); + Input >> point.x >> point.y >> point.z; + return point; } // extracts a group of tokens from provided data stream, returns one of them picked randomly -std::string -deserialize_random_set( cParser &Input, char const *Break ) { - - auto token { Input.getToken( true, Break ) }; - std::replace(token.begin(), token.end(), '\\', '/'); - if( token != "[" ) { - // simple case, single token - return token; - } - // if instead of a single token we've encountered '[' this marks a beginning of a random set - // we retrieve all entries, then return a random one - std::vector tokens; - while( ( ( token = deserialize_random_set( Input, Break ) ) != "" ) - && ( token != "]" ) ) { - tokens.emplace_back( token ); - } - if( false == tokens.empty() ) { - std::shuffle( std::begin( tokens ), std::end( tokens ), Global.random_engine ); - return tokens.front(); - } - else { - // shouldn't ever get here but, eh - return ""; - } -} - -int count_trailing_zeros( uint32_t val ) +std::string deserialize_random_set(cParser &Input, char const *Break) { - int r = 0; - for( uint32_t shift = 1; !( val & shift ); shift <<= 1 ) - r++; - - return r; + auto token{Input.getToken(true, Break)}; + std::replace(token.begin(), token.end(), '\\', '/'); + if (token != "[") + { + // simple case, single token + return token; + } + // if instead of a single token we've encountered '[' this marks a beginning of a random set + // we retrieve all entries, then return a random one + std::vector tokens; + while (((token = deserialize_random_set(Input, Break)) != "") && (token != "]")) + { + tokens.emplace_back(token); + } + if (false == tokens.empty()) + { + std::shuffle(std::begin(tokens), std::end(tokens), Global.random_engine); + return tokens.front(); + } + else + { + // shouldn't ever get here but, eh + return ""; + } +} + +int count_trailing_zeros(uint32_t val) +{ + int r = 0; + + for (uint32_t shift = 1; !(val & shift); shift <<= 1) + r++; + + return r; } diff --git a/utilities.h b/utilities.h index cd8ca7c9..1a072e7d 100644 --- a/utilities.h +++ b/utilities.h @@ -36,7 +36,7 @@ template T sign(T x) #define szSoundPath "sounds/" #define szDataPath "data/" -#define MAKE_ID4(a,b,c,d) (((std::uint32_t)(d)<<24)|((std::uint32_t)(c)<<16)|((std::uint32_t)(b)<<8)|(std::uint32_t)(a)) +#define MAKE_ID4(a, b, c, d) (((std::uint32_t)(d) << 24) | ((std::uint32_t)(c) << 16) | ((std::uint32_t)(b) << 8) | (std::uint32_t)(a)) extern bool DebugModeFlag; extern bool FreeFlyModeFlag; @@ -50,22 +50,23 @@ double Min0R(double x1, double x2); inline double Sign(double x) { - return x >= 0 ? 1.0 : -1.0; + return x >= 0 ? 1.0 : -1.0; } inline long Round(double const f) { return (long)(f + 0.5); - //return lround(f); + // return lround(f); } double Random(double a, double b); int RandomInt(int min, int max); +std::string generate_uuid_v4(); double LocalRandom(double a, double b); inline double Random() { - return Random(0.0,1.0); + return Random(0.0, 1.0); } inline double Random(double b) @@ -75,39 +76,39 @@ inline double Random(double b) inline double LocalRandom() { - return LocalRandom( 0.0, 1.0 ); + return LocalRandom(0.0, 1.0); } -inline double LocalRandom( double b ) +inline double LocalRandom(double b) { - return LocalRandom( 0.0, b ); + return LocalRandom(0.0, b); } inline double BorlandTime() { - auto timesinceepoch = std::time( nullptr ); - return timesinceepoch / (24.0 * 60 * 60); -/* - // std alternative - auto timesinceepoch = std::chrono::system_clock::now().time_since_epoch(); - return std::chrono::duration_cast( timesinceepoch ).count() / (24.0 * 60 * 60); -*/ + auto timesinceepoch = std::time(nullptr); + return timesinceepoch / (24.0 * 60 * 60); + /* + // std alternative + auto timesinceepoch = std::chrono::system_clock::now().time_since_epoch(); + return std::chrono::duration_cast( timesinceepoch ).count() / (24.0 * 60 * 60); + */ } std::string Now(); -double CompareTime( double t1h, double t1m, double t2h, double t2m ); +double CompareTime(double t1h, double t1m, double t2h, double t2m); /*funkcje logiczne*/ -inline -bool TestFlag( int const Flag, int const Value ) { - return ( ( Flag & Value ) == Value ); +inline bool TestFlag(int const Flag, int const Value) +{ + return ((Flag & Value) == Value); } -inline -bool TestFlagAny( int const Flag, int const Value ) { - return ( ( Flag & Value ) != 0 ); +inline bool TestFlagAny(int const Flag, int const Value) +{ + return ((Flag & Value) != 0); } -bool SetFlag( int &Flag, int const Value); +bool SetFlag(int &Flag, int const Value); bool ClearFlag(int &Flag, int const Value); bool FuzzyLogic(double Test, double Threshold, double Probability); @@ -116,13 +117,13 @@ bool FuzzyLogicAI(double Test, double Threshold, double Probability); /*to samo ale zawsze niezaleznie od DebugFlag*/ /*operacje na stringach*/ -std::string DUE(std::string s); /*Delete Until Equal sign*/ -std::string DWE(std::string s); /*Delete While Equal sign*/ -std::string ExchangeCharInString( std::string const &Source, char const From, char const To ); // zamienia jeden znak na drugi +std::string DUE(std::string s); /*Delete Until Equal sign*/ +std::string DWE(std::string s); /*Delete While Equal sign*/ +std::string ExchangeCharInString(std::string const &Source, char const From, char const To); // zamienia jeden znak na drugi std::vector &Split(const std::string &s, char delim, std::vector &elems); std::vector Split(const std::string &s, char delim); -//std::vector Split(const std::string &s); -std::pair split_string_and_number( std::string const &Key ); +// std::vector Split(const std::string &s); +std::pair split_string_and_number(std::string const &Key); std::string to_string(int Value); std::string to_string(unsigned int Value); @@ -130,210 +131,207 @@ std::string to_string(int Value, int width); std::string to_string(double Value); std::string to_string(double Value, int precision); std::string to_string(double Value, int precision, int width); -std::string to_hex_str( int const Value, int const width = 4 ); -std::string to_minutes_str( float const Minutes, bool const Leadingzero, int const Width ); +std::string to_hex_str(int const Value, int const width = 4); +std::string to_minutes_str(float const Minutes, bool const Leadingzero, int const Width); -inline -std::string to_string(bool Value) { - return ( Value == true ? "true" : "false" ); +inline std::string to_string(bool Value) +{ + return (Value == true ? "true" : "false"); } -template -std::string to_string( glm::tvec3 const &Value ) { - return to_string( Value.x, 2 ) + ", " + to_string( Value.y, 2 ) + ", " + to_string( Value.z, 2 ); +template std::string to_string(glm::tvec3 const &Value) +{ + return to_string(Value.x, 2) + ", " + to_string(Value.y, 2) + ", " + to_string(Value.z, 2); } -template -std::string to_string( glm::tvec4 const &Value, int const Width = 2 ) { - return to_string( Value.x, Width ) + ", " + to_string( Value.y, Width ) + ", " + to_string( Value.z, Width ) + ", " + to_string( Value.w, Width ); +template std::string to_string(glm::tvec4 const &Value, int const Width = 2) +{ + return to_string(Value.x, Width) + ", " + to_string(Value.y, Width) + ", " + to_string(Value.z, Width) + ", " + to_string(Value.w, Width); } bool string_ends_with(std::string const &string, std::string const &ending); bool string_starts_with(std::string const &string, std::string const &begin); -int stol_def(const std::string & str, const int & DefaultValue); +int stol_def(const std::string &str, const int &DefaultValue); std::string ToLower(std::string const &text); std::string ToUpper(std::string const &text); // replaces polish letters with basic ascii -void win1250_to_ascii( std::string &Input ); +void win1250_to_ascii(std::string &Input); // TODO: unify with win1250_to_ascii() -std::string Bezogonkow( std::string Input, bool const Underscorestospaces = false ); +std::string Bezogonkow(std::string Input, bool const Underscorestospaces = false); std::string win1250_to_utf8(const std::string &input); -inline -std::string -extract_value( std::string const &Key, std::string const &Input ) { - // NOTE, HACK: the leading space allows to uniformly look for " variable=" substring - std::string const input { " " + Input }; - std::string value; - auto lookup = input.find( " " + Key + "=" ); - if( lookup != std::string::npos ) { - value = input.substr( input.find_first_not_of( ' ', lookup + Key.size() + 2 ) ); - lookup = value.find( ' ' ); - if( lookup != std::string::npos ) { - // trim everything past the value - value.erase( lookup ); - } - } - return value; +inline std::string extract_value(std::string const &Key, std::string const &Input) +{ + // NOTE, HACK: the leading space allows to uniformly look for " variable=" substring + std::string const input{" " + Input}; + std::string value; + auto lookup = input.find(" " + Key + "="); + if (lookup != std::string::npos) + { + value = input.substr(input.find_first_not_of(' ', lookup + Key.size() + 2)); + lookup = value.find(' '); + if (lookup != std::string::npos) + { + // trim everything past the value + value.erase(lookup); + } + } + return value; } -template -bool -extract_value( Type_ &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) { +template bool extract_value(Type_ &Variable, std::string const &Key, std::string const &Input, std::string const &Default) +{ - auto value = extract_value( Key, Input ); - if( false == value.empty() ) { - // set the specified variable to retrieved value - std::stringstream converter; - converter << value; - converter >> Variable; - return true; // located the variable - } - else { - // set the variable to provided default value - if( false == Default.empty() ) { - std::stringstream converter; - converter << Default; - converter >> Variable; - } - return false; // couldn't locate the variable in provided input - } + auto value = extract_value(Key, Input); + if (false == value.empty()) + { + // set the specified variable to retrieved value + std::stringstream converter; + converter << value; + converter >> Variable; + return true; // located the variable + } + else + { + // set the variable to provided default value + if (false == Default.empty()) + { + std::stringstream converter; + converter << Default; + converter >> Variable; + } + return false; // couldn't locate the variable in provided input + } } -template <> -bool -extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default ); +template <> bool extract_value(bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default); -bool FileExists( std::string const &Filename ); +bool FileExists(std::string const &Filename); -std::pair FileExists( std::vector const &Names, std::vector const &Extensions ); +std::pair FileExists(std::vector const &Names, std::vector const &Extensions); // returns time of last modification for specified file -std::time_t last_modified( std::string const &Filename ); +std::time_t last_modified(std::string const &Filename); // potentially erases file extension from provided file name. returns: true if extension was removed, false otherwise -bool -erase_extension( std::string &Filename ); +bool erase_extension(std::string &Filename); // potentially erase leading slashes from provided file path -void -erase_leading_slashes( std::string &Filename ); +void erase_leading_slashes(std::string &Filename); // potentially replaces backward slashes in provided file path with unix-compatible forward slashes -void -replace_slashes( std::string &Filename ); +void replace_slashes(std::string &Filename); // returns potential path part from provided file name -std::string substr_path( std::string const &Filename ); +std::string substr_path(std::string const &Filename); // returns common prefix of two provided strings -std::ptrdiff_t len_common_prefix( std::string const &Left, std::string const &Right ); +std::ptrdiff_t len_common_prefix(std::string const &Left, std::string const &Right); // returns true if provided string ends with another provided string -bool ends_with( std::string_view String, std::string_view Suffix ); +bool ends_with(std::string_view String, std::string_view Suffix); // returns true if provided string begins with another provided string -bool starts_with( std::string_view String, std::string_view Prefix ); +bool starts_with(std::string_view String, std::string_view Prefix); // returns true if provided string contains another provided string -bool contains( std::string_view const String, std::string_view Substring ); -bool contains( std::string_view const String, char Character ); +bool contains(std::string_view const String, std::string_view Substring); +bool contains(std::string_view const String, char Character); -template -void SafeDelete( Type_ &Pointer ) { - delete Pointer; - Pointer = nullptr; +template void SafeDelete(Type_ &Pointer) +{ + delete Pointer; + Pointer = nullptr; } -template -void SafeDeleteArray( Type_ &Pointer ) { - delete[] Pointer; - Pointer = nullptr; +template void SafeDeleteArray(Type_ &Pointer) +{ + delete[] Pointer; + Pointer = nullptr; } -template -Type_ -is_equal( Type_ const &Left, Type_ const &Right, Type_ const Epsilon = 1e-5 ) { +template Type_ is_equal(Type_ const &Left, Type_ const &Right, Type_ const Epsilon = 1e-5) +{ - if( Epsilon != 0 ) { - return glm::epsilonEqual( Left, Right, Epsilon ); - } - else { - return ( Left == Right ); - } + if (Epsilon != 0) + { + return glm::epsilonEqual(Left, Right, Epsilon); + } + else + { + return (Left == Right); + } } -template -Type_ -clamp( Type_ const Value, Type_ const Min, Type_ const Max ) { +template Type_ clamp(Type_ const Value, Type_ const Min, Type_ const Max) +{ - Type_ value = Value; - if( value < Min ) { value = Min; } - if( value > Max ) { value = Max; } - return value; + Type_ value = Value; + if (value < Min) + { + value = Min; + } + if (value > Max) + { + value = Max; + } + return value; } // keeps the provided value in specified range 0-Range, as if the range was circular buffer -template -Type_ -clamp_circular( Type_ Value, Type_ const Range = static_cast(360) ) { +template Type_ clamp_circular(Type_ Value, Type_ const Range = static_cast(360)) +{ - Value -= Range * (int)( Value / Range ); // clamp the range to 0-360 - if( Value < Type_(0) ) Value += Range; + Value -= Range * (int)(Value / Range); // clamp the range to 0-360 + if (Value < Type_(0)) + Value += Range; - return Value; + return Value; } // rounds down provided value to nearest power of two -template -Type_ -clamp_power_of_two( Type_ Value, Type_ const Min = static_cast(1), Type_ const Max = static_cast(16384) ) { +template Type_ clamp_power_of_two(Type_ Value, Type_ const Min = static_cast(1), Type_ const Max = static_cast(16384)) +{ - Type_ p2size{ Min }; - Type_ size; - while( ( p2size <= Max ) && ( p2size <= Value ) ) { - size = p2size; - p2size = p2size << 1; - } - return size; + Type_ p2size{Min}; + Type_ size; + while ((p2size <= Max) && (p2size <= Value)) + { + size = p2size; + p2size = p2size << 1; + } + return size; } -template -Type_ -quantize( Type_ const Value, Type_ const Step ) { +template Type_ quantize(Type_ const Value, Type_ const Step) +{ - return ( Step * std::round( Value / Step ) ); + return (Step * std::round(Value / Step)); } -template -Type_ -min_speed( Type_ const Left, Type_ const Right ) { +template Type_ min_speed(Type_ const Left, Type_ const Right) +{ - if( Left == Right ) { return Left; } + if (Left == Right) + { + return Left; + } - return std::min( - ( Left != -1 ? - Left : - std::numeric_limits::max() ), - ( Right != -1 ? - Right : - std::numeric_limits::max() ) ); + return std::min((Left != -1 ? Left : std::numeric_limits::max()), (Right != -1 ? Right : std::numeric_limits::max())); } -template -Type_ -interpolate( Type_ const &First, Type_ const &Second, float const Factor ) { +template Type_ interpolate(Type_ const &First, Type_ const &Second, float const Factor) +{ - return static_cast( ( First * ( 1.0f - Factor ) ) + ( Second * Factor ) ); + return static_cast((First * (1.0f - Factor)) + (Second * Factor)); } -template -Type_ -interpolate( Type_ const &First, Type_ const &Second, double const Factor ) { +template Type_ interpolate(Type_ const &First, Type_ const &Second, double const Factor) +{ - return static_cast( ( First * ( 1.0 - Factor ) ) + ( Second * Factor ) ); + return static_cast((First * (1.0 - Factor)) + (Second * Factor)); } template Type_ smoothInterpolate(Type_ const &First, Type_ const &Second, double Factor) @@ -345,124 +343,120 @@ template Type_ smoothInterpolate(Type_ const &First, Type_ cons } // tests whether provided points form a degenerate triangle -template -bool -degenerate( VecType_ const &Vertex1, VecType_ const &Vertex2, VecType_ const &Vertex3 ) { +template bool degenerate(VecType_ const &Vertex1, VecType_ const &Vertex2, VecType_ const &Vertex3) +{ - // degenerate( A, B, C, minarea ) = ( ( B - A ).cross( C - A ) ).lengthSquared() < ( 4.0f * minarea * minarea ); - return ( glm::length2( glm::cross( Vertex2 - Vertex1, Vertex3 - Vertex1 ) ) == 0.0 ); + // degenerate( A, B, C, minarea ) = ( ( B - A ).cross( C - A ) ).lengthSquared() < ( 4.0f * minarea * minarea ); + return (glm::length2(glm::cross(Vertex2 - Vertex1, Vertex3 - Vertex1)) == 0.0); } // calculates bounding box for provided set of points -template -void -bounding_box( VecType_ &Mincorner, VecType_ &Maxcorner, Iterator_ First, Iterator_ Last ) { +template void bounding_box(VecType_ &Mincorner, VecType_ &Maxcorner, Iterator_ First, Iterator_ Last) +{ - Mincorner = VecType_( std::numeric_limits::max() ); - Maxcorner = VecType_( std::numeric_limits::lowest() ); + Mincorner = VecType_(std::numeric_limits::max()); + Maxcorner = VecType_(std::numeric_limits::lowest()); - std::for_each( - First, Last, - [&]( typename Iterator_::value_type &point ) { - Mincorner = glm::min( Mincorner, VecType_{ point } ); - Maxcorner = glm::max( Maxcorner, VecType_{ point } ); } ); + std::for_each(First, Last, + [&](typename Iterator_::value_type &point) + { + Mincorner = glm::min(Mincorner, VecType_{point}); + Maxcorner = glm::max(Maxcorner, VecType_{point}); + }); } // finds point on specified segment closest to specified point in 3d space. returns: point on segment as value in range 0-1 where 0 = start and 1 = end of the segment -template -typename VecType_::value_type -nearest_segment_point( VecType_ const &Segmentstart, VecType_ const &Segmentend, VecType_ const &Point ) { +template typename VecType_::value_type nearest_segment_point(VecType_ const &Segmentstart, VecType_ const &Segmentend, VecType_ const &Point) +{ - auto const v = Segmentend - Segmentstart; - auto const w = Point - Segmentstart; + auto const v = Segmentend - Segmentstart; + auto const w = Point - Segmentstart; - auto const c1 = glm::dot( w, v ); - if( c1 <= 0.0 ) { - return 0.0; - } - auto const c2 = glm::dot( v, v ); - if( c2 <= c1 ) { - return 1.0; - } - return c1 / c2; + auto const c1 = glm::dot(w, v); + if (c1 <= 0.0) + { + return 0.0; + } + auto const c2 = glm::dot(v, v); + if (c2 <= c1) + { + return 1.0; + } + return c1 / c2; } -glm::dvec3 LoadPoint( class cParser &Input ); +glm::dvec3 LoadPoint(class cParser &Input); // extracts a group of tokens from provided data stream -std::string -deserialize_random_set( cParser &Input, char const *Break = "\n\r\t ;" ); +std::string deserialize_random_set(cParser &Input, char const *Break = "\n\r\t ;"); -int count_trailing_zeros( uint32_t val ); +int count_trailing_zeros(uint32_t val); // extracts a group of pairs from provided data stream // NOTE: expects no more than single pair per line -template -void -deserialize_map( MapType_ &Map, cParser &Input ) { +template void deserialize_map(MapType_ &Map, cParser &Input) +{ - while( Input.ok() && !Input.eof() ) { - auto const key { Input.getToken( false ) }; - auto const value { Input.getToken( false, "\n" ) }; - Map.emplace( key, value ); - } + while (Input.ok() && !Input.eof()) + { + auto const key{Input.getToken(false)}; + auto const value{Input.getToken(false, "\n")}; + Map.emplace(key, value); + } } -namespace threading { +namespace threading +{ // simple POD pairing of a data item and a mutex // NOTE: doesn't do any locking itself, it's merely for cleaner argument arrangement and passing -template -struct lockable { +template struct lockable +{ - Type_ data; - std::mutex mutex; + Type_ data; + std::mutex mutex; }; // basic wrapper simplifying use of std::condition_variable for most typical cases. // has its own mutex and secondary variable to ignore spurious wakeups -class condition_variable { +class condition_variable +{ -public: -// methods - void - wait() { - std::unique_lock lock( m_mutex ); - m_condition.wait( - lock, - [ this ]() { - return m_spurious == false; } ); } - template< class Rep_, class Period_ > - void - wait_for( const std::chrono::duration &Time ) { - std::unique_lock lock( m_mutex ); - m_condition.wait_for( - lock, - Time, - [ this ]() { - return m_spurious == false; } ); } - void - notify_one() { - spurious( false ); - m_condition.notify_one(); - } - void - notify_all() { - spurious( false ); - m_condition.notify_all(); - } - void - spurious( bool const Spurious ) { - std::lock_guard lock( m_mutex ); - m_spurious = Spurious; } + public: + // methods + void wait() + { + std::unique_lock lock(m_mutex); + m_condition.wait(lock, [this]() { return m_spurious == false; }); + } + template void wait_for(const std::chrono::duration &Time) + { + std::unique_lock lock(m_mutex); + m_condition.wait_for(lock, Time, [this]() { return m_spurious == false; }); + } + void notify_one() + { + spurious(false); + m_condition.notify_one(); + } + void notify_all() + { + spurious(false); + m_condition.notify_all(); + } + void spurious(bool const Spurious) + { + std::lock_guard lock(m_mutex); + m_spurious = Spurious; + } -private: -// members - mutable std::mutex m_mutex; - std::condition_variable m_condition; - bool m_spurious { true }; + private: + // members + mutable std::mutex m_mutex; + std::condition_variable m_condition; + bool m_spurious{true}; }; -} // threading +} // namespace threading //---------------------------------------------------------------------------